diff --git a/docs-site/src/content/docs/guides/claude-code.md b/docs-site/src/content/docs/guides/claude-code.md index 02d3d78875c..d3c60e845af 100644 --- a/docs-site/src/content/docs/guides/claude-code.md +++ b/docs-site/src/content/docs/guides/claude-code.md @@ -510,7 +510,8 @@ Anthropic passthrough is untouched. replaced by a stub when the lowercased JSON input contains a blocked name. 2. **Text-block carrier:** a user text block ≥10,000 characters starting with `Base directory for this skill: ` — matched when the directory basename equals a blocked name - (case-insensitive). + (case-insensitive). The directory line is inspected only up to 4,096 UTF-16 code units; + a longer line is sent unchanged, including when it has no terminating newline. Configure with `claudeCode.blockedSkills` (default `["claude-api"]`; `[]` disables elision entirely). The stub keeps tool call/result pairing intact. diff --git a/structure/clients/claude-desktop.md b/structure/clients/claude-desktop.md index 9c21b161663..8be7c02d7d4 100644 --- a/structure/clients/claude-desktop.md +++ b/structure/clients/claude-desktop.md @@ -263,3 +263,6 @@ Native steering generation overrides, explicit public-API eligibility and the co Dashboard Fast-row persistence and client refresh follow the [Fast selector rows setting contract](../gui-and-management-api.md#fast-selector-rows-setting). The [compaction routing override](../transports/responses-failover.md#compaction-routing-overrides) is scoped to Codex Responses metadata and original Responses ingress; Claude Messages replay retains its own routing. +## Routed bundled-skill text + +`src/claude/inbound.ts` bounds the text-carrier skill-directory probe to 4,096 UTF-16 code units, plus one character to recognize the terminating newline. A longer first line is preserved intact instead of being scanned or stubbed; normal POSIX, Windows, mixed and UNC separators retain their basename matching. The existing 10,000-character payload threshold and `claudeCode.blockedSkills` policy remain: `claude-api` is blocked by default, and an explicit empty list disables elision. Native Anthropic passthrough and tool-call/result pairing are unchanged. `tests/claude-integration/claude-inbound.test.ts` covers the exact 4,096/4,097 boundary and a long newline-free carrier. diff --git a/tests/claude-integration/claude-inbound.test.ts b/tests/claude-integration/claude-inbound.test.ts index 308f06b0c80..2390d7f82d9 100644 --- a/tests/claude-integration/claude-inbound.test.ts +++ b/tests/claude-integration/claude-inbound.test.ts @@ -681,6 +681,34 @@ describe("bundled-skill elision for routed models (devlog 260712 060)", () => { const texts = userTexts(requestWithSkillTextBlock("claude-api", 20_000, undefined, oversizedDir)); expect(texts.some(t => t.startsWith(`Base directory for this skill: ${oversizedDir}`))).toBe(true); }); + + for (const [prefix, separator] of [["/", "/"], ["C:\\", "\\"]] as const) { + for (const pathLength of [4_096, 4_097]) { + test(`text-block carrier: ${prefix} marker path at ${pathLength} characters`, () => { + const suffix = `${separator}claude-api${separator}`; + const dir = prefix + "a".repeat(pathLength - prefix.length - suffix.length) + suffix; + const texts = userTexts(requestWithSkillTextBlock("claude-api", 20_000, undefined, dir)); + const bundle = `Base directory for this skill: ${dir}\n\n` + "DOCS ".repeat(4_000); + expect(dir.length).toBe(pathLength); + if (pathLength === 4_096) { + expect(texts.some(text => text.includes("'claude-api'") && text.includes("elided"))).toBe(true); + expect(texts.every(text => text.length < 10_000)).toBe(true); + } else { + expect(texts).toContain(bundle); + } + }); + } + } + + test("text-block carrier: an oversized first line without a newline stays byte-for-byte intact", () => { + const text = "Base directory for this skill: /" + "a/".repeat(10_000) + "claude-api"; + const body = anthropicToResponsesTranslation({ + model: "gemini/gemini-3-pro", + max_tokens: 100, + messages: [{ role: "user", content: [{ type: "text", text }] }], + }).body; + expect(userTexts(body)).toContain(text); + }); }); describe("ocx-route directive (devlog 072)", () => {