@silverprotocol/openai-agents
v0.6.1
Published
AgJSON normalizer for the OpenAI Agents SDK (RunItemStreamEvent / Responses streaming → AgEvent[]) — fixture-tested.
Downloads
11,016
Readme
@silverprotocol/openai-agents
AgJSON normalizer for the OpenAI Agents SDK (RunItemStreamEvent / Responses
streaming → AgEvent[]) — fixture-tested. It sits on top of your OpenAI
Agents run and translates its native stream into framework-neutral AgJSON;
it doesn't replace the SDK you already use.
Install
npm install @silverprotocol/openai-agents @openai/agents@silverprotocol/core is a required peer (pulled in automatically).
@openai/agents is the OpenAI Agents SDK itself — you need it to produce the
stream. (The normalizer handles the native events structurally, so if you only
feed it already-captured events it's just a type-level peer.)
Upstream compatibility
Supported peer range: @openai/agents >=0.2.0 <0.18 (npm-enforced, optional — this package never imports the SDK).
Wire shapes outside the verified set never crash the normalizer, and the
fixture-drift gate (scripts/check-fixture-drift.mjs) turns every newly-appeared
upstream field into a tracked triage disposition rather than an unnoticed drop —
carried losslessly where a carry channel exists (see sdk-surface.json for this
facet's per-field dispositions, including its disclosed silently-dropped gaps).
| @openai/agents | verified | with | evidence |
| --- | --- | --- | --- |
| 0.17.0 | 2026-09-05 | 0.6.1 | Re-attestation at the SAME peer (0.17.0 still latest) with the transitive openai-node client deliberately floated 7.8.0->7.10.0 (fresh resolution): the SSE ResponseStreamEvent union is IDENTICAL (58 members) across 7.8/7.9/7.10 over the HTTP transport the facet and capture agent use; 7.10.0 adds WebSocket-only steering events (response.steer.), an input-only configuration_update item, FunctionToolCall.async, incomplete_details.reason 'max_messages' (7.9.0) / 'steered' (7.10.0) - the response.incomplete arm goes straight to turn.error{code: reason, message: reason}, so the raw reason survives with zero code change (regression pin added) - and ResponseError.misalignment {detailed_explanation, error_type, steer{message}} with code misalignment_policy_violation (GPT-6 Astra misalignment monitoring). CARRY added: the response.failed arm now emits a turn-scoped ext.openai.misalignment {responseId, misalignment} verbatim immediately before turn.error (turn.error has no providerMetadata slot per spec section 4); absent => byte-identical; synthetic-tested only - documented auto-stop applies to persisted-reasoning / WebSocket / compaction requests, none used by the e2e HTTP path. compute_units watch item CLOSED: added in 7.8.0 types, removed in 7.9.0, never on the wire. 7.10.0 also adds a resources/safety SafetyAlert surface (webhook plane, out of scope). MODEL RELEASE: gpt-6-astra (GA 2026-09-03; sole id, no dated snapshot; effort low..max, 'none' -> 400; temperature/top_p rejected; $10/$1 cached/$50) captured live as echo-gpt6astra through @openai/agents 0.17.0 (no temperature/top_p/effort sent by the runner for this model) - census: ONE new response-level attribute response.access_programs.cyber = 'standard' at three norm-paths (allowlisted as router-plane program-tier metadata beside service_tier); zero drops otherwise; 0 reasoning tokens on the echo (Astra chose not to reason). DEFAULT_MODEL.openai/vercel stay gpt-5.6-sol (the founder's call, outstanding). |
| 0.17.0 | 2026-09-02 | 0.5.4 | Re-attestation at the SAME peer (0.17.0 is still latest; published 2026-08-19) after the cohort's fresh lockfile resolution floated the transitive openai client 7.4.0->7.8.0 (agents-openai depends on openai ^7.2.0): openai-node 7.5.0+ adds five response.shell_call_command./shell_call_output_content.* stream events (hosted shell tool; ignored by the facet's default arm, cannot appear in MCP-only scenarios) and 7.8.0 adds ResponseUsage.compute_units?: number|null ('Currently null when available'; already gone again from 7.9.0's types) - census watch item. LIVE: echo-gpt56/openai RE-CAPTURED (gpt-5.6-sol) - census ZERO drops / ZERO new fields; the gpt-5.6 alias still routes to gpt-5.6-sol (OpenAI docs re-checked 2026-09-02; no newer public model family - new ids are the Daybreak-gated gpt-5.6-cyber / gpt-daybreak--latest). |
| 0.17.0 | 2026-08-28 | 0.5.3 | 0.17.0 MINOR study (typescript-sdk#20/#24, downstream guuey#338): all seven consumed agents-core dist files BYTE-IDENTICAL to 0.16.0 (events.d.ts, types/protocol.d.ts, items.d.ts, result.d.ts, usage.d.ts, runner/streaming.mjs, runner/modelOutputs.mjs; RunItemStreamEventName 10, protocolItem 17) and agents-openai's only change is websocket replay-safety bookkeeping in openaiResponsesModel.mjs (no event emission touched) -- wire-no-op on every consumed surface; drift gate zero member drift. LIVE capture: echo-gpt56 standing seed REFRESHED at 0.17.0 (gpt-5.6-sol), 46 native events, event-type census identical to the 0.14.2 capture. The census caught ONE wrapper-level field the d.ts-pair inventory cannot see: RunToolCallOutputItem.executionStatus ('executed', introduced in agents-core 0.15.0 -- present since the 0.15/0.16 studies, first observed live here). Disposition handled: carried verbatim on tool.done providerMetadata alongside caller (set only when the runner actually invoked the function tool; absent on guardrail/cancellation-synthesized results); 3 facet tests, transforms + registry entries, snapshot regenerated. Peer range widened >=0.2.0 <0.17 -> <0.18; e2e pin 0.17.0; full gate suite green. |
| 0.16.0 | 2026-08-15 | 0.4.4 | 0.16.0 MINOR study: both consumed agents-core dist files BYTE-IDENTICAL to 0.15.0 (events.d.ts and types/protocol.d.ts; RunItemStreamEventName 10 members, protocolItem 17, full zod-literal inventory zero-delta) - the minor is agent/handoff/runner internals the facet does not ingest. Peer range widened >=0.2.0 <0.16 -> <0.17 (ships as 0.4.4 so consumers installing 0.16.x stop getting npm peer warnings); e2e pin 0.16.0, forced gate suite green. |
| 0.15.0 | 2026-08-13 | 0.4.2 | 0.15.0 MINOR study (typescript-sdk#15, filed as [peer-drift] — the nightly's forced-0.15.0 gate suite was already green): RunItemStreamEventName unchanged (10 members incl. compaction_item_created), protocolItem unchanged (17) — both drift-gate-verified; wire-no-op on every consumed surface. Peer range widened >=0.2.0 <0.15 -> <0.16 (ships as 0.4.3 so consumers installing latest stop getting npm peer warnings); e2e pin 0.15.0. |
| 0.14.3 | 2026-08-09 | 0.4.1 | peer sweep: 0.14.2->0.14.3 d.ts diff — ONE new RunItemStreamEventName member (compaction_item_created, drift-gate-caught), protocolItem union unchanged (17). Disposition handled: mapped to the first-class compaction content.block converging with the claude facet (synthetic test pins the mapping + no-double-carry + clean fold). Full gate suite green at the new pin (110 facet tests, 949 workspace). |
| 0.14.2 | 2026-08-04 | 0.3.9 | 0.14.0→0.14.2 verified a run-stream wire no-op: agents-core events.d.ts / types/protocol.d.ts / items.d.ts / result.d.ts byte-identical across 0.14.0/0.14.1/0.14.2 (both hops diffed); agents-openai 0.14.2 metadata-only. Non-wire: 0.14.1 = type re-exports + sandbox runtime; 0.14.2 = RunState CURRENT_SCHEMA_VERSION 1.15 (serialized state, not streamed), MCP credential redaction, realtime transport_event now preserving raw fields (realtime-only — this facet does not normalize realtime transports; noted for any future realtime facet). Pin bumped; live re-capture in this cohort's capture step. |
| 0.14.0 | 2026-07-29 | 0.3.7 | Live capture landed (echo-gpt56 @ gpt-5.6-sol, agents-core 0.14.0): gpt-5.6-sol populates AssistantMessageItem.phase='final_answer' on the real wire, and the census caught that the synthetic-frame text.end carry never fires live — message_output_created for the final round arrives after response_done closes the message. Fixed with ext.openai.late-phase {itemId, phase} on the id'd post-close path (late-citations degrade convention); 2 unit tests added (carry + 0.13.5-shaped negative control); census transforms/registry updated ([].data.response.output[].phase, [].item.rawItem.phase); replay + census gates green. program/program_output and caller remain synthetic-only (programmatic tool calling needs the hosted tool enabled in an e2e scenario — future capture). |
| 0.14.0 | 2026-07-29 | 0.3.7 | fixture suite + drift gate + full 0.13.5->0.14.0 agents-core d.ts diff audit: envelopes unchanged (RunItemStreamEventName still the same 9 names; raw StreamEvent kinds identical) — all five wire additions carried at the facet layer: program/program_output protocol items (openai >=6.46 programmatic tool calling, SUPERSEDES the 0.13.2 KNOWN-DEFERRED bullet — the SDK's converters now push them as RunToolCallItem/RunToolCallOutputItem, dist/runner/modelOutputs.mjs; tool.start name:'builtin:program' with {code,fingerprint} verbatim args, callId-correlated tool.done, status incomplete->error), optional ToolCaller caller provenance on function/hosted/shell/apply-patch call+result items (tool.start/tool.done providerMetadata, camelCase verbatim; the authoritative raw output_item.added path normalizes openai-node's snake_case caller_id), AssistantMessageItem.phase (matching text.end providerMetadata, per-part + the id-less late-message ext payload), ShellCallResultItem.status (NEW optional enum — 'incomplete' joins the error mapping even on all-clean exits; carried verbatim on tool.done providerMetadata); synthetic-frame unit tests incl. 0.13.5-shaped negative controls (output unchanged); live capture pending (echo-gpt56 refresh) |
| 0.13.5 | 2026-07-22 | 0.3.5 | LIVE capture: echo-gpt56 standing seed REFRESHED at 0.13.5 (gpt-5.6) — the new itemId OBSERVED live on the flattened output_text_delta arm and triaged (census allowlist + field registry, first-observed provenance recorded); replay + census gates green (zero untriaged drops) |
| 0.13.5 | 2026-07-22 | 0.3.5 | fixture suite + drift gate + full 0.13.2->0.13.5 agents-core d.ts/dist diff audit: events/items/usage/protocol item shapes and the stream emitters (runner/streaming.mjs, runner/modelOutputs.mjs) byte-identical; sole wire-relevant delta is an optional camelCase itemId on the SDK-flattened output_text_delta arm (protocol.d.ts StreamEventTextStream) — deliberately no-op'd as the documented duplicate of the authoritative model:response.output_text.delta path, whose snake_case item_id is unchanged; the rest is request-side tool-definition plumbing (FunctionTool/SerializedFunctionTool providerData, explicitly stripped from tool_search_output payloads by serializeFunctionToolForToolSearchOutput) and sandbox/tracing infra |
| 0.13.2 | 2026-07-13 | 0.3.3 | LIVE capture: echo-gpt56 corpus (gpt-5.6) — landed as a standing replay/census seed; cache_write_tokens mapping confirmed on real wire (turn.done usage.cacheWriteTokens); zero unparsed events |
| 0.13.2 | 2026-07-13 | 0.3.3 | fixture suite + drift gate + adversarially-verified 0.12.0->0.13.2 wire-surface audit (GPT-5.6 era: cache_write_tokens mapped, invalidFinalOutput late-message rescue; hosted multi-agent + programmatic tool calling documented KNOWN-DEFERRED); live capture pending (echo-gpt56 scenario ready) |
| 0.12.0 | 2026-07-03 | 0.1.0 | live captures: echo-gpt55 + app-spec-structured-result corpus (gpt-5.5) |
Usage
import { Agent, run } from "@openai/agents";
import { createOpenaiNormalizer } from "@silverprotocol/openai-agents";
const agent = new Agent({ name: "Assistant", instructions: "Use the echo tool." });
const n = createOpenaiNormalizer();
const agEvents = [];
// `run(..., { stream: true })` is the OpenAI Agents SDK's own streamed run —
// you keep using your framework as-is; this package normalizes what it emits.
const stream = await run(agent, "call the echo tool", { stream: true });
for await (const native of stream) agEvents.push(...n.push(native));
await stream.completed; // let the run finish
agEvents.push(...n.flush()); // seal anything still openpush() returns the AgEvent[] synthesized from each native stream event
(RunItemStreamEvents or raw Responses-API events — both handled); flush()
drains buffered end-of-stream state. Any async/sync iterable of those native
events works — a live streamed run, or events you captured earlier.
Then fold the resulting AgEvents into messages and turns with
@silverprotocol/core's reduce() — the same client code regardless of which
framework produced the stream.
Spec: silverprotocol.io/AgJSON — canonical
in silverprotocol/AgJSON; wire
version 1.0.0-draft.3.
