@graphorin/core 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +88 -0
- package/README.md +14 -8
- package/dist/channels/channels.d.ts.map +1 -1
- package/dist/channels/index.d.ts +2 -2
- package/dist/channels/index.js +2 -2
- package/dist/channels/pause.d.ts +47 -2
- package/dist/channels/pause.d.ts.map +1 -1
- package/dist/channels/pause.js +62 -2
- package/dist/channels/pause.js.map +1 -1
- package/dist/contracts/checkpoint-store.d.ts +97 -1
- package/dist/contracts/checkpoint-store.d.ts.map +1 -1
- package/dist/contracts/checkpoint-store.js.map +1 -1
- package/dist/contracts/index.d.ts +5 -5
- package/dist/contracts/index.js +2 -1
- package/dist/contracts/memory-store.d.ts +59 -2
- package/dist/contracts/memory-store.d.ts.map +1 -1
- package/dist/contracts/provider.d.ts +20 -6
- package/dist/contracts/provider.d.ts.map +1 -1
- package/dist/contracts/session-store.d.ts +10 -2
- package/dist/contracts/session-store.d.ts.map +1 -1
- package/dist/contracts/tool.d.ts +75 -1
- package/dist/contracts/tool.d.ts.map +1 -1
- package/dist/contracts/tool.js +57 -0
- package/dist/contracts/tool.js.map +1 -0
- package/dist/contracts/tracer.d.ts +53 -5
- package/dist/contracts/tracer.d.ts.map +1 -1
- package/dist/contracts/tracer.js.map +1 -1
- package/dist/index.d.ts +14 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +11 -7
- package/dist/index.js.map +1 -1
- package/dist/package.js +6 -0
- package/dist/package.js.map +1 -0
- package/dist/types/agent-event-wire.d.ts +74 -0
- package/dist/types/agent-event-wire.d.ts.map +1 -0
- package/dist/types/agent-event-wire.js +130 -0
- package/dist/types/agent-event-wire.js.map +1 -0
- package/dist/types/agent-event.d.ts +48 -6
- package/dist/types/agent-event.d.ts.map +1 -1
- package/dist/types/index.d.ts +3 -2
- package/dist/types/index.js +2 -1
- package/dist/types/memory.d.ts +11 -0
- package/dist/types/memory.d.ts.map +1 -1
- package/dist/types/run.d.ts +86 -4
- package/dist/types/run.d.ts.map +1 -1
- package/dist/types/run.js.map +1 -1
- package/dist/types/tool.d.ts +10 -0
- package/dist/types/tool.d.ts.map +1 -1
- package/dist/types/usage.d.ts +11 -1
- package/dist/types/usage.d.ts.map +1 -1
- package/dist/types/usage.js.map +1 -1
- package/dist/utils/binary-json.d.ts +165 -0
- package/dist/utils/binary-json.d.ts.map +1 -0
- package/dist/utils/binary-json.js +240 -0
- package/dist/utils/binary-json.js.map +1 -0
- package/dist/utils/index.d.ts +2 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/validation.d.ts +10 -1
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +1 -1
- package/dist/utils/validation.js.map +1 -1
- package/package.json +9 -7
- package/src/channels/channels.ts +206 -0
- package/src/channels/directive.ts +41 -0
- package/src/channels/dispatch.ts +37 -0
- package/src/channels/durable.ts +151 -0
- package/src/channels/index.ts +62 -0
- package/src/channels/pause.ts +216 -0
- package/src/contracts/auth-token-store.ts +42 -0
- package/src/contracts/checkpoint-store.ts +256 -0
- package/src/contracts/embedder.ts +42 -0
- package/src/contracts/eval-scorer.ts +44 -0
- package/src/contracts/index.ts +112 -0
- package/src/contracts/local-provider-trust.ts +33 -0
- package/src/contracts/logger.ts +61 -0
- package/src/contracts/memory-store.ts +187 -0
- package/src/contracts/oauth-server-store.ts +78 -0
- package/src/contracts/preferred-model.ts +56 -0
- package/src/contracts/provider.ts +316 -0
- package/src/contracts/reasoning-retention.ts +52 -0
- package/src/contracts/redaction-validator.ts +56 -0
- package/src/contracts/sandbox.ts +70 -0
- package/src/contracts/secret-ref.ts +22 -0
- package/src/contracts/secret-value.ts +117 -0
- package/src/contracts/secrets-store.ts +90 -0
- package/src/contracts/session-store.ts +163 -0
- package/src/contracts/token-counter.ts +23 -0
- package/src/contracts/tool.ts +397 -0
- package/src/contracts/tracer.ts +219 -0
- package/src/contracts/trigger-store.ts +40 -0
- package/src/index.ts +23 -0
- package/src/types/agent-event-wire.ts +193 -0
- package/src/types/agent-event.ts +579 -0
- package/src/types/handoff.ts +111 -0
- package/src/types/index.ts +148 -0
- package/src/types/memory.ts +427 -0
- package/src/types/message.ts +174 -0
- package/src/types/run.ts +312 -0
- package/src/types/sensitivity.ts +35 -0
- package/src/types/session-scope.ts +18 -0
- package/src/types/stop-condition.ts +108 -0
- package/src/types/tool-call.ts +24 -0
- package/src/types/tool.ts +324 -0
- package/src/types/usage.ts +120 -0
- package/src/types/workflow-event.ts +132 -0
- package/src/utils/assert-never.ts +24 -0
- package/src/utils/async-context.ts +55 -0
- package/src/utils/binary-json.ts +425 -0
- package/src/utils/hash.ts +122 -0
- package/src/utils/index.ts +57 -0
- package/src/utils/streams.ts +233 -0
- package/src/utils/validation.ts +82 -0
package/dist/types/run.d.ts
CHANGED
|
@@ -73,14 +73,24 @@ interface RunStateUsageByModel {
|
|
|
73
73
|
* to the checkpoint store on every `awaiting_approval` boundary, so a
|
|
74
74
|
* separate process can resume the run.
|
|
75
75
|
*
|
|
76
|
-
*
|
|
77
|
-
* `JSON
|
|
76
|
+
* JSON stability is guaranteed by the serializer, not by naive
|
|
77
|
+
* `JSON.stringify`: `messages` and tool-outcome `contentParts` may carry
|
|
78
|
+
* `Uint8Array | URL` payloads, which the documented wire projection
|
|
79
|
+
* (`WireRunState` via `toJsonSafeRunState`) encodes as base64 / href
|
|
80
|
+
* envelopes before stringification. No `Map`, `Set` or `Date` appears
|
|
81
|
+
* anywhere in the shape.
|
|
78
82
|
*
|
|
79
83
|
* @stable
|
|
80
84
|
*/
|
|
81
85
|
interface RunState {
|
|
82
86
|
readonly id: string;
|
|
83
87
|
readonly agentId: string;
|
|
88
|
+
/**
|
|
89
|
+
* The agent whose model drives the NEXT step. During a handoff it is
|
|
90
|
+
* the target for exactly the child observation window and is restored
|
|
91
|
+
* to the parent when the child returns (W-034) - the child's identity
|
|
92
|
+
* is durably recorded in {@link RunState.handoffs}, never here.
|
|
93
|
+
*/
|
|
84
94
|
readonly currentAgentId: string;
|
|
85
95
|
readonly sessionId: string;
|
|
86
96
|
readonly userId?: string;
|
|
@@ -119,10 +129,76 @@ interface RunState {
|
|
|
119
129
|
* prompt each turn). Absent until the agent writes one.
|
|
120
130
|
*/
|
|
121
131
|
todos?: ReadonlyArray<TodoItem>;
|
|
132
|
+
/**
|
|
133
|
+
* W-001: sub-agent runs parked on this (parent) run because the
|
|
134
|
+
* child suspended with `awaiting_approval`. Each entry snapshots the
|
|
135
|
+
* suspended child state; the child's pending approvals are mirrored
|
|
136
|
+
* onto this run's `pendingApprovals` with `subRunToolCallId` set to
|
|
137
|
+
* the entry's `toolCallId`. Absent until a child parks.
|
|
138
|
+
*/
|
|
139
|
+
pendingSubRuns?: PendingSubRun[];
|
|
122
140
|
readonly startedAt: string;
|
|
123
141
|
finishedAt?: string;
|
|
124
142
|
error?: RunError;
|
|
125
143
|
}
|
|
144
|
+
/**
|
|
145
|
+
* One sub-agent run parked on its parent because the child suspended
|
|
146
|
+
* awaiting approvals (W-001). `state` is a JSON-compatible snapshot of
|
|
147
|
+
* the suspended child run; in serialized form (the agent package's
|
|
148
|
+
* `SerializedRunState`) it carries the child's own version-stamped,
|
|
149
|
+
* secret-redacted snapshot, recursively.
|
|
150
|
+
*
|
|
151
|
+
* @stable
|
|
152
|
+
*/
|
|
153
|
+
interface PendingSubRun {
|
|
154
|
+
/** The PARENT's toolCallId of the parked handoff / sub-agent call. */
|
|
155
|
+
readonly toolCallId: string;
|
|
156
|
+
/** The parent-side tool name (`transfer_to_<name>` or the toTool name). */
|
|
157
|
+
readonly toolName: string;
|
|
158
|
+
/** The child agent's configured name (for diagnostics and usage folding). */
|
|
159
|
+
readonly targetAgentName: string;
|
|
160
|
+
/** Suspended child run state (carries the child's own pendingApprovals). */
|
|
161
|
+
readonly state: RunState;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Read-only projection of {@link RunState} handed to tools and hooks
|
|
165
|
+
* via {@link RunContext.state} (W-047). Structurally identical to
|
|
166
|
+
* `RunState` - `RunState` is assignable to it - but every property is
|
|
167
|
+
* `readonly` and every array a `ReadonlyArray`, so typed tool code
|
|
168
|
+
* cannot corrupt run bookkeeping (splice `pendingApprovals`, flip
|
|
169
|
+
* `status`, ...). This is a compile-time contract only: there is no
|
|
170
|
+
* runtime freeze. A hand-written mirror (not a generic DeepReadonly):
|
|
171
|
+
* the nested types are already readonly-typed, and keyof-parity with
|
|
172
|
+
* `RunState` is pinned by type tests.
|
|
173
|
+
*
|
|
174
|
+
* @stable
|
|
175
|
+
*/
|
|
176
|
+
interface ReadonlyRunState {
|
|
177
|
+
readonly id: string;
|
|
178
|
+
readonly agentId: string;
|
|
179
|
+
readonly currentAgentId: string;
|
|
180
|
+
readonly sessionId: string;
|
|
181
|
+
readonly userId?: string;
|
|
182
|
+
readonly status: RunStatus;
|
|
183
|
+
readonly steps: ReadonlyArray<RunStep>;
|
|
184
|
+
readonly messages: ReadonlyArray<Message>;
|
|
185
|
+
readonly pendingApprovals: ReadonlyArray<ToolApproval>;
|
|
186
|
+
readonly handoffs: ReadonlyArray<HandoffRecord>;
|
|
187
|
+
readonly usage: Usage;
|
|
188
|
+
/** See {@link RunState.usageByModel}. */
|
|
189
|
+
readonly usageByModel?: RunStateUsageByModel;
|
|
190
|
+
/** See {@link RunState.taintSummary}. */
|
|
191
|
+
readonly taintSummary?: RunTaintSummary;
|
|
192
|
+
/** See {@link RunState.promotedTools}. */
|
|
193
|
+
readonly promotedTools?: ReadonlyArray<string>;
|
|
194
|
+
/** See {@link RunState.todos}. */
|
|
195
|
+
readonly todos?: ReadonlyArray<TodoItem>;
|
|
196
|
+
/** See {@link RunState.pendingSubRuns}. */
|
|
197
|
+
readonly pendingSubRuns?: ReadonlyArray<PendingSubRun>;
|
|
198
|
+
readonly startedAt: string;
|
|
199
|
+
readonly finishedAt?: string;
|
|
200
|
+
readonly error?: RunError;
|
|
201
|
+
}
|
|
126
202
|
/**
|
|
127
203
|
* Coarse, serializable data-flow taint summary persisted in {@link RunState}
|
|
128
204
|
* across suspend/resume (AG-19). Structurally identical to
|
|
@@ -195,7 +271,13 @@ interface RunContext<TDeps = unknown> {
|
|
|
195
271
|
readonly usage: UsageAccumulator;
|
|
196
272
|
readonly stepNumber: number;
|
|
197
273
|
readonly messages: ReadonlyArray<Message>;
|
|
198
|
-
|
|
274
|
+
/**
|
|
275
|
+
* Read-only snapshot of the run's state (W-047). Tools observe the
|
|
276
|
+
* run; they do not mutate its bookkeeping - writes to `status`,
|
|
277
|
+
* `pendingApprovals` etc. are compile errors. The runtime keeps the
|
|
278
|
+
* only mutable reference.
|
|
279
|
+
*/
|
|
280
|
+
readonly state: ReadonlyRunState;
|
|
199
281
|
/**
|
|
200
282
|
* C7: the current `agent.step` span (when the runtime traces). Spans
|
|
201
283
|
* created inside tool execution parent under it so a run's traces
|
|
@@ -204,5 +286,5 @@ interface RunContext<TDeps = unknown> {
|
|
|
204
286
|
readonly span?: AISpan;
|
|
205
287
|
}
|
|
206
288
|
//#endregion
|
|
207
|
-
export { RunContext, RunError, RunState, RunStateUsageByModel, RunStatus, RunStep, RunStepProviderResponse, RunTaintSummary, TodoItem, flattenUsageByModel };
|
|
289
|
+
export { PendingSubRun, ReadonlyRunState, RunContext, RunError, RunState, RunStateUsageByModel, RunStatus, RunStep, RunStepProviderResponse, RunTaintSummary, TodoItem, flattenUsageByModel };
|
|
208
290
|
//# sourceMappingURL=run.d.ts.map
|
package/dist/types/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","names":[],"sources":["../../src/types/run.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAaA;AAQA;;;AAgB8B,KAxBlB,SAAA,GAwBkB,SAAA,GAAA,WAAA,GAAA,QAAA,GAAA,SAAA,GAAA,mBAAA;;AAW9B;AAkBA;
|
|
1
|
+
{"version":3,"file":"run.d.ts","names":[],"sources":["../../src/types/run.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;AAaA;AAQA;;;AAgB8B,KAxBlB,SAAA,GAwBkB,SAAA,GAAA,WAAA,GAAA,QAAA,GAAA,SAAA,GAAA,mBAAA;;AAW9B;AAkBA;AAkBA;;;AAcqB,UA7EJ,OAAA,CA6EI;EACQ,SAAA,UAAA,EAAA,MAAA;EACR,SAAA,SAAA,EAAA,MAAA;EACH,SAAA,OAAA,CAAA,EAAA,MAAA;EAQD,SAAA,KAAA,CAAA,EApFE,KAoFF;EASA,SAAA,SAAA,EAAA,SA5Fc,iBA4Fd,EAAA;EAKC;;;EAeC,SAAA,OAAA,EAAA,MAAA;EAGT;;AAYV;AAwBA;;;EAOkB,SAAA,gBAAA,CAAA,EAnJY,uBAmJZ;;;;;;;;;;AAUS,UAlJV,uBAAA,CAkJU;EAEM,SAAA,OAAA,EAAA,MAAA;EAAd,SAAA,IAAA,CAAA,EAAA,MAAA;EAEuB,SAAA,SAAA,CAAA,EAnJnB,aAmJmB,CAnJL,QAmJK,CAAA;;;;AAa1C;AAoBA;AAeA;;;;;AA0BA;AAeA;;AAMmB,UAnOF,oBAAA,CAmOE;EACA,UAAA,OAAA,EAAA,MAAA,CAAA,EAnOW,KAmOX,GAAA;IACD,SAAA,YAAA,EAAA,MAAA;EAEiB,CAAA;;;;;;;;;;;;;;;;UArNlB,QAAA;;;;;;;;;;;;UAYP;kBACQ;qBACG;6BACQ;qBACR;kBACH;;;;;;;;iBAQD;;;;;;;;;iBASA;;;;;kBAKC;;;;;;;UAOR,cAAc;;;;;;;;mBAQL;;;UAGT;;;;;;;;;;;UAYO,aAAA;;;;;;;;kBAQC;;;;;;;;;;;;;;;UAgBD,gBAAA;;;;;;mBAME;kBACD,cAAc;qBACX,cAAc;6BACN,cAAc;qBACtB,cAAc;kBACjB;;0BAEQ;;0BAEA;;2BAEC;;mBAER,cAAc;;4BAEL,cAAc;;;mBAGvB;;;;;;;;;UAUF,eAAA;;;iCAGgB;;;;;;;4BAOL;;;;;;;;;UAUX,QAAA;;;;;;;;;;;;;;iBAeD,mBAAA,UACL,mCACR,cAAc;;;;;;;UAwBA,QAAA;;;;;;;;;;;;;;UAeA;;;;;iBAKA;mBACE;mBACA;kBACD;;qBAEG,cAAc;;;;;;;kBAOjB;;;;;;kBAAgB"}
|
package/dist/types/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","names":["out: ModelUsage[]","m: ModelUsage"],"sources":["../../src/types/run.ts"],"sourcesContent":["import type { Tracer } from '../contracts/tracer.js';\nimport type { HandoffRecord } from './handoff.js';\nimport type { Message } from './message.js';\nimport type { CompletedToolCall, ToolApproval } from './tool.js';\nimport type { ToolCall } from './tool-call.js';\nimport type { ModelUsage, Usage, UsageAccumulator } from './usage.js';\n\n/**\n * Status of an in-flight or completed agent run. Append-only persistence\n * stores expose this verbatim on the `runs` table.\n *\n * @stable\n */\nexport type RunStatus = 'running' | 'completed' | 'failed' | 'aborted' | 'awaiting_approval';\n\n/**\n * Single step inside an agent run. The agent runtime appends one\n * `RunStep` per provider call.\n *\n * @stable\n */\nexport interface RunStep {\n readonly stepNumber: number;\n readonly startedAt: string;\n readonly endedAt?: string;\n readonly usage?: Usage;\n readonly toolCalls: readonly CompletedToolCall[];\n /**\n * Stable agent id active for this step (changes after a handoff).\n */\n readonly agentId: string;\n /**\n * The model response this step produced, recorded when the agent runs\n * with `recordProviderResponses: true` (C3). Enables deterministic\n * replay: `createReplayProvider(state)` serves these back in order so\n * a run re-executes without live model calls.\n */\n readonly providerResponse?: RunStepProviderResponse;\n}\n\n/**\n * Journaled model response for one step (C3, opt-in via the agent's\n * `recordProviderResponses`). Captures the RAW model output - the text\n * before any lateral-leak block replaced it in the transcript - so a\n * replay reproduces the original run faithfully.\n *\n * @stable\n */\nexport interface RunStepProviderResponse {\n readonly modelId: string;\n readonly text?: string;\n readonly toolCalls?: ReadonlyArray<ToolCall>;\n}\n\n/**\n * Per-model usage breakdown carried alongside the aggregate\n * {@link Usage} on {@link RunState}. Populated by the per-step retry\n * loop when `Agent.fallbackModels` fires; for runs that never fall\n * back, the map carries a single entry for the primary model with\n * `attemptCount: 1`.\n *\n * The aggregate `RunState.usage` is always the sum of every entry's\n * `Usage` portion (the field is asserted in tests).\n *\n * @stable\n */\nexport interface RunStateUsageByModel {\n readonly [modelId: string]: Usage & { readonly attemptCount: number };\n}\n\n/**\n * The full, serializable state of a run. The agent runtime persists this\n * to the checkpoint store on every `awaiting_approval` boundary, so a\n * separate process can resume the run.\n *\n * The shape is intentionally JSON-stable: every nested type is plain\n * `JSON`-encodable (no `Map`, no `Set`, no `Date`).\n *\n * @stable\n */\nexport interface RunState {\n readonly id: string;\n readonly agentId: string;\n readonly currentAgentId: string;\n readonly sessionId: string;\n readonly userId?: string;\n status: RunStatus;\n readonly steps: RunStep[];\n readonly messages: Message[];\n readonly pendingApprovals: ToolApproval[];\n readonly handoffs: HandoffRecord[];\n readonly usage: Usage;\n /**\n * Per-model usage breakdown. Populated by the per-step retry loop\n * when `Agent.fallbackModels` fires (RB-48 / suggested DEC-164 /\n * suggested ADR-052). Backward-compat: rehydrating a serialized\n * state that omits the field synthesizes a single-entry map for\n * the primary model.\n */\n usageByModel?: RunStateUsageByModel;\n /**\n * AG-19: coarse data-flow taint summary, carried across suspend/resume so a\n * resumed run does not start with an empty ledger that silently un-gates\n * sinks exposed before the suspend. Structurally matches\n * `@graphorin/security`'s `TaintLedgerSnapshot` (core takes no security\n * dependency); only the load-bearing flags are persisted - never the tracked\n * untrusted text spans.\n */\n taintSummary?: RunTaintSummary;\n /**\n * AG-19: names of deferred tools promoted by `tool_search` this run, carried\n * across suspend/resume so discovered tools remain in the per-step catalogue.\n */\n promotedTools?: ReadonlyArray<string>;\n /**\n * D6 structured plan/todo list - the agent's own working plan,\n * journaled so it survives suspend/resume (a TodoWrite-style tool\n * mutates it, and attention-recitation renders it back into the\n * prompt each turn). Absent until the agent writes one.\n */\n todos?: ReadonlyArray<TodoItem>;\n readonly startedAt: string;\n finishedAt?: string;\n error?: RunError;\n}\n\n/**\n * Coarse, serializable data-flow taint summary persisted in {@link RunState}\n * across suspend/resume (AG-19). Structurally identical to\n * `@graphorin/security`'s `TaintLedgerSnapshot`; carries no untrusted text.\n *\n * @stable\n */\nexport interface RunTaintSummary {\n readonly untrustedSeen: boolean;\n readonly sensitiveSeen: boolean;\n readonly untrustedSourceKinds: ReadonlyArray<string>;\n /**\n * C6: one-way FNV-1a hashes of normalized untrusted-span tiles. Re-arms\n * the verbatim-carry probe after a resume at tile granularity. Hashes\n * only - no untrusted text is ever persisted (the invariant above\n * holds).\n */\n readonly spanTileHashes?: ReadonlyArray<string>;\n}\n\n/**\n * One item in the agent's structured plan (D6). `status` drives both\n * the recitation rendering and progress reporting; `id` lets a\n * status-flip mutation target an item without rewriting the list.\n *\n * @stable\n */\nexport interface TodoItem {\n readonly id: string;\n readonly content: string;\n readonly status: 'pending' | 'in_progress' | 'completed';\n}\n\n/**\n * Snapshot helper used by `@graphorin/observability` aggregators to\n * convert the on-disk `usageByModel` shape into the canonical\n * {@link ModelUsage} array. Pure utility - kept in core so consumers\n * do not have to take an observability dependency just to flatten a\n * run-state breakdown.\n *\n * @stable\n */\nexport function flattenUsageByModel(\n byModel: RunStateUsageByModel | undefined,\n): ReadonlyArray<ModelUsage> {\n if (byModel === undefined) return [];\n const out: ModelUsage[] = [];\n for (const [modelId, entry] of Object.entries(byModel)) {\n const m: ModelUsage = {\n modelId,\n promptTokens: entry.promptTokens,\n completionTokens: entry.completionTokens,\n totalTokens: entry.totalTokens,\n callCount: entry.attemptCount,\n ...(entry.reasoningTokens !== undefined ? { reasoningTokens: entry.reasoningTokens } : {}),\n ...(entry.cost !== undefined ? { cost: entry.cost } : {}),\n };\n out.push(m);\n }\n return out;\n}\n\n/**\n * Failure carried by `RunState.error`. The shape mirrors the wire format\n * used by `agent.error` events.\n *\n * @stable\n */\nexport interface RunError {\n readonly message: string;\n readonly code: string;\n readonly details?: unknown;\n}\n\n/**\n * Per-run dependency / context bag handed to every tool, hook and\n * provider middleware in scope. Generic over the user-defined deps shape.\n *\n * `tracer`, `signal`, `usage` and `state` are always present; everything\n * else is optional.\n *\n * @stable\n */\nexport interface RunContext<TDeps = unknown> {\n readonly runId: string;\n readonly sessionId: string;\n readonly userId?: string;\n readonly agentId: string;\n readonly deps: TDeps;\n readonly tracer: Tracer;\n readonly signal: AbortSignal;\n readonly usage: UsageAccumulator;\n readonly stepNumber: number;\n readonly messages: ReadonlyArray<Message>;\n readonly state: RunState;\n /**\n * C7: the current `agent.step` span (when the runtime traces). Spans\n * created inside tool execution parent under it so a run's traces\n * form one tree.\n */\n readonly span?: import('../contracts/tracer.js').AISpan;\n}\n"],"mappings":";;;;;;;;;;AAwKA,SAAgB,oBACd,SAC2B;AAC3B,KAAI,YAAY,OAAW,QAAO,EAAE;CACpC,MAAMA,MAAoB,EAAE;AAC5B,MAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,QAAQ,EAAE;EACtD,MAAMC,IAAgB;GACpB;GACA,cAAc,MAAM;GACpB,kBAAkB,MAAM;GACxB,aAAa,MAAM;GACnB,WAAW,MAAM;GACjB,GAAI,MAAM,oBAAoB,SAAY,EAAE,iBAAiB,MAAM,iBAAiB,GAAG,EAAE;GACzF,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GACzD;AACD,MAAI,KAAK,EAAE;;AAEb,QAAO"}
|
|
1
|
+
{"version":3,"file":"run.js","names":["out: ModelUsage[]","m: ModelUsage"],"sources":["../../src/types/run.ts"],"sourcesContent":["import type { Tracer } from '../contracts/tracer.js';\nimport type { HandoffRecord } from './handoff.js';\nimport type { Message } from './message.js';\nimport type { CompletedToolCall, ToolApproval } from './tool.js';\nimport type { ToolCall } from './tool-call.js';\nimport type { ModelUsage, Usage, UsageAccumulator } from './usage.js';\n\n/**\n * Status of an in-flight or completed agent run. Append-only persistence\n * stores expose this verbatim on the `runs` table.\n *\n * @stable\n */\nexport type RunStatus = 'running' | 'completed' | 'failed' | 'aborted' | 'awaiting_approval';\n\n/**\n * Single step inside an agent run. The agent runtime appends one\n * `RunStep` per provider call.\n *\n * @stable\n */\nexport interface RunStep {\n readonly stepNumber: number;\n readonly startedAt: string;\n readonly endedAt?: string;\n readonly usage?: Usage;\n readonly toolCalls: readonly CompletedToolCall[];\n /**\n * Stable agent id active for this step (changes after a handoff).\n */\n readonly agentId: string;\n /**\n * The model response this step produced, recorded when the agent runs\n * with `recordProviderResponses: true` (C3). Enables deterministic\n * replay: `createReplayProvider(state)` serves these back in order so\n * a run re-executes without live model calls.\n */\n readonly providerResponse?: RunStepProviderResponse;\n}\n\n/**\n * Journaled model response for one step (C3, opt-in via the agent's\n * `recordProviderResponses`). Captures the RAW model output - the text\n * before any lateral-leak block replaced it in the transcript - so a\n * replay reproduces the original run faithfully.\n *\n * @stable\n */\nexport interface RunStepProviderResponse {\n readonly modelId: string;\n readonly text?: string;\n readonly toolCalls?: ReadonlyArray<ToolCall>;\n}\n\n/**\n * Per-model usage breakdown carried alongside the aggregate\n * {@link Usage} on {@link RunState}. Populated by the per-step retry\n * loop when `Agent.fallbackModels` fires; for runs that never fall\n * back, the map carries a single entry for the primary model with\n * `attemptCount: 1`.\n *\n * The aggregate `RunState.usage` is always the sum of every entry's\n * `Usage` portion (the field is asserted in tests).\n *\n * @stable\n */\nexport interface RunStateUsageByModel {\n readonly [modelId: string]: Usage & { readonly attemptCount: number };\n}\n\n/**\n * The full, serializable state of a run. The agent runtime persists this\n * to the checkpoint store on every `awaiting_approval` boundary, so a\n * separate process can resume the run.\n *\n * JSON stability is guaranteed by the serializer, not by naive\n * `JSON.stringify`: `messages` and tool-outcome `contentParts` may carry\n * `Uint8Array | URL` payloads, which the documented wire projection\n * (`WireRunState` via `toJsonSafeRunState`) encodes as base64 / href\n * envelopes before stringification. No `Map`, `Set` or `Date` appears\n * anywhere in the shape.\n *\n * @stable\n */\nexport interface RunState {\n readonly id: string;\n readonly agentId: string;\n /**\n * The agent whose model drives the NEXT step. During a handoff it is\n * the target for exactly the child observation window and is restored\n * to the parent when the child returns (W-034) - the child's identity\n * is durably recorded in {@link RunState.handoffs}, never here.\n */\n readonly currentAgentId: string;\n readonly sessionId: string;\n readonly userId?: string;\n status: RunStatus;\n readonly steps: RunStep[];\n readonly messages: Message[];\n readonly pendingApprovals: ToolApproval[];\n readonly handoffs: HandoffRecord[];\n readonly usage: Usage;\n /**\n * Per-model usage breakdown. Populated by the per-step retry loop\n * when `Agent.fallbackModels` fires (RB-48 / suggested DEC-164 /\n * suggested ADR-052). Backward-compat: rehydrating a serialized\n * state that omits the field synthesizes a single-entry map for\n * the primary model.\n */\n usageByModel?: RunStateUsageByModel;\n /**\n * AG-19: coarse data-flow taint summary, carried across suspend/resume so a\n * resumed run does not start with an empty ledger that silently un-gates\n * sinks exposed before the suspend. Structurally matches\n * `@graphorin/security`'s `TaintLedgerSnapshot` (core takes no security\n * dependency); only the load-bearing flags are persisted - never the tracked\n * untrusted text spans.\n */\n taintSummary?: RunTaintSummary;\n /**\n * AG-19: names of deferred tools promoted by `tool_search` this run, carried\n * across suspend/resume so discovered tools remain in the per-step catalogue.\n */\n promotedTools?: ReadonlyArray<string>;\n /**\n * D6 structured plan/todo list - the agent's own working plan,\n * journaled so it survives suspend/resume (a TodoWrite-style tool\n * mutates it, and attention-recitation renders it back into the\n * prompt each turn). Absent until the agent writes one.\n */\n todos?: ReadonlyArray<TodoItem>;\n /**\n * W-001: sub-agent runs parked on this (parent) run because the\n * child suspended with `awaiting_approval`. Each entry snapshots the\n * suspended child state; the child's pending approvals are mirrored\n * onto this run's `pendingApprovals` with `subRunToolCallId` set to\n * the entry's `toolCallId`. Absent until a child parks.\n */\n pendingSubRuns?: PendingSubRun[];\n readonly startedAt: string;\n finishedAt?: string;\n error?: RunError;\n}\n\n/**\n * One sub-agent run parked on its parent because the child suspended\n * awaiting approvals (W-001). `state` is a JSON-compatible snapshot of\n * the suspended child run; in serialized form (the agent package's\n * `SerializedRunState`) it carries the child's own version-stamped,\n * secret-redacted snapshot, recursively.\n *\n * @stable\n */\nexport interface PendingSubRun {\n /** The PARENT's toolCallId of the parked handoff / sub-agent call. */\n readonly toolCallId: string;\n /** The parent-side tool name (`transfer_to_<name>` or the toTool name). */\n readonly toolName: string;\n /** The child agent's configured name (for diagnostics and usage folding). */\n readonly targetAgentName: string;\n /** Suspended child run state (carries the child's own pendingApprovals). */\n readonly state: RunState;\n}\n\n/**\n * Read-only projection of {@link RunState} handed to tools and hooks\n * via {@link RunContext.state} (W-047). Structurally identical to\n * `RunState` - `RunState` is assignable to it - but every property is\n * `readonly` and every array a `ReadonlyArray`, so typed tool code\n * cannot corrupt run bookkeeping (splice `pendingApprovals`, flip\n * `status`, ...). This is a compile-time contract only: there is no\n * runtime freeze. A hand-written mirror (not a generic DeepReadonly):\n * the nested types are already readonly-typed, and keyof-parity with\n * `RunState` is pinned by type tests.\n *\n * @stable\n */\nexport interface ReadonlyRunState {\n readonly id: string;\n readonly agentId: string;\n readonly currentAgentId: string;\n readonly sessionId: string;\n readonly userId?: string;\n readonly status: RunStatus;\n readonly steps: ReadonlyArray<RunStep>;\n readonly messages: ReadonlyArray<Message>;\n readonly pendingApprovals: ReadonlyArray<ToolApproval>;\n readonly handoffs: ReadonlyArray<HandoffRecord>;\n readonly usage: Usage;\n /** See {@link RunState.usageByModel}. */\n readonly usageByModel?: RunStateUsageByModel;\n /** See {@link RunState.taintSummary}. */\n readonly taintSummary?: RunTaintSummary;\n /** See {@link RunState.promotedTools}. */\n readonly promotedTools?: ReadonlyArray<string>;\n /** See {@link RunState.todos}. */\n readonly todos?: ReadonlyArray<TodoItem>;\n /** See {@link RunState.pendingSubRuns}. */\n readonly pendingSubRuns?: ReadonlyArray<PendingSubRun>;\n readonly startedAt: string;\n readonly finishedAt?: string;\n readonly error?: RunError;\n}\n\n/**\n * Coarse, serializable data-flow taint summary persisted in {@link RunState}\n * across suspend/resume (AG-19). Structurally identical to\n * `@graphorin/security`'s `TaintLedgerSnapshot`; carries no untrusted text.\n *\n * @stable\n */\nexport interface RunTaintSummary {\n readonly untrustedSeen: boolean;\n readonly sensitiveSeen: boolean;\n readonly untrustedSourceKinds: ReadonlyArray<string>;\n /**\n * C6: one-way FNV-1a hashes of normalized untrusted-span tiles. Re-arms\n * the verbatim-carry probe after a resume at tile granularity. Hashes\n * only - no untrusted text is ever persisted (the invariant above\n * holds).\n */\n readonly spanTileHashes?: ReadonlyArray<string>;\n}\n\n/**\n * One item in the agent's structured plan (D6). `status` drives both\n * the recitation rendering and progress reporting; `id` lets a\n * status-flip mutation target an item without rewriting the list.\n *\n * @stable\n */\nexport interface TodoItem {\n readonly id: string;\n readonly content: string;\n readonly status: 'pending' | 'in_progress' | 'completed';\n}\n\n/**\n * Snapshot helper used by `@graphorin/observability` aggregators to\n * convert the on-disk `usageByModel` shape into the canonical\n * {@link ModelUsage} array. Pure utility - kept in core so consumers\n * do not have to take an observability dependency just to flatten a\n * run-state breakdown.\n *\n * @stable\n */\nexport function flattenUsageByModel(\n byModel: RunStateUsageByModel | undefined,\n): ReadonlyArray<ModelUsage> {\n if (byModel === undefined) return [];\n const out: ModelUsage[] = [];\n for (const [modelId, entry] of Object.entries(byModel)) {\n const m: ModelUsage = {\n modelId,\n promptTokens: entry.promptTokens,\n completionTokens: entry.completionTokens,\n totalTokens: entry.totalTokens,\n callCount: entry.attemptCount,\n ...(entry.reasoningTokens !== undefined ? { reasoningTokens: entry.reasoningTokens } : {}),\n ...(entry.cost !== undefined ? { cost: entry.cost } : {}),\n };\n out.push(m);\n }\n return out;\n}\n\n/**\n * Failure carried by `RunState.error`. The shape mirrors the wire format\n * used by `agent.error` events.\n *\n * @stable\n */\nexport interface RunError {\n readonly message: string;\n readonly code: string;\n readonly details?: unknown;\n}\n\n/**\n * Per-run dependency / context bag handed to every tool, hook and\n * provider middleware in scope. Generic over the user-defined deps shape.\n *\n * `tracer`, `signal`, `usage` and `state` are always present; everything\n * else is optional.\n *\n * @stable\n */\nexport interface RunContext<TDeps = unknown> {\n readonly runId: string;\n readonly sessionId: string;\n readonly userId?: string;\n readonly agentId: string;\n readonly deps: TDeps;\n readonly tracer: Tracer;\n readonly signal: AbortSignal;\n readonly usage: UsageAccumulator;\n readonly stepNumber: number;\n readonly messages: ReadonlyArray<Message>;\n /**\n * Read-only snapshot of the run's state (W-047). Tools observe the\n * run; they do not mutate its bookkeeping - writes to `status`,\n * `pendingApprovals` etc. are compile errors. The runtime keeps the\n * only mutable reference.\n */\n readonly state: ReadonlyRunState;\n /**\n * C7: the current `agent.step` span (when the runtime traces). Spans\n * created inside tool execution parent under it so a run's traces\n * form one tree.\n */\n readonly span?: import('../contracts/tracer.js').AISpan;\n}\n"],"mappings":";;;;;;;;;;AAsPA,SAAgB,oBACd,SAC2B;AAC3B,KAAI,YAAY,OAAW,QAAO,EAAE;CACpC,MAAMA,MAAoB,EAAE;AAC5B,MAAK,MAAM,CAAC,SAAS,UAAU,OAAO,QAAQ,QAAQ,EAAE;EACtD,MAAMC,IAAgB;GACpB;GACA,cAAc,MAAM;GACpB,kBAAkB,MAAM;GACxB,aAAa,MAAM;GACnB,WAAW,MAAM;GACjB,GAAI,MAAM,oBAAoB,SAAY,EAAE,iBAAiB,MAAM,iBAAiB,GAAG,EAAE;GACzF,GAAI,MAAM,SAAS,SAAY,EAAE,MAAM,MAAM,MAAM,GAAG,EAAE;GACzD;AACD,MAAI,KAAK,EAAE;;AAEb,QAAO"}
|
package/dist/types/tool.d.ts
CHANGED
|
@@ -268,6 +268,16 @@ interface ToolApproval {
|
|
|
268
268
|
readonly args: unknown;
|
|
269
269
|
readonly reason?: string;
|
|
270
270
|
readonly requestedAt: string;
|
|
271
|
+
/**
|
|
272
|
+
* W-001: set when this approval belongs to a PARKED sub-agent run.
|
|
273
|
+
* It is the PARENT's toolCallId of the parked handoff / sub-agent
|
|
274
|
+
* call (the `RunState.pendingSubRuns` key), never a child-local id.
|
|
275
|
+
* Operators echo it back on the matching `ApprovalDecision` so
|
|
276
|
+
* resume decisions match on the composite (toolCallId,
|
|
277
|
+
* subRunToolCallId) key - child-local toolCallIds of two different
|
|
278
|
+
* children may collide.
|
|
279
|
+
*/
|
|
280
|
+
readonly subRunToolCallId?: string;
|
|
271
281
|
}
|
|
272
282
|
/**
|
|
273
283
|
* A `ToolCall` paired with its outcome and execution metadata. Captured
|
package/dist/types/tool.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool.d.ts","names":[],"sources":["../../src/types/tool.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAsBA;AAyBA;AAmBA;AAuBA;AAUA;AAeY,KAlHA,aAAA,GAkHU,MAAA,GAAA,WAAA,GAAA,UAAA,GAAA,QAAA;AAmBtB;AAgBA;;;;;AAgCA;AA+BA;AA8BA;AAQA;AAyBA;;;;;AASA;
|
|
1
|
+
{"version":3,"file":"tool.d.ts","names":[],"sources":["../../src/types/tool.ts"],"sourcesContent":[],"mappings":";;;;;;;;AAWA;AAsBA;AAyBA;AAmBA;AAuBA;AAUA;AAeY,KAlHA,aAAA,GAkHU,MAAA,GAAA,WAAA,GAAA,UAAA,GAAA,QAAA;AAmBtB;AAgBA;;;;;AAgCA;AA+BA;AA8BA;AAQA;AAyBA;;;;;AASA;AAwBA;;;;AAE+B,KAhSnB,eAAA,GAgSmB,MAAA,GAAA,0BAAA,GAAA,cAAA,GAAA,SAAA,GAAA,WAAA;;;;;;;;;;;;;;;;;;;KAvQnB,eAAA;;;;;;;;;;;;;;;;;;KAmBA,yBAAA;;;;;;;;;;;;;;;;;KAuBA,kBAAA;;;;;;;;;KAUA,cAAA;;;;;;;;KAeA,UAAA;;;;;;;;;;;;;;;;;;;;;;;;KAmBA,YAAA;;;;;;;;;iBAGiC;;;;;;;;UAa5B;;;mBAGE;;;;;;mCAAO,cAAA;;;;;;;;;;0BAgBA;;;;;;;;;;;;UAaT,YAAA;;;;;;;;;;;;;;;;;;;;;;gCAsBe;;;;;;;;KASpB,aAAA;;;;;;;;;;;;;;;;;KA8BA,YAAA;;;;;;;UAQK,SAAA;;;iBAGA;;;;;;;;;;;;;0BAaS;;;;;;;;KASd,iCAAiC,WAAW,WAAW;;;;;;;;UASlD,YAAA;;;;;;;;;;;;;;;;;;;;;;;UAwBA;iBACA;oBACG,YAAY"}
|
package/dist/types/usage.d.ts
CHANGED
|
@@ -44,7 +44,17 @@ interface Usage {
|
|
|
44
44
|
* @stable
|
|
45
45
|
*/
|
|
46
46
|
interface Cost {
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Amount in WHOLE units of `currency` - for USD that is dollars, and
|
|
49
|
+
* fractional values are expected (a typical LLM call costs a fraction
|
|
50
|
+
* of a cent, e.g. `0.0042`). This is deliberately NOT "minor units" /
|
|
51
|
+
* cents (W-045): the canonical producer -
|
|
52
|
+
* `calculateCost` in `@graphorin/pricing` - and every consumer
|
|
53
|
+
* (`CostTracker` in `@graphorin/observability`, the memory
|
|
54
|
+
* consolidator's `costUsd` budget, persisted checkpoints) already
|
|
55
|
+
* operate in whole currency units, and sub-cent per-call figures make
|
|
56
|
+
* minor units impractical. Do not divide by 100.
|
|
57
|
+
*/
|
|
48
58
|
amount: number;
|
|
49
59
|
/** ISO-4217 currency code; default `'USD'`. */
|
|
50
60
|
currency: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","names":[],"sources":["../../src/types/usage.ts"],"sourcesContent":[],"mappings":";;AASA;AAoCA;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","names":[],"sources":["../../src/types/usage.ts"],"sourcesContent":[],"mappings":";;AASA;AAoCA;AAuBA;AAoBA;;;;;AAWc,UA1FG,KAAA,CA0FH;EAAa;AAQ3B;AAUA;;;;;;;;;;;;;;;;;;;;;;;;SAjFS;;;;;;;;UASQ,IAAA;;;;;;;;;;;;;;;;;;;;;;UAuBA,UAAA;;;;;;;;SAQR;;;;;;;;;;;UAYQ,gBAAA;;kBAEC;;oBAEE,oBAAoB;;8BAGV;;;;cAIhB;;;;;;;UAQG,aAAA;kBACC;6BACW;;;;;;;iBAQb,SAAA,CAAA,GAAa"}
|
package/dist/types/usage.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.js","names":[],"sources":["../../src/types/usage.ts"],"sourcesContent":["/**\n * Token / cost metrics for a single LLM call.\n *\n * `cost` is optional because the framework cannot compute it without a\n * pricing snapshot - providers/middleware fill it in (e.g. through the\n * separate `@graphorin/pricing` package) when the snapshot is available.\n *\n * @stable\n */\nexport interface Usage {\n /**\n * Total input tokens for the call, INCLUDING any prompt-cache reads and\n * writes (`cachedReadTokens` / `cacheWriteTokens` are informational\n * subsets, not additions). This matches the context size the model saw.\n */\n promptTokens: number;\n completionTokens: number;\n /**\n * Reasoning tokens billed IN ADDITION to `completionTokens` (exclusive;\n * adapters that receive an inclusive total split it so the sum stays\n * exact). Cost formulas may add this to the output leg without\n * double-counting.\n */\n reasoningTokens?: number;\n /**\n * Prompt tokens served from the provider's prompt cache (a subset of\n * `promptTokens`), billed at the discounted cache-read rate.\n */\n cachedReadTokens?: number;\n /**\n * Prompt tokens written to the provider's prompt cache this call (a\n * subset of `promptTokens`), billed at the cache-write premium where the\n * provider charges one (Anthropic does; OpenAI does not report writes).\n */\n cacheWriteTokens?: number;\n totalTokens: number;\n cost?: Cost;\n}\n\n/**\n * Money figure attached to a `Usage`. Always carries a 3-letter currency\n * code so that consumers can perform aggregation safely.\n *\n * @stable\n */\nexport interface Cost {\n
|
|
1
|
+
{"version":3,"file":"usage.js","names":[],"sources":["../../src/types/usage.ts"],"sourcesContent":["/**\n * Token / cost metrics for a single LLM call.\n *\n * `cost` is optional because the framework cannot compute it without a\n * pricing snapshot - providers/middleware fill it in (e.g. through the\n * separate `@graphorin/pricing` package) when the snapshot is available.\n *\n * @stable\n */\nexport interface Usage {\n /**\n * Total input tokens for the call, INCLUDING any prompt-cache reads and\n * writes (`cachedReadTokens` / `cacheWriteTokens` are informational\n * subsets, not additions). This matches the context size the model saw.\n */\n promptTokens: number;\n completionTokens: number;\n /**\n * Reasoning tokens billed IN ADDITION to `completionTokens` (exclusive;\n * adapters that receive an inclusive total split it so the sum stays\n * exact). Cost formulas may add this to the output leg without\n * double-counting.\n */\n reasoningTokens?: number;\n /**\n * Prompt tokens served from the provider's prompt cache (a subset of\n * `promptTokens`), billed at the discounted cache-read rate.\n */\n cachedReadTokens?: number;\n /**\n * Prompt tokens written to the provider's prompt cache this call (a\n * subset of `promptTokens`), billed at the cache-write premium where the\n * provider charges one (Anthropic does; OpenAI does not report writes).\n */\n cacheWriteTokens?: number;\n totalTokens: number;\n cost?: Cost;\n}\n\n/**\n * Money figure attached to a `Usage`. Always carries a 3-letter currency\n * code so that consumers can perform aggregation safely.\n *\n * @stable\n */\nexport interface Cost {\n /**\n * Amount in WHOLE units of `currency` - for USD that is dollars, and\n * fractional values are expected (a typical LLM call costs a fraction\n * of a cent, e.g. `0.0042`). This is deliberately NOT \"minor units\" /\n * cents (W-045): the canonical producer -\n * `calculateCost` in `@graphorin/pricing` - and every consumer\n * (`CostTracker` in `@graphorin/observability`, the memory\n * consolidator's `costUsd` budget, persisted checkpoints) already\n * operate in whole currency units, and sub-cent per-call figures make\n * minor units impractical. Do not divide by 100.\n */\n amount: number;\n /** ISO-4217 currency code; default `'USD'`. */\n currency: string;\n}\n\n/**\n * Per-model breakdown used by aggregators (e.g. `CostTracker` in\n * `@graphorin/observability`).\n *\n * @stable\n */\nexport interface ModelUsage {\n modelId: string;\n promptTokens: number;\n completionTokens: number;\n reasoningTokens?: number;\n cachedReadTokens?: number;\n cacheWriteTokens?: number;\n totalTokens: number;\n cost?: Cost;\n callCount: number;\n}\n\n/**\n * A live accumulator of token / cost figures. Implementations live in\n * `@graphorin/observability`. The contract sits here so every package\n * (agent, workflow, server, …) can type a parameter as `UsageAccumulator`\n * without taking an observability dependency.\n *\n * @stable\n */\nexport interface UsageAccumulator {\n /** Current rolled-up totals across every model that has been added. */\n readonly total: Usage;\n /** Per-model breakdown; preserves call counts for observability. */\n readonly byModel: ReadonlyMap<string, ModelUsage>;\n\n /** Add a single LLM-call usage record under the given model id. */\n add(modelId: string, usage: Usage): void;\n /** Reset the accumulator to a zeroed state. */\n reset(): void;\n /** Render an immutable snapshot suitable for serialization / span attrs. */\n snapshot(): UsageSnapshot;\n}\n\n/**\n * Immutable, JSON-serializable snapshot of a `UsageAccumulator`.\n *\n * @stable\n */\nexport interface UsageSnapshot {\n readonly total: Usage;\n readonly byModel: readonly ModelUsage[];\n}\n\n/**\n * Returns a fresh, zeroed `Usage` value.\n *\n * @stable\n */\nexport function zeroUsage(): Usage {\n return { promptTokens: 0, completionTokens: 0, totalTokens: 0 };\n}\n"],"mappings":";;;;;;AAqHA,SAAgB,YAAmB;AACjC,QAAO;EAAE,cAAc;EAAG,kBAAkB;EAAG,aAAa;EAAG"}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { AssistantMessage, AudioContent, FileContent, ImageContent, Message, MessageContent, SystemMessage, ToolMessage, UserMessage } from "../types/message.js";
|
|
2
|
+
import { CompletedToolCall, ToolError, ToolResult } from "../types/tool.js";
|
|
3
|
+
import { PendingSubRun, RunState, RunStep } from "../types/run.js";
|
|
4
|
+
|
|
5
|
+
//#region src/utils/binary-json.d.ts
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Base64-encoded binary payload as it appears on the wire.
|
|
9
|
+
*
|
|
10
|
+
* @stable
|
|
11
|
+
*/
|
|
12
|
+
interface EncodedBytes {
|
|
13
|
+
readonly enc: 'base64';
|
|
14
|
+
readonly data: string;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* URL reference as it appears on the wire (`URL` instances do not
|
|
18
|
+
* survive `JSON.stringify`).
|
|
19
|
+
*
|
|
20
|
+
* @stable
|
|
21
|
+
*/
|
|
22
|
+
interface EncodedUrl {
|
|
23
|
+
readonly enc: 'url';
|
|
24
|
+
readonly href: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Wire form of a `Uint8Array | URL` binary field.
|
|
28
|
+
*
|
|
29
|
+
* @stable
|
|
30
|
+
*/
|
|
31
|
+
type EncodedBinary = EncodedBytes | EncodedUrl;
|
|
32
|
+
/** Wire twin of {@link ImageContent}. @stable */
|
|
33
|
+
interface WireImageContent extends Omit<ImageContent, 'image'> {
|
|
34
|
+
readonly image: EncodedBinary;
|
|
35
|
+
}
|
|
36
|
+
/** Wire twin of {@link AudioContent}. @stable */
|
|
37
|
+
interface WireAudioContent extends Omit<AudioContent, 'audio'> {
|
|
38
|
+
readonly audio: EncodedBinary;
|
|
39
|
+
}
|
|
40
|
+
/** Wire twin of {@link FileContent}. @stable */
|
|
41
|
+
interface WireFileContent extends Omit<FileContent, 'file'> {
|
|
42
|
+
readonly file: EncodedBinary;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* JSON-safe twin of {@link MessageContent}: binary-bearing variants
|
|
46
|
+
* carry {@link EncodedBinary} envelopes, text/reasoning variants pass
|
|
47
|
+
* through untouched.
|
|
48
|
+
*
|
|
49
|
+
* @stable
|
|
50
|
+
*/
|
|
51
|
+
type WireMessageContent = Exclude<MessageContent, ImageContent | AudioContent | FileContent> | WireImageContent | WireAudioContent | WireFileContent;
|
|
52
|
+
/** Wire twin of {@link UserMessage}. @stable */
|
|
53
|
+
interface WireUserMessage extends Omit<UserMessage, 'content'> {
|
|
54
|
+
readonly content: string | readonly WireMessageContent[];
|
|
55
|
+
}
|
|
56
|
+
/** Wire twin of {@link AssistantMessage}. @stable */
|
|
57
|
+
interface WireAssistantMessage extends Omit<AssistantMessage, 'content'> {
|
|
58
|
+
readonly content: string | readonly WireMessageContent[];
|
|
59
|
+
}
|
|
60
|
+
/** Wire twin of {@link ToolMessage}. @stable */
|
|
61
|
+
interface WireToolMessage extends Omit<ToolMessage, 'content'> {
|
|
62
|
+
readonly content: string | readonly WireMessageContent[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* JSON-safe twin of {@link Message}. System messages are plain strings
|
|
66
|
+
* and pass through unchanged.
|
|
67
|
+
*
|
|
68
|
+
* @stable
|
|
69
|
+
*/
|
|
70
|
+
type WireMessage = SystemMessage | WireUserMessage | WireAssistantMessage | WireToolMessage;
|
|
71
|
+
/** Wire twin of {@link ToolResult}: `contentParts` are encoded. @stable */
|
|
72
|
+
type WireToolResult<TOutput = unknown> = Omit<ToolResult<TOutput>, 'contentParts'> & {
|
|
73
|
+
readonly contentParts?: readonly WireMessageContent[];
|
|
74
|
+
};
|
|
75
|
+
/** Wire twin of `ToolOutcome`. @stable */
|
|
76
|
+
type WireToolOutcome<TOutput = unknown> = WireToolResult<TOutput> | ToolError;
|
|
77
|
+
/** Wire twin of {@link CompletedToolCall}. @stable */
|
|
78
|
+
type WireCompletedToolCall<TOutput = unknown> = Omit<CompletedToolCall<TOutput>, 'outcome'> & {
|
|
79
|
+
readonly outcome: WireToolOutcome<TOutput>;
|
|
80
|
+
};
|
|
81
|
+
/** Wire twin of {@link RunStep}. @stable */
|
|
82
|
+
type WireRunStep = Omit<RunStep, 'toolCalls'> & {
|
|
83
|
+
readonly toolCalls: readonly WireCompletedToolCall[];
|
|
84
|
+
};
|
|
85
|
+
/** Wire twin of {@link PendingSubRun}: the child state recurses. @stable */
|
|
86
|
+
type WirePendingSubRun = Omit<PendingSubRun, 'state'> & {
|
|
87
|
+
readonly state: WireRunState;
|
|
88
|
+
};
|
|
89
|
+
/**
|
|
90
|
+
* JSON-safe twin of {@link RunState}: `messages`, every
|
|
91
|
+
* `steps[].toolCalls[].outcome.contentParts`, and each parked
|
|
92
|
+
* `pendingSubRuns[].state` (recursively, W-001) are projected through
|
|
93
|
+
* the binary codec. Everything else is structurally identical.
|
|
94
|
+
*
|
|
95
|
+
* `pendingApprovals[].args` and `ToolResult.output` are model-produced
|
|
96
|
+
* JSON and are assumed JSON-safe already - the projection does not
|
|
97
|
+
* walk them.
|
|
98
|
+
*
|
|
99
|
+
* @stable
|
|
100
|
+
*/
|
|
101
|
+
type WireRunState = Omit<RunState, 'messages' | 'steps' | 'pendingSubRuns'> & {
|
|
102
|
+
readonly messages: readonly WireMessage[];
|
|
103
|
+
readonly steps: readonly WireRunStep[];
|
|
104
|
+
readonly pendingSubRuns?: readonly WirePendingSubRun[];
|
|
105
|
+
};
|
|
106
|
+
/**
|
|
107
|
+
* Encode bytes as standard (padded) base64 without relying on `Buffer`
|
|
108
|
+
* or `btoa`.
|
|
109
|
+
*
|
|
110
|
+
* @stable
|
|
111
|
+
*/
|
|
112
|
+
declare function bytesToBase64(bytes: Uint8Array): string;
|
|
113
|
+
/**
|
|
114
|
+
* Decode standard base64 (padding optional). Throws on characters
|
|
115
|
+
* outside the base64 alphabet.
|
|
116
|
+
*
|
|
117
|
+
* @stable
|
|
118
|
+
*/
|
|
119
|
+
declare function base64ToBytes(data: string): Uint8Array;
|
|
120
|
+
/**
|
|
121
|
+
* Project multimodal content parts into their JSON-safe wire form.
|
|
122
|
+
* Text and reasoning parts pass through untouched.
|
|
123
|
+
*
|
|
124
|
+
* @stable
|
|
125
|
+
*/
|
|
126
|
+
declare function toJsonSafeContentParts(parts: readonly MessageContent[]): readonly WireMessageContent[];
|
|
127
|
+
/**
|
|
128
|
+
* Inverse of {@link toJsonSafeContentParts}. Accepts legacy corrupted
|
|
129
|
+
* payloads (numeric-key byte objects) and repairs them best-effort.
|
|
130
|
+
*
|
|
131
|
+
* @stable
|
|
132
|
+
*/
|
|
133
|
+
declare function fromJsonSafeContentParts(parts: readonly WireMessageContent[]): readonly MessageContent[];
|
|
134
|
+
/**
|
|
135
|
+
* Project a {@link Message} into its JSON-safe wire form. Idempotent:
|
|
136
|
+
* projecting an already-wire message returns an equivalent value.
|
|
137
|
+
*
|
|
138
|
+
* @stable
|
|
139
|
+
*/
|
|
140
|
+
declare function toJsonSafeMessage(message: Message | WireMessage): WireMessage;
|
|
141
|
+
/**
|
|
142
|
+
* Inverse of {@link toJsonSafeMessage}.
|
|
143
|
+
*
|
|
144
|
+
* @stable
|
|
145
|
+
*/
|
|
146
|
+
declare function fromJsonSafeMessage(message: WireMessage | Message): Message;
|
|
147
|
+
/**
|
|
148
|
+
* Project a full {@link RunState} into its JSON-safe {@link WireRunState}
|
|
149
|
+
* twin: `messages` and `steps[].toolCalls[].outcome.contentParts` go
|
|
150
|
+
* through the binary codec, everything else is copied structurally.
|
|
151
|
+
*
|
|
152
|
+
* @stable
|
|
153
|
+
*/
|
|
154
|
+
declare function toJsonSafeRunState(state: RunState | WireRunState): WireRunState;
|
|
155
|
+
/**
|
|
156
|
+
* Inverse of {@link toJsonSafeRunState}. Best-effort: legacy corrupted
|
|
157
|
+
* binary fields (numeric-key byte objects from schema <= 1.1 payloads)
|
|
158
|
+
* are repaired to `Uint8Array`; unrecoverable shapes are left as-is.
|
|
159
|
+
*
|
|
160
|
+
* @stable
|
|
161
|
+
*/
|
|
162
|
+
declare function fromJsonSafeRunState(state: WireRunState): RunState;
|
|
163
|
+
//#endregion
|
|
164
|
+
export { EncodedBinary, EncodedBytes, EncodedUrl, WireAssistantMessage, WireAudioContent, WireCompletedToolCall, WireFileContent, WireImageContent, WireMessage, WireMessageContent, WireRunState, WireRunStep, WireToolMessage, WireToolOutcome, WireToolResult, WireUserMessage, base64ToBytes, bytesToBase64, fromJsonSafeContentParts, fromJsonSafeMessage, fromJsonSafeRunState, toJsonSafeContentParts, toJsonSafeMessage, toJsonSafeRunState };
|
|
165
|
+
//# sourceMappingURL=binary-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"binary-json.d.ts","names":[],"sources":["../../src/utils/binary-json.ts"],"sourcesContent":[],"mappings":";;;;;;;;;AAkFA;;AAC4B,UA9CX,YAAA,CA8CW;EAAe,SAAA,GAAA,EAAA,QAAA;EAAe,SAAA,IAAA,EAAA,MAAA;;;;;;AAM1D;;AACsC,UA1CrB,UAAA,CA0CqB;EADG,SAAA,GAAA,EAAA,KAAA;EAAI,SAAA,IAAA,EAAA,MAAA;AAK7C;;;;;AAKA;AAA8C,KAzClC,aAAA,GAAgB,YAyCkB,GAzCH,UAyCG;;AAAL,UAtCxB,gBAAA,SAAyB,IAsCD,CAtCM,YAsCN,EAAA,OAAA,CAAA,CAAA;EAAI,SAAA,KAAA,EArC3B,aAqC2B;AAU7C;;AAA0C,UA3CzB,gBAAA,SAAyB,IA2CA,CA3CK,YA2CL,EAAA,OAAA,CAAA,CAAA;EAAkB,SAAA,KAAA,EA1C1C,aA0C0C;;;AAGhD,UAzCK,eAAA,SAAwB,IAyCf,CAzCoB,WAyCpB,EAAA,MAAA,CAAA,CAAA;EAAsC,SAAA,IAAA,EAxC/C,aAwC+C;;;;;AAKhE;;;;AAAoF,KAnCxE,kBAAA,GACR,OAkCgF,CAlCxE,cAkCwE,EAlCxD,YAkCwD,GAlCzC,YAkCyC,GAlC1B,WAkC0B,CAAA,GAjChF,gBAiCgF,GAhChF,gBAgCgF,GA/BhF,eA+BgF;AAGpF;AACoB,UAhCH,eAAA,SAAwB,IAgCrB,CAhC0B,WAgC1B,EAAA,SAAA,CAAA,CAAA;EAAlB,SAAA,OAAA,EAAA,MAAA,GAAA,SA/BoC,kBA+BpC,EAAA;;;AAGkB,UA9BH,oBAAA,SAA6B,IA8B1B,CA9B+B,gBA8B/B,EAAA,SAAA,CAAA,CAAA;EAAe,SAAA,OAAA,EAAA,MAAA,GAAA,SA7BG,kBA6BH,EAAA;AAInC;;AAA0B,UA7BT,eAAA,SAAwB,IA6Bf,CA7BoB,WA6BpB,EAAA,SAAA,CAAA,CAAA;EACK,SAAA,OAAA,EAAA,MAAA,GAAA,SA7BO,kBA6BP,EAAA;;AAI/B;;;;;AAgBA;AAAgC,KAxCpB,WAAA,GAAc,aAwCM,GAxCU,eAwCV,GAxC4B,oBAwC5B,GAxCmD,eAwCnD;;AACF,KAtClB,cAsCkB,CAAA,UAAA,OAAA,CAAA,GAtCkB,IAsClB,CAtCuB,UAsCvB,CAtCkC,OAsClC,CAAA,EAAA,cAAA,CAAA,GAAA;EACH,SAAA,YAAA,CAAA,EAAA,SAtCQ,kBAsCR,EAAA;CACU;;AAerB,KAlDJ,eAkDiB,CAAA,UAAQ,OAAU,CAAA,GAlDE,cAkDF,CAlDiB,OAkDjB,CAAA,GAlD4B,SAkD5B;AAoB/C;AAyGgB,KA5KJ,qBA4K0B,CAAA,UACpB,OAAA,CAAA,GA7KqC,IA8K3C,CA7KV,iBA6K4B,CA7KV,OA6KU,CAAA,EAAA,SAAA,CAAA,GAAA;EAUd,SAAA,OAAA,EApLI,eAoLoB,CApLJ,OAqLlB,CAAA;AAWlB,CAAA;;AAAqD,KA5LzC,WAAA,GAAc,IA4L2B,CA5LtB,OA4LsB,EAAA,WAAA,CAAA,GAAA;EAAc,SAAA,SAAA,EAAA,SA3LpC,qBA2LoC,EAAA;CAAW;AAY9E;AAA6C,KAnMjC,iBAAA,GAAoB,IAmMa,CAnMR,aAmMQ,EAAA,OAAA,CAAA,GAAA;EAAc,SAAA,KAAA,EAlMzC,YAkMyC;CAAU;;AAuDrE;;;;;AA0BA;;;;;;KApQY,YAAA,GAAe,KAAK;8BACF;2BACH;qCACU;;;;;;;;iBAerB,aAAA,QAAqB;;;;;;;iBAoBrB,aAAA,gBAA6B;;;;;;;iBAyG7B,sBAAA,iBACE,4BACN;;;;;;;iBAUI,wBAAA,iBACE,gCACN;;;;;;;iBAUI,iBAAA,UAA2B,UAAU,cAAc;;;;;;iBAYnD,mBAAA,UAA6B,cAAc,UAAU;;;;;;;;iBAuDrD,kBAAA,QAA0B,WAAW,eAAe;;;;;;;;iBA0BpD,oBAAA,QAA4B,eAAe"}
|
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
//#region src/utils/binary-json.ts
|
|
2
|
+
const B64_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
3
|
+
const B64_LOOKUP = new Map([...B64_ALPHABET].map((ch, i) => [ch, i]));
|
|
4
|
+
/**
|
|
5
|
+
* Encode bytes as standard (padded) base64 without relying on `Buffer`
|
|
6
|
+
* or `btoa`.
|
|
7
|
+
*
|
|
8
|
+
* @stable
|
|
9
|
+
*/
|
|
10
|
+
function bytesToBase64(bytes) {
|
|
11
|
+
let out = "";
|
|
12
|
+
for (let i = 0; i < bytes.length; i += 3) {
|
|
13
|
+
const b0 = bytes[i];
|
|
14
|
+
const b1 = i + 1 < bytes.length ? bytes[i + 1] : void 0;
|
|
15
|
+
const b2 = i + 2 < bytes.length ? bytes[i + 2] : void 0;
|
|
16
|
+
out += B64_ALPHABET[b0 >> 2];
|
|
17
|
+
out += B64_ALPHABET[(b0 & 3) << 4 | (b1 ?? 0) >> 4];
|
|
18
|
+
out += b1 === void 0 ? "=" : B64_ALPHABET[(b1 & 15) << 2 | (b2 ?? 0) >> 6];
|
|
19
|
+
out += b2 === void 0 ? "=" : B64_ALPHABET[b2 & 63];
|
|
20
|
+
}
|
|
21
|
+
return out;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Decode standard base64 (padding optional). Throws on characters
|
|
25
|
+
* outside the base64 alphabet.
|
|
26
|
+
*
|
|
27
|
+
* @stable
|
|
28
|
+
*/
|
|
29
|
+
function base64ToBytes(data) {
|
|
30
|
+
let end = data.length;
|
|
31
|
+
while (end > 0 && data.charCodeAt(end - 1) === 61) end -= 1;
|
|
32
|
+
const stripped = data.slice(0, end);
|
|
33
|
+
const out = new Uint8Array(Math.floor(stripped.length * 6 / 8));
|
|
34
|
+
let offset = 0;
|
|
35
|
+
let buffer = 0;
|
|
36
|
+
let bits = 0;
|
|
37
|
+
for (const ch of stripped) {
|
|
38
|
+
const value = B64_LOOKUP.get(ch);
|
|
39
|
+
if (value === void 0) throw new Error(`base64ToBytes: invalid base64 character ${JSON.stringify(ch)}`);
|
|
40
|
+
buffer = buffer << 6 | value;
|
|
41
|
+
bits += 6;
|
|
42
|
+
if (bits >= 8) {
|
|
43
|
+
bits -= 8;
|
|
44
|
+
out[offset] = buffer >> bits & 255;
|
|
45
|
+
offset += 1;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return out;
|
|
49
|
+
}
|
|
50
|
+
function isRecord(v) {
|
|
51
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
52
|
+
}
|
|
53
|
+
function encodeBinary(value) {
|
|
54
|
+
if (value instanceof Uint8Array) return {
|
|
55
|
+
enc: "base64",
|
|
56
|
+
data: bytesToBase64(value)
|
|
57
|
+
};
|
|
58
|
+
if (value instanceof URL) return {
|
|
59
|
+
enc: "url",
|
|
60
|
+
href: value.href
|
|
61
|
+
};
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Repair the exact corruption `JSON.stringify(Uint8Array)` produces: an
|
|
66
|
+
* object whose keys are the dense indices `0..n-1` with byte values.
|
|
67
|
+
* Applied ONLY to known binary fields of legacy (schema <= 1.1)
|
|
68
|
+
* payloads; anything else is returned as-is.
|
|
69
|
+
*/
|
|
70
|
+
function repairNumericKeyBytes(value) {
|
|
71
|
+
const keys = Object.keys(value);
|
|
72
|
+
if (keys.length === 0) return void 0;
|
|
73
|
+
const out = new Uint8Array(keys.length);
|
|
74
|
+
for (let i = 0; i < keys.length; i += 1) {
|
|
75
|
+
const raw = value[String(i)];
|
|
76
|
+
if (typeof raw !== "number" || !Number.isInteger(raw) || raw < 0 || raw > 255) return;
|
|
77
|
+
out[i] = raw;
|
|
78
|
+
}
|
|
79
|
+
return out;
|
|
80
|
+
}
|
|
81
|
+
function decodeBinary(value) {
|
|
82
|
+
if (value instanceof Uint8Array || value instanceof URL) return value;
|
|
83
|
+
if (!isRecord(value)) return value;
|
|
84
|
+
if (value.enc === "base64" && typeof value.data === "string") return base64ToBytes(value.data);
|
|
85
|
+
if (value.enc === "url" && typeof value.href === "string") return new URL(value.href);
|
|
86
|
+
return repairNumericKeyBytes(value) ?? value;
|
|
87
|
+
}
|
|
88
|
+
function encodeContentPart(part) {
|
|
89
|
+
switch (part.type) {
|
|
90
|
+
case "image": return {
|
|
91
|
+
...part,
|
|
92
|
+
image: encodeBinary(part.image)
|
|
93
|
+
};
|
|
94
|
+
case "audio": return {
|
|
95
|
+
...part,
|
|
96
|
+
audio: encodeBinary(part.audio)
|
|
97
|
+
};
|
|
98
|
+
case "file": return {
|
|
99
|
+
...part,
|
|
100
|
+
file: encodeBinary(part.file)
|
|
101
|
+
};
|
|
102
|
+
default: return part;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function decodeContentPart(part) {
|
|
106
|
+
switch (part.type) {
|
|
107
|
+
case "image": return {
|
|
108
|
+
...part,
|
|
109
|
+
image: decodeBinary(part.image)
|
|
110
|
+
};
|
|
111
|
+
case "audio": return {
|
|
112
|
+
...part,
|
|
113
|
+
audio: decodeBinary(part.audio)
|
|
114
|
+
};
|
|
115
|
+
case "file": return {
|
|
116
|
+
...part,
|
|
117
|
+
file: decodeBinary(part.file)
|
|
118
|
+
};
|
|
119
|
+
default: return part;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Project multimodal content parts into their JSON-safe wire form.
|
|
124
|
+
* Text and reasoning parts pass through untouched.
|
|
125
|
+
*
|
|
126
|
+
* @stable
|
|
127
|
+
*/
|
|
128
|
+
function toJsonSafeContentParts(parts) {
|
|
129
|
+
return parts.map(encodeContentPart);
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Inverse of {@link toJsonSafeContentParts}. Accepts legacy corrupted
|
|
133
|
+
* payloads (numeric-key byte objects) and repairs them best-effort.
|
|
134
|
+
*
|
|
135
|
+
* @stable
|
|
136
|
+
*/
|
|
137
|
+
function fromJsonSafeContentParts(parts) {
|
|
138
|
+
return parts.map(decodeContentPart);
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Project a {@link Message} into its JSON-safe wire form. Idempotent:
|
|
142
|
+
* projecting an already-wire message returns an equivalent value.
|
|
143
|
+
*
|
|
144
|
+
* @stable
|
|
145
|
+
*/
|
|
146
|
+
function toJsonSafeMessage(message) {
|
|
147
|
+
if (message.role === "system" || typeof message.content === "string") return message;
|
|
148
|
+
return {
|
|
149
|
+
...message,
|
|
150
|
+
content: message.content.map(encodeContentPart)
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Inverse of {@link toJsonSafeMessage}.
|
|
155
|
+
*
|
|
156
|
+
* @stable
|
|
157
|
+
*/
|
|
158
|
+
function fromJsonSafeMessage(message) {
|
|
159
|
+
if (message.role === "system" || typeof message.content === "string") return message;
|
|
160
|
+
return {
|
|
161
|
+
...message,
|
|
162
|
+
content: message.content.map(decodeContentPart)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function encodeOutcome(outcome) {
|
|
166
|
+
if (isRecord(outcome) && Array.isArray(outcome.contentParts)) return {
|
|
167
|
+
...outcome,
|
|
168
|
+
contentParts: toJsonSafeContentParts(outcome.contentParts)
|
|
169
|
+
};
|
|
170
|
+
return outcome;
|
|
171
|
+
}
|
|
172
|
+
function decodeOutcome(outcome) {
|
|
173
|
+
if (isRecord(outcome) && Array.isArray(outcome.contentParts)) return {
|
|
174
|
+
...outcome,
|
|
175
|
+
contentParts: fromJsonSafeContentParts(outcome.contentParts)
|
|
176
|
+
};
|
|
177
|
+
return outcome;
|
|
178
|
+
}
|
|
179
|
+
function encodeStep(step) {
|
|
180
|
+
if (step.toolCalls.length === 0) return step;
|
|
181
|
+
return {
|
|
182
|
+
...step,
|
|
183
|
+
toolCalls: step.toolCalls.map((tc) => ({
|
|
184
|
+
...tc,
|
|
185
|
+
outcome: encodeOutcome(tc.outcome)
|
|
186
|
+
}))
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
function decodeStep(step) {
|
|
190
|
+
if (step.toolCalls.length === 0) return step;
|
|
191
|
+
return {
|
|
192
|
+
...step,
|
|
193
|
+
toolCalls: step.toolCalls.map((tc) => ({
|
|
194
|
+
...tc,
|
|
195
|
+
outcome: decodeOutcome(tc.outcome)
|
|
196
|
+
}))
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Project a full {@link RunState} into its JSON-safe {@link WireRunState}
|
|
201
|
+
* twin: `messages` and `steps[].toolCalls[].outcome.contentParts` go
|
|
202
|
+
* through the binary codec, everything else is copied structurally.
|
|
203
|
+
*
|
|
204
|
+
* @stable
|
|
205
|
+
*/
|
|
206
|
+
function toJsonSafeRunState(state) {
|
|
207
|
+
const subRuns = state.pendingSubRuns;
|
|
208
|
+
return {
|
|
209
|
+
...state,
|
|
210
|
+
messages: state.messages.map(toJsonSafeMessage),
|
|
211
|
+
steps: state.steps.map(encodeStep),
|
|
212
|
+
...subRuns !== void 0 && subRuns.length > 0 ? { pendingSubRuns: subRuns.map((sub) => ({
|
|
213
|
+
...sub,
|
|
214
|
+
state: toJsonSafeRunState(sub.state)
|
|
215
|
+
})) } : {}
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Inverse of {@link toJsonSafeRunState}. Best-effort: legacy corrupted
|
|
220
|
+
* binary fields (numeric-key byte objects from schema <= 1.1 payloads)
|
|
221
|
+
* are repaired to `Uint8Array`; unrecoverable shapes are left as-is.
|
|
222
|
+
*
|
|
223
|
+
* @stable
|
|
224
|
+
*/
|
|
225
|
+
function fromJsonSafeRunState(state) {
|
|
226
|
+
const subRuns = state.pendingSubRuns;
|
|
227
|
+
return {
|
|
228
|
+
...state,
|
|
229
|
+
messages: state.messages.map(fromJsonSafeMessage),
|
|
230
|
+
steps: state.steps.map(decodeStep),
|
|
231
|
+
...subRuns !== void 0 && subRuns.length > 0 ? { pendingSubRuns: subRuns.map((sub) => ({
|
|
232
|
+
...sub,
|
|
233
|
+
state: fromJsonSafeRunState(sub.state)
|
|
234
|
+
})) } : {}
|
|
235
|
+
};
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
//#endregion
|
|
239
|
+
export { base64ToBytes, bytesToBase64, fromJsonSafeContentParts, fromJsonSafeMessage, fromJsonSafeRunState, toJsonSafeContentParts, toJsonSafeMessage, toJsonSafeRunState };
|
|
240
|
+
//# sourceMappingURL=binary-json.js.map
|