Skip to content

Commit ea6542a

Browse files
Copilotdgageot
andcommitted
Add tests and documentation for enable_bang_commands feature
- Add integration test for bang commands configuration loading - Update USAGE.md with enable_bang_commands documentation - Add security warning about bang commands - Document TUI bang commands feature with examples Co-authored-by: dgageot <153495+dgageot@users.noreply.github.com>
1 parent 9cc94e5 commit ea6542a

2 files changed

Lines changed: 114 additions & 0 deletions

File tree

docs/USAGE.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,18 @@ During CLI sessions, you can use special commands:
8484
| `/eval` | Save current conversation for evaluation |
8585
| `/compact` | Compact conversation to lower context usage |
8686

87+
#### TUI Bang Commands
88+
89+
When `enable_bang_commands: true` is set for an agent, you can execute shell commands directly in the TUI by prefixing them with `!`:
90+
91+
```
92+
!ls -la
93+
!pwd
94+
!echo "Hello from shell"
95+
```
96+
97+
**⚠️ Security Note**: Bang commands are disabled by default. Only enable them for trusted agents in secure environments, as they execute arbitrary shell commands with the same permissions as the cagent process.
98+
8799
## 🔧 Configuration Reference
88100

89101
### Agent Properties
@@ -100,6 +112,7 @@ During CLI sessions, you can use special commands:
100112
| `add_environment_info` | boolean | Add information about the environment (working dir, OS, git...) ||
101113
| `max_iterations` | int | Specifies how many times the agent can loop when using tools ||
102114
| `commands` | object/array | Named prompts for /commands ||
115+
| `enable_bang_commands` | boolean | Allow shell commands via `!` prefix in TUI (default: false) ||
103116

104117
#### Example
105118

@@ -114,6 +127,7 @@ agents:
114127
add_date: boolean # Add current date to context (optional)
115128
add_environment_info: boolean # Add information about the environment (working dir, OS, git...) (optional)
116129
max_iterations: int # How many times this agent can loop when calling tools (optional, default = unlimited)
130+
enable_bang_commands: boolean # Allow shell commands via ! prefix in TUI (optional, default: false)
117131
commands: # Either mapping or list of singleton maps
118132
df: "check how much free space i have on my disk"
119133
ls: "list the files in the current directory"
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package teamloader
2+
3+
import (
4+
"context"
5+
"os"
6+
"path/filepath"
7+
"testing"
8+
9+
"github.com/docker/cagent/pkg/config"
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestBangCommandsIntegration(t *testing.T) {
15+
// Set a fake API key for testing
16+
t.Setenv("OPENAI_API_KEY", "fake-key-for-testing")
17+
18+
t.Run("load config with bang commands enabled", func(t *testing.T) {
19+
yamlContent := `version: "2"
20+
agents:
21+
root:
22+
model: openai/gpt-4o
23+
enable_bang_commands: true
24+
toolsets:
25+
- type: think
26+
`
27+
// Create temp file
28+
tmpDir := t.TempDir()
29+
tmpFile := filepath.Join(tmpDir, "test.yaml")
30+
err := os.WriteFile(tmpFile, []byte(yamlContent), 0644)
31+
require.NoError(t, err)
32+
33+
// Load team
34+
team, err := Load(context.Background(), tmpFile, config.RuntimeConfig{}, WithModelOverrides(nil))
35+
require.NoError(t, err)
36+
require.NotNil(t, team)
37+
38+
// Get root agent
39+
agent, err := team.Agent("root")
40+
require.NoError(t, err)
41+
42+
// Verify bang commands are enabled
43+
assert.True(t, agent.EnableBangCommands())
44+
})
45+
46+
t.Run("load config with bang commands disabled", func(t *testing.T) {
47+
yamlContent := `version: "2"
48+
agents:
49+
root:
50+
model: openai/gpt-4o
51+
enable_bang_commands: false
52+
toolsets:
53+
- type: think
54+
`
55+
// Create temp file
56+
tmpDir := t.TempDir()
57+
tmpFile := filepath.Join(tmpDir, "test.yaml")
58+
err := os.WriteFile(tmpFile, []byte(yamlContent), 0644)
59+
require.NoError(t, err)
60+
61+
// Load team
62+
team, err := Load(context.Background(), tmpFile, config.RuntimeConfig{}, WithModelOverrides(nil))
63+
require.NoError(t, err)
64+
require.NotNil(t, team)
65+
66+
// Get root agent
67+
agent, err := team.Agent("root")
68+
require.NoError(t, err)
69+
70+
// Verify bang commands are disabled
71+
assert.False(t, agent.EnableBangCommands())
72+
})
73+
74+
t.Run("default is false when omitted", func(t *testing.T) {
75+
yamlContent := `version: "2"
76+
agents:
77+
root:
78+
model: openai/gpt-4o
79+
toolsets:
80+
- type: think
81+
`
82+
// Create temp file
83+
tmpDir := t.TempDir()
84+
tmpFile := filepath.Join(tmpDir, "test.yaml")
85+
err := os.WriteFile(tmpFile, []byte(yamlContent), 0644)
86+
require.NoError(t, err)
87+
88+
// Load team
89+
team, err := Load(context.Background(), tmpFile, config.RuntimeConfig{}, WithModelOverrides(nil))
90+
require.NoError(t, err)
91+
require.NotNil(t, team)
92+
93+
// Get root agent
94+
agent, err := team.Agent("root")
95+
require.NoError(t, err)
96+
97+
// Verify bang commands default to false
98+
assert.False(t, agent.EnableBangCommands())
99+
})
100+
}

0 commit comments

Comments
 (0)