diff --git a/CHANGELOG.md b/CHANGELOG.md index 3738b2c03..403ec062a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ - CI: fix lint ordering after merge cleanup (#156) — thanks @steipete. - CI: consolidate checks to avoid redundant installs (#144) — thanks @thewilloftheshadow. - WhatsApp: support `gifPlayback` for MP4 GIF sends via CLI/gateway. +- Sessions: prevent `sessions_send` timeouts by running nested agent turns on a separate lane. - Auto-reply: drop final payloads when block streaming to avoid duplicate Discord sends. - Auto-reply: fix typing TTL to 2 minutes and log TTL with s/m units. - Bash tool: default auto-background delay to 10s. diff --git a/src/agents/clawdis-tools.sessions.test.ts b/src/agents/clawdis-tools.sessions.test.ts index 9fab95ac0..c30d5a71b 100644 --- a/src/agents/clawdis-tools.sessions.test.ts +++ b/src/agents/clawdis-tools.sessions.test.ts @@ -183,6 +183,9 @@ describe("sessions tools", () => { (call) => call.method === "chat.history", ); expect(agentCalls).toHaveLength(2); + for (const call of agentCalls) { + expect(call.params).toMatchObject({ lane: "nested" }); + } expect(waitCalls).toHaveLength(1); expect(historyOnlyCalls).toHaveLength(1); expect(waitCalls[0]?.params).toMatchObject({ afterMs: 1234 }); diff --git a/src/agents/clawdis-tools.ts b/src/agents/clawdis-tools.ts index 3c9c367f0..7e2ca4d15 100644 --- a/src/agents/clawdis-tools.ts +++ b/src/agents/clawdis-tools.ts @@ -2748,6 +2748,7 @@ function createSessionsSendTool(): AnyAgentTool { sessionKey: resolvedKey, idempotencyKey, deliver: false, + lane: "nested", }; if (timeoutSeconds === 0) { diff --git a/src/commands/agent.ts b/src/commands/agent.ts index 1300f493b..83ca4e1f9 100644 --- a/src/commands/agent.ts +++ b/src/commands/agent.ts @@ -60,6 +60,7 @@ type AgentCommandOpts = { provider?: string; // delivery provider (whatsapp|telegram|...) bestEffortDeliver?: boolean; abortSignal?: AbortSignal; + lane?: string; }; type SessionResolution = { @@ -383,6 +384,7 @@ export async function agentCommand( verboseLevel: resolvedVerboseLevel, timeoutMs, runId: sessionId, + lane: opts.lane, abortSignal: opts.abortSignal, onAgentEvent: (evt) => { emitAgentEvent({ diff --git a/src/gateway/protocol/schema.ts b/src/gateway/protocol/schema.ts index cd1de8060..796cbac98 100644 --- a/src/gateway/protocol/schema.ts +++ b/src/gateway/protocol/schema.ts @@ -208,6 +208,7 @@ export const AgentParamsSchema = Type.Object( deliver: Type.Optional(Type.Boolean()), channel: Type.Optional(Type.String()), timeout: Type.Optional(Type.Integer({ minimum: 0 })), + lane: Type.Optional(Type.String()), idempotencyKey: NonEmptyString, }, { additionalProperties: false }, diff --git a/src/gateway/server-methods.ts b/src/gateway/server-methods.ts index 02c0dc002..ca4af6440 100644 --- a/src/gateway/server-methods.ts +++ b/src/gateway/server-methods.ts @@ -2930,6 +2930,7 @@ export async function handleGatewayRequest( thinking?: string; deliver?: boolean; channel?: string; + lane?: string; idempotencyKey: string; timeout?: number; }; @@ -3118,6 +3119,7 @@ export async function handleGatewayRequest( timeout: params.timeout?.toString(), bestEffortDeliver, surface: "VoiceWake", + lane: params.lane, }, defaultRuntime, deps,