From d40c0b898a94d6e6da68d8a71e9faac332774642 Mon Sep 17 00:00:00 2001 From: Mathias Fredriksson Date: Mon, 20 Jul 2026 10:03:13 +0000 Subject: [PATCH] fix(coderd/x/chatd): clarify wait agent timeout The model-visible timeout schema did not state its five-minute default. Clarify that waits return on completion and that a timeout leaves the agent running. --- coderd/x/chatd/subagent.go | 10 +++++----- coderd/x/chatd/subagent_internal_test.go | 22 ++++++++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/coderd/x/chatd/subagent.go b/coderd/x/chatd/subagent.go index f2c50e3023c..cf5a209542f 100644 --- a/coderd/x/chatd/subagent.go +++ b/coderd/x/chatd/subagent.go @@ -95,7 +95,7 @@ Guidelines: type waitAgentArgs struct { ChatID string `json:"chat_id"` - TimeoutSeconds *int `json:"timeout_seconds,omitempty"` + TimeoutSeconds *int `json:"timeout_seconds,omitempty" description:"Defaults to 5 minutes."` } type messageAgentArgs struct { @@ -620,10 +620,10 @@ func (p *Server) subagentTools( ), fantasy.NewAgentTool( "wait_agent", - "Wait until a spawned child agent finishes its task. "+ - "Returns the agent's response and status. A timeout is not "+ - "a failure: the agent is still running. Call wait_agent again "+ - "or use list_agents to check its status.", + "Wait for a spawned child agent to finish and return its response "+ + "and status. Returns immediately when the agent finishes, even if "+ + "a longer timeout is set. A timeout does not stop the agent; call "+ + "wait_agent again or use list_agents to check its status.", func(ctx context.Context, args waitAgentArgs, _ fantasy.ToolCall) (fantasy.ToolResponse, error) { if currentChat == nil { return fantasy.NewTextErrorResponse("subagent callbacks are not configured"), nil diff --git a/coderd/x/chatd/subagent_internal_test.go b/coderd/x/chatd/subagent_internal_test.go index 896d658106d..f7b7c051e9c 100644 --- a/coderd/x/chatd/subagent_internal_test.go +++ b/coderd/x/chatd/subagent_internal_test.go @@ -3647,6 +3647,28 @@ func TestAwaitSubagentCompletion(t *testing.T) { }) } +func TestWaitAgentToolSchema(t *testing.T) { + t.Parallel() + + db, ps := dbtestutil.NewDB(t) + server := newInternalTestServer(t, db, ps, chatprovider.ProviderAPIKeys{}) + ctx := chatdTestContext(t) + user, org, model := seedInternalChatDeps(t, db) + parent, _ := createParentChildChats(ctx, t, server, user, org, model) + + tool := findToolByName(server.subagentTools(ctx, func() database.Chat { + return parent + }, parent.LastModelConfigID), "wait_agent") + require.NotNil(t, tool) + + timeoutSeconds, ok := tool.Info().Parameters["timeout_seconds"].(map[string]any) + require.True(t, ok) + assert.Equal(t, "integer", timeoutSeconds["type"]) + assert.Equal(t, "Defaults to 5 minutes.", timeoutSeconds["description"]) + assert.Contains(t, tool.Info().Description, "Returns immediately when the agent finishes") + assert.Contains(t, tool.Info().Description, "A timeout does not stop the agent") +} + func TestWaitAgentTimeoutReturnsInformationalPayload(t *testing.T) { t.Parallel()