fix(interface): bound a turn prompt as content, not as metadata - #314
Merged
Conversation
`prompt` was `boundedStringSchema` — CONTRACT_MAX_STRING_LENGTH, 16,384 characters. That is the bound for identifiers and accounting fields. A prompt is what an agent is asked to do: its size is set by the work, not by the protocol. Held to the metadata bound it silently capped what a manager could delegate. Measured 2026-09-11 in a live run already carrying both prior bound fixes (agent-provider-tangle 1.1.10, agent-runtime 0.214.0): two of ten child deaths were `Too big: expected string to have <=16384 characters` at path ["prompt"], refusing a director that was handing an independent-checker child a 27 KB patch so it could rebuild and re-verify a measured result. This is the third time agent-authored content has been held to the metadata bound — tool output twice (#311, #312), now the prompt. The distinguishing test is worth stating once: if an agent or a tool produced it, it is content; if it names, routes, or accounts for the turn, it is metadata. `context` keeps the metadata bound on exactly that reading. Moved at all four sites: AgentTurnInput, the runtime-control prompt command, portable context continuation, and interactive session control. The interactive site kept its non-empty requirement as a refinement, because the content schema is a custom schema and carries no `.min`. Truncation is deliberately NOT used here, unlike tool output: a silently shortened instruction is worse than a refused one. Only the ceiling moves, to where the producer's own limits already sit. Tests: three added to the turn-input bounds case, failing on the previous code. agent-interface suite 546 pass. `src/certified-context.test.ts` has one pre-existing failure that reproduces identically on unmodified main. Closes #313. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
drewstone
added a commit
that referenced
this pull request
Sep 11, 2026
…eeds (#315) Every bound defect this package shipped this week lived at the seam between what the Sandbox SDK writes and what this provider accepts, and none was caught by a unit test, because each side is individually correct. #311: tool output written at 4 MiB, validated at 16 KiB. #312: widened to 1 MiB, still 4x and the same failure mode. #314: a turn prompt held to the metadata bound. 143 of 199 children in one Lab archive. This test asserts the pair, not either side. It reads each producer limit out of the SHIPPED sandbox dist — a renamed constant fails loudly rather than silently dropping the check — and asserts it fits the contract bound it feeds, unless the boundary is recorded as truncating instead of throwing, with the reason. A second case enumerates every MAX_ limit the SDK ships and refuses an unpaired one, so a new producer bound cannot arrive undecided. On its first run it found three limits nobody had paired, and it could not read four contract constants at all: agent-interface exported only CONTRACT_MAX_JSON_BYTES. The full set is public now, which is what lets a package that writes values assert its own limits fit. agent-provider-tangle suite 271 pass. agent-interface 547 of 548; the one failure, src/certified-context.test.ts, reproduces identically on unmodified main. Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
drewstone
added a commit
that referenced
this pull request
Sep 11, 2026
…320) `@tangle-network/agent-provider-tangle` is the code that VALIDATES a turn, so the agent-interface copy IT resolves decides what a turn may contain — not the copy the consumer installed at its own top level. It declared `^2.6.1`, which still admits the release whose bug it was shipped to escape. agent-interface 2.7.0 (#314) moved every `prompt` field off the 16 KiB metadata bound (`CONTRACT_MAX_STRING_LENGTH`) onto the 1 MiB content bound, and 2.8.0 (#315) made the contract bounds public. Measured 2026-09-11: a consumer whose lockfile already held 2.6.1 for this package, and which then raised its own top-level agent-interface to 2.8.0, ended up with two copies — agent-runtime on 2.8.0, the provider on 2.6.1. Because the provider validates, children kept dying on the 16 KiB bound with a ZodError at `path: ["prompt"]` on a stack whose package.json said the bug was fixed: 14 of 34 children of one run and 8 of 52 of another, every one at iterations 0, surfaced as "retained provider execution requires reconciliation before replacement". Ranges raised, each decided on whether the package's own validation depends on the change: agent-provider-tangle ^2.6.1 -> ^2.8.0 parses every turn with AgentTurnInputSchema and every interactive command with AgentInteractiveSessionPromptCommandSchema; also imports the bounds 2.8.0 made public. agent-provider-cli-bridge ^2.4.0 -> ^2.7.0 prepareCliBridgeRun parses every turn with AgentTurnInputSchema. Same exposure, and 2.7.0 is where the bound it needs arrived. Left alone, each checked rather than assumed: agent-core ^2.0.0 interaction schemas and stream event types only; the interaction-answer bound did not move in 2.7.0. agent-provider-{e2b,daytona} ^2.4.0 type-only imports; validate no turn. agent-provider-computesdk ^2.4.0 parses WorkspaceRequestSchema only. agent-provider-testkit ^2.4.0 builds short conformance prompts and asserts digest replay, not size; a prompt digest is content-addressed and identical across the bound change. agent-trace-contract no agent-interface dependency. `producer-consumer-bounds.test.ts` (#315) cannot see this split: it reads the shipped Sandbox dist and compares it against contract constants it imports, and the workspace pins `overrides["@tangle-network/agent-interface"]: workspace:*`, so in this repo it always links the workspace copy. `resolved-interface-floor.test.ts` checks the other half — behaviour first, then the versions: - `promptFromTurnInput` accepts a prompt one character over the metadata bound; - `AgentInteractiveSessionPromptCommandSchema` reports no issue at `path: ["prompt"]` for an oversized prompt; - the resolved copy exports the contract bounds `producer-consumer-bounds.test.ts` imports by name — on an older copy that file does not fail, it fails to LOAD; - the agent-interface this package resolves is at or above its declared floor; - the declared floor is at or above the release the validation needs, which is what the workspace override would otherwise hide. It imports agent-interface as a namespace on purpose: a named import of a constant an old resolution does not export fails at link time with a SyntaxError naming no package, no version and no reason, and this file exists to diagnose exactly that resolution. Proven against a deliberately old resolution rather than only asserted. The published provider 1.2.0 installed beside agent-interface 2.6.1, with no override, shares the 2.6.1 copy and refuses a 20,000-character prompt with `too_big maximum 16384 path ["prompt"]`; this branch's tarball, in the same tree, makes npm nest 2.9.0 under the provider and the same prompt is accepted unchanged. The new test file, run against an installed 2.6.1, fails 4 of its 5 cases with those messages, and passes 5 of 5 against the published 2.9.0. Tests, serialized (`--fileParallelism=false`): agent-provider-tangle 285 pass in 20 files, up from 280 in 19; cli-bridge 214; testkit 27; agent-core 506; trace-contract 182; computesdk 6; daytona 4; e2b 4. agent-interface 554 of 555 — `certified-context.test.ts` fails 1 of 12 identically on unmodified origin/main in this worktree. `pnpm -r check-types`, `pnpm -r build`, `pnpm check:package-artifacts` (9 packages, 31 exports, 62 export targets) and `pnpm check:control-artifacts` (183 tests) all pass. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #313. Third in the series after #311 and #312.
Problem
promptwasboundedStringSchema—CONTRACT_MAX_STRING_LENGTH, 16,384 characters. That is the bound for identifiers and accounting fields. A prompt is what an agent is asked to do; its size is set by the work, not by the protocol.Observed in a live run already carrying both prior fixes
zkp-frontier-20260911d, on agent-provider-tangle 1.1.10 and agent-runtime 0.214.0:2 of that run's 10 child deaths. The director was handing an independent-checker child a 27 KB patch so it could rebuild from a pinned commit and re-verify a measured result. The transfer could not be expressed as a prompt, so the result stayed unverified.
Worth noting: this was only diagnosable because agent-runtime 0.213.0 now carries the cause chain into the settle reason. Before that it read as a bare wrapper with no cause.
The pattern, stated once
toolInvocations[].resultpromptIf an agent or a tool produced it, it is content. If it names, routes, or accounts for the turn, it is metadata.
contextkeeps the metadata bound on exactly that reading, and the test asserts both halves.Change
Moved to
boundedEventContentStringSchema(1 MiB) at all four sites:AgentTurnInput, the runtime-control prompt command, portable context continuation, and interactive session control. The interactive site keeps its non-empty requirement as a refinement, since the content schema is aZodCustomand carries no.min.Truncation is deliberately not used here, unlike tool output: a silently shortened instruction is worse than a refused one. Only the ceiling moves.
Tests
Three added to the turn-input bounds case, failing on the previous code: a prompt one character over the old bound is accepted, 200 KB is accepted, 2 MiB is still refused.
contextover the metadata bound still throws.agent-interface suite 546 pass.
src/certified-context.test.tshas one failure that reproduces identically on unmodified main — measured both ways, not assumed.Version 2.6.1 → 2.7.0 (added export surface behaviour change on a published schema).
🤖 Generated with Claude Code