Skip to content

Commit e2aca72

Browse files
committed
Merge branch 'main' of https://github.com/venkat1701/cagent
2 parents 8f0d456 + deaaafa commit e2aca72

145 files changed

Lines changed: 7920 additions & 1399 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
agents:
2+
root:
3+
model: anthropic/claude-sonnet-4-5
4+
instruction: |
5+
You are a code reviewer. Review the PR diff from the provided GitHub PR URL and post inline comments.
6+
The user's message contains a GitHub Pull Request URL (e.g., https://github.com/owner/repo/pull/123).
7+
8+
Steps:
9+
1. Use the shell to call "gh" to get all of the information about the Pr
10+
2. Review the PR diff, focusing on lines that were ADDED (+) or MODIFIED.
11+
3. Make sure to get the overall picture about the changes, read the files from the current directory as needed
12+
4. Review the code changes in detail
13+
5. Use gh to add inline comments for specific lines of code that need attention
14+
6. Post the review to GitHub using gh CLI:
15+
a. Create a JSON payload for the review with inline comments
16+
b. Use shell tool to execute:
17+
```
18+
echo '{"body":"OVERALL_SUMMARY","event":"COMMENT","comments":[{"path":"FILE","line":LINE,"body":"COMMENT"},...]}' | \
19+
gh api repos/{owner}/{repo}/pulls/{pr}/reviews --input -
20+
```
21+
c. Map your verdict to event: "APPROVE", "REQUEST_CHANGES", or "COMMENT"
22+
23+
## Review Focus
24+
**Code Quality:** Readability, naming, structure, DRY
25+
**Correctness:** Logic errors, edge cases, error handling, type safety
26+
**Security:** Input validation, SQL/XSS vulnerabilities, hardcoded secrets
27+
**Performance:** Inefficient algorithms, unnecessary operations, memory leaks
28+
**Best Practices:** Framework conventions, testing, documentation, accessibility
29+
30+
# Go Specialization to Add
31+
32+
## Focus Areas (for `+` lines only)
33+
- **Correctness:** Control flow, edge cases, nil checks
34+
- **Idiomatic Go:** Conventions, stdlib patterns
35+
- **Error Handling:** Proper wrapping (fmt.Errorf %w), sentinel errors, avoid panic
36+
- **Concurrency:** Race conditions, mutex usage, channels, context cancellation
37+
- **Performance:** Unnecessary allocations, strings.Builder, efficient algorithms
38+
- **Context:** As first parameter, respect cancellation, don't store in structs
39+
- **Resource Management:** Proper defer (Close, Unlock), no leaks
40+
- **Interfaces:** Accept interfaces, return structs, small focused interfaces
41+
- **Testing:** testify, table-driven tests, proper naming
42+
- **Security:** SQL/command injection, input validation, hardcoded secrets
43+
- `interface{}`/`any` without type assertions
44+
- Not checking error returns
45+
- Goroutine leaks
46+
- Mutex copied by value
47+
- Range variable capture in goroutines
48+
- Comparing errors with == (use errors.Is/As)
49+
50+
**Be constructive, concise, specific, respectful.**
51+
toolsets:
52+
- type: filesystem
53+
tools: [read_file, read_multiple_files, list_directory, directory_tree]
54+
- type: shell
55+
56+
permissions:
57+
allow:
58+
- shell:cmd=gh *

.github/workflows/pr-review.yml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
name: PR Review on Command
2+
3+
on:
4+
issue_comment:
5+
types: [created]
6+
7+
permissions:
8+
contents: read
9+
pull-requests: write
10+
issues: write
11+
12+
jobs:
13+
run-review:
14+
if: github.event.issue.pull_request && contains(github.event.comment.body, '/review')
15+
runs-on: ubuntu-latest
16+
steps:
17+
- name: Checkout repository
18+
uses: actions/checkout@v4
19+
20+
- name: Run PR Reviewer Agent
21+
uses: docker/cagent-action@1f7ec0445e138a587639fc9c046076e22d184349
22+
with:
23+
cagent-version: "v1.19.1"
24+
agent: ${{ github.workspace }}/.github/workflows/agents/pr-review.yaml
25+
prompt: "Please review this GitHub Pull Request: https://github.com/${{ github.repository }}/pull/${{ github.event.issue.number }}"
26+
mcp-gateway: true
27+
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
28+
github-token: ${{ secrets.GITHUB_TOKEN }}

AGENTS.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,7 @@ for _, tt := range tests {
239239
- All agent references must exist in config
240240
- Model references can be inline (e.g., `openai/gpt-4o`) or defined in models section
241241
- Tool configurations validated at startup
242-
- Config versioning: Currently on v3 (sequential migration: v0 → v1 → v2 → v3)
242+
- Config versioning
243243
- Environment variables not stored in configs - gathered dynamically at startup
244244
- Missing required env vars (e.g., API keys) trigger startup errors
245245

@@ -1005,7 +1005,7 @@ task push-image # Build and push multi-platform
10051005
| `pkg/agent/agent.go` | Agent abstraction, tool discovery |
10061006
| `pkg/session/session.go` | Message history management |
10071007
| `pkg/config/config.go` | Config loading, versioning, migration |
1008-
| `pkg/config/latest/types.go` | Current config schema (v3) |
1008+
| `pkg/config/latest/types.go` | Current config schema |
10091009
| `pkg/tools/tools.go` | Tool interface definitions |
10101010
| `pkg/tools/builtin/` | Built-in tool implementations |
10111011
| `pkg/tools/mcp/` | MCP protocol client implementations |

README.md

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -100,14 +100,17 @@ corresponding provider API key accordingly, all these keys are optional, you
100100
will likely need at least one of these, though:
101101

102102
```bash
103-
export OPENAI_API_KEY=your_api_key_here # For OpenAI models
104-
export ANTHROPIC_API_KEY=your_api_key_here # For Anthropic models
105-
export GOOGLE_API_KEY=your_api_key_here # For Gemini models
106-
export XAI_API_KEY=your_api_key_here # For xAI models
107-
export NEBIUS_API_KEY=your_api_key_here # For Nebius models
108-
export MISTRAL_API_KEY=your_api_key_here # For Mistral models
103+
export OPENAI_API_KEY=your_api_key_here # For OpenAI models
104+
export ANTHROPIC_API_KEY=your_api_key_here # For Anthropic models
105+
export GOOGLE_API_KEY=your_api_key_here # For Gemini models
106+
export AWS_BEARER_TOKEN_BEDROCK=your_api_key_here # For AWS Bedrock available models
107+
export XAI_API_KEY=your_api_key_here # For xAI models
108+
export NEBIUS_API_KEY=your_api_key_here # For Nebius models
109+
export MISTRAL_API_KEY=your_api_key_here # For Mistral models
109110
```
110111

112+
**Note:** For the different AWS Bedrock authentication options, take a look [here](docs/USAGE.md#aws-bedrock-provider-usage).
113+
111114
### Run Agents!
112115

113116
```bash
@@ -530,5 +533,4 @@ features!
530533

531534
## Share your feedback
532535

533-
We’d love to hear your thoughts on this project. You can find us on
534-
[Slack](https://dockercommunity.slack.com/archives/C09DASHHRU4)
536+
We’d love to hear your thoughts on this project. Feel free to join the [Docker Community Slack workspace](http://dockr.ly/comm-slack) and the [cagent Slack channel](https://dockercommunity.slack.com/archives/C09DASHHRU4).

Taskfile.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ tasks:
5555
test:
5656
aliases: [t]
5757
desc: Run tests
58-
cmd: OPENAI_API_KEY= ANTHROPIC_API_KEY= GOOGLE_API_KEY= MISTRAL_API_KEY= GITHUB_TOKEN= go test {{.CLI_ARGS}} ./...
58+
cmd: CAGENT_MODELS_GATEWAY= OPENAI_API_KEY= ANTHROPIC_API_KEY= GOOGLE_API_KEY= MISTRAL_API_KEY= GITHUB_TOKEN= go test {{.CLI_ARGS}} ./...
5959

6060
build-local:
6161
desc: Build binaries for local host platform

cagent-schema.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"$schema": "http://json-schema.org/draft-07/schema#",
33
"$id": "https://github.com/cagent/cagent/blob/main/cagent-schema.json",
44
"title": "Cagent Configuration",
5-
"description": "Configuration schema for Cagent v3",
5+
"description": "Configuration schema for Cagent v4",
66
"type": "object",
77
"properties": {
88
"version": {
@@ -12,13 +12,15 @@
1212
"0",
1313
"1",
1414
"2",
15-
"3"
15+
"3",
16+
"4"
1617
],
1718
"examples": [
1819
"0",
1920
"1",
2021
"2",
21-
"3"
22+
"3",
23+
"4"
2224
]
2325
},
2426
"providers": {

cmd/root/alias.go

Lines changed: 82 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@ import (
99
"github.com/mattn/go-runewidth"
1010
"github.com/spf13/cobra"
1111

12-
"github.com/docker/cagent/pkg/aliases"
1312
"github.com/docker/cagent/pkg/cli"
1413
"github.com/docker/cagent/pkg/paths"
1514
"github.com/docker/cagent/pkg/telemetry"
15+
"github.com/docker/cagent/pkg/userconfig"
1616
)
1717

1818
func newAliasCmd() *cobra.Command {
@@ -41,13 +41,45 @@ func newAliasCmd() *cobra.Command {
4141
return cmd
4242
}
4343

44+
type aliasAddFlags struct {
45+
yolo bool
46+
model string
47+
}
48+
4449
func newAliasAddCmd() *cobra.Command {
45-
return &cobra.Command{
50+
var flags aliasAddFlags
51+
52+
cmd := &cobra.Command{
4653
Use: "add <alias-name> <agent-path>",
4754
Short: "Add a new alias",
48-
Args: cobra.ExactArgs(2),
49-
RunE: runAliasAddCommand,
55+
Long: `Add a new alias for an agent configuration or catalog reference.
56+
57+
You can optionally specify runtime options that will be applied whenever
58+
the alias is used:
59+
60+
--yolo Automatically approve all tool calls without prompting
61+
--model Override the agent's model (format: [agent=]provider/model)`,
62+
Example: ` # Create a simple alias
63+
cagent alias add code agentcatalog/notion-expert
64+
65+
# Create an alias that always runs in yolo mode
66+
cagent alias add yolo-coder agentcatalog/coder --yolo
67+
68+
# Create an alias with a specific model
69+
cagent alias add fast-coder agentcatalog/coder --model openai/gpt-4o-mini
70+
71+
# Create an alias with both options
72+
cagent alias add turbo agentcatalog/coder --yolo --model anthropic/claude-sonnet-4-0`,
73+
Args: cobra.ExactArgs(2),
74+
RunE: func(cmd *cobra.Command, args []string) error {
75+
return runAliasAddCommand(cmd, args, &flags)
76+
},
5077
}
78+
79+
cmd.Flags().BoolVar(&flags.yolo, "yolo", false, "Automatically approve all tool calls without prompting")
80+
cmd.Flags().StringVar(&flags.model, "model", "", "Override agent model (format: [agent=]provider/model)")
81+
82+
return cmd
5183
}
5284

5385
func newAliasListCmd() *cobra.Command {
@@ -70,17 +102,17 @@ func newAliasRemoveCmd() *cobra.Command {
70102
}
71103
}
72104

73-
func runAliasAddCommand(cmd *cobra.Command, args []string) error {
105+
func runAliasAddCommand(cmd *cobra.Command, args []string, flags *aliasAddFlags) error {
74106
telemetry.TrackCommand("alias", append([]string{"add"}, args...))
75107

76108
out := cli.NewPrinter(cmd.OutOrStdout())
77109
name := args[0]
78110
agentPath := args[1]
79111

80-
// Load existing aliases
81-
s, err := aliases.Load()
112+
// Load existing config
113+
cfg, err := userconfig.Load()
82114
if err != nil {
83-
return fmt.Errorf("failed to load aliases: %w", err)
115+
return fmt.Errorf("failed to load config: %w", err)
84116
}
85117

86118
// Expand tilde in path if it's a local file path
@@ -89,17 +121,32 @@ func runAliasAddCommand(cmd *cobra.Command, args []string) error {
89121
return err
90122
}
91123

124+
// Create alias with options
125+
alias := &userconfig.Alias{
126+
Path: absAgentPath,
127+
Yolo: flags.yolo,
128+
Model: flags.model,
129+
}
130+
92131
// Store the alias
93-
s.Set(name, absAgentPath)
132+
if err := cfg.SetAlias(name, alias); err != nil {
133+
return err
134+
}
94135

95136
// Save to file
96-
if err := s.Save(); err != nil {
97-
return fmt.Errorf("failed to save aliases: %w", err)
137+
if err := cfg.Save(); err != nil {
138+
return fmt.Errorf("failed to save config: %w", err)
98139
}
99140

100141
out.Printf("Alias '%s' created successfully\n", name)
101142
out.Printf(" Alias: %s\n", name)
102143
out.Printf(" Agent: %s\n", absAgentPath)
144+
if flags.yolo {
145+
out.Printf(" Yolo: enabled\n")
146+
}
147+
if flags.model != "" {
148+
out.Printf(" Model: %s\n", flags.model)
149+
}
103150

104151
if name == "default" {
105152
out.Printf("\nYou can now run: cagent run %s (or even cagent run)\n", name)
@@ -115,12 +162,12 @@ func runAliasListCommand(cmd *cobra.Command, args []string) error {
115162

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

118-
s, err := aliases.Load()
165+
cfg, err := userconfig.Load()
119166
if err != nil {
120-
return fmt.Errorf("failed to load aliases: %w", err)
167+
return fmt.Errorf("failed to load config: %w", err)
121168
}
122169

123-
allAliases := s.List()
170+
allAliases := cfg.Aliases
124171
if len(allAliases) == 0 {
125172
out.Println("No aliases registered.")
126173
out.Println("\nCreate an alias with: cagent alias add <name> <agent-path>")
@@ -143,9 +190,23 @@ func runAliasListCommand(cmd *cobra.Command, args []string) error {
143190
}
144191

145192
for _, name := range names {
146-
path := allAliases[name]
193+
alias := allAliases[name]
147194
padding := strings.Repeat(" ", maxLen-runewidth.StringWidth(name))
148-
out.Printf(" %s%s → %s\n", name, padding, path)
195+
196+
// Build options string
197+
var options []string
198+
if alias.Yolo {
199+
options = append(options, "yolo")
200+
}
201+
if alias.Model != "" {
202+
options = append(options, "model="+alias.Model)
203+
}
204+
205+
if len(options) > 0 {
206+
out.Printf(" %s%s → %s [%s]\n", name, padding, alias.Path, strings.Join(options, ", "))
207+
} else {
208+
out.Printf(" %s%s → %s\n", name, padding, alias.Path)
209+
}
149210
}
150211

151212
out.Println("\nRun an alias with: cagent run <alias>")
@@ -159,17 +220,17 @@ func runAliasRemoveCommand(cmd *cobra.Command, args []string) error {
159220
out := cli.NewPrinter(cmd.OutOrStdout())
160221
name := args[0]
161222

162-
s, err := aliases.Load()
223+
cfg, err := userconfig.Load()
163224
if err != nil {
164-
return fmt.Errorf("failed to load aliases: %w", err)
225+
return fmt.Errorf("failed to load config: %w", err)
165226
}
166227

167-
if !s.Delete(name) {
228+
if !cfg.DeleteAlias(name) {
168229
return fmt.Errorf("alias '%s' not found", name)
169230
}
170231

171-
if err := s.Save(); err != nil {
172-
return fmt.Errorf("failed to save aliases: %w", err)
232+
if err := cfg.Save(); err != nil {
233+
return fmt.Errorf("failed to save config: %w", err)
173234
}
174235

175236
out.Printf("Alias '%s' removed successfully\n", name)

cmd/root/completion.go

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@ import (
88

99
"github.com/spf13/cobra"
1010

11-
"github.com/docker/cagent/pkg/aliases"
1211
"github.com/docker/cagent/pkg/config"
12+
"github.com/docker/cagent/pkg/userconfig"
1313
)
1414

1515
func completeRunExec(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
@@ -31,11 +31,11 @@ func completeAlias(toComplete string) ([]string, cobra.ShellCompDirective) {
3131
var candidates []string
3232

3333
// Add matching aliases
34-
s, err := aliases.Load()
34+
cfg, err := userconfig.Load()
3535
if err == nil {
36-
for k, v := range s.List() {
36+
for k, v := range cfg.Aliases {
3737
if strings.HasPrefix(k, toComplete) {
38-
candidates = append(candidates, k+"\t"+v)
38+
candidates = append(candidates, k+"\t"+v.Path)
3939
}
4040
}
4141
}
@@ -66,9 +66,13 @@ func completeMessage(cmd *cobra.Command, args []string, toComplete string) ([]st
6666
if agent == "" {
6767
agent = "root"
6868
}
69+
agentCfg, found := cfg.Agents.Lookup(agent)
70+
if !found {
71+
return nil, cobra.ShellCompDirectiveNoFileComp
72+
}
6973

7074
var candidates []string
71-
for k, v := range cfg.Agents[agent].Commands {
75+
for k, v := range agentCfg.Commands {
7276
if strings.HasPrefix("/"+k, toComplete) {
7377
candidates = append(candidates, "/"+k+"\t"+v.DisplayText())
7478
}

0 commit comments

Comments
 (0)