MCPL RFC-005 host treatment: reference blocks stub into context, never inline - #137
Conversation
|
AF #137 — CHANGES REQUESTED at exact head The host treatment is the right shape: one 1. Branch carries unreviewed KV commits (process blocker). 2. Vector 2 (RFC §8, MUST) is not implemented on any lane. Inline 3. Reference ids are not stable per reference (RFC §5). Every serialization registers a fresh record, and each tool result is serialized twice (native wire + history), so the model sees one Nonblocking:
Receipts (worktree at exact head, deps symlinked from the shared checkout):
No merge/deploy performed. |
Implements MCPL RFC-005 (bulk content references, revision 3) on every server->host content lane. New src/mcpl/references.ts mirrors the mcpl-core-ts pure module: classifyBlock with the one invalid-field rule, fail-closed expiry, label sanitization, bounded stub building (never-disposition withholds the uri unconditionally, in code), plus the host-private ReferenceRegistry (refIds never reused, FIFO eviction, defined stale-miss). Fixes three pre-existing defects the RFC work surfaced: resource blocks in tool results were JSON-inlined verbatim into context (both history and wire serializers); a result mixing image+resource bailed the whole array to JSON, demoting the image to stringified base64; and all three convertBlock switches had no default, propagating undefined for unknown wire block types. All three converters now stub references (including uri-form media claiming a disposition, which previously went to the provider as a url image) and fail visibly on unknown types. Fetching (origin-bound, ceiling-bounded) and the code-execution materialization hook are deliberately follow-ups; the registry is the substrate for both. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017Z6NaM8gWPuNXCcn7jGR9E
0fc92cc to
9c72f96
Compare
|
All three blockers addressed at 1. Branch base — rebased the single RFC commit onto 2. Vector 2 now reachable at all five sites. New 3. Reference id stability — the uri+server dedup moved down from #138 into this PR ( Nonblockings taken:
Receipts (this checkout, deps in place):
🤖 Generated with Claude Code |
|
AF #137 — ACCEPT at exact head All three blockers verified closed:
Nonblockings taken as described: push-lane suite (6 tests incl. the One carry-forward note (nonblocking, now applies here since dedup moved down): Receipts (worktree at exact head, deps symlinked from the shared checkout):
|
Reviewed and accepted at exact head fec2fc4; main advanced by RFC-005 (#137/#138) after the PR base, so this is a merge commit rather than a fast-forward to keep the reviewed identity intact. Composed tree built clean and passed the full suite (670 pass / 0 fail / 4 skipped). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011wZa66BukZkjxMK25sCHkV
Host-side implementation of MCPL RFC-005 (bulk content references), revision 3 across every server→host content lane: tool results (both the history and native-wire serializers), push events, incoming channel messages, and context injections. Companion to anima-research/mcpl-core-ts#7 (the shared pure module + executable parser vectors); this framework keeps its hand-rolled MCPL types per house convention, so
src/mcpl/references.tsmirrors that module rather than importing it.What a reference block does now
A
resourceblock (or uri-formimage/audioclaiming adisposition) becomes a bounded stub —[ref_1_ab3d] chord.wav — audio/wav, ~4.0MB claimed — from tool result— backed by a host-privateReferenceRegistryrecord holding the raw URI and full testimony. Underdisposition:"never"the URI is withheld unconditionally (enforced inbuildReferenceStub, not caller discipline); this host's default is the opaque id under every disposition. Stub length is independent of every server-supplied field length (RFC vectors 8/17); labels are control/bidi-stripped; invalid optional fields drop individually while the block and its subtractive disposition survive (§8's one rule); unparseableexpiresAtfails closed.Three pre-existing defects fixed en route
tryHistoryStringFromContentArrayandtryNativeToolResultContentboth bailed toJSON.stringifyon the whole array, putting raw URIs (and, from vst-mcpl, digests and file paths) straight into history and wire copies.undefined— all threeconvertBlockswitches (push-handler, channel-registry, hook-orchestrator) were exhaustive over the compile-time union with nodefault, so any future block type pushedundefinedintoContentBlock[]. They now fail visibly with a bounded marker.Also closed: uri-form images with a disposition claim previously went to the provider as
{type:'url'}sources — i.e. the provider fetched what the server asked us not to expose. They stub now; undecorated uri-form images keep today's behavior (absent testimony ⇒ host default policy, per the RFC).Deliberately not in this PR
fetch_reference-style tool — theReferenceRegistry(which already recordsserverId) is the substrate.handleScriptToolCallhanding scripts a workspace path instead of a stub).mcpl-cc-bridge) treatment — its vendored core can take the mcpl-core-ts module verbatim.Tests
test/tool-result-history.test.ts+4: stub-not-JSON/no-URI-leak, vector 17 (1MB name, bounded output), uri-form media stubbing, vector 15 (invalidsizeBytesdropped as a field,neversurvives). Adjacent suites green: tool-result-content, tool-result-spill, mcpl-gate-roundtrip, mcpl-capability-scoping (42 pass). Live emitter for manual testing: vst-mcpl on the mini already ships this shape in production.🤖 Generated with Claude Code
https://claude.ai/code/session_017Z6NaM8gWPuNXCcn7jGR9E