diff --git a/adk/prebuilt/deep/deep.go b/adk/prebuilt/deep/deep.go index 531511319..cf428e5c4 100644 --- a/adk/prebuilt/deep/deep.go +++ b/adk/prebuilt/deep/deep.go @@ -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) @@ -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, diff --git a/adk/prebuilt/deep/deep_test.go b/adk/prebuilt/deep/deep_test.go index b39cfe9f5..3f07d3504 100644 --- a/adk/prebuilt/deep/deep_test.go +++ b/adk/prebuilt/deep/deep_test.go @@ -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{} diff --git a/adk/prebuilt/deep/task_tool.go b/adk/prebuilt/deep/task_tool.go index 5c7e50b63..f66ef9fe2 100644 --- a/adk/prebuilt/deep/task_tool.go +++ b/adk/prebuilt/deep/task_tool.go @@ -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, @@ -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 }