From 648787e73966574480d1eb71f38090cfab301e91 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 6 Apr 2026 16:20:14 -0400 Subject: [PATCH] feat: expose busy_behavior on chat message API (#24054) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend (`chatd.go`) already fully implements both `"queue"` and `"interrupt"` busy behaviors for `SendMessage`, and the `message_agent` subagent tool already leverages both internally. However the HTTP API hardcoded `"queue"` and the SDK had no way for callers to request interrupt-on-send. This adds a `ChatBusyBehavior` enum type to the SDK and an optional `busy_behavior` field on `CreateChatMessageRequest`. The HTTP handler validates the field and passes it through to `chatd.SendMessage`. Default remains `"queue"` for full backward compatibility.
Implementation notes - `codersdk/chats.go`: New `ChatBusyBehavior` type with `ChatBusyBehaviorQueue` and `ChatBusyBehaviorInterrupt` constants. Added `BusyBehavior` field to `CreateChatMessageRequest` with `enums` tag for codegen. - `coderd/exp_chats.go`: `postChatMessages` now reads `req.BusyBehavior`, maps SDK constants to `chatd.SendMessageBusyBehavior*`, returns 400 on invalid values. - `site/src/api/typesGenerated.ts`: Auto-generated via `make gen`. - No frontend behavior changes — the field is available but unused by the UI.
> [!NOTE] > Generated by Coder Agents --- coderd/exp_chats.go | 16 +++++++++++++++- codersdk/chats.go | 22 +++++++++++++++++++--- site/src/api/typesGenerated.ts | 6 ++++++ 3 files changed, 40 insertions(+), 4 deletions(-) diff --git a/coderd/exp_chats.go b/coderd/exp_chats.go index 86713b8201..44d3ac3886 100644 --- a/coderd/exp_chats.go +++ b/coderd/exp_chats.go @@ -1830,6 +1830,20 @@ func (api *API) postChatMessages(rw http.ResponseWriter, r *http.Request) { } } + busyBehavior := chatd.SendMessageBusyBehaviorQueue + switch req.BusyBehavior { + case codersdk.ChatBusyBehaviorInterrupt: + busyBehavior = chatd.SendMessageBusyBehaviorInterrupt + case codersdk.ChatBusyBehaviorQueue, "": + // Default to queue. + default: + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Invalid busy_behavior value.", + Detail: `Must be "queue" or "interrupt".`, + }) + return + } + sendResult, sendErr := api.chatDaemon.SendMessage( ctx, chatd.SendMessageOptions{ @@ -1837,7 +1851,7 @@ func (api *API) postChatMessages(rw http.ResponseWriter, r *http.Request) { CreatedBy: apiKey.UserID, Content: contentBlocks, ModelConfigID: req.ModelConfigID, - BusyBehavior: chatd.SendMessageBusyBehaviorQueue, + BusyBehavior: busyBehavior, MCPServerIDs: req.MCPServerIDs, }, ) diff --git a/codersdk/chats.go b/codersdk/chats.go index 1a4a865d08..f62a843553 100644 --- a/codersdk/chats.go +++ b/codersdk/chats.go @@ -369,11 +369,27 @@ type UpdateChatRequest struct { Labels *map[string]string `json:"labels,omitempty"` } +// ChatBusyBehavior controls what happens when a user sends a message +// while the chat is already processing. +type ChatBusyBehavior string + +const ( + // ChatBusyBehaviorQueue queues the message for processing after + // the current run finishes. + ChatBusyBehaviorQueue ChatBusyBehavior = "queue" + // ChatBusyBehaviorInterrupt queues the message and interrupts + // the active run. The partial assistant response is persisted + // before the queued message is promoted, preserving correct + // conversation order. + ChatBusyBehaviorInterrupt ChatBusyBehavior = "interrupt" +) + // CreateChatMessageRequest is the request to add a message to a chat. type CreateChatMessageRequest struct { - Content []ChatInputPart `json:"content"` - ModelConfigID *uuid.UUID `json:"model_config_id,omitempty" format:"uuid"` - MCPServerIDs *[]uuid.UUID `json:"mcp_server_ids,omitempty" format:"uuid"` + Content []ChatInputPart `json:"content"` + ModelConfigID *uuid.UUID `json:"model_config_id,omitempty" format:"uuid"` + MCPServerIDs *[]uuid.UUID `json:"mcp_server_ids,omitempty" format:"uuid"` + BusyBehavior ChatBusyBehavior `json:"busy_behavior,omitempty" enums:"queue,interrupt"` } // EditChatMessageRequest is the request to edit a user message in a chat. diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index f502de0395..0e657b5d14 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -1215,6 +1215,11 @@ export interface Chat { readonly last_injected_context?: readonly ChatMessagePart[]; } +// From codersdk/chats.go +export type ChatBusyBehavior = "interrupt" | "queue"; + +export const ChatBusyBehaviors: ChatBusyBehavior[] = ["interrupt", "queue"]; + // From codersdk/chats.go /** * ChatCompactionThresholdKeyPrefix scopes per-model chat compaction @@ -2338,6 +2343,7 @@ export interface CreateChatMessageRequest { readonly content: readonly ChatInputPart[]; readonly model_config_id?: string; readonly mcp_server_ids?: string[]; + readonly busy_behavior?: ChatBusyBehavior; } // From codersdk/chats.go