Skip to content

Commit 9acae13

Browse files
committed
refactor: remove DescriptionToolSet wrapper
Move description parameter handling from a wrapper struct to a simple function called at tool retrieval time. This eliminates the need for DescriptionToolSet to implement all capability interfaces (Startable, Instructable, Elicitable, OAuthCapable) just to forward calls. Changes: - Add addDescriptionParameter field to Agent struct - Add WithAddDescriptionParameter option - Add tools.AddDescriptionParameter function to transform tool lists - Remove DescriptionToolSet wrapper entirely - Apply transformation in agent.Tools() when flag is enabled Assisted-By: cagent
1 parent c686267 commit 9acae13

5 files changed

Lines changed: 92 additions & 116 deletions

File tree

pkg/agent/agent.go

Lines changed: 26 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,28 @@ import (
1515

1616
// Agent represents an AI agent
1717
type Agent struct {
18-
name string
19-
description string
20-
welcomeMessage string
21-
instruction string
22-
toolsets []*tools.StartableToolSet
23-
models []provider.Provider
24-
modelOverrides atomic.Pointer[[]provider.Provider] // Optional model override(s) set at runtime (supports alloy)
25-
subAgents []*Agent
26-
handoffs []*Agent
27-
parents []*Agent
28-
addDate bool
29-
addEnvironmentInfo bool
30-
maxIterations int
31-
numHistoryItems int
32-
addPromptFiles []string
33-
tools []tools.Tool
34-
commands types.Commands
35-
pendingWarnings []string
36-
skillsEnabled bool
37-
hooks *latest.HooksConfig
38-
thinkingConfigured bool // true if thinking_budget was explicitly set in config
18+
name string
19+
description string
20+
welcomeMessage string
21+
instruction string
22+
toolsets []*tools.StartableToolSet
23+
models []provider.Provider
24+
modelOverrides atomic.Pointer[[]provider.Provider] // Optional model override(s) set at runtime (supports alloy)
25+
subAgents []*Agent
26+
handoffs []*Agent
27+
parents []*Agent
28+
addDate bool
29+
addEnvironmentInfo bool
30+
addDescriptionParameter bool
31+
maxIterations int
32+
numHistoryItems int
33+
addPromptFiles []string
34+
tools []tools.Tool
35+
commands types.Commands
36+
pendingWarnings []string
37+
skillsEnabled bool
38+
hooks *latest.HooksConfig
39+
thinkingConfigured bool // true if thinking_budget was explicitly set in config
3940
}
4041

4142
// New creates a new agent
@@ -203,6 +204,10 @@ func (a *Agent) Tools(ctx context.Context) ([]tools.Tool, error) {
203204

204205
agentTools = append(agentTools, a.tools...)
205206

207+
if a.addDescriptionParameter {
208+
agentTools = tools.AddDescriptionParameter(agentTools)
209+
}
210+
206211
return agentTools, nil
207212
}
208213

pkg/agent/opts.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ func WithAddEnvironmentInfo(addEnvironmentInfo bool) Opt {
8383
}
8484
}
8585

86+
func WithAddDescriptionParameter(addDescriptionParameter bool) Opt {
87+
return func(a *Agent) {
88+
a.addDescriptionParameter = addDescriptionParameter
89+
}
90+
}
91+
8692
func WithAddPromptFiles(addPromptFiles []string) Opt {
8793
return func(a *Agent) {
8894
a.addPromptFiles = addPromptFiles

pkg/teamloader/teamloader.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,7 @@ func LoadWithConfig(ctx context.Context, agentSource config.Source, runConfig *c
149149
agent.WithWelcomeMessage(expander.Expand(ctx, agentConfig.WelcomeMessage)),
150150
agent.WithAddDate(agentConfig.AddDate),
151151
agent.WithAddEnvironmentInfo(agentConfig.AddEnvironmentInfo),
152+
agent.WithAddDescriptionParameter(agentConfig.AddDescriptionParameter),
152153
agent.WithAddPromptFiles(agentConfig.AddPromptFiles),
153154
agent.WithMaxIterations(agentConfig.MaxIterations),
154155
agent.WithNumHistoryItems(agentConfig.NumHistoryItems),
@@ -344,11 +345,6 @@ func getToolsForAgent(ctx context.Context, a *latest.AgentConfig, parentDir stri
344345
}
345346
}
346347

347-
// Apply friendly tools wrapper if enabled
348-
if a.AddDescriptionParameter {
349-
wrapped = tools.NewDescriptionToolSet(wrapped)
350-
}
351-
352348
toolSets = append(toolSets, wrapped)
353349
}
354350

pkg/tools/description.go

Lines changed: 9 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
package tools
22

33
import (
4-
"context"
54
"encoding/json"
65
)
76

@@ -10,76 +9,18 @@ const (
109
DescriptionParam = "description"
1110
)
1211

13-
// DescriptionToolSet wraps a ToolSet and adds a "description" parameter to all tools.
14-
// This allows the LLM to provide context about what it's doing with each tool call.
15-
type DescriptionToolSet struct {
16-
inner ToolSet
17-
}
18-
19-
// Verify interface compliance
20-
var (
21-
_ ToolSet = (*DescriptionToolSet)(nil)
22-
_ Startable = (*DescriptionToolSet)(nil)
23-
_ Instructable = (*DescriptionToolSet)(nil)
24-
_ Elicitable = (*DescriptionToolSet)(nil)
25-
_ OAuthCapable = (*DescriptionToolSet)(nil)
26-
)
27-
28-
// NewDescriptionToolSet creates a new DescriptionToolSet wrapping the given ToolSet.
29-
func NewDescriptionToolSet(inner ToolSet) *DescriptionToolSet {
30-
return &DescriptionToolSet{inner: inner}
31-
}
32-
33-
func (f *DescriptionToolSet) Tools(ctx context.Context) ([]Tool, error) {
34-
tools, err := f.inner.Tools(ctx)
35-
if err != nil {
36-
return nil, err
37-
}
38-
39-
result := make([]Tool, len(tools))
40-
for i, tool := range tools {
41-
result[i] = f.addDescriptionParam(tool)
42-
}
43-
return result, nil
44-
}
45-
46-
func (f *DescriptionToolSet) Instructions() string {
47-
return GetInstructions(f.inner)
48-
}
49-
50-
func (f *DescriptionToolSet) Start(ctx context.Context) error {
51-
if s, ok := As[Startable](f.inner); ok {
52-
return s.Start(ctx)
53-
}
54-
return nil
55-
}
56-
57-
func (f *DescriptionToolSet) Stop(ctx context.Context) error {
58-
if s, ok := As[Startable](f.inner); ok {
59-
return s.Stop(ctx)
60-
}
61-
return nil
62-
}
63-
64-
func (f *DescriptionToolSet) SetElicitationHandler(handler ElicitationHandler) {
65-
if e, ok := As[Elicitable](f.inner); ok {
66-
e.SetElicitationHandler(handler)
67-
}
68-
}
69-
70-
func (f *DescriptionToolSet) SetOAuthSuccessHandler(handler func()) {
71-
if o, ok := As[OAuthCapable](f.inner); ok {
72-
o.SetOAuthSuccessHandler(handler)
73-
}
74-
}
75-
76-
func (f *DescriptionToolSet) SetManagedOAuth(managed bool) {
77-
if o, ok := As[OAuthCapable](f.inner); ok {
78-
o.SetManagedOAuth(managed)
12+
// AddDescriptionParameter adds a "description" parameter to tools that have
13+
// AddDescriptionParameter set to true. This allows the LLM to provide context
14+
// about what it's doing with each tool call.
15+
func AddDescriptionParameter(toolList []Tool) []Tool {
16+
result := make([]Tool, len(toolList))
17+
for i, tool := range toolList {
18+
result[i] = addDescriptionParam(tool)
7919
}
20+
return result
8021
}
8122

82-
func (f *DescriptionToolSet) addDescriptionParam(tool Tool) Tool {
23+
func addDescriptionParam(tool Tool) Tool {
8324
if !tool.AddDescriptionParameter {
8425
return tool
8526
}

pkg/tools/description_test.go

Lines changed: 50 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
package tools
22

33
import (
4-
"context"
54
"testing"
65

76
"github.com/stretchr/testify/assert"
87
"github.com/stretchr/testify/require"
98
)
109

11-
type mockToolSet struct{}
10+
func TestAddDescriptionParameter_AddsDescriptionParameter(t *testing.T) {
11+
t.Parallel()
1212

13-
func (m *mockToolSet) Tools(_ context.Context) ([]Tool, error) {
14-
return []Tool{
13+
tools := []Tool{
1514
{
1615
Name: "test_tool",
1716
Description: "A test tool",
@@ -25,23 +24,14 @@ func (m *mockToolSet) Tools(_ context.Context) ([]Tool, error) {
2524
},
2625
"required": []string{"path"},
2726
},
28-
Handler: func(_ context.Context, _ ToolCall) (*ToolCallResult, error) {
29-
return &ToolCallResult{Output: "ok"}, nil
30-
},
3127
AddDescriptionParameter: true,
3228
},
33-
}, nil
34-
}
35-
36-
func TestDescriptionToolSet_AddsDescriptionParameter(t *testing.T) {
37-
t.Parallel()
38-
desc := NewDescriptionToolSet(&mockToolSet{})
29+
}
3930

40-
tools, err := desc.Tools(t.Context())
41-
require.NoError(t, err)
42-
require.Len(t, tools, 1)
31+
result := AddDescriptionParameter(tools)
32+
require.Len(t, result, 1)
4333

44-
tool := tools[0]
34+
tool := result[0]
4535
schema, ok := tool.Parameters.(map[string]any)
4636
require.True(t, ok)
4737

@@ -54,14 +44,28 @@ func TestDescriptionToolSet_AddsDescriptionParameter(t *testing.T) {
5444
assert.Contains(t, descProp["description"], "human-readable")
5545
}
5646

57-
func TestDescriptionToolSet_PreservesOriginalParameters(t *testing.T) {
47+
func TestAddDescriptionParameter_PreservesOriginalParameters(t *testing.T) {
5848
t.Parallel()
59-
desc := NewDescriptionToolSet(&mockToolSet{})
6049

61-
tools, err := desc.Tools(t.Context())
62-
require.NoError(t, err)
50+
tools := []Tool{
51+
{
52+
Name: "test_tool",
53+
Parameters: map[string]any{
54+
"type": "object",
55+
"properties": map[string]any{
56+
"path": map[string]any{
57+
"type": "string",
58+
"description": "The file path",
59+
},
60+
},
61+
},
62+
AddDescriptionParameter: true,
63+
},
64+
}
6365

64-
schema := tools[0].Parameters.(map[string]any)
66+
result := AddDescriptionParameter(tools)
67+
68+
schema := result[0].Parameters.(map[string]any)
6569
properties := schema["properties"].(map[string]any)
6670

6771
pathProp, ok := properties["path"].(map[string]any)
@@ -70,6 +74,30 @@ func TestDescriptionToolSet_PreservesOriginalParameters(t *testing.T) {
7074
assert.Equal(t, "The file path", pathProp["description"])
7175
}
7276

77+
func TestAddDescriptionParameter_SkipsToolsWithoutFlag(t *testing.T) {
78+
t.Parallel()
79+
80+
tools := []Tool{
81+
{
82+
Name: "test_tool",
83+
Parameters: map[string]any{
84+
"type": "object",
85+
"properties": map[string]any{},
86+
},
87+
AddDescriptionParameter: false,
88+
},
89+
}
90+
91+
result := AddDescriptionParameter(tools)
92+
require.Len(t, result, 1)
93+
94+
schema := result[0].Parameters.(map[string]any)
95+
properties := schema["properties"].(map[string]any)
96+
97+
_, hasDesc := properties[DescriptionParam]
98+
assert.False(t, hasDesc, "description parameter should not be added")
99+
}
100+
73101
func TestExtractDescription(t *testing.T) {
74102
t.Parallel()
75103
tests := []struct {

0 commit comments

Comments
 (0)