@graphorin/core 0.6.1 → 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.
Files changed (110) hide show
  1. package/CHANGELOG.md +82 -0
  2. package/README.md +8 -5
  3. package/dist/channels/index.d.ts +2 -2
  4. package/dist/channels/index.js +2 -2
  5. package/dist/channels/pause.d.ts +47 -2
  6. package/dist/channels/pause.d.ts.map +1 -1
  7. package/dist/channels/pause.js +62 -2
  8. package/dist/channels/pause.js.map +1 -1
  9. package/dist/contracts/checkpoint-store.d.ts +97 -1
  10. package/dist/contracts/checkpoint-store.d.ts.map +1 -1
  11. package/dist/contracts/checkpoint-store.js.map +1 -1
  12. package/dist/contracts/index.d.ts +5 -5
  13. package/dist/contracts/index.js +2 -1
  14. package/dist/contracts/memory-store.d.ts +59 -2
  15. package/dist/contracts/memory-store.d.ts.map +1 -1
  16. package/dist/contracts/provider.d.ts +20 -6
  17. package/dist/contracts/provider.d.ts.map +1 -1
  18. package/dist/contracts/session-store.d.ts +10 -2
  19. package/dist/contracts/session-store.d.ts.map +1 -1
  20. package/dist/contracts/tool.d.ts +75 -1
  21. package/dist/contracts/tool.d.ts.map +1 -1
  22. package/dist/contracts/tool.js +57 -0
  23. package/dist/contracts/tool.js.map +1 -0
  24. package/dist/contracts/tracer.d.ts +53 -5
  25. package/dist/contracts/tracer.d.ts.map +1 -1
  26. package/dist/contracts/tracer.js.map +1 -1
  27. package/dist/index.d.ts +9 -7
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +5 -5
  30. package/dist/package.js +1 -1
  31. package/dist/package.js.map +1 -1
  32. package/dist/types/agent-event-wire.d.ts +74 -0
  33. package/dist/types/agent-event-wire.d.ts.map +1 -0
  34. package/dist/types/agent-event-wire.js +130 -0
  35. package/dist/types/agent-event-wire.js.map +1 -0
  36. package/dist/types/agent-event.d.ts +48 -6
  37. package/dist/types/agent-event.d.ts.map +1 -1
  38. package/dist/types/index.d.ts +3 -2
  39. package/dist/types/index.js +2 -1
  40. package/dist/types/memory.d.ts +11 -0
  41. package/dist/types/memory.d.ts.map +1 -1
  42. package/dist/types/run.d.ts +86 -4
  43. package/dist/types/run.d.ts.map +1 -1
  44. package/dist/types/run.js.map +1 -1
  45. package/dist/types/tool.d.ts +10 -0
  46. package/dist/types/tool.d.ts.map +1 -1
  47. package/dist/types/usage.d.ts +11 -1
  48. package/dist/types/usage.d.ts.map +1 -1
  49. package/dist/types/usage.js.map +1 -1
  50. package/dist/utils/binary-json.d.ts +165 -0
  51. package/dist/utils/binary-json.d.ts.map +1 -0
  52. package/dist/utils/binary-json.js +240 -0
  53. package/dist/utils/binary-json.js.map +1 -0
  54. package/dist/utils/index.d.ts +2 -1
  55. package/dist/utils/index.js +2 -1
  56. package/dist/utils/validation.d.ts +10 -1
  57. package/dist/utils/validation.d.ts.map +1 -1
  58. package/dist/utils/validation.js +1 -1
  59. package/dist/utils/validation.js.map +1 -1
  60. package/package.json +9 -7
  61. package/src/channels/channels.ts +206 -0
  62. package/src/channels/directive.ts +41 -0
  63. package/src/channels/dispatch.ts +37 -0
  64. package/src/channels/durable.ts +151 -0
  65. package/src/channels/index.ts +62 -0
  66. package/src/channels/pause.ts +216 -0
  67. package/src/contracts/auth-token-store.ts +42 -0
  68. package/src/contracts/checkpoint-store.ts +256 -0
  69. package/src/contracts/embedder.ts +42 -0
  70. package/src/contracts/eval-scorer.ts +44 -0
  71. package/src/contracts/index.ts +112 -0
  72. package/src/contracts/local-provider-trust.ts +33 -0
  73. package/src/contracts/logger.ts +61 -0
  74. package/src/contracts/memory-store.ts +187 -0
  75. package/src/contracts/oauth-server-store.ts +78 -0
  76. package/src/contracts/preferred-model.ts +56 -0
  77. package/src/contracts/provider.ts +316 -0
  78. package/src/contracts/reasoning-retention.ts +52 -0
  79. package/src/contracts/redaction-validator.ts +56 -0
  80. package/src/contracts/sandbox.ts +70 -0
  81. package/src/contracts/secret-ref.ts +22 -0
  82. package/src/contracts/secret-value.ts +117 -0
  83. package/src/contracts/secrets-store.ts +90 -0
  84. package/src/contracts/session-store.ts +163 -0
  85. package/src/contracts/token-counter.ts +23 -0
  86. package/src/contracts/tool.ts +397 -0
  87. package/src/contracts/tracer.ts +219 -0
  88. package/src/contracts/trigger-store.ts +40 -0
  89. package/src/index.ts +23 -0
  90. package/src/types/agent-event-wire.ts +193 -0
  91. package/src/types/agent-event.ts +579 -0
  92. package/src/types/handoff.ts +111 -0
  93. package/src/types/index.ts +148 -0
  94. package/src/types/memory.ts +427 -0
  95. package/src/types/message.ts +174 -0
  96. package/src/types/run.ts +312 -0
  97. package/src/types/sensitivity.ts +35 -0
  98. package/src/types/session-scope.ts +18 -0
  99. package/src/types/stop-condition.ts +108 -0
  100. package/src/types/tool-call.ts +24 -0
  101. package/src/types/tool.ts +324 -0
  102. package/src/types/usage.ts +120 -0
  103. package/src/types/workflow-event.ts +132 -0
  104. package/src/utils/assert-never.ts +24 -0
  105. package/src/utils/async-context.ts +55 -0
  106. package/src/utils/binary-json.ts +425 -0
  107. package/src/utils/hash.ts +122 -0
  108. package/src/utils/index.ts +57 -0
  109. package/src/utils/streams.ts +233 -0
  110. package/src/utils/validation.ts +82 -0
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Framework-known discriminators for typed observability spans.
3
+ *
4
+ * The list mirrors the span taxonomy documented for the observability
5
+ * layer; concrete implementations live in `@graphorin/observability`.
6
+ * Promoting a frequently-used custom span kind (see
7
+ * {@link CustomSpanType}) into this union is an additive minor change.
8
+ *
9
+ * @stable
10
+ */
11
+ export type KnownSpanType =
12
+ | 'agent.run'
13
+ | 'agent.step'
14
+ | 'agent.handoff'
15
+ | 'agent.suspend'
16
+ | 'agent.resume'
17
+ | 'provider.generate'
18
+ | 'provider.stream'
19
+ | 'tool.execute'
20
+ | 'tool.approval'
21
+ | 'memory.read.working'
22
+ | 'memory.read.session'
23
+ | 'memory.read.episodic'
24
+ | 'memory.read.semantic'
25
+ | 'memory.read.procedural'
26
+ | 'memory.read.shared'
27
+ | 'memory.write.working'
28
+ | 'memory.write.session'
29
+ | 'memory.write.episodic'
30
+ | 'memory.write.semantic'
31
+ | 'memory.write.procedural'
32
+ | 'memory.write.shared'
33
+ | 'memory.search.working'
34
+ | 'memory.search.session'
35
+ | 'memory.search.episodic'
36
+ | 'memory.search.semantic'
37
+ | 'memory.search.procedural'
38
+ | 'memory.search.shared'
39
+ | 'memory.consolidate.light'
40
+ | 'memory.consolidate.standard'
41
+ | 'memory.consolidate.deep'
42
+ | 'memory.consolidate.reflect'
43
+ | 'memory.consolidate.learned-context'
44
+ | 'memory.search.insight'
45
+ | 'memory.read.insight'
46
+ | 'memory.write.insight'
47
+ | 'memory.conflict'
48
+ | 'memory.embed'
49
+ | 'workflow.run'
50
+ | 'workflow.step'
51
+ | 'workflow.task'
52
+ | 'workflow.checkpoint'
53
+ | 'skill.activate'
54
+ | 'skill.load'
55
+ | 'mcp.connect'
56
+ | 'mcp.call'
57
+ | 'mcp.list-tools';
58
+
59
+ /**
60
+ * Namespaced escape hatch for user-defined span kinds (W-126): any
61
+ * string under the `x.` prefix, e.g. `'x.acme.rerank'`. The prefix
62
+ * keeps typo-safety for the known literals - `'memory.serch.semantic'`
63
+ * is still a compile error because it does not start with `x.` -
64
+ * which is why this is a template-literal type and not `string & {}`.
65
+ *
66
+ * Convention: `x.<vendor>.<operation>`. Backends and analytics must
67
+ * tolerate unknown span-type strings (the same policy events already
68
+ * follow). When a custom kind becomes common, promote it into
69
+ * {@link KnownSpanType} (additive minor).
70
+ *
71
+ * @stable
72
+ */
73
+ export type CustomSpanType = `x.${string}`;
74
+
75
+ /**
76
+ * Discriminator union for typed observability spans: every
77
+ * {@link KnownSpanType} literal plus the {@link CustomSpanType}
78
+ * namespaced escape. Exhaustive switches over `SpanType` need a
79
+ * default branch for the custom domain.
80
+ *
81
+ * @stable
82
+ */
83
+ export type SpanType = KnownSpanType | CustomSpanType;
84
+
85
+ /**
86
+ * Status of a finished span. Mirrors the OTel status convention with
87
+ * `'ok' | 'error'` short forms instead of the verbose tristate.
88
+ *
89
+ * @stable
90
+ */
91
+ export type SpanStatus = 'ok' | 'error' | 'cancelled';
92
+
93
+ /**
94
+ * Free-form attributes attached to a span.
95
+ *
96
+ * @stable
97
+ */
98
+ export type SpanAttributes = Readonly<Record<string, SpanAttributeValue>>;
99
+
100
+ /** @stable */
101
+ export type SpanAttributeValue =
102
+ | string
103
+ | number
104
+ | boolean
105
+ | null
106
+ | ReadonlyArray<string>
107
+ | ReadonlyArray<number>
108
+ | ReadonlyArray<boolean>;
109
+
110
+ /**
111
+ * W-094: sensitivity opts for {@link AISpan.addEvent}. Event attributes
112
+ * used to be un-taggable, so a default-`'public'` export floor dropped
113
+ * ALL of them - including `exception.type` from `recordException`.
114
+ *
115
+ * @stable
116
+ */
117
+ export interface AddEventOptions {
118
+ /** Default tier applied to every attribute of this event. */
119
+ readonly sensitivity?: import('../types/sensitivity.js').Sensitivity;
120
+ /** Per-attribute overrides; win over {@link AddEventOptions.sensitivity}. */
121
+ readonly sensitivityByAttribute?: Readonly<
122
+ Record<string, import('../types/sensitivity.js').Sensitivity>
123
+ >;
124
+ }
125
+
126
+ /**
127
+ * Typed span. Generic over `SpanType` so consumers can specialize a
128
+ * function on a particular span kind without losing the discriminator.
129
+ *
130
+ * @stable
131
+ */
132
+ export interface AISpan<T extends SpanType = SpanType> {
133
+ readonly type: T;
134
+ readonly id: string;
135
+ readonly traceId: string;
136
+ readonly parentId?: string;
137
+ /** Add or replace attributes. Repeated calls are merged (last write wins). */
138
+ setAttributes(attrs: SpanAttributes): void;
139
+ /**
140
+ * Append a span event (attribute-bearing time-stamped marker). The
141
+ * optional `opts` (W-094) tags the event's attributes with a
142
+ * sensitivity tier so the validation exporter can pass safe ones
143
+ * through the default-deny floor - untagged attributes keep being
144
+ * dropped below the floor.
145
+ */
146
+ addEvent(name: string, attrs?: SpanAttributes, opts?: AddEventOptions): void;
147
+ /** Record an exception. Multiple calls are kept in the span event log. */
148
+ recordException(err: unknown): void;
149
+ /** Set the terminal status. */
150
+ setStatus(status: SpanStatus, message?: string): void;
151
+ /** End the span. Idempotent. */
152
+ end(): void;
153
+ }
154
+
155
+ /**
156
+ * Span constructor parameters.
157
+ *
158
+ * @stable
159
+ */
160
+ export interface StartSpanOptions<T extends SpanType = SpanType> {
161
+ readonly type: T;
162
+ readonly attrs?: SpanAttributes;
163
+ readonly parent?: AISpan;
164
+ }
165
+
166
+ /**
167
+ * Pluggable tracer. Implementations live in `@graphorin/observability`.
168
+ * The interface intentionally mirrors a subset of the OTel API so that
169
+ * adapter code is a thin pass-through.
170
+ *
171
+ * @stable
172
+ */
173
+ export interface Tracer {
174
+ startSpan<T extends SpanType>(opts: StartSpanOptions<T>): AISpan<T>;
175
+ /**
176
+ * Convenience wrapper: start a span, run `fn` inside, and call
177
+ * `setStatus('ok' | 'error')` + `end()` based on the outcome.
178
+ */
179
+ span<T extends SpanType, R>(
180
+ opts: StartSpanOptions<T>,
181
+ fn: (span: AISpan<T>) => R | Promise<R>,
182
+ ): Promise<R>;
183
+ /** Force-flush any pending spans. */
184
+ shutdown(): Promise<void>;
185
+ }
186
+
187
+ /**
188
+ * Minimal no-op tracer. Useful as a typed default when downstream code
189
+ * needs a non-null `Tracer` without taking the observability dependency.
190
+ *
191
+ * @stable
192
+ */
193
+ export const NOOP_TRACER: Tracer = {
194
+ startSpan<T extends SpanType>(opts: StartSpanOptions<T>): AISpan<T> {
195
+ const span: AISpan<T> = {
196
+ type: opts.type,
197
+ id: '',
198
+ traceId: '',
199
+ setAttributes(): void {},
200
+ addEvent(): void {},
201
+ recordException(): void {},
202
+ setStatus(): void {},
203
+ end(): void {},
204
+ };
205
+ return span;
206
+ },
207
+ async span<T extends SpanType, R>(
208
+ opts: StartSpanOptions<T>,
209
+ fn: (span: AISpan<T>) => R | Promise<R>,
210
+ ): Promise<R> {
211
+ const span = this.startSpan(opts);
212
+ try {
213
+ return await fn(span);
214
+ } finally {
215
+ span.end();
216
+ }
217
+ },
218
+ async shutdown(): Promise<void> {},
219
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Persisted trigger state row. Lives in the `trigger_state` table per
3
+ * the durable-trigger contract: library and server modes share a single
4
+ * code path.
5
+ *
6
+ * @stable
7
+ */
8
+ export interface TriggerState {
9
+ readonly id: string;
10
+ readonly kind: 'cron' | 'interval' | 'idle' | 'event';
11
+ readonly spec: string;
12
+ readonly callbackRef: string;
13
+ /** ISO-8601 of the next scheduled fire. */
14
+ readonly nextFireAt?: string;
15
+ /** ISO-8601 of the most recent fire. */
16
+ readonly lastFiredAt?: string;
17
+ /** Number of consecutive missed fires. */
18
+ readonly missedFires: number;
19
+ readonly disabled: boolean;
20
+ readonly catchupPolicy: 'none' | 'last' | 'all';
21
+ readonly maxCatchupRuns: number;
22
+ readonly catchupWindowMs: number;
23
+ readonly tags?: ReadonlyArray<string>;
24
+ readonly createdAt: string;
25
+ readonly updatedAt?: string;
26
+ }
27
+
28
+ /**
29
+ * Pluggable persistent storage for triggers. Default impl lives in
30
+ * `@graphorin/store-sqlite`.
31
+ *
32
+ * @stable
33
+ */
34
+ export interface TriggerStore {
35
+ upsert(state: TriggerState): Promise<void>;
36
+ get(id: string): Promise<TriggerState | null>;
37
+ list(): Promise<ReadonlyArray<TriggerState>>;
38
+ remove(id: string): Promise<void>;
39
+ recordFire(id: string, firedAt: string, nextFireAt?: string): Promise<void>;
40
+ }
package/src/index.ts ADDED
@@ -0,0 +1,23 @@
1
+ /**
2
+ * @graphorin/core - types, contracts, and utilities for the Graphorin
3
+ * framework. Dependency-free root package every other `@graphorin/*`
4
+ * package depends on.
5
+ *
6
+ * The full documentation lives in the package `README.md` and the
7
+ * sub-module barrels (`./types`, `./contracts`, `./utils`, `./channels`).
8
+ *
9
+ * @packageDocumentation
10
+ */
11
+
12
+ import pkg from '../package.json' with { type: 'json' };
13
+
14
+ /**
15
+ * Canonical version constant, derived from `package.json` at build
16
+ * time so a release bump never has to edit source.
17
+ */
18
+ export const VERSION: string = pkg.version;
19
+
20
+ export * from './channels/index.js';
21
+ export * from './contracts/index.js';
22
+ export * from './types/index.js';
23
+ export * from './utils/index.js';
@@ -0,0 +1,193 @@
1
+ /**
2
+ * JSON-safe wire projection of {@link AgentEvent} (W-046).
3
+ *
4
+ * Three `AgentEvent` variants carry payloads that `JSON.stringify`
5
+ * corrupts: `file.generated` (`data: Uint8Array`),
6
+ * `tool.execute.partial` (binary `ContentChunk`) and - the bulk -
7
+ * `agent.end`, whose `result.state: RunState` embeds multimodal
8
+ * messages and tool-outcome `contentParts`. The wire twins below
9
+ * project those payloads through the binary codec so a server can
10
+ * `JSON.stringify` any event without silently mangling it.
11
+ *
12
+ * `AgentResult.output` (`TOutput`) is assumed JSON-safe already
13
+ * (a string, or a value parsed from JSON structured output) - the
14
+ * projection does not touch it.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
19
+ import {
20
+ base64ToBytes,
21
+ bytesToBase64,
22
+ type EncodedBytes,
23
+ fromJsonSafeRunState,
24
+ toJsonSafeRunState,
25
+ type WireRunState,
26
+ } from '../utils/binary-json.js';
27
+ import type {
28
+ AgentEndEvent,
29
+ AgentEvent,
30
+ AgentResult,
31
+ FileGeneratedEvent,
32
+ SubagentEvent,
33
+ ToolExecutePartialEvent,
34
+ } from './agent-event.js';
35
+ import type { ContentChunk } from './tool.js';
36
+
37
+ /** Wire twin of the binary {@link ContentChunk} variant. @stable */
38
+ export type WireContentChunk =
39
+ | Exclude<ContentChunk, { readonly kind: 'image' }>
40
+ | { readonly kind: 'image'; readonly data: EncodedBytes; readonly mediaType: string };
41
+
42
+ /** Wire twin of `FileGeneratedEvent`. @stable */
43
+ export interface WireFileGeneratedEvent extends Omit<FileGeneratedEvent, 'data'> {
44
+ readonly data: EncodedBytes;
45
+ }
46
+
47
+ /** Wire twin of {@link ToolExecutePartialEvent}. @stable */
48
+ export interface WireToolExecutePartialEvent extends Omit<ToolExecutePartialEvent, 'chunk'> {
49
+ readonly chunk: WireContentChunk;
50
+ }
51
+
52
+ /**
53
+ * Wire twin of {@link AgentEndEvent}: `result.state` is the JSON-safe
54
+ * {@link WireRunState} projection.
55
+ *
56
+ * @stable
57
+ */
58
+ export interface WireAgentEndEvent<TOutput = string>
59
+ extends Omit<AgentEndEvent<TOutput>, 'result'> {
60
+ readonly result: Omit<AgentResult<TOutput>, 'state'> & { readonly state: WireRunState };
61
+ }
62
+
63
+ /**
64
+ * JSON-safe twin of {@link AgentEvent}: the three binary-bearing
65
+ * variants are replaced by their wire twins, every other variant
66
+ * passes through structurally unchanged.
67
+ *
68
+ * This is the actual payload shape a server puts on the wire (inside
69
+ * the `{ eventId, subject, type, payload }` envelope) - see
70
+ * {@link toWireAgentEvent}.
71
+ *
72
+ * @stable
73
+ */
74
+ /**
75
+ * Wire twin of {@link SubagentEvent} (W-036): the wrapped child event
76
+ * projects recursively - a forwarded child `agent.end` carries a full
77
+ * `RunState` of its own.
78
+ *
79
+ * @stable
80
+ */
81
+ export interface WireSubagentEvent extends Omit<SubagentEvent, 'event'> {
82
+ readonly event: WireAgentEvent<unknown>;
83
+ }
84
+
85
+ export type WireAgentEvent<TOutput = string> =
86
+ | Exclude<
87
+ AgentEvent<TOutput>,
88
+ FileGeneratedEvent | ToolExecutePartialEvent | AgentEndEvent<TOutput> | SubagentEvent
89
+ >
90
+ | WireFileGeneratedEvent
91
+ | WireToolExecutePartialEvent
92
+ | WireSubagentEvent
93
+ | WireAgentEndEvent<TOutput>;
94
+
95
+ function isRecord(v: unknown): v is Record<string, unknown> {
96
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
97
+ }
98
+
99
+ /**
100
+ * Registry-hosted agents are structurally typed and may emit an
101
+ * `agent.end` without a full `result.state` (e.g. plain `{ status,
102
+ * output }`). Only a state that actually carries the walked arrays is
103
+ * projected; anything else passes through untouched.
104
+ */
105
+ function hasProjectableState(result: unknown): result is { state: { messages: unknown[] } } {
106
+ if (!isRecord(result)) return false;
107
+ const state = result.state;
108
+ return isRecord(state) && Array.isArray(state.messages) && Array.isArray(state.steps);
109
+ }
110
+
111
+ function encodeBytesField(data: Uint8Array | EncodedBytes): EncodedBytes {
112
+ if (data instanceof Uint8Array) return { enc: 'base64', data: bytesToBase64(data) };
113
+ return data;
114
+ }
115
+
116
+ function decodeBytesField(data: EncodedBytes | Uint8Array | unknown): Uint8Array {
117
+ if (data instanceof Uint8Array) return data;
118
+ if (isRecord(data) && data.enc === 'base64' && typeof data.data === 'string') {
119
+ return base64ToBytes(data.data);
120
+ }
121
+ // Unrecoverable legacy shape - degrade to empty bytes rather than throw.
122
+ return new Uint8Array(0);
123
+ }
124
+
125
+ /**
126
+ * Project an {@link AgentEvent} into its JSON-safe {@link WireAgentEvent}
127
+ * twin. Idempotent: projecting an already-wire event returns an
128
+ * equivalent value. Events of unknown `type` pass through untouched.
129
+ *
130
+ * @stable
131
+ */
132
+ export function toWireAgentEvent<TOutput = string>(
133
+ ev: AgentEvent<TOutput> | WireAgentEvent<TOutput>,
134
+ ): WireAgentEvent<TOutput> {
135
+ switch (ev.type) {
136
+ case 'file.generated':
137
+ return { ...ev, data: encodeBytesField(ev.data) };
138
+ case 'tool.execute.partial': {
139
+ const chunk = ev.chunk;
140
+ if (chunk.kind === 'image') {
141
+ return { ...ev, chunk: { ...chunk, data: encodeBytesField(chunk.data) } };
142
+ }
143
+ return ev as WireAgentEvent<TOutput>;
144
+ }
145
+ case 'agent.end':
146
+ if (!hasProjectableState(ev.result)) return ev as WireAgentEvent<TOutput>;
147
+ return {
148
+ ...ev,
149
+ result: { ...ev.result, state: toJsonSafeRunState(ev.result.state) },
150
+ };
151
+ case 'subagent.event':
152
+ // W-036: the wrapped child event projects recursively.
153
+ return { ...ev, event: toWireAgentEvent(ev.event) };
154
+ default:
155
+ return ev as WireAgentEvent<TOutput>;
156
+ }
157
+ }
158
+
159
+ /**
160
+ * Inverse of {@link toWireAgentEvent}: decode base64 envelopes back
161
+ * into `Uint8Array` / `URL` instances. Exposed for `@graphorin/client`
162
+ * consumers that want runtime types back after `JSON.parse`.
163
+ *
164
+ * @stable
165
+ */
166
+ export function fromWireAgentEvent<TOutput = string>(
167
+ ev: WireAgentEvent<TOutput> | AgentEvent<TOutput>,
168
+ ): AgentEvent<TOutput> {
169
+ switch (ev.type) {
170
+ case 'file.generated':
171
+ return { ...ev, data: decodeBytesField(ev.data) };
172
+ case 'tool.execute.partial': {
173
+ const chunk = ev.chunk;
174
+ if (chunk.kind === 'image') {
175
+ return { ...ev, chunk: { ...chunk, data: decodeBytesField(chunk.data) } };
176
+ }
177
+ return ev as AgentEvent<TOutput>;
178
+ }
179
+ case 'agent.end':
180
+ if (!hasProjectableState(ev.result)) return ev as AgentEvent<TOutput>;
181
+ return {
182
+ ...ev,
183
+ result: {
184
+ ...ev.result,
185
+ state: fromJsonSafeRunState(ev.result.state as unknown as WireRunState),
186
+ },
187
+ } as AgentEvent<TOutput>;
188
+ case 'subagent.event':
189
+ return { ...ev, event: fromWireAgentEvent(ev.event) } as AgentEvent<TOutput>;
190
+ default:
191
+ return ev as AgentEvent<TOutput>;
192
+ }
193
+ }