From 6962d2d79fedbbbed507f37b91bd3734cbdcc645 Mon Sep 17 00:00:00 2001 From: Ayaan Zaidi Date: Wed, 4 Mar 2026 10:05:14 +0530 Subject: [PATCH] fix: harden sessions_spawn attachment schema landing (#33648) (thanks @anisoptera) --- CHANGELOG.md | 1 + src/agents/subagent-spawn.ts | 5 +++-- src/agents/tools/sessions-spawn-tool.test.ts | 22 ++++++++++++++++++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 55dacd73e60..bab85ad73c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai ### Fixes +- Sessions/subagent attachments: remove `attachments[].content.maxLength` from `sessions_spawn` schema to avoid llama.cpp GBNF repetition overflow, and preflight UTF-8 byte size before buffer allocation while keeping runtime file-size enforcement unchanged. (#33648) Thanks @anisoptera. - Runtime/tool-state stability: recover from dangling Anthropic `tool_use` after compaction, serialize long-running Discord handler runs without blocking new inbound events, and prevent stale busy snapshots from suppressing stuck-channel recovery. (from #33630, #33583) Thanks @kevinWangSheng and @theotarr. - Extensions/media local-root propagation: consistently forward `mediaLocalRoots` through extension `sendMedia` adapters (Google Chat, Slack, iMessage, Signal, WhatsApp), preserving non-local media behavior while restoring local attachment resolution from configured roots. Synthesis of #33581, #33545, #33540, #33536, #33528. Thanks @bmendonca3. - Gateway/security default response headers: add `Permissions-Policy: camera=(), microphone=(), geolocation=()` to baseline gateway HTTP security headers for all responses. (#30186) thanks @habakan. diff --git a/src/agents/subagent-spawn.ts b/src/agents/subagent-spawn.ts index 7068a057803..592d6d47ea3 100644 --- a/src/agents/subagent-spawn.ts +++ b/src/agents/subagent-spawn.ts @@ -611,13 +611,14 @@ export async function spawnSubagentDirect( } buf = strictBuf; } else { - buf = Buffer.from(contentVal, "utf8"); - const estimatedBytes = buf.byteLength; + // Avoid allocating oversized UTF-8 buffers before enforcing file limits. + const estimatedBytes = Buffer.byteLength(contentVal, "utf8"); if (estimatedBytes > maxFileBytes) { fail( `attachments_file_bytes_exceeded (name=${name} bytes=${estimatedBytes} maxFileBytes=${maxFileBytes})`, ); } + buf = Buffer.from(contentVal, "utf8"); } const bytes = buf.byteLength; diff --git a/src/agents/tools/sessions-spawn-tool.test.ts b/src/agents/tools/sessions-spawn-tool.test.ts index db4396c78b8..3b6b67dbe47 100644 --- a/src/agents/tools/sessions-spawn-tool.test.ts +++ b/src/agents/tools/sessions-spawn-tool.test.ts @@ -164,4 +164,26 @@ describe("sessions_spawn tool", () => { expect(hoisted.spawnAcpDirectMock).not.toHaveBeenCalled(); expect(hoisted.spawnSubagentDirectMock).not.toHaveBeenCalled(); }); + + it("keeps attachment content schema unconstrained for llama.cpp grammar safety", () => { + const tool = createSessionsSpawnTool(); + const schema = tool.parameters as { + properties?: { + attachments?: { + items?: { + properties?: { + content?: { + type?: string; + maxLength?: number; + }; + }; + }; + }; + }; + }; + + const contentSchema = schema.properties?.attachments?.items?.properties?.content; + expect(contentSchema?.type).toBe("string"); + expect(contentSchema?.maxLength).toBeUndefined(); + }); });