Skip to content
Closed
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/nightly-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ jobs:
scan:
runs-on: ubuntu-latest
timeout-minutes: 30
# Skip if no API keys are configured
if: |
secrets.ANTHROPIC_API_KEY != '' ||
secrets.OPENAI_API_KEY != '' ||
secrets.GEMINI_API_KEY != ''
env:
HAS_APP_SECRETS: ${{ secrets.CAGENT_REVIEWER_APP_ID != '' }}

Expand Down
13 changes: 8 additions & 5 deletions cmd/root/otel.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import (
"context"
"fmt"
"os"
"strings"
"time"

"github.com/docker/cagent/pkg/version"
"go.opentelemetry.io/otel"
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp"
"go.opentelemetry.io/otel/sdk/resource"
Expand All @@ -22,7 +24,7 @@ func initOTelSDK(ctx context.Context) (err error) {
resource.NewWithAttributes(
semconv.SchemaURL,
semconv.ServiceName(AppName),
semconv.ServiceVersion("dev"), // TODO: use actual version
semconv.ServiceVersion(version.Version),
),
)
if err != nil {
Expand All @@ -34,10 +36,11 @@ func initOTelSDK(ctx context.Context) (err error) {

// Only initialize if endpoint is configured
if endpoint != "" {
traceExporter, err = otlptracehttp.New(ctx,
otlptracehttp.WithEndpoint(endpoint),
otlptracehttp.WithInsecure(), // TODO: make configurable
)
opts := []otlptracehttp.Option{otlptracehttp.WithEndpoint(endpoint)}
if strings.HasPrefix(endpoint, "http://") {
opts = append(opts, otlptracehttp.WithInsecure())
}
traceExporter, err = otlptracehttp.New(ctx, opts...)
if err != nil {
return fmt.Errorf("failed to create trace exporter: %w", err)
}
Expand Down
21 changes: 21 additions & 0 deletions examples/new_agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env cagent run
## Generated by GitHub Copilot on 2026-02-05
agents:
new_agent:
model: openai/gpt-4o
description: "Scaffolded agent for concise help, code, and file tasks."
instruction: |
You are the `new_agent`. Follow these rules:
- Be concise, helpful, and actionable.
- Prefer short examples; provide runnable snippets when applicable.
- Ask a clarifying question if the user's intent is ambiguous.
toolsets:
- type: filesystem
- type: shell
- type: memory
path: ./examples/new_agent_memory.db
- type: think
max_iterations: 10
num_history_items: 20
add_date: true
code_mode_tools: true
9 changes: 9 additions & 0 deletions examples/scaffolded_default_agent.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
agents:
scaffolded_default:
model: openai/gpt-5-mini
description: "Scaffolded default agent"
instruction: |
You are a helpful assistant. Respond concisely and ask clarifying questions when necessary.
toolsets:
- type: think
- type: todo
11 changes: 8 additions & 3 deletions pkg/runtime/runtime.go
Original file line number Diff line number Diff line change
Expand Up @@ -1614,7 +1614,7 @@ func (r *LocalRuntime) executeToolWithHandler(
a *agent.Agent,
spanName string,
execute func(ctx context.Context) (*tools.ToolCallResult, time.Duration, error),
) {
) *tools.ToolCallResult {
ctx, span := r.startSpan(ctx, spanName, trace.WithAttributes(
attribute.String("tool.name", toolCall.Function.Name),
attribute.String("agent", a.Name()),
Expand Down Expand Up @@ -1660,6 +1660,7 @@ func (r *LocalRuntime) executeToolWithHandler(
CreatedAt: time.Now().Format(time.RFC3339),
}
addAgentMessage(sess, a, &toolResponseMsg, events)
return res
}

// runTool executes agent tools from toolsets (MCP, filesystem, etc.).
Expand Down Expand Up @@ -1693,7 +1694,7 @@ func (r *LocalRuntime) runTool(ctx context.Context, tool tools.Tool, toolCall to
}
}

r.executeToolWithHandler(ctx, toolCall, tool, events, sess, a, "runtime.tool.handler",
toolResult := r.executeToolWithHandler(ctx, toolCall, tool, events, sess, a, "runtime.tool.handler",
func(ctx context.Context) (*tools.ToolCallResult, time.Duration, error) {
res, err := tool.Handler(ctx, toolCall)
return res, 0, err
Expand All @@ -1702,13 +1703,17 @@ func (r *LocalRuntime) runTool(ctx context.Context, tool tools.Tool, toolCall to
// Execute post-tool hooks if configured
if hooksExec != nil && hooksExec.HasPostToolUseHooks() {
toolInput := parseToolInput(toolCall.Function.Arguments)
var toolResponse any
if toolResult != nil {
toolResponse = toolResult.Output
}
input := &hooks.Input{
SessionID: sess.ID,
Cwd: r.workingDir,
ToolName: toolCall.Function.Name,
ToolUseID: toolCall.ID,
ToolInput: toolInput,
ToolResponse: nil, // TODO: pass actual tool response if needed
ToolResponse: toolResponse,
}

result, err := hooksExec.ExecutePostToolUse(ctx, input)
Expand Down
7 changes: 4 additions & 3 deletions pkg/session/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,14 +96,15 @@ func (m *MigrationManager) isMigrationApplied(ctx context.Context, name string)
}

// applyMigration applies a single migration
func (m *MigrationManager) applyMigration(ctx context.Context, migration *Migration) error {
func (m *MigrationManager) applyMigration(ctx context.Context, migration *Migration) (retErr error) {
tx, err := m.db.BeginTx(ctx, nil)
if err != nil {
return err
}
defer func() {
// TODO: handle error
_ = tx.Rollback()
if rbErr := tx.Rollback(); rbErr != nil && !errors.Is(rbErr, sql.ErrTxDone) {
retErr = errors.Join(retErr, fmt.Errorf("failed to rollback migration transaction: %w", rbErr))
}
}()

// Execute SQL migration if present
Expand Down