Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
6 changes: 4 additions & 2 deletions cmd/root/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/agentfile"
"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/config"
"github.com/docker/cagent/pkg/remote"
"github.com/docker/cagent/pkg/server"
Expand Down Expand Up @@ -58,6 +59,7 @@ func (f *apiFlags) runAPICommand(cmd *cobra.Command, args []string) error {
telemetry.TrackCommand("api", args)

ctx := cmd.Context()
out := cli.NewPrinter(cmd.OutOrStdout())
agentsPath := args[0]

// Make sure no question is ever asked to the user in api mode.
Expand All @@ -67,7 +69,7 @@ func (f *apiFlags) runAPICommand(cmd *cobra.Command, args []string) error {
return fmt.Errorf("--pull-interval flag can only be used with OCI references, not local files")
}

resolvedPath, err := agentfile.Resolve(ctx, agentsPath)
resolvedPath, err := agentfile.Resolve(ctx, out, agentsPath)
if err != nil {
return err
}
Expand Down Expand Up @@ -139,7 +141,7 @@ func (f *apiFlags) runAPICommand(cmd *cobra.Command, args []string) error {
}

// Resolve the OCI reference to get the updated file path
newResolvedPath, err := agentfile.Resolve(ctx, agentsPath)
newResolvedPath, err := agentfile.Resolve(ctx, out, agentsPath)
if err != nil {
slog.Error("Failed to resolve OCI reference after pull", "reference", agentsPath, "error", err)
continue
Expand Down
6 changes: 5 additions & 1 deletion cmd/root/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package root
import (
"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/filesystem"
"github.com/docker/cagent/pkg/oci"
"github.com/docker/cagent/pkg/telemetry"
Expand Down Expand Up @@ -33,11 +34,14 @@ func newBuildCmd() *cobra.Command {
func (f *buildFlags) runBuildCommand(cmd *cobra.Command, args []string) error {
telemetry.TrackCommand("build", args)

ctx := cmd.Context()
out := cli.NewPrinter(cmd.OutOrStdout())

agentFilePath := args[0]
dockerImageName := ""
if len(args) > 1 {
dockerImageName = args[1]
}

return oci.BuildDockerImage(cmd.Context(), agentFilePath, filesystem.AllowAll, dockerImageName, f.opts)
return oci.BuildDockerImage(ctx, out, agentFilePath, filesystem.AllowAll, dockerImageName, f.opts)
}
11 changes: 6 additions & 5 deletions cmd/root/eval.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
package root

import (
"fmt"

"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/config"
"github.com/docker/cagent/pkg/evaluation"
"github.com/docker/cagent/pkg/teamloader"
Expand Down Expand Up @@ -33,6 +32,8 @@ func newEvalCmd() *cobra.Command {
func (f *evalFlags) runEvalCommand(cmd *cobra.Command, args []string) error {
telemetry.TrackCommand("eval", args)

out := cli.NewPrinter(cmd.OutOrStdout())

agents, err := teamloader.Load(cmd.Context(), args[0], f.runConfig)
if err != nil {
return err
Expand All @@ -44,9 +45,9 @@ func (f *evalFlags) runEvalCommand(cmd *cobra.Command, args []string) error {
}

for _, evalResult := range evalResults {
fmt.Printf("Eval file: %s\n", evalResult.EvalFile)
fmt.Printf("Tool trajectory score: %f\n", evalResult.Score.ToolTrajectoryScore)
fmt.Printf("Rouge-1 score: %f\n", evalResult.Score.Rouge1Score)
out.Printf("Eval file: %s\n", evalResult.EvalFile)
out.Printf("Tool trajectory score: %f\n", evalResult.Score.ToolTrajectoryScore)
out.Printf("Rouge-1 score: %f\n", evalResult.Score.Rouge1Score)
}

return nil
Expand Down
5 changes: 4 additions & 1 deletion cmd/root/mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package root
import (
"github.com/spf13/cobra"

"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/config"
"github.com/docker/cagent/pkg/mcp"
"github.com/docker/cagent/pkg/telemetry"
Expand Down Expand Up @@ -35,11 +36,13 @@ func newMCPCmd() *cobra.Command {

func (f *mcpFlags) runMCPCommand(cmd *cobra.Command, args []string) error {
telemetry.TrackCommand("mcp", args)

ctx := cmd.Context()
out := cli.NewPrinter(cmd.OutOrStdout())

if err := setupWorkingDirectory(f.workingDir); err != nil {
return err
}

return mcp.StartMCPServer(ctx, args[0], f.runConfig)
return mcp.StartMCPServer(ctx, out, args[0], f.runConfig)
}
6 changes: 3 additions & 3 deletions cmd/root/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func (f *runExecFlags) runOrExec(ctx context.Context, out *cli.Printer, args []s
return err
}
} else {
agentFileName, err = f.resolveAgentFile(ctx, args[0])
agentFileName, err = f.resolveAgentFile(ctx, out, args[0])
if err != nil {
return err
}
Expand Down Expand Up @@ -127,11 +127,11 @@ func (f *runExecFlags) setupWorkingDirectory() error {

// resolveAgentFile is a wrapper method that calls the agentfile.Resolve function
// after checking for remote address
func (f *runExecFlags) resolveAgentFile(ctx context.Context, agentFilename string) (string, error) {
func (f *runExecFlags) resolveAgentFile(ctx context.Context, out *cli.Printer, agentFilename string) (string, error) {
if f.remoteAddress != "" {
return agentFilename, nil
}
return agentfile.Resolve(ctx, agentFilename)
return agentfile.Resolve(ctx, out, agentFilename)
}

func (f *runExecFlags) loadAgents(ctx context.Context, agentFilename string) (*team.Team, error) {
Expand Down
14 changes: 7 additions & 7 deletions cmd/root/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ agents:
defer cancel()

// Test resolving a local file
resolved, err := agentfile.Resolve(ctx, yamlFile)
resolved, err := agentfile.Resolve(ctx, nil, yamlFile)
require.NoError(t, err)

// Should return absolute path
Expand Down Expand Up @@ -115,7 +115,7 @@ agents:
defer cancel()

// First resolution
resolved1, err := agentfile.Resolve(ctx, ociRef)
resolved1, err := agentfile.Resolve(ctx, nil, ociRef)
require.NoError(t, err)
assert.NotEmpty(t, resolved1)

Expand All @@ -132,7 +132,7 @@ agents:
firstResolvedPath := resolved1

// Second resolution (simulating a reload)
resolved2, err := agentfile.Resolve(ctx, ociRef)
resolved2, err := agentfile.Resolve(ctx, nil, ociRef)
require.NoError(t, err)

// Should return the SAME filename
Expand All @@ -158,7 +158,7 @@ agents:
require.NoError(t, err)

// Third resolution (simulating reload after update)
resolved3, err := agentfile.Resolve(ctx, ociRef)
resolved3, err := agentfile.Resolve(ctx, nil, ociRef)
require.NoError(t, err)

// Should STILL use the same filename
Expand Down Expand Up @@ -211,10 +211,10 @@ agents:
defer cancel()

// Resolve both OCI refs
resolved1, err := agentfile.Resolve(ctx, ociRef1)
resolved1, err := agentfile.Resolve(ctx, nil, ociRef1)
require.NoError(t, err)

resolved2, err := agentfile.Resolve(ctx, ociRef2)
resolved2, err := agentfile.Resolve(ctx, nil, ociRef2)
require.NoError(t, err)

// Should have DIFFERENT filenames
Expand Down Expand Up @@ -262,7 +262,7 @@ agents:
ctx, cancel := context.WithCancel(t.Context())

// Resolve the OCI ref
resolved, err := agentfile.Resolve(ctx, ociRef)
resolved, err := agentfile.Resolve(ctx, nil, ociRef)
require.NoError(t, err)
assert.FileExists(t, resolved)

Expand Down
7 changes: 4 additions & 3 deletions cmd/root/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,10 @@ func newVersionCmd() *cobra.Command {
}
}

func runVersionCommand(_ *cobra.Command, args []string) {
func runVersionCommand(cmd *cobra.Command, args []string) {
telemetry.TrackCommand("version", args)

fmt.Printf("cagent version %s\n", version.Version)
fmt.Printf("Commit: %s\n", version.Commit)
out := cmd.OutOrStdout()
fmt.Fprintf(out, "cagent version %s\n", version.Version)
fmt.Fprintf(out, "Commit: %s\n", version.Commit)
}
5 changes: 3 additions & 2 deletions pkg/agentfile/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"strings"

"github.com/docker/cagent/pkg/aliases"
"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/content"
"github.com/docker/cagent/pkg/remote"
)
Expand Down Expand Up @@ -55,7 +56,7 @@ func OciRefToFilename(ociRef string) string {
}

// Resolve resolves an agent file reference (local file or OCI image) to a local file path
func Resolve(ctx context.Context, agentFilename string) (string, error) {
func Resolve(ctx context.Context, out *cli.Printer, agentFilename string) (string, error) {
originalOCIRef := agentFilename // Store the original for OCI ref tracking

// Try to resolve as an alias first
Expand Down Expand Up @@ -83,7 +84,7 @@ func Resolve(ctx context.Context, agentFilename string) (string, error) {
// Treat as an OCI image reference. Try local store first, otherwise pull then load.
a, err := FromStore(agentFilename)
if err != nil {
fmt.Println("Pulling agent", agentFilename)
out.Println("Pulling agent", agentFilename)
if _, pullErr := remote.Pull(agentFilename); pullErr != nil {
return "", fmt.Errorf("failed to pull OCI image %s: %w", agentFilename, pullErr)
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/cli/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/base64"
"fmt"
"io"
"log/slog"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -397,7 +398,7 @@ func createUserMessageWithAttachment(agentFilename, userContent, attachmentPath
// Convert file to data URL
dataURL, err := fileToDataURL(attachmentPath)
if err != nil {
fmt.Printf("Warning: Failed to attach file %s: %v\n", attachmentPath, err)
slog.Warn("Failed to attach file", "path", attachmentPath, "error", err)
return session.UserMessage(agentFilename, userContent)
}

Expand Down
5 changes: 3 additions & 2 deletions pkg/creator/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
_ "embed"
"encoding/json"
"fmt"
"log/slog"
"os"
"path/filepath"
"strings"
Expand Down Expand Up @@ -91,7 +92,7 @@ func CreateAgent(ctx context.Context, baseDir, prompt string, runConfig config.R
return "", "", fmt.Errorf("failed to create LLM client: %w", err)
}

fmt.Println("Generating agent configuration....")
slog.Info("Generating agent configuration....")

fsToolset := fsToolset{inner: builtin.NewFilesystemTool([]string{baseDir})}
fileName := filepath.Base(fsToolset.path)
Expand Down Expand Up @@ -142,7 +143,7 @@ func Agent(ctx context.Context, baseDir string, runConfig config.RuntimeConfig,
if modelNameOverride != "" {
modelName = modelNameOverride
} else {
fmt.Printf("Using default model: %s\n", modelName)
slog.Info("Using default model: " + modelName)
}

// If not using a model gateway, avoid selecting a provider the user can't run
Expand Down
5 changes: 3 additions & 2 deletions pkg/mcp/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/modelcontextprotocol/go-sdk/mcp"

"github.com/docker/cagent/pkg/agentfile"
"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/config"
"github.com/docker/cagent/pkg/runtime"
"github.com/docker/cagent/pkg/session"
Expand All @@ -25,10 +26,10 @@ type ToolOutput struct {
Response string `json:"response" jsonschema:"the response from the agent"`
}

func StartMCPServer(ctx context.Context, agentFilename string, runConfig config.RuntimeConfig) error {
func StartMCPServer(ctx context.Context, out *cli.Printer, agentFilename string, runConfig config.RuntimeConfig) error {
slog.Debug("Starting MCP server", "agent_ref", agentFilename)

agentFilename, err := agentfile.Resolve(ctx, agentFilename)
agentFilename, err := agentfile.Resolve(ctx, out, agentFilename)
if err != nil {
return err
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/modelsdev/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"io"
"log/slog"
"net/http"
"os"
"path/filepath"
Expand Down Expand Up @@ -91,7 +92,7 @@ func (s *Store) GetDatabase(ctx context.Context) (*Database, error) {
// Save to cache
if err := s.saveToCache(cacheFile, database); err != nil {
// Log the error but don't fail the request
fmt.Printf("Warning: failed to save to cache: %v\n", err)
slog.Warn("Warning: failed to save to cache", "error", err)
}

return database, nil
Expand Down
6 changes: 3 additions & 3 deletions pkg/oci/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"context"
_ "embed"
"fmt"
"log/slog"
"os"
"os/exec"
Expand All @@ -14,6 +13,7 @@ import (

"github.com/goccy/go-yaml"

"github.com/docker/cagent/pkg/cli"
"github.com/docker/cagent/pkg/config"
"github.com/docker/cagent/pkg/filesystem"
)
Expand All @@ -28,7 +28,7 @@ type Options struct {
Pull bool
}

func BuildDockerImage(ctx context.Context, agentFilePath string, fs filesystem.FS, dockerImageName string, opts Options) error {
func BuildDockerImage(ctx context.Context, out *cli.Printer, agentFilePath string, fs filesystem.FS, dockerImageName string, opts Options) error {
cfg, err := config.LoadConfig(agentFilePath, fs)
if err != nil {
return err
Expand Down Expand Up @@ -71,7 +71,7 @@ func BuildDockerImage(ctx context.Context, agentFilePath string, fs filesystem.F

dockerfile := dockerfileBuf.String()
if opts.DryRun {
fmt.Println(dockerfile)
out.Println(dockerfile)
return nil
}

Expand Down
1 change: 0 additions & 1 deletion pkg/remote/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ func Pull(registryRef string, opts ...crane.Option) (string, error) {

if meta, metaErr := store.GetArtifactMetadata(localRef); metaErr == nil {
if meta.Digest == remoteDigest {
fmt.Printf("Artifact %s already exists in the store (digest %s). Using cache.\n", localRef, remoteDigest)
return meta.Digest, nil
}
}
Expand Down
Loading