@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
|
@@ -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
|
+
}
|