Skip to content
Open
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ evals

# agents
agent.yaml
docker-agent.yaml
docker-agent.yml
vendor

# Local environment files
Expand Down
28 changes: 28 additions & 0 deletions pkg/config/resolve.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,36 @@ func singleSource(key string, source Source) Sources {
return Sources{key: source}
}

// autodiscoverConfigFile checks the current working directory for a
// docker-agent.yaml or docker-agent.yml file. It returns the absolute
// path of the first match found, or "" if neither file exists.
var autodiscoverConfigNames = []string{"docker-agent.yaml", "docker-agent.yml"}

func autodiscoverConfigFile() string {
wd, err := os.Getwd()
if err != nil {
return ""
}
for _, name := range autodiscoverConfigNames {
path := filepath.Join(wd, name)
if fileExists(path) {
slog.Debug("Auto-discovered agent config", "path", path)
return path
}
}
return ""
}

// resolve resolves an agent reference, handling aliases and defaults
func resolve(agentFilename string) (string, error) {
// When no agent file is specified, try to auto-discover a config file
// in the current directory before falling back to the embedded default.
if agentFilename == "" {
if discovered := autodiscoverConfigFile(); discovered != "" {
agentFilename = discovered
}
}

agentFilename = cmp.Or(agentFilename, "default")

// Try to resolve as an alias first
Expand Down
84 changes: 84 additions & 0 deletions pkg/config/resolve_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,96 @@ func TestResolveAgentFile_EmptyIsDefault(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

// Ensure no docker-agent.yaml in the working directory
t.Chdir(t.TempDir())

resolved, err := resolve("")

require.NoError(t, err)
assert.Equal(t, "default", resolved)
}

func TestResolveAgentFile_AutodiscoverYaml(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

dir := t.TempDir()
configFile := filepath.Join(dir, "docker-agent.yaml")
require.NoError(t, os.WriteFile(configFile, []byte(`version: "1"`), 0o644))
t.Chdir(dir)

resolved, err := resolve("")

require.NoError(t, err)
assert.Equal(t, configFile, resolved)
}

func TestResolveAgentFile_AutodiscoverYml(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

dir := t.TempDir()
configFile := filepath.Join(dir, "docker-agent.yml")
require.NoError(t, os.WriteFile(configFile, []byte(`version: "1"`), 0o644))
t.Chdir(dir)

resolved, err := resolve("")

require.NoError(t, err)
assert.Equal(t, configFile, resolved)
}

func TestResolveAgentFile_AutodiscoverYamlTakesPrecedenceOverYml(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

dir := t.TempDir()
primaryConfig := filepath.Join(dir, "docker-agent.yaml")
secondaryConfig := filepath.Join(dir, "docker-agent.yml")
require.NoError(t, os.WriteFile(primaryConfig, []byte(`version: "1"`), 0o644))
require.NoError(t, os.WriteFile(secondaryConfig, []byte(`version: "1"`), 0o644))
t.Chdir(dir)

resolved, err := resolve("")

require.NoError(t, err)
assert.Equal(t, primaryConfig, resolved)
}

func TestResolveAgentFile_AutodiscoverIgnoredWhenExplicitArg(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

dir := t.TempDir()
// Place a docker-agent.yaml in cwd
require.NoError(t, os.WriteFile(filepath.Join(dir, "docker-agent.yaml"), []byte(`version: "1"`), 0o644))
t.Chdir(dir)

// Explicitly passing "default" should not trigger autodiscovery
resolved, err := resolve("default")

require.NoError(t, err)
assert.Equal(t, "default", resolved)
}

func TestResolveAgentFile_AutodiscoverIgnoredWhenExplicitFile(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)

dir := t.TempDir()
// Place a docker-agent.yaml in cwd
require.NoError(t, os.WriteFile(filepath.Join(dir, "docker-agent.yaml"), []byte(`version: "1"`), 0o644))
// Place an explicit agent file
explicitFile := filepath.Join(dir, "my-agent.yaml")
require.NoError(t, os.WriteFile(explicitFile, []byte(`version: "1"`), 0o644))
t.Chdir(dir)

resolved, err := resolve(explicitFile)

require.NoError(t, err)
assert.Equal(t, explicitFile, resolved)
}

func TestResolveAgentFile_DefaultIsDefault(t *testing.T) {
home := t.TempDir()
t.Setenv("HOME", home)
Expand Down
4 changes: 2 additions & 2 deletions pkg/creator/instructions.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
You are an agent builder. Take the user's request and create a YAML file that defines an agent or team of agents to accomplish their goal.

Use the filesystem tool to write the agent YAML configuration to a file named after the agent's purpose (keep the filename short and descriptive).
Use the filesystem tool to write the agent YAML configuration to a file named `docker-agent.yaml` in the current directory.

You MUST define at least one agent named "root" - this is the entrypoint.

Expand Down Expand Up @@ -189,5 +189,5 @@ agents:
After writing the YAML file, tell the user to run their agent with:

```console
docker agent run <file.yaml>
docker agent
```