Updates

Release notes for the @silverprotocol/* packages. Every cohort ships all packages in lockstep, npm-attested, with the verification evidence on each package's compatibility table.

0.12.3

Security patch: a `__proto__` member in received data no longer picks an object's prototype

A security patch. All six packages move to 0.12.3 together. The spec revision stays 1.0.0-draft.8. Details are in the advisory, GHSA-4pcf-49g3-h325: who is affected, workarounds, and what isn’t covered.

What changed

  • @silverprotocol/core requires zod 4.4.0 or later. With an older zod, AgEvent.parse() could give a received ext.* event a prototype taken from its own __proto__ member. Three side effects:
    • An application that pins an older zod for itself gets a second copy of zod for core.
    • An application that combines core’s exported schemas with its own zod should move its own zod to 4.4.0 or later.
    • overrides or resolutions that force zod below 4.4.0 defeat the requirement. Remove them, or decode with ingestAgEvent().
  • Claude Agent SDK: a model name in the native modelUsage no longer sets the prototype of usage.byModel or of modelUsage in ext.anthropic.result-meta, and a supersedes list is copied like the other carries.
  • Vercel AI SDK: an emitted value never holds a member named __proto__, at any depth, and a step’s stop details in message.metadata no longer take their prototype from one; the members beside it are carried as before.
  • Google ADK: a member named __proto__ in a native is dropped at every depth, and the unparsed-native carry no longer takes its prototype from one.
  • OpenAI Agents SDK: a host error’s usage reaches turn.error copied, without an own __proto__ key; a well-formed usage is unchanged. A host usage that isn’t a valid usage once that key is dropped is no longer put on turn.error; it rides ext.openai.unparsed instead.

What to do

  1. Upgrade every @silverprotocol/* package to 0.12.3, including where another package pins one (check your lockfile).
  2. If your application decodes received events with AgEvent.parse() or ingestAgEvent(), upgrade core now. Versions of core before 0.6.4 are being deprecated on npm.
  3. Review the advisory for what to check in application code that copies values taken from events.

0.12.2

Security patch: Google ADK stops emitting a remote agent's repeat of the forwarded request

A security patch. All six packages move to 0.12.2 together, and only @silverprotocol/google-adk changes. The spec revision stays 1.0.0-draft.8. Details are in the advisory, GHSA-7mgv-vf77-ch53. This is separate from the 0.12.1 patch, which doesn’t stop the repeat described here.

What changed

  • A remote agent’s repeat of the forwarded message is no longer mapped. Some remote A2A agents repeat the forwarded message back in their first reply. ADK-Python’s A2A executor on a2a-sdk 0.3.x sends it back as a new task’s submitted status, in the "user" role, and the relay yields it as the remote agent’s own output: model text on @google/adk, reasoning on ADK-Python’s relay. Before 0.12.2 the normalizer mapped that output like any other content, so the forwarded conversation reached the emitted events. It can hold the user’s text, other agents’ replies, tool-call arguments and tool results, and, on @google/adk before 2.1.0, an adk_request_credential call’s OAuth client secret.
  • 0.12.2 recognizes the repeat in a relayed event whose recorded reply is a submitted status with its message in the "user" role, and maps the event as if the repeated message’s parts were absent. Every other part of the event, including a task’s artifact parts, is mapped as before. In their place it emits one ext.google.relay-echo-omitted event inside the turn the relayed event belongs to. That event carries only the number of parts omitted, and none of their content.
  • A user-role message relayed in any other state, such as a remote workflow’s tool result while it’s working, is mapped as before.

Who is affected

An application on @silverprotocol/google-adk 0.3.0 to 0.12.1 that runs an agent tree containing a RemoteA2AAgent, or feeds the normalizer ADK events serialized from ADK-Python’s relay, when the remote agent repeats the forwarded message. An application that doesn’t relay to a remote A2A agent, or whose remote agents don’t repeat it, isn’t affected.

What to do

  1. Upgrade every @silverprotocol/* package to 0.12.2, including where another package pins one (check your lockfile), and rebuild any image that bundles the normalizer.
  2. Rotate any secret that could have ridden in the repeat, as the advisory lists.
  3. Purge those relay turns’ stored output, as the advisory describes.

Until you can upgrade, the advisory describes a workaround for each relay. What 0.12.2 doesn’t cover is listed there too.

0.12.1

Security patch: Google ADK stops carrying an A2A relay's forwarded request

A security patch. All six packages move to 0.12.1 together, and only @silverprotocol/google-adk changes. The spec revision stays 1.0.0-draft.8. Details are in the advisory, GHSA-685v-3m98-6f7p.

What changed

  • Google ADK no longer carries an A2A relay’s bookkeeping. When a run relays a conversation through @google/adk’s RemoteA2AAgent, ADK records its exchange with the remote agent in the customMetadata of the events it relays, under a2a:request, a2a:response, a2a:task_id and a2a:context_id. The forwarded request can hold the host’s A2A push-notification token and credentials, request metadata, local ids and the conversation it forwards. Before 0.12.1, the normalizer copied customMetadata unchanged into provider-raw blocks, and a relayed event it couldn’t map reached an ext.google.unparsed event with its native copy intact.
  • 0.12.1 drops those four entries from each event’s customMetadata, and from the native copy in an ext.google.unparsed event under either spelling of the field (customMetadata or custom_metadata). Every other entry still rides, and no customMetadata member is emitted when none remains. The package’s README documents this exception to draft.8’s carry of unmapped ADK event fields.
  • No recorded stream carries these entries, so none changes.

Who is affected

An application on @silverprotocol/google-adk 0.3.0 to 0.12.0 (the versions before 0.12.1 that declare @google/adk as a peer) that either runs an agent tree containing a RemoteA2AAgent, or feeds the normalizer ADK events serialized from ADK-Python’s relay. An application that doesn’t relay to a remote A2A agent isn’t affected.

What to do

  1. Upgrade every @silverprotocol/* package to 0.12.1, including where another package pins one (check your lockfile), and rebuild any image that bundles the normalizer.
  2. If AgJSON events from an affected version were forwarded or persisted while your application relayed through a RemoteA2AAgent, rotate the credentials the advisory lists, starting with the A2A push-notification token and credentials.
  3. Purge stored provider-raw blocks, and ext.google.unparsed events whose native carries a2a:* entries in customMetadata or custom_metadata.

Not covered

These are unchanged in every version, 0.12.1 included:

  • other customMetadata entries, which 0.12.1 still carries;
  • copies of ADK’s native events that your application reads, stores or forwards itself;
  • copies ADK keeps or forwards itself;
  • a remote agent that repeats the forwarded message in its reply, which @google/adk yields as the relay’s own output. Upgrading doesn’t stop this. The advisory describes a RemoteA2AAgent afterRequestCallbacks entry that removes the repeated message from a response in the submitted state, and what to rotate and purge for it. ADK’s own copies and the repeated message have been reported to Google. For the repeated message in the events this package emits, 0.12.2 addresses it; see its release note.

0.12.0

Node 22.12 or later, and which APIs the 1.x promise covers

A minor release of the SDK on the unchanged spec revision 1.0.0-draft.8. Every package now declares Node.js 22.12 or later, the types that restate an upstream SDK’s native shapes are marked @beta, and a Google ADK error close now carries the turn’s usage. It also publishes draft.8’s first erratum, which changes no set, meaning, wire, fold or golden.

Upgrading from 0.11.x

  • Node.js 22.12 or later. Every package now declares "engines": {"node": ">=22.12.0"}. The packages are ES modules and use no Node API; the floor is 22.12 because that’s the first 22.x whose require() loads ES modules from CommonJS. CI now runs on Node 22 and 24. On an older Node, npm warns (EBADENGINE); nothing is removed.
  • The 1.x promise, and what @beta means. A symbol marked @beta in the type declarations is outside the 1.x promise: it may change in a minor release. This release marks as @beta the types that restate an upstream SDK’s native shapes: the OpenAI Agents SDK package’s 31 native-mirror types, and the Google ADK package’s AdkEvent, AdkContent and AdkPart. These follow the package’s peer range. Core’s producer helpers were already @beta. Each package’s own API (its createXNormalizer(), the options it takes and its helpers) carries the 1.x promise. It’s a marking, not a removal: nothing stops compiling. The rule is stated in core’s README, under “API stability”.

Google ADK

  • An error close carries the turn’s usage. When ADK ends a turn with an error in the stream (errorCode and errorMessage), the turn’s turn.error now carries the turn’s usage, as a host-reported error close already did. No recorded stream reaches this path, so none changes. This is a producer fix: the in-band close now carries the usage the spec defines for turn.error, and no field’s meaning changes.
  • An empty artifactDelta no longer rides a provider-raw block. ADK gives every event an empty artifactDelta, and the normalizer carried it each time as a provider-raw block in the message content. It now skips artifactDelta only when it’s an empty object. A non-empty one still rides exactly as before, alone or beside another unmapped action. Recorded ADK streams change by design: those blocks leave, a block that also carried another action keeps it without the empty key, and seq renumbers. The fold keeps every message, and every turn record is unchanged.

OpenAI Agents SDK

  • A handoff at the start of a resumed run gets a real parent turn. A resumed run can stream a handoff before any turn of the invoke has opened. The normalizer now opens the invoke’s own turn (turn_resume_<callId>) at the handoff’s handoff_requested, instead of at handoff_occurred, and makes it the parent of the handoff’s nested turn, so the nested turn carries the host’s thread. Before, the nested turn’s parentTurnId was a placeholder that named no turn. In a stored fold, the nested turn’s parentTurnId changes, and the resumed turn now comes before it in turns[]. Messages and artifacts are unchanged, and no recorded stream has this shape. This is a defect fix: the nested turn now gets the parent the spec already prescribes (§1.1: a nested turn’s parentTurnId points at the enclosing turn), and no field’s meaning changes.

@silverprotocol/core

  • The MCP App display-mode request lists its modes in AgDisplayMode’s order (inline, pip, fullscreen). The values are the same, so validation is unchanged; the type unions print in the new order.
  • The README gains the “API stability” section described above.

Spec: an erratum to draft.8

The first erratum to draft.8, applied in place under §15’s errata policy, with no version change. §12’s closed-set paragraph now notes, in an informative parenthetical, that the reference SDK checks its schema against the table: its spec-drift check reads the table and compares its sets. §3’s mcp-app mode union is listed in AgDisplayMode’s order. Neither edit changes a set, a meaning, the wire, a fold or a golden.

Wire version

1.0.0-draft.8, unchanged. Replaying every recorded stream through the 0.11.0 and 0.12.0 packages, the Claude Agent SDK (30), OpenAI Agents SDK (15) and Vercel AI SDK (8) streams are byte-identical, in their events and in the fold. Of the 116 Google ADK runs (the recorded streams, the same streams with and without the host-completion event, and the pause fixtures in both modes), 6 are identical, and 110 differ only by the removed empty artifactDelta blocks, the empty key taken off the blocks that also carry another action, and the seq numbering that follows. Every fold matches once the same changes are applied.

The v0.12.0 release is tagged at typescript-sdk commit ef24ebd4, the commit npm’s provenance for all six 0.12.0 packages attests.