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
3 changes: 3 additions & 0 deletions adk/prebuilt/deep/deep.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,8 @@ type TypedConfig[M adk.MessageType] struct {
WithoutWriteTodos bool
// WithoutGeneralSubAgent disables the general-purpose subagent when set to true.
WithoutGeneralSubAgent bool
// WithoutTaskPrompt disables the built-in task tool prompt injection when set to true.
WithoutTaskPrompt bool
// TaskToolDescriptionGenerator allows customizing the description for the task tool.
// If provided, this function generates the tool description based on available subagents.
TaskToolDescriptionGenerator func(ctx context.Context, availableAgents []adk.TypedAgent[M]) (string, error)
Expand Down Expand Up @@ -134,6 +136,7 @@ func NewTyped[M adk.MessageType](ctx context.Context, cfg *TypedConfig[M]) (adk.
cfg.SubAgents,

cfg.WithoutGeneralSubAgent,
cfg.WithoutTaskPrompt,
cfg.ChatModel,
instruction,
cfg.ToolsConfig,
Expand Down
82 changes: 82 additions & 0 deletions adk/prebuilt/deep/deep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,88 @@ func TestWriteTodos(t *testing.T) {
assert.Equal(t, fmt.Sprintf("Updated todo list to %s", todos), result)
}

func TestDeepAgentTaskPromptConfig(t *testing.T) {
ctx := context.Background()

tests := []struct {
name string
withoutTaskPrompt bool
wantTaskPrompt bool
}{
{
name: "default injects task prompt",
wantTaskPrompt: true,
},
{
name: "without task prompt keeps task tool",
withoutTaskPrompt: true,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()

cm := mockModel.NewMockToolCallingChatModel(ctrl)

var capturedTools []*schema.ToolInfo
cm.EXPECT().WithTools(gomock.Any()).Return(cm, nil).AnyTimes()

var capturedMessages []*schema.Message
cm.EXPECT().Generate(gomock.Any(), gomock.Any(), gomock.Any()).
DoAndReturn(func(_ context.Context, msgs []*schema.Message, opts ...model.Option) (*schema.Message, error) {
capturedMessages = msgs
options := model.GetCommonOptions(&model.Options{}, opts...)
capturedTools = options.Tools
return schema.AssistantMessage("done", nil), nil
}).
Times(1)

agent, err := New(ctx, &Config{
Name: "deep",
Description: "deep agent",
ChatModel: cm,
Instruction: "you are deep agent",
SubAgents: []adk.Agent{&spySubAgent{}},
MaxIteration: 2,
WithoutWriteTodos: true,
WithoutGeneralSubAgent: true,
WithoutTaskPrompt: tt.withoutTaskPrompt,
})
assert.NoError(t, err)

r := adk.NewRunner(ctx, adk.RunnerConfig{Agent: agent})
it := r.Run(ctx, []adk.Message{schema.UserMessage("hi")})
for {
event, ok := it.Next()
if !ok {
break
}
assert.NoError(t, event.Err)
}

assert.NotEmpty(t, capturedMessages)
assert.Equal(t, schema.System, capturedMessages[0].Role)
assert.Contains(t, capturedMessages[0].Content, "you are deep agent")
if tt.wantTaskPrompt {
assert.Contains(t, capturedMessages[0].Content, "# 'task' (subagent spawner)")
} else {
assert.NotContains(t, capturedMessages[0].Content, "# 'task' (subagent spawner)")
}

var hasTaskTool bool
for _, toolInfo := range capturedTools {
if toolInfo.Name == taskToolName {
hasTaskTool = true
break
}
}
assert.True(t, hasTaskTool)
})
}
}

func TestDeepSubAgentSharesSessionValues(t *testing.T) {
ctx := context.Background()
spy := &spySubAgent{}
Expand Down
12 changes: 8 additions & 4 deletions adk/prebuilt/deep/task_tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ func typedTaskToolMiddleware[M adk.MessageType](
subAgents []adk.TypedAgent[M],

withoutGeneralSubAgent bool,
withoutTaskPrompt bool,
cm model.BaseModel[M],
instruction string,
toolsConfig adk.ToolsConfig,
Expand All @@ -50,10 +51,13 @@ func typedTaskToolMiddleware[M adk.MessageType](
if err != nil {
return nil, err
}
prompt := internal.SelectPrompt(internal.I18nPrompts{
English: taskPrompt,
Chinese: taskPromptChinese,
})
var prompt string
if !withoutTaskPrompt {
prompt = internal.SelectPrompt(internal.I18nPrompts{
English: taskPrompt,
Chinese: taskPromptChinese,
})
}

return typedBuildAppendPromptTool[M](prompt, t), nil
}
Expand Down