feat: configure acquire chat batch size (#23196)

## Summary
- add a hidden deployment config option for chat acquire batch size
(`CODER_CHAT_ACQUIRE_BATCH_SIZE` / `chat.acquireBatchSize`)
- thread the configured value into chatd startup while preserving the
existing default of `10`
- clamp the deployment value to the `int32` range before passing it into
chatd
- regenerate the API/docs/types/testdata artifacts for the new config
field

## Why
`chatd` currently acquires pending chats in batches of `10` via a
compile-time default. This change makes that batch size
operator-configurable from deployment config, so we can tune acquisition
behavior without another code change.
This commit is contained in:
Ethan
2026-03-19 00:54:32 +11:00
committed by GitHub
parent 8b4d35798a
commit fc3508dc60
9 changed files with 113 additions and 13 deletions
+11
View File
@@ -12714,6 +12714,9 @@ const docTemplate = `{
},
"bridge": {
"$ref": "#/definitions/codersdk.AIBridgeConfig"
},
"chat": {
"$ref": "#/definitions/codersdk.ChatConfig"
}
}
},
@@ -13771,6 +13774,14 @@ const docTemplate = `{
}
}
},
"codersdk.ChatConfig": {
"type": "object",
"properties": {
"acquire_batch_size": {
"type": "integer"
}
}
},
"codersdk.ConnectionLatency": {
"type": "object",
"properties": {
+11
View File
@@ -11320,6 +11320,9 @@
},
"bridge": {
"$ref": "#/definitions/codersdk.AIBridgeConfig"
},
"chat": {
"$ref": "#/definitions/codersdk.ChatConfig"
}
}
},
@@ -12342,6 +12345,14 @@
}
}
},
"codersdk.ChatConfig": {
"type": "object",
"properties": {
"acquire_batch_size": {
"type": "integer"
}
}
},
"codersdk.ConnectionLatency": {
"type": "object",
"properties": {
+11 -3
View File
@@ -58,11 +58,11 @@ const (
// of 5 means recovery runs at 1/5 of the stale-after duration.
staleRecoveryIntervalDivisor = 5
// maxChatsPerAcquire is the maximum number of chats to
// DefaultMaxChatsPerAcquire is the maximum number of chats to
// acquire in a single processOnce call. Batching avoids
// waiting a full polling interval between acquisitions
// when many chats are pending.
maxChatsPerAcquire int32 = 10
DefaultMaxChatsPerAcquire int32 = 10
defaultSubagentInstruction = "You are running as a delegated sub-agent chat. Complete the delegated task and provide clear, concise assistant responses for the parent agent."
)
@@ -98,6 +98,7 @@ type Server struct {
// Configuration
pendingChatAcquireInterval time.Duration
maxChatsPerAcquire int32
inFlightChatStaleAfter time.Duration
}
@@ -1174,6 +1175,7 @@ type Config struct {
ReplicaID uuid.UUID
SubscribeFn SubscribeFn
PendingChatAcquireInterval time.Duration
MaxChatsPerAcquire int32
InFlightChatStaleAfter time.Duration
AgentConn AgentConnFunc
CreateWorkspace chattool.CreateWorkspaceFn
@@ -1199,6 +1201,11 @@ func New(cfg Config) *Server {
inFlightChatStaleAfter = DefaultInFlightChatStaleAfter
}
maxChatsPerAcquire := cfg.MaxChatsPerAcquire
if maxChatsPerAcquire <= 0 {
maxChatsPerAcquire = DefaultMaxChatsPerAcquire
}
workerID := cfg.ReplicaID
if workerID == uuid.Nil {
workerID = uuid.New()
@@ -1219,6 +1226,7 @@ func New(cfg Config) *Server {
providerAPIKeys: cfg.ProviderAPIKeys,
instructionCache: make(map[uuid.UUID]cachedInstruction),
pendingChatAcquireInterval: pendingChatAcquireInterval,
maxChatsPerAcquire: maxChatsPerAcquire,
inFlightChatStaleAfter: inFlightChatStaleAfter,
}
@@ -1272,7 +1280,7 @@ func (p *Server) processOnce(ctx context.Context) {
chats, err := p.db.AcquireChats(acquireCtx, database.AcquireChatsParams{
StartedAt: time.Now(),
WorkerID: p.workerID,
NumChats: maxChatsPerAcquire,
NumChats: p.maxChatsPerAcquire,
})
acquireCancel()
if err != nil {
+20 -10
View File
@@ -10,6 +10,7 @@ import (
"flag"
"fmt"
"io"
"math"
"net/http"
httppprof "net/http/pprof"
"net/url"
@@ -766,17 +767,26 @@ func New(options *Options) *API {
}
api.agentProvider = stn
maxChatsPerAcquire := options.DeploymentValues.AI.Chat.AcquireBatchSize.Value()
if maxChatsPerAcquire > math.MaxInt32 {
maxChatsPerAcquire = math.MaxInt32
}
if maxChatsPerAcquire < math.MinInt32 {
maxChatsPerAcquire = math.MinInt32
}
api.chatDaemon = chatd.New(chatd.Config{
Logger: options.Logger.Named("chats"),
Database: options.Database,
ReplicaID: api.ID,
SubscribeFn: options.ChatSubscribeFn,
ProviderAPIKeys: chatProviderAPIKeysFromDeploymentValues(options.DeploymentValues),
AgentConn: api.agentProvider.AgentConn,
CreateWorkspace: api.chatCreateWorkspace,
StartWorkspace: api.chatStartWorkspace,
Pubsub: options.Pubsub,
WebpushDispatcher: options.WebPushDispatcher,
Logger: options.Logger.Named("chats"),
Database: options.Database,
ReplicaID: api.ID,
SubscribeFn: options.ChatSubscribeFn,
MaxChatsPerAcquire: int32(maxChatsPerAcquire), //nolint:gosec // maxChatsPerAcquire is clamped to int32 range above.
ProviderAPIKeys: chatProviderAPIKeysFromDeploymentValues(options.DeploymentValues),
AgentConn: api.agentProvider.AgentConn,
CreateWorkspace: api.chatCreateWorkspace,
StartWorkspace: api.chatStartWorkspace,
Pubsub: options.Pubsub,
WebpushDispatcher: options.WebPushDispatcher,
})
gitSyncLogger := options.Logger.Named("gitsync")
refresher := gitsync.NewRefresher(