1.0.0-rc.1
The first release candidate for 1.0.0. All six packages move to 1.0.0-rc.1 together, and they ship spec revision 1.0.0-rc.1 (AGJSON_VERSION). From here to 1.0.0, only errata and fixes change the spec, each as a further release candidate.
Installing the release candidate
The release candidate is published under the rc tag. latest stays on 0.12.5, so a plain install doesn’t pick it up:
npm i @silverprotocol/core@rc
Install each framework package you use the same way (for example @silverprotocol/google-adk@rc), so every @silverprotocol/* package in your lockfile is on 1.0.0-rc.1. A receiver on 0.12.x accepts 1.0.0-rc.1 envelopes: it’s the same major (§12). While a release candidate is the most recent publish, a package’s page on npmjs.com shows no README; each package still carries its README.
Upgrading from 0.12.x
These change what you see without a code change on your side. Each is described in its package’s section below.
- Four fold rules are stricter or newly defined. A repeated
message.startid, or amore: trueafter a call’s final result, now parks the fold. A nested turn’s thread is defined, and an empty JSON Patch is a no-op (see “Fold changes”). - Google ADK: an in-band error no longer closes the turn at once. The
errorevent arrives when ADK reports the error, and the turn closes once, asturn.error, at the invocation’s end, even when a later sub-agent answered. A host-reported error’s usage now adds to the turn’s usage instead of replacing it. - Google ADK: without the host-completion event, a later event after a final answer opens the next turn (
<turn id>_g<n>), instead of landing after the closed turn’s terminal. - Claude Agent SDK: a refusal the CLI doesn’t retry now closes as
turn.donewithfinishReason: "refusal", where 0.12.x closed it asturn.error. - OpenAI Agents SDK: a hosted MCP call’s
tool.start.nameis the MCP tool’s own name, and a hosted-MCP approval request stays a pending call until its answer closes it.
Fold changes
These change what reduce() builds, or when it stops and asks for a snapshot resync. They are tracked, with their spec rules, in AgJSON#5.
- A
message.startnaming an id the fold already holds as a message parks (§5.0 INV-MSG). Earlier releases replaced the message. The held set spans the whole fold, so a later invoke that reuses a held id parks too, until amessage.remove, or a snapshot that omits the id, releases it. - A
tool.donewithmore: truefor a call whose final result the invoke already landed parks (§5.0 INV-BLOCK). Earlier releases appended a secondtool-resultblock. A result delivered across invokes is onetool.donewithoutmore: true(INV-XINV). - A nested turn takes its parent’s thread when that thread is known, else the fold’s root thread. Until one is known, its record is held and
result()leaves it out. Earlier releases sometimes gave it theparentTurnIditself as itsthreadId. The referenceReducerholds up to 64 nested turns waiting for a thread, and a further one parks. - A turn-less terminal lands on the sole open turn even when that turn was opened only by a
message.start. 0.12.x parked there. With a second turn open and no record for it, a turn-less terminal ortool.donenow parks, where 0.12.x folded it onto the turn that held a record. - An empty JSON Patch (
[]) applies as a no-op. As the first state event, or against an unseeded memory record, it no longer asks for a resync.
What you may see: a stream that re-sends a message.start or a preliminary result after the final one now sets needsResync. No recorded stream has either shape, and the recorded streams that reach the nested-turn change fold as before.
@silverprotocol/core
- A
messages.snapshotthat carriesturnskeeps a helddisplay.required. It used to discard it, though the spec says a reducer must never drop one. A turn the snapshot carries gets the held entries merged into its record, and a turn it doesn’t name keeps them held until its thread is known. This is a defect fix. - A
subagent.startfor a turn the fold already holds gives that record itsparentTurnIdwhen it has none. - The sole open turn counts every turn the fold has seen opened and not closed, not only turns that hold a record. A call whose final result parks is no longer marked as landed.
- A message with no
turnIdis never attachable, even when a turn is namedunknown-turn. checkAgInput()rejects an A2UI surface action that asks for a response without anactionId, asmalformedat the action’sactionId. The spec already required it.- New exports:
AG_EVENT_MAX_DEPTH(1,016) andAG_EVENT_DEPTH_ALLOWANCE(16), the depth bound that 0.12.5 introduced, andcopyJson, for a host that seeds a fold from its own store. All three are@beta. - A member named
__proto__is omitted at every depth of an event the reducer folds, whether or not the event was decoded first, and by core’s emit helpers. A JSON Patch path orfromnaming that token fails. - The 0.12.5 fixes are here too: a JSON Patch operation naming an inherited member fails, an event nested past the depth bound is kept as an ignored event in its
seqslot, and no consumer-side parse throws on a deep value.
Google ADK
- An in-band error no longer closes the turn at once. ADK keeps running after an event that carries
errorCodeanderrorMessage: a SequentialAgent’s next sub-agent, a retried Workflow node, a callback or a further model round. The package now emits the non-terminalerrorevent when the error arrives, and closes the invocation’s turn once, asturn.error, at the invocation’s end. That close carries the host-terminal event’s code when one was fed, otherwise the first in-band error’s, and the turn’s accumulated usage. Such a turn never closes as success, even when a later sub-agent or a retried node answered. When the turn’s pause was signalled, it closes paused with its asks, and the error closes on a new turn,<turn id>_error. - A host-reported error’s usage adds to the turn’s usage. A
__host_error__that carries usage used to replace the usage the stream had already reported. It’s now added, field by field. A host that passes the whole run’s total there will see it counted twice: pass the usage of unreported work only. - Without the host-completion event, a later event of the invocation opens the next turn. A final answer still closes its turn as
successon arrival, but a later event of the same invocation (content, a usage report, an interruption, or a member carried verbatim) now opens the invocation’s next turn,<turn id>_g<n>, instead of landing after that turn’s terminal, and aninterrupted: truethat follows a completed Live generation closes that next turn asturn.abort(interrupted). An event that only changes shared state, and an aggregate that only repeats the closed turn’s text, stay on the closed turn, where they add nothing but astate.delta. - A ParallelAgent branch’s final answer ends its branch, not the invocation’s turn. Without the host-completion event, such a turn now closes at
flush()asturn.abort(stream-truncated), as a completed Workflow does. - A model call’s closing aggregate is matched to the text that call streamed, per source, so the aggregate no longer renders its text a second time or parks the fold on interleaved streams. This is a defect fix.
- On the Live path, a second barge-in now interrupts its generation, where it used to be dropped as a re-yield.
- ADK’s prompt-block event records
prompt.blocked. InStreamingMode.NONE, ADK turns a blocked prompt into an event whoseerrorCodeis the block reason. The package now records oneprompt.blockedfor each such event, before the turn’s terminal, andADK_PROMPT_BLOCK_REASONS(@beta) lists the values it treats. No event that ADK’s A2A relay forwards is read as a prompt block. The terminal is unchanged, so read a block fromprompt.blocked. - A
safety_blockedclose names its block value assafety[].categorywhen no safety rating does.IMAGE_PROHIBITED_CONTENTandIMAGE_RECITATIONnow map tosafety_blocked, like the other six block values. - Values that were dropped now ride the event-level
provider-rawcarry: anerrorMessagethat arrives without anerrorCode, and a grounding support’s members of an unexpected type. A part that holds text beside a call, a result or media now maps each member, and a part markedthought: truethat carries a call, a result or media maps through its own arm, with{thought: true}carried. The message carry and the two part mappings are defect fixes. - A relayed remote failure that ADK’s A2A relay repeats in its closing event is one error.
Claude Agent SDK
- A refusal the CLI doesn’t retry closes as
turn.done. The CLI reports it as an API error and then a result markedis_error. The package now closes the turn asturn.donewithfinishReason: "refusal"andsafety: [{category: "refusal", blocked: true}], and keeps the CLI’s error as its outcome. 0.12.x closed it asturn.error. The refusal’sstop_detailsalso ride the refused message’smessage.metadata, less any provider credit token. - A correlated
task_notification’s carry follows the subagent run’s close it produced. Three recorded subagent streams reorder: theext.anthropic.framecarry moves after the nested terminal andsubagent.done. - The startup failure
org_config_required_unavailable, new in 0.3.296, closes the turn asturn.errorwithretriable: true, since a retry may succeed.org_config_refusedstaysretriable: false. claude-haiku-5-5is now the Claude capture default. It affects how the test recordings are made, and nothing a host sees.
OpenAI Agents SDK
@silverprotocol/openai-agentsnow supports@openai/agentsup to 0.20.x (peer range>=0.2.0 <0.21). 0.20 reads the run state 0.19 saves, so a run paused under 0.19 can be resumed on 0.20. The reverse doesn’t hold: 0.19 rejects a run state that 0.20 saved.- A change in
@openai/agents0.20 that hosts may notice. It’s the SDK’s, not the package’s. After an approval is answered, the next model call now counts towardmaxTurns. So a resumed run with a tightmaxTurns, such as 1, now stops withMaxTurnsExceededErrorwhere 0.19 let it finish. A host that reports that error to the package as documented, as a__host_error__with codemax_turns, sees the turn close asturn.errorwith that code. RaisemaxTurnsif a resumed approval needs a follow-up model response. - A run state saved by 0.19 that holds a deferred hosted MCP call needs a fresh tool search on 0.20 before that call runs.
- A tool search’s hosted MCP discovery names (
toolSearchMcpToolNames, new in 0.20) ride that search’stool.doneproviderMetadata, next totoolSearchAgentName. - A built-in tool call stays in the round that made it.
@openai/agentsstreams a round’s run-items after itsresponse.completed. A round that lists a built-in call now waits for them, instead of closing without them and opening a turn that held them. A client-executed call’s round (shell, apply-patch, computer) closes only after its result lands, which is a defect fix. - A hosted-MCP approval request stays a pending call until its answer closes it, with one
tool.done:okwhen approved,deniedwhen not. A round still waiting on its requests atflush()closes paused. A hosted MCP call and an approval request now name the MCP tool intool.start.name, and the item’s type ridesproviderMetadata.type. - Hosted calls carry what they used to drop: their arguments, server label, results and failures; a file search’s queries and results; a code interpreter’s code and outputs; an image generation result as a file block, with its own fields; an MCP call’s error object; and an answer’s citations, which now land on its text block.
- A refusal’s text lands as one text block in its round’s message, where it was dropped, and a refusal now closes its own round with
finishReason: "refusal"instead of the round after it. - A hosted call whose native status is
incompletecloses as an error, and a status other thancompletedridestool.doneproviderMetadata.status. - The
@betatypeOpenAIOutputTextnow declares theproviderDataits annotations arrive in.
Performance
Measured against 0.12.5 on a quiet machine:
- Folding costs the same, within measurement noise, over the recorded streams and the engine-built fixtures.
- Emitting takes about 10% longer per event over the recorded streams. By framework, it’s about 7% longer for the Claude Agent SDK, 5% for the OpenAI Agents SDK, 17% for the Vercel AI SDK and 33% for Google ADK.
Spec: AgJSON 1.0.0-rc.1
rc.1 revises draft.8. The revision note in SPEC §15 lists every change. Among them:
- The fold rules above, with a normalizer and a host rule for message ids. Within an invoke, a normalizer must not reuse a message id an earlier
message.startortool.done.messageIdnamed. A host must not deliver amessage.startreusing such an id, or one its own earlier invokes of the thread named. - §0.2 lets a consumer bound nesting depth and ignore, in its
seqslot, a well-formed envelope past the bound. - §4 states how a block is signalled: from
prompt.blocked, or from thefinishReasonof theturn.donethat closes the turn, never fromoutcome.type. - Google ADK rules: the in-band error close (§8.0 item 35), the prompt-block record (item 34), the interrupted close (item 17), and the A2A relay rules (item 36). Each binds a normalizer targeting ADK.
- §8.0 item 17 now directs an interrupted turn’s close (
turn.abort, reasoninterrupted, frompush()orflush()), where draft.8’s INV-TURN flush list named aturn.error; the reference ADK package already closed this way. - OpenAI built-in rounds and hosted-MCP approvals (§8.0 items 14 and 20, §10 item 59).
- §13.7 names where a member named
__proto__is omitted (emit, decode and fold), and §5 resolves JSON Patch tokens by own members, as RFC 6901 reads them. - §12 defines OPEN STRING, the class its table already used for
effort, and defines its direction column. - The A2UI reference now pins the v1.0 Candidate at a commit, and the OpenAI Apps reference cites an archived capture of its page.
- Restatements that disagreed with the rules they restate are corrected, and the rows that left a case undefined now state it as the reference folds it.
draft.8 envelopes remain accepted (same major, §12).
Toolchain
The packages are built with TypeScript 7 and pnpm 12. They still require Node.js 22.12 or later, and the exported API is unchanged apart from the exports listed above.
Verified versions
Each framework package is verified end to end, tool calls included, against a live run at:
@anthropic-ai/claude-agent-sdk0.3.296;@openai/agents0.20.0;@google/adk2.2.1, with@google/genai2.28.0;ai7.0.137.
Wire version
1.0.0-rc.1. Replaying every recorded stream through the 0.12.5 and 1.0.0-rc.1 packages, 102 of the 105 runs give byte-identical events: the OpenAI Agents SDK (16) and Vercel AI SDK (9) streams, the Google ADK streams (24, each with and without the host-completion event), and 29 of the 32 Claude Agent SDK streams. The other three are the Claude subagent streams, which carry the same events in a new order (above). All 105 fold to the same result. Of the 619 runs of the engine-built ADK and OpenAI fixtures, 142 park on 0.12.5 and 14 on rc.1, and none parks on rc.1 that didn’t on 0.12.5.
The 1.0.0-rc.1 packages are built from typescript-sdk commit 8cf67384, the commit npm’s provenance for all six 1.0.0-rc.1 packages attests.