@aexhq/sdk 0.13.6
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/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/_contracts/connection-ticket.d.ts +21 -0
- package/dist/_contracts/connection-ticket.js +49 -0
- package/dist/_contracts/event-envelope.d.ts +276 -0
- package/dist/_contracts/event-envelope.js +324 -0
- package/dist/_contracts/event-stream-client.d.ts +47 -0
- package/dist/_contracts/event-stream-client.js +141 -0
- package/dist/_contracts/http.d.ts +35 -0
- package/dist/_contracts/http.js +114 -0
- package/dist/_contracts/index.d.ts +28 -0
- package/dist/_contracts/index.js +29 -0
- package/dist/_contracts/managed-key.d.ts +74 -0
- package/dist/_contracts/managed-key.js +110 -0
- package/dist/_contracts/operations.d.ts +237 -0
- package/dist/_contracts/operations.js +632 -0
- package/dist/_contracts/provider-support.d.ts +220 -0
- package/dist/_contracts/provider-support.js +90 -0
- package/dist/_contracts/proxy-protocol.d.ts +257 -0
- package/dist/_contracts/proxy-protocol.js +234 -0
- package/dist/_contracts/proxy-validation.d.ts +19 -0
- package/dist/_contracts/proxy-validation.js +51 -0
- package/dist/_contracts/run-artifacts.d.ts +47 -0
- package/dist/_contracts/run-artifacts.js +101 -0
- package/dist/_contracts/run-config.d.ts +304 -0
- package/dist/_contracts/run-config.js +659 -0
- package/dist/_contracts/run-cost.d.ts +125 -0
- package/dist/_contracts/run-cost.js +616 -0
- package/dist/_contracts/run-custody.d.ts +226 -0
- package/dist/_contracts/run-custody.js +465 -0
- package/dist/_contracts/run-record.d.ts +127 -0
- package/dist/_contracts/run-record.js +177 -0
- package/dist/_contracts/run-retention.d.ts +213 -0
- package/dist/_contracts/run-retention.js +484 -0
- package/dist/_contracts/run-unit.d.ts +194 -0
- package/dist/_contracts/run-unit.js +215 -0
- package/dist/_contracts/runner-event.d.ts +114 -0
- package/dist/_contracts/runner-event.js +187 -0
- package/dist/_contracts/runtime-manifest.d.ts +106 -0
- package/dist/_contracts/runtime-manifest.js +98 -0
- package/dist/_contracts/runtime-security-profile.d.ts +27 -0
- package/dist/_contracts/runtime-security-profile.js +82 -0
- package/dist/_contracts/runtime-sizes.d.ts +144 -0
- package/dist/_contracts/runtime-sizes.js +136 -0
- package/dist/_contracts/runtime-types.d.ts +212 -0
- package/dist/_contracts/runtime-types.js +2 -0
- package/dist/_contracts/sdk-errors.d.ts +34 -0
- package/dist/_contracts/sdk-errors.js +52 -0
- package/dist/_contracts/sdk-secrets.d.ts +31 -0
- package/dist/_contracts/sdk-secrets.js +220 -0
- package/dist/_contracts/side-effect-audit.d.ts +129 -0
- package/dist/_contracts/side-effect-audit.js +494 -0
- package/dist/_contracts/sse.d.ts +74 -0
- package/dist/_contracts/sse.js +0 -0
- package/dist/_contracts/stable.d.ts +26 -0
- package/dist/_contracts/stable.js +44 -0
- package/dist/_contracts/status.d.ts +19 -0
- package/dist/_contracts/status.js +61 -0
- package/dist/_contracts/submission.d.ts +383 -0
- package/dist/_contracts/submission.js +1380 -0
- package/dist/agents-md.d.ts +46 -0
- package/dist/agents-md.js +83 -0
- package/dist/agents-md.js.map +1 -0
- package/dist/asset-upload.d.ts +66 -0
- package/dist/asset-upload.js +168 -0
- package/dist/asset-upload.js.map +1 -0
- package/dist/bundle.d.ts +33 -0
- package/dist/bundle.js +89 -0
- package/dist/bundle.js.map +1 -0
- package/dist/cli.mjs +4140 -0
- package/dist/cli.mjs.sha256 +1 -0
- package/dist/client.d.ts +460 -0
- package/dist/client.js +857 -0
- package/dist/client.js.map +1 -0
- package/dist/fetch-archive.d.ts +16 -0
- package/dist/fetch-archive.js +170 -0
- package/dist/fetch-archive.js.map +1 -0
- package/dist/file.d.ts +57 -0
- package/dist/file.js +153 -0
- package/dist/file.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server.d.ts +84 -0
- package/dist/mcp-server.js +114 -0
- package/dist/mcp-server.js.map +1 -0
- package/dist/node-fs.d.ts +12 -0
- package/dist/node-fs.js +44 -0
- package/dist/node-fs.js.map +1 -0
- package/dist/proxy-endpoint.d.ts +131 -0
- package/dist/proxy-endpoint.js +147 -0
- package/dist/proxy-endpoint.js.map +1 -0
- package/dist/skill.d.ts +117 -0
- package/dist/skill.js +169 -0
- package/dist/skill.js.map +1 -0
- package/dist/version.d.ts +9 -0
- package/dist/version.js +10 -0
- package/dist/version.js.map +1 -0
- package/docs/cleanup.md +38 -0
- package/docs/credentials.md +153 -0
- package/docs/events.md +76 -0
- package/docs/mcp.md +47 -0
- package/docs/outputs.md +157 -0
- package/docs/product-boundaries.md +57 -0
- package/docs/provider-runtime-capabilities.md +103 -0
- package/docs/quickstart.md +110 -0
- package/docs/release.md +99 -0
- package/docs/run-config.md +53 -0
- package/docs/run-record.md +39 -0
- package/docs/skills.md +139 -0
- package/docs/testing.md +29 -0
- package/package.json +47 -0
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unified aex event envelope.
|
|
3
|
+
*
|
|
4
|
+
* One versioned, self-describing record that every subscriber sees, derived
|
|
5
|
+
* from the unified {@link RunnerEvent}. Managed runtime adapters emit
|
|
6
|
+
* byte-identical envelopes for the same logical event by construction. This is
|
|
7
|
+
* the shape the coordinator (Phase 2) appends, broadcasts, and archives.
|
|
8
|
+
*
|
|
9
|
+
* - **CloudEvents-shaped** self-describing envelope: a stable `id`, the
|
|
10
|
+
* coarse `source`, the AG-UI-aligned `type`, the `subject` (run), a
|
|
11
|
+
* `time`, the `sequence` cursor, and the typed `data`.
|
|
12
|
+
* - **AG-UI vocabulary** for `type` where it maps; aex-specific events
|
|
13
|
+
* ride AG-UI's reserved `CUSTOM` carrier under an `aex.*` name, so an
|
|
14
|
+
* off-the-shelf AG-UI client reads an aex run with no glue.
|
|
15
|
+
* - Two aex extensions: a coarse `source` (filter first by origin) and
|
|
16
|
+
* an optional human `message` (log / CLI / dashboard rendering).
|
|
17
|
+
*
|
|
18
|
+
* Unified observability spine:
|
|
19
|
+
* the envelope additionally carries four ordering attributes so BOTH the typed
|
|
20
|
+
* event stream and the high-volume hosted runtime log stream ride one per-run
|
|
21
|
+
* coordinator:
|
|
22
|
+
* - `channel` — "event" (the typed AG-UI stream) or "log" (a verbose log
|
|
23
|
+
* line). The single axis a consumer splits the unified stream
|
|
24
|
+
* on. Absent ⇒ "event" (back-compat for existing producers).
|
|
25
|
+
* - `sourceSeq` — a per-SOURCE monotonic counter assigned AT the source. The
|
|
26
|
+
* DO's hard guarantee is that records of the same source are
|
|
27
|
+
* never reordered relative to their `sourceSeq`.
|
|
28
|
+
* - `emittedAt` — source wall-clock ms at emit. Carried, never trusted for
|
|
29
|
+
* cross-source ordering (clocks are independent; the coordinator gives
|
|
30
|
+
* no synchronized clock). A client may re-sort by it for a
|
|
31
|
+
* best-effort time view.
|
|
32
|
+
* The coordinator remains the single serial ordering authority: it assigns the global
|
|
33
|
+
* `sequence` on arrival, which is the canonical stream order. `sourceSeq` /
|
|
34
|
+
* `emittedAt` are CARRIED through broadcast + archive, not used to reorder.
|
|
35
|
+
*
|
|
36
|
+
* This module is **additive**: it does not change {@link RunnerEvent} or any
|
|
37
|
+
* existing wire shape. It is a pure projection plus honest guards and a strict
|
|
38
|
+
* AG-UI projection for consumers.
|
|
39
|
+
*/
|
|
40
|
+
import type { JsonValue } from "./submission.js";
|
|
41
|
+
import type { RunnerEvent } from "./runner-event.js";
|
|
42
|
+
/** CloudEvents `specversion` the envelope conforms to. */
|
|
43
|
+
export declare const AEX_EVENT_SPECVERSION: "1.0";
|
|
44
|
+
/**
|
|
45
|
+
* Mapping version. Bump when the RunnerEvent → envelope projection changes
|
|
46
|
+
* shape (new `source`/`type`, renamed data field). Independent of
|
|
47
|
+
* {@link AEX_EVENT_SPECVERSION} (the CloudEvents version) and of
|
|
48
|
+
* `RUNNER_EVENT_VERSION` (the upstream wire version).
|
|
49
|
+
*/
|
|
50
|
+
export declare const AEX_EVENT_MAP_VERSION: 1;
|
|
51
|
+
/**
|
|
52
|
+
* Coarse origin classifier — the first axis a consumer filters on.
|
|
53
|
+
* - `agent` — the model: text, reasoning, builtin tool calls/results.
|
|
54
|
+
* - `worker` — the hosted aex edge itself.
|
|
55
|
+
* - `runtime` — the execution runtime (Goose container / Anthropic session):
|
|
56
|
+
* lifecycle, diagnostics, non-fatal stream errors.
|
|
57
|
+
* - `mcp` — an MCP server (a tool call/result routed through MCP).
|
|
58
|
+
* - `aex` — the platform: skills, files, and other aex-native events.
|
|
59
|
+
* - `workflow`— the orchestration layer (Cloudflare Workflows trace).
|
|
60
|
+
* - `machine` — the managed host the runtime executes on (machine-level host
|
|
61
|
+
* logs). A forthcoming source; `runtime` stays the
|
|
62
|
+
* Goose-container / Anthropic-session source, distinct from the
|
|
63
|
+
* host machine that carries it.
|
|
64
|
+
*/
|
|
65
|
+
export declare const AEX_EVENT_SOURCES: readonly ["agent", "worker", "runtime", "mcp", "aex", "workflow", "machine"];
|
|
66
|
+
export type AexEventSource = (typeof AEX_EVENT_SOURCES)[number];
|
|
67
|
+
/**
|
|
68
|
+
* The channel a record rides on the unified per-run stream:
|
|
69
|
+
* - `event` — the typed, low-volume, fully-replayed AG-UI event stream.
|
|
70
|
+
* - `log` — a high-volume verbose log line (level + message + fields). The
|
|
71
|
+
* coordinator prunes flushed log rows after R2 archival (logs are
|
|
72
|
+
* append-only, events are kept). Absent on the wire ⇒ `event`.
|
|
73
|
+
*/
|
|
74
|
+
export declare const AEX_EVENT_CHANNELS: readonly ["event", "log"];
|
|
75
|
+
export type AexEventChannel = (typeof AEX_EVENT_CHANNELS)[number];
|
|
76
|
+
/**
|
|
77
|
+
* Log severity carried by a `channel: "log"` record (the `LOG` event type).
|
|
78
|
+
* NOTE: the platform owner's canonical term for the middle level is "warning";
|
|
79
|
+
* we keep "warn" for consistency with the existing in-code vocabulary — the
|
|
80
|
+
* mapping is `warning ≡ warn`.
|
|
81
|
+
*/
|
|
82
|
+
export declare const AEX_LOG_LEVELS: readonly ["info", "warn", "error"];
|
|
83
|
+
export type AexLogLevel = (typeof AEX_LOG_LEVELS)[number];
|
|
84
|
+
/**
|
|
85
|
+
* The AG-UI-aligned `type` vocabulary the envelope emits. A subset of the
|
|
86
|
+
* full AG-UI protocol — the events aex actually produces today — plus
|
|
87
|
+
* `CUSTOM`, AG-UI's reserved carrier for aex-native events.
|
|
88
|
+
*/
|
|
89
|
+
export declare const AEX_EVENT_TYPES: readonly ["RUN_STARTED", "RUN_FINISHED", "RUN_ERROR", "TEXT_MESSAGE_CONTENT", "TOOL_CALL_START", "TOOL_CALL_RESULT", "CUSTOM", "LOG"];
|
|
90
|
+
export type AexEventType = (typeof AEX_EVENT_TYPES)[number];
|
|
91
|
+
/**
|
|
92
|
+
* One event on the unified log. CloudEvents core attributes (`specversion`,
|
|
93
|
+
* `id`, `source`, `type`, `subject`, `time`) plus the `sequence` extension
|
|
94
|
+
* (the ordering cursor) and the typed `data`.
|
|
95
|
+
*/
|
|
96
|
+
export interface AexEvent {
|
|
97
|
+
/** CloudEvents specversion. Always {@link AEX_EVENT_SPECVERSION}. */
|
|
98
|
+
readonly specversion: typeof AEX_EVENT_SPECVERSION;
|
|
99
|
+
/** Stable, globally-unique event id: `${runId}:${sequence}`. Dedupe key. */
|
|
100
|
+
readonly id: string;
|
|
101
|
+
/** Coarse origin classifier. */
|
|
102
|
+
readonly source: AexEventSource;
|
|
103
|
+
/** AG-UI-aligned event type. */
|
|
104
|
+
readonly type: AexEventType;
|
|
105
|
+
/** The run this event belongs to (CloudEvents `subject`). */
|
|
106
|
+
readonly subject: string;
|
|
107
|
+
/** ISO-8601 event time (run base + the RunnerEvent's relative `tMs`). */
|
|
108
|
+
readonly time: string;
|
|
109
|
+
/**
|
|
110
|
+
* Monotonic ordering cursor within the run — the GLOBAL `seq` the coordinator
|
|
111
|
+
* assigns on arrival. This is the canonical stream order and the dedupe key.
|
|
112
|
+
*/
|
|
113
|
+
readonly sequence: number;
|
|
114
|
+
/**
|
|
115
|
+
* Which sub-stream this record rides. Absent ⇒ `"event"` (existing typed
|
|
116
|
+
* producers don't set it; the coordinator defaults it on ingest).
|
|
117
|
+
*/
|
|
118
|
+
readonly channel?: AexEventChannel;
|
|
119
|
+
/**
|
|
120
|
+
* Per-SOURCE monotonic counter assigned at the source. The coordinator
|
|
121
|
+
* preserves the order of same-source records by `sourceSeq` and never
|
|
122
|
+
* reorders them; cross-source order is by arrival (`sequence`) only.
|
|
123
|
+
*/
|
|
124
|
+
readonly sourceSeq?: number;
|
|
125
|
+
/** Source wall-clock ms at emit. Carried for a best-effort client time view. */
|
|
126
|
+
readonly emittedAt?: number;
|
|
127
|
+
/**
|
|
128
|
+
* The DO's authoritative receive time (wall-clock ms), stamped at ingest
|
|
129
|
+
* alongside the global {@link sequence}. This is the authoritative wall-clock
|
|
130
|
+
* companion to `sequence` — distinct from `emittedAt` (the SOURCE's clock) and
|
|
131
|
+
* `time` (the LOGICAL time = run base + relative tMs).
|
|
132
|
+
*
|
|
133
|
+
* NOTE: a Workers clock is coarsened/frozen-at-I/O (a side-channel
|
|
134
|
+
* mitigation), so `receivedAt` is precisely "the DO's last-I/O wall-clock at
|
|
135
|
+
* ingest" — that is fine as the authoritative receive marker. It does NOT need
|
|
136
|
+
* to exceed `emittedAt`: the source runs on a different machine with an
|
|
137
|
+
* independent clock, so cross-machine drift can leave `receivedAt < emittedAt`
|
|
138
|
+
* and that is expected, not an error. Absent on records produced before this
|
|
139
|
+
* field existed (back-compat with archived records).
|
|
140
|
+
*/
|
|
141
|
+
readonly receivedAt?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Log severity, first-class on a `channel: "log"` record (mirrors
|
|
144
|
+
* `data.level`). Optional: only `log`-channel records carry it; typed `event`
|
|
145
|
+
* records omit it. ("warn" ≡ the owner's "warning" — see {@link AEX_LOG_LEVELS}.)
|
|
146
|
+
*/
|
|
147
|
+
readonly level?: AexLogLevel;
|
|
148
|
+
/** Optional human-readable summary for log / CLI / dashboard rendering. */
|
|
149
|
+
readonly message?: string;
|
|
150
|
+
/**
|
|
151
|
+
* Typed payload. For `CUSTOM` events this is `{ name, value }` (AG-UI's
|
|
152
|
+
* custom carrier, `name` = `aex.<kind>`); for typed events it is the
|
|
153
|
+
* RunnerEvent's own data, projected to AG-UI fields by {@link toAGUI}.
|
|
154
|
+
*/
|
|
155
|
+
readonly data: Readonly<Record<string, JsonValue>>;
|
|
156
|
+
}
|
|
157
|
+
/** Context the mapper needs to stamp absolute identity/time onto an event. */
|
|
158
|
+
export interface AexEventContext {
|
|
159
|
+
readonly runId: string;
|
|
160
|
+
/**
|
|
161
|
+
* Run-start epoch ms. The RunnerEvent's `tMs` is relative to this, so
|
|
162
|
+
* `time = new Date(baseMs + tMs)`. Pass the run's `createdAtMs`.
|
|
163
|
+
*/
|
|
164
|
+
readonly baseMs: number;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Project a {@link RunnerEvent} onto the unified envelope. Pure and total:
|
|
168
|
+
* every RunnerEvent kind maps to exactly one envelope. Both runtimes feed
|
|
169
|
+
* RunnerEvents through this same function, so identical logical events
|
|
170
|
+
* produce identical envelopes.
|
|
171
|
+
*/
|
|
172
|
+
export declare function runnerEventToAexEvent(evt: RunnerEvent, ctx: AexEventContext): AexEvent;
|
|
173
|
+
/** A log line as a producer hands it to {@link logToInbound} (pre-coordinator). */
|
|
174
|
+
export interface AexLogLine {
|
|
175
|
+
readonly level: AexLogLevel;
|
|
176
|
+
readonly message: string;
|
|
177
|
+
readonly fields?: Readonly<Record<string, JsonValue>>;
|
|
178
|
+
/** Source wall-clock ms at emit. */
|
|
179
|
+
readonly emittedAt: number;
|
|
180
|
+
/** Per-source monotonic counter assigned at the source. */
|
|
181
|
+
readonly sourceSeq: number;
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* The inbound (pre-seq) envelope a producer POSTs for a `channel: "log"` line.
|
|
185
|
+
* The coordinator stamps `specversion`/`id`/`subject`/`sequence` (the ordering
|
|
186
|
+
* authority) AND `receivedAt` (its authoritative receive time) on ingest, so a
|
|
187
|
+
* producer never supplies any of them.
|
|
188
|
+
*/
|
|
189
|
+
export type AexInboundLog = Omit<AexEvent, "specversion" | "id" | "subject" | "sequence" | "receivedAt">;
|
|
190
|
+
/**
|
|
191
|
+
* Project a log line onto an inbound coordinator envelope. The coordinator
|
|
192
|
+
* stamps `specversion`/`id`/`subject`/`sequence` on ingest (it is the ordering
|
|
193
|
+
* authority); everything else — `channel`, `source`, `sourceSeq`, `emittedAt`,
|
|
194
|
+
* and the `LOG` payload — is supplied here.
|
|
195
|
+
*/
|
|
196
|
+
export declare function logToInbound(source: AexEventSource, line: AexLogLine): AexInboundLog;
|
|
197
|
+
export declare function isRunStarted(e: AexEvent): boolean;
|
|
198
|
+
export declare function isRunFinished(e: AexEvent): boolean;
|
|
199
|
+
export declare function isRunError(e: AexEvent): boolean;
|
|
200
|
+
/** A terminal event of either flavour (finished or error). */
|
|
201
|
+
export declare function isRunTerminal(e: AexEvent): boolean;
|
|
202
|
+
export declare function isTextMessage(e: AexEvent): boolean;
|
|
203
|
+
export declare function isToolCallStart(e: AexEvent): boolean;
|
|
204
|
+
export declare function isToolCallResult(e: AexEvent): boolean;
|
|
205
|
+
export declare function isCustom(e: AexEvent): boolean;
|
|
206
|
+
/** The `aex.*` name of a CUSTOM event, or null for typed events. */
|
|
207
|
+
export declare function customName(e: AexEvent): string | null;
|
|
208
|
+
export declare function isFromSource(e: AexEvent, source: AexEventSource): boolean;
|
|
209
|
+
/** The channel a record rides, defaulting an absent value to `"event"`. */
|
|
210
|
+
export declare function channelOf(e: AexEvent): AexEventChannel;
|
|
211
|
+
/** True when a record is a log line (the `log` channel / `LOG` type). */
|
|
212
|
+
export declare function isLog(e: AexEvent): boolean;
|
|
213
|
+
/** True when a record is a typed AG-UI event (the `event` channel). */
|
|
214
|
+
export declare function isEventChannel(e: AexEvent): boolean;
|
|
215
|
+
/**
|
|
216
|
+
* The coordinator's embedded store caps a
|
|
217
|
+
* single row at 2 MB. Events whose serialized form exceeds the budget must be
|
|
218
|
+
* split before insert (the coordinator's responsibility); the archive uses the
|
|
219
|
+
* same bound. A conservative margin under the hard 2 MiB leaves room for row
|
|
220
|
+
* overhead and column framing.
|
|
221
|
+
*/
|
|
222
|
+
export declare const MAX_SQLITE_ROW_BYTES: 2000000;
|
|
223
|
+
/** Serialized UTF-8 byte length of an event (the size the row must hold). */
|
|
224
|
+
export declare function serializedEventBytes(e: AexEvent): number;
|
|
225
|
+
/** True when an event's serialized form exceeds the row budget and must be split. */
|
|
226
|
+
export declare function exceedsRowBudget(e: AexEvent, max?: number): boolean;
|
|
227
|
+
/**
|
|
228
|
+
* AG-UI events aex projects to. Each carries the AG-UI `type` discriminant
|
|
229
|
+
* and a numeric `timestamp` (ms), plus the type-specific fields an off-the-shelf
|
|
230
|
+
* AG-UI client expects. Aex's envelope extensions (`source`, `message`, the
|
|
231
|
+
* CloudEvents framing) are dropped — `rawEvent` carries the original for clients
|
|
232
|
+
* that want it.
|
|
233
|
+
*/
|
|
234
|
+
export type AguiEvent = {
|
|
235
|
+
type: "RUN_STARTED";
|
|
236
|
+
timestamp: number;
|
|
237
|
+
threadId: string;
|
|
238
|
+
runId: string;
|
|
239
|
+
} | {
|
|
240
|
+
type: "RUN_FINISHED";
|
|
241
|
+
timestamp: number;
|
|
242
|
+
threadId: string;
|
|
243
|
+
runId: string;
|
|
244
|
+
} | {
|
|
245
|
+
type: "RUN_ERROR";
|
|
246
|
+
timestamp: number;
|
|
247
|
+
message: string;
|
|
248
|
+
code?: string;
|
|
249
|
+
} | {
|
|
250
|
+
type: "TEXT_MESSAGE_CONTENT";
|
|
251
|
+
timestamp: number;
|
|
252
|
+
messageId: string;
|
|
253
|
+
delta: string;
|
|
254
|
+
} | {
|
|
255
|
+
type: "TOOL_CALL_START";
|
|
256
|
+
timestamp: number;
|
|
257
|
+
toolCallId: string;
|
|
258
|
+
toolCallName: string;
|
|
259
|
+
} | {
|
|
260
|
+
type: "TOOL_CALL_RESULT";
|
|
261
|
+
timestamp: number;
|
|
262
|
+
messageId: string;
|
|
263
|
+
toolCallId: string;
|
|
264
|
+
content: JsonValue;
|
|
265
|
+
} | {
|
|
266
|
+
type: "CUSTOM";
|
|
267
|
+
timestamp: number;
|
|
268
|
+
name: string;
|
|
269
|
+
value: JsonValue;
|
|
270
|
+
};
|
|
271
|
+
/**
|
|
272
|
+
* Project an aex envelope to a strict AG-UI event so an off-the-shelf
|
|
273
|
+
* AG-UI client can consume an aex run with no glue. This is the
|
|
274
|
+
* client-side projection the SDK exposes.
|
|
275
|
+
*/
|
|
276
|
+
export declare function toAGUI(e: AexEvent): AguiEvent;
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The unified aex event envelope.
|
|
3
|
+
*
|
|
4
|
+
* One versioned, self-describing record that every subscriber sees, derived
|
|
5
|
+
* from the unified {@link RunnerEvent}. Managed runtime adapters emit
|
|
6
|
+
* byte-identical envelopes for the same logical event by construction. This is
|
|
7
|
+
* the shape the coordinator (Phase 2) appends, broadcasts, and archives.
|
|
8
|
+
*
|
|
9
|
+
* - **CloudEvents-shaped** self-describing envelope: a stable `id`, the
|
|
10
|
+
* coarse `source`, the AG-UI-aligned `type`, the `subject` (run), a
|
|
11
|
+
* `time`, the `sequence` cursor, and the typed `data`.
|
|
12
|
+
* - **AG-UI vocabulary** for `type` where it maps; aex-specific events
|
|
13
|
+
* ride AG-UI's reserved `CUSTOM` carrier under an `aex.*` name, so an
|
|
14
|
+
* off-the-shelf AG-UI client reads an aex run with no glue.
|
|
15
|
+
* - Two aex extensions: a coarse `source` (filter first by origin) and
|
|
16
|
+
* an optional human `message` (log / CLI / dashboard rendering).
|
|
17
|
+
*
|
|
18
|
+
* Unified observability spine:
|
|
19
|
+
* the envelope additionally carries four ordering attributes so BOTH the typed
|
|
20
|
+
* event stream and the high-volume hosted runtime log stream ride one per-run
|
|
21
|
+
* coordinator:
|
|
22
|
+
* - `channel` — "event" (the typed AG-UI stream) or "log" (a verbose log
|
|
23
|
+
* line). The single axis a consumer splits the unified stream
|
|
24
|
+
* on. Absent ⇒ "event" (back-compat for existing producers).
|
|
25
|
+
* - `sourceSeq` — a per-SOURCE monotonic counter assigned AT the source. The
|
|
26
|
+
* DO's hard guarantee is that records of the same source are
|
|
27
|
+
* never reordered relative to their `sourceSeq`.
|
|
28
|
+
* - `emittedAt` — source wall-clock ms at emit. Carried, never trusted for
|
|
29
|
+
* cross-source ordering (clocks are independent; the coordinator gives
|
|
30
|
+
* no synchronized clock). A client may re-sort by it for a
|
|
31
|
+
* best-effort time view.
|
|
32
|
+
* The coordinator remains the single serial ordering authority: it assigns the global
|
|
33
|
+
* `sequence` on arrival, which is the canonical stream order. `sourceSeq` /
|
|
34
|
+
* `emittedAt` are CARRIED through broadcast + archive, not used to reorder.
|
|
35
|
+
*
|
|
36
|
+
* This module is **additive**: it does not change {@link RunnerEvent} or any
|
|
37
|
+
* existing wire shape. It is a pure projection plus honest guards and a strict
|
|
38
|
+
* AG-UI projection for consumers.
|
|
39
|
+
*/
|
|
40
|
+
/** CloudEvents `specversion` the envelope conforms to. */
|
|
41
|
+
export const AEX_EVENT_SPECVERSION = "1.0";
|
|
42
|
+
/**
|
|
43
|
+
* Mapping version. Bump when the RunnerEvent → envelope projection changes
|
|
44
|
+
* shape (new `source`/`type`, renamed data field). Independent of
|
|
45
|
+
* {@link AEX_EVENT_SPECVERSION} (the CloudEvents version) and of
|
|
46
|
+
* `RUNNER_EVENT_VERSION` (the upstream wire version).
|
|
47
|
+
*/
|
|
48
|
+
export const AEX_EVENT_MAP_VERSION = 1;
|
|
49
|
+
/**
|
|
50
|
+
* Coarse origin classifier — the first axis a consumer filters on.
|
|
51
|
+
* - `agent` — the model: text, reasoning, builtin tool calls/results.
|
|
52
|
+
* - `worker` — the hosted aex edge itself.
|
|
53
|
+
* - `runtime` — the execution runtime (Goose container / Anthropic session):
|
|
54
|
+
* lifecycle, diagnostics, non-fatal stream errors.
|
|
55
|
+
* - `mcp` — an MCP server (a tool call/result routed through MCP).
|
|
56
|
+
* - `aex` — the platform: skills, files, and other aex-native events.
|
|
57
|
+
* - `workflow`— the orchestration layer (Cloudflare Workflows trace).
|
|
58
|
+
* - `machine` — the managed host the runtime executes on (machine-level host
|
|
59
|
+
* logs). A forthcoming source; `runtime` stays the
|
|
60
|
+
* Goose-container / Anthropic-session source, distinct from the
|
|
61
|
+
* host machine that carries it.
|
|
62
|
+
*/
|
|
63
|
+
export const AEX_EVENT_SOURCES = ["agent", "worker", "runtime", "mcp", "aex", "workflow", "machine"];
|
|
64
|
+
/**
|
|
65
|
+
* The channel a record rides on the unified per-run stream:
|
|
66
|
+
* - `event` — the typed, low-volume, fully-replayed AG-UI event stream.
|
|
67
|
+
* - `log` — a high-volume verbose log line (level + message + fields). The
|
|
68
|
+
* coordinator prunes flushed log rows after R2 archival (logs are
|
|
69
|
+
* append-only, events are kept). Absent on the wire ⇒ `event`.
|
|
70
|
+
*/
|
|
71
|
+
export const AEX_EVENT_CHANNELS = ["event", "log"];
|
|
72
|
+
/**
|
|
73
|
+
* Log severity carried by a `channel: "log"` record (the `LOG` event type).
|
|
74
|
+
* NOTE: the platform owner's canonical term for the middle level is "warning";
|
|
75
|
+
* we keep "warn" for consistency with the existing in-code vocabulary — the
|
|
76
|
+
* mapping is `warning ≡ warn`.
|
|
77
|
+
*/
|
|
78
|
+
export const AEX_LOG_LEVELS = ["info", "warn", "error"];
|
|
79
|
+
/**
|
|
80
|
+
* The AG-UI-aligned `type` vocabulary the envelope emits. A subset of the
|
|
81
|
+
* full AG-UI protocol — the events aex actually produces today — plus
|
|
82
|
+
* `CUSTOM`, AG-UI's reserved carrier for aex-native events.
|
|
83
|
+
*/
|
|
84
|
+
export const AEX_EVENT_TYPES = [
|
|
85
|
+
"RUN_STARTED",
|
|
86
|
+
"RUN_FINISHED",
|
|
87
|
+
"RUN_ERROR",
|
|
88
|
+
"TEXT_MESSAGE_CONTENT",
|
|
89
|
+
"TOOL_CALL_START",
|
|
90
|
+
"TOOL_CALL_RESULT",
|
|
91
|
+
"CUSTOM",
|
|
92
|
+
// The carrier type for a `channel: "log"` record. Kept out of the AG-UI
|
|
93
|
+
// typed-event vocabulary on purpose: a `LOG` is never a run-lifecycle signal,
|
|
94
|
+
// so terminal detection (RUN_FINISHED/RUN_ERROR) is unaffected and an
|
|
95
|
+
// off-the-shelf AG-UI client filters logs out by `channel`.
|
|
96
|
+
"LOG"
|
|
97
|
+
];
|
|
98
|
+
/**
|
|
99
|
+
* Project a {@link RunnerEvent} onto the unified envelope. Pure and total:
|
|
100
|
+
* every RunnerEvent kind maps to exactly one envelope. Both runtimes feed
|
|
101
|
+
* RunnerEvents through this same function, so identical logical events
|
|
102
|
+
* produce identical envelopes.
|
|
103
|
+
*/
|
|
104
|
+
export function runnerEventToAexEvent(evt, ctx) {
|
|
105
|
+
const projection = project(evt);
|
|
106
|
+
return {
|
|
107
|
+
specversion: AEX_EVENT_SPECVERSION,
|
|
108
|
+
id: `${ctx.runId}:${evt.seq}`,
|
|
109
|
+
source: projection.source,
|
|
110
|
+
type: projection.type,
|
|
111
|
+
subject: ctx.runId,
|
|
112
|
+
time: new Date(ctx.baseMs + evt.tMs).toISOString(),
|
|
113
|
+
sequence: evt.seq,
|
|
114
|
+
...(projection.message !== undefined ? { message: projection.message } : {}),
|
|
115
|
+
data: Object.freeze(projection.data)
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function project(evt) {
|
|
119
|
+
const data = evt.data;
|
|
120
|
+
switch (evt.kind) {
|
|
121
|
+
case "runtime_started":
|
|
122
|
+
return { type: "RUN_STARTED", source: "runtime", message: "run started", data: { ...data } };
|
|
123
|
+
case "assistant_text": {
|
|
124
|
+
const text = str(data.text);
|
|
125
|
+
return {
|
|
126
|
+
type: "TEXT_MESSAGE_CONTENT",
|
|
127
|
+
source: "agent",
|
|
128
|
+
...(text ? { message: clip(text) } : {}),
|
|
129
|
+
data: { ...data }
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
case "tool_request": {
|
|
133
|
+
const name = str(data.name);
|
|
134
|
+
return {
|
|
135
|
+
type: "TOOL_CALL_START",
|
|
136
|
+
source: data.extension ? "mcp" : "agent",
|
|
137
|
+
...(name ? { message: `tool ${name}` } : {}),
|
|
138
|
+
data: { ...data }
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
case "tool_response":
|
|
142
|
+
return {
|
|
143
|
+
type: "TOOL_CALL_RESULT",
|
|
144
|
+
source: data.extension ? "mcp" : "agent",
|
|
145
|
+
data: { ...data }
|
|
146
|
+
};
|
|
147
|
+
case "skill_loaded":
|
|
148
|
+
return custom("aex.skill_loaded", "aex", data, "skill loaded");
|
|
149
|
+
case "file_uploaded":
|
|
150
|
+
return custom("aex.file_uploaded", "aex", data, "file uploaded");
|
|
151
|
+
case "notification":
|
|
152
|
+
return custom("aex.notification", "runtime", data, str(data.reason) || undefined);
|
|
153
|
+
case "stream_error":
|
|
154
|
+
return custom("aex.stream_error", "runtime", data, str(data.message) || "stream error");
|
|
155
|
+
case "runtime_terminal": {
|
|
156
|
+
const reason = str(data.reason);
|
|
157
|
+
return {
|
|
158
|
+
// The event's own reason types it (error vs finished); the
|
|
159
|
+
// authoritative run *status* is still owned by the orchestrator and
|
|
160
|
+
// is never re-derived from this event.
|
|
161
|
+
type: reason === "error" ? "RUN_ERROR" : "RUN_FINISHED",
|
|
162
|
+
source: "runtime",
|
|
163
|
+
message: reason ? `run ${reason}` : "run finished",
|
|
164
|
+
data: { ...data }
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Project a log line onto an inbound coordinator envelope. The coordinator
|
|
171
|
+
* stamps `specversion`/`id`/`subject`/`sequence` on ingest (it is the ordering
|
|
172
|
+
* authority); everything else — `channel`, `source`, `sourceSeq`, `emittedAt`,
|
|
173
|
+
* and the `LOG` payload — is supplied here.
|
|
174
|
+
*/
|
|
175
|
+
export function logToInbound(source, line) {
|
|
176
|
+
return {
|
|
177
|
+
source,
|
|
178
|
+
type: "LOG",
|
|
179
|
+
channel: "log",
|
|
180
|
+
sourceSeq: line.sourceSeq,
|
|
181
|
+
emittedAt: line.emittedAt,
|
|
182
|
+
// First-class severity on the envelope (not only inside `data`). `data.level`
|
|
183
|
+
// is kept too so an existing `data`-reading consumer still works.
|
|
184
|
+
level: line.level,
|
|
185
|
+
time: new Date(line.emittedAt).toISOString(),
|
|
186
|
+
message: line.message,
|
|
187
|
+
data: {
|
|
188
|
+
level: line.level,
|
|
189
|
+
message: line.message,
|
|
190
|
+
...(line.fields ? { fields: { ...line.fields } } : {})
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
function custom(name, source, value, message) {
|
|
195
|
+
return {
|
|
196
|
+
type: "CUSTOM",
|
|
197
|
+
source,
|
|
198
|
+
...(message !== undefined ? { message } : {}),
|
|
199
|
+
data: { name, value: { ...value } }
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
// --- Honest guards over the emitted vocabulary --------------------------------
|
|
203
|
+
// These match the vocabulary a consumer of the unified stream actually receives.
|
|
204
|
+
export function isRunStarted(e) {
|
|
205
|
+
return e.type === "RUN_STARTED";
|
|
206
|
+
}
|
|
207
|
+
export function isRunFinished(e) {
|
|
208
|
+
return e.type === "RUN_FINISHED";
|
|
209
|
+
}
|
|
210
|
+
export function isRunError(e) {
|
|
211
|
+
return e.type === "RUN_ERROR";
|
|
212
|
+
}
|
|
213
|
+
/** A terminal event of either flavour (finished or error). */
|
|
214
|
+
export function isRunTerminal(e) {
|
|
215
|
+
return e.type === "RUN_FINISHED" || e.type === "RUN_ERROR";
|
|
216
|
+
}
|
|
217
|
+
export function isTextMessage(e) {
|
|
218
|
+
return e.type === "TEXT_MESSAGE_CONTENT";
|
|
219
|
+
}
|
|
220
|
+
export function isToolCallStart(e) {
|
|
221
|
+
return e.type === "TOOL_CALL_START";
|
|
222
|
+
}
|
|
223
|
+
export function isToolCallResult(e) {
|
|
224
|
+
return e.type === "TOOL_CALL_RESULT";
|
|
225
|
+
}
|
|
226
|
+
export function isCustom(e) {
|
|
227
|
+
return e.type === "CUSTOM";
|
|
228
|
+
}
|
|
229
|
+
/** The `aex.*` name of a CUSTOM event, or null for typed events. */
|
|
230
|
+
export function customName(e) {
|
|
231
|
+
return e.type === "CUSTOM" ? str(e.data.name) || null : null;
|
|
232
|
+
}
|
|
233
|
+
export function isFromSource(e, source) {
|
|
234
|
+
return e.source === source;
|
|
235
|
+
}
|
|
236
|
+
/** The channel a record rides, defaulting an absent value to `"event"`. */
|
|
237
|
+
export function channelOf(e) {
|
|
238
|
+
return e.channel ?? "event";
|
|
239
|
+
}
|
|
240
|
+
/** True when a record is a log line (the `log` channel / `LOG` type). */
|
|
241
|
+
export function isLog(e) {
|
|
242
|
+
return channelOf(e) === "log";
|
|
243
|
+
}
|
|
244
|
+
/** True when a record is a typed AG-UI event (the `event` channel). */
|
|
245
|
+
export function isEventChannel(e) {
|
|
246
|
+
return channelOf(e) === "event";
|
|
247
|
+
}
|
|
248
|
+
// --- Oversized-payload rule (2 MB SQLite row cap) -----------------------------
|
|
249
|
+
/**
|
|
250
|
+
* The coordinator's embedded store caps a
|
|
251
|
+
* single row at 2 MB. Events whose serialized form exceeds the budget must be
|
|
252
|
+
* split before insert (the coordinator's responsibility); the archive uses the
|
|
253
|
+
* same bound. A conservative margin under the hard 2 MiB leaves room for row
|
|
254
|
+
* overhead and column framing.
|
|
255
|
+
*/
|
|
256
|
+
export const MAX_SQLITE_ROW_BYTES = 2_000_000;
|
|
257
|
+
/** Serialized UTF-8 byte length of an event (the size the row must hold). */
|
|
258
|
+
export function serializedEventBytes(e) {
|
|
259
|
+
return new TextEncoder().encode(JSON.stringify(e)).byteLength;
|
|
260
|
+
}
|
|
261
|
+
/** True when an event's serialized form exceeds the row budget and must be split. */
|
|
262
|
+
export function exceedsRowBudget(e, max = MAX_SQLITE_ROW_BYTES) {
|
|
263
|
+
return serializedEventBytes(e) > max;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Project an aex envelope to a strict AG-UI event so an off-the-shelf
|
|
267
|
+
* AG-UI client can consume an aex run with no glue. This is the
|
|
268
|
+
* client-side projection the SDK exposes.
|
|
269
|
+
*/
|
|
270
|
+
export function toAGUI(e) {
|
|
271
|
+
const timestamp = Date.parse(e.time);
|
|
272
|
+
const d = e.data;
|
|
273
|
+
switch (e.type) {
|
|
274
|
+
case "RUN_STARTED":
|
|
275
|
+
return { type: "RUN_STARTED", timestamp, threadId: e.subject, runId: e.subject };
|
|
276
|
+
case "RUN_FINISHED":
|
|
277
|
+
return { type: "RUN_FINISHED", timestamp, threadId: e.subject, runId: e.subject };
|
|
278
|
+
case "RUN_ERROR": {
|
|
279
|
+
const code = str(d.failureClass);
|
|
280
|
+
return {
|
|
281
|
+
type: "RUN_ERROR",
|
|
282
|
+
timestamp,
|
|
283
|
+
message: str(d.failureMessage) || e.message || "run error",
|
|
284
|
+
...(code ? { code } : {})
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
case "TEXT_MESSAGE_CONTENT":
|
|
288
|
+
return {
|
|
289
|
+
type: "TEXT_MESSAGE_CONTENT",
|
|
290
|
+
timestamp,
|
|
291
|
+
messageId: str(d.messageId) || str(d.eventId) || e.id,
|
|
292
|
+
delta: str(d.text)
|
|
293
|
+
};
|
|
294
|
+
case "TOOL_CALL_START":
|
|
295
|
+
return {
|
|
296
|
+
type: "TOOL_CALL_START",
|
|
297
|
+
timestamp,
|
|
298
|
+
toolCallId: str(d.id) || e.id,
|
|
299
|
+
toolCallName: str(d.name)
|
|
300
|
+
};
|
|
301
|
+
case "TOOL_CALL_RESULT":
|
|
302
|
+
return {
|
|
303
|
+
type: "TOOL_CALL_RESULT",
|
|
304
|
+
timestamp,
|
|
305
|
+
messageId: str(d.messageId) || e.id,
|
|
306
|
+
toolCallId: str(d.id) || e.id,
|
|
307
|
+
content: d.content ?? null
|
|
308
|
+
};
|
|
309
|
+
case "CUSTOM":
|
|
310
|
+
return { type: "CUSTOM", timestamp, name: str(d.name), value: d.value ?? null };
|
|
311
|
+
case "LOG":
|
|
312
|
+
// Logs ride the `log` channel and are normally filtered out before
|
|
313
|
+
// projection. If a consumer projects one anyway, carry it under AG-UI's
|
|
314
|
+
// reserved CUSTOM so the client still receives a valid record.
|
|
315
|
+
return { type: "CUSTOM", timestamp, name: "aex.log", value: { ...d } };
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
function str(v) {
|
|
319
|
+
return typeof v === "string" ? v : "";
|
|
320
|
+
}
|
|
321
|
+
function clip(s, max = 200) {
|
|
322
|
+
return s.length <= max ? s : `${s.slice(0, max - 1)}…`;
|
|
323
|
+
}
|
|
324
|
+
//# sourceMappingURL=event-envelope.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side consumer of the event coordinator's WebSocket stream.
|
|
3
|
+
*
|
|
4
|
+
* One mechanism for catch-up + resume + live: subscribe = read-from-cursor +
|
|
5
|
+
* tail. The consumer opens a WS to the coordinator with a connection ticket,
|
|
6
|
+
* replays from its cursor, and yields {@link AexEvent}s as they arrive.
|
|
7
|
+
* On a transport drop it reconnects with backoff and resumes from the last
|
|
8
|
+
* sequence it saw — `from = lastSeq + 1` — so delivery is exactly-once across
|
|
9
|
+
* reconnects (no gap, no duplicate). It stops on a terminal event, on abort,
|
|
10
|
+
* or when the caller breaks the iterator.
|
|
11
|
+
*
|
|
12
|
+
* Filtering and projection are the client's concern (the wire carries the
|
|
13
|
+
* whole run): compose {@link filterStream} with the envelope guards, and
|
|
14
|
+
* {@link mapStream} with {@link toAGUI}, on top of this stream.
|
|
15
|
+
*
|
|
16
|
+
* The WebSocket is injectable so the SDK/CLI use the Node/global `WebSocket`
|
|
17
|
+
* (Node 22+ ships it; no dependency) and tests drive a fake.
|
|
18
|
+
*/
|
|
19
|
+
import type { AexEvent } from "./event-envelope.js";
|
|
20
|
+
/** The slice of the WHATWG WebSocket this client depends on. */
|
|
21
|
+
export interface WebSocketLike {
|
|
22
|
+
close(code?: number, reason?: string): void;
|
|
23
|
+
addEventListener(type: "open" | "message" | "close" | "error", listener: (ev: {
|
|
24
|
+
data?: unknown;
|
|
25
|
+
}) => void): void;
|
|
26
|
+
}
|
|
27
|
+
export type WebSocketFactory = (url: string) => WebSocketLike;
|
|
28
|
+
export interface CoordinatorStreamOptions {
|
|
29
|
+
/** Base subscribe URL, e.g. `wss://coordinator/runs/<id>/subscribe`. */
|
|
30
|
+
readonly wsUrl: string;
|
|
31
|
+
/** Starting cursor: events with `sequence >= from` are delivered. Default 0 (from start). */
|
|
32
|
+
readonly from?: number;
|
|
33
|
+
/** Mint/refresh a short-lived connection ticket (called before each connect). */
|
|
34
|
+
readonly fetchTicket: () => Promise<string>;
|
|
35
|
+
readonly signal?: AbortSignal;
|
|
36
|
+
/** Injected WebSocket constructor; defaults to the global `WebSocket`. */
|
|
37
|
+
readonly webSocketFactory?: WebSocketFactory;
|
|
38
|
+
/** Reconnect ceiling (default: unlimited until terminal/abort). */
|
|
39
|
+
readonly maxReconnects?: number;
|
|
40
|
+
/** Backoff between reconnect attempts (default 500 ms). */
|
|
41
|
+
readonly reconnectDelayMs?: number;
|
|
42
|
+
}
|
|
43
|
+
export declare function streamCoordinatorEvents(opts: CoordinatorStreamOptions): AsyncGenerator<AexEvent, void, void>;
|
|
44
|
+
/** Async-iterable filter — keep only events matching the predicate. */
|
|
45
|
+
export declare function filterStream<T>(stream: AsyncIterable<T>, predicate: (event: T) => boolean): AsyncGenerator<T, void, void>;
|
|
46
|
+
/** Async-iterable map — project each event (e.g. with `toAGUI`). */
|
|
47
|
+
export declare function mapStream<T, U>(stream: AsyncIterable<T>, project: (event: T) => U): AsyncGenerator<U, void, void>;
|