@ai-matrx/agents 0.3.0 → 0.5.1

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.
@@ -0,0 +1,691 @@
1
+ import { MatrxStreamEnvelope, MatrxNdjsonIssue, MatrxStreamEnvelopeObservation } from '../stream/ndjson.cjs';
2
+ import { MatrxSseFrame } from '../stream/sse.cjs';
3
+
4
+ /**
5
+ * `@ai-matrx/agents/matrx` — the Matrx transport port.
6
+ *
7
+ * The ONE seam between this package's wire semantics and a host's connection
8
+ * policy. This package owns WHAT is said to the AI Matrx server — paths,
9
+ * methods, JSON bodies, streaming Accept headers, the `Last-Event-ID` cursor
10
+ * header — and the host owns HOW the connection is made:
11
+ *
12
+ * - base-URL / backend-channel resolution (global, sandbox override, local
13
+ * engine, EC2-dedicated — whatever ladder the host runs);
14
+ * - credentials (Supabase JWT `Authorization: Bearer`, guest
15
+ * `X-Fingerprint-ID`, or the API-key lane) — NEVER implemented here;
16
+ * - the `X-Organization-Id` context header;
17
+ * - retry policy, network-level timeouts, and diagnostics capture.
18
+ *
19
+ * A host implements the port in a few lines:
20
+ *
21
+ * ```ts
22
+ * const transport: MatrxTransport = {
23
+ * fetch: (path, init) =>
24
+ * fetch(`${baseUrl}${path}`, {
25
+ * ...init,
26
+ * headers: { ...init.headers, ...authHeaders() },
27
+ * }),
28
+ * };
29
+ * ```
30
+ *
31
+ * The port is deliberately structural and `fetch`-shaped so `@ai-matrx/data`'s
32
+ * `/api` transport can implement it without importing this package.
33
+ */
34
+ /**
35
+ * The request this package hands the port. A strict subset of `RequestInit`,
36
+ * so a host can spread it straight into `fetch`.
37
+ */
38
+ interface MatrxTransportRequest {
39
+ method: "GET" | "POST";
40
+ /**
41
+ * Wire-semantic headers the CALL requires (`Content-Type`, `Accept`,
42
+ * `Last-Event-ID`). The host merges its policy headers (auth, org) on top;
43
+ * it must not drop these.
44
+ */
45
+ headers: Record<string, string>;
46
+ /** Pre-serialized JSON body, present on POST calls that carry one. */
47
+ body?: string;
48
+ /** Caller cancellation. The host must wire it to the underlying fetch. */
49
+ signal?: AbortSignal;
50
+ }
51
+ /**
52
+ * The transport port. `path` is server-relative and always starts with `/`
53
+ * (`/ai/...`, `/runtime/...`); the host prepends its resolved base URL.
54
+ */
55
+ interface MatrxTransport {
56
+ fetch(path: string, init: MatrxTransportRequest): Promise<Response>;
57
+ }
58
+ /**
59
+ * A non-2xx response from the Matrx API, with the server's structured error
60
+ * body preserved and its richest human-readable message extracted.
61
+ */
62
+ declare class MatrxApiError extends Error {
63
+ readonly name = "MatrxApiError";
64
+ /** HTTP status of the failed response. */
65
+ readonly status: number;
66
+ /** Machine code from the server body (`code`, or `detail.code`), when present. */
67
+ readonly code: string | null;
68
+ /** The parsed server error body, verbatim (undefined when unparsable). */
69
+ readonly serverDetail: unknown;
70
+ /** The request path the failure came from (server-relative). */
71
+ readonly path: string;
72
+ constructor(args: {
73
+ status: number;
74
+ path: string;
75
+ serverDetail?: unknown;
76
+ message?: string;
77
+ });
78
+ }
79
+ /**
80
+ * Extract the richest human-readable message from a Matrx/FastAPI error body.
81
+ *
82
+ * aidream 4xx validation errors look like
83
+ * `{ error, user_message, details: [{ field, message, help }] }`; hand-raised
84
+ * HTTPExceptions carry `{ detail: { code, message } }`; FastAPI's defaults are
85
+ * `{ detail: string | [{ msg }] }`. Preference order: `user_message` →
86
+ * `message` → joined `details[].message` → `detail.message` →
87
+ * `detail` string → joined `detail[].msg`. Returns undefined for
88
+ * unrecognized bodies so callers fall back to the bare status line.
89
+ */
90
+ declare function extractMatrxErrorMessage(serverDetail: unknown): string | undefined;
91
+ /**
92
+ * Extract the machine error code from a Matrx error body: top-level `code`,
93
+ * else `detail.code` (the hand-raised HTTPException shape). Null when absent.
94
+ */
95
+ declare function extractMatrxErrorCode(serverDetail: unknown): string | null;
96
+
97
+ /**
98
+ * The conversation-start contract — client-minted `conversation_id`, `is_new`,
99
+ * `store` — typed exactly per the cross-repo System of Record
100
+ * (`common-docs/systems/agents/conversation-start-contract/FEATURE.md`;
101
+ * server truth `aidream/services/conversation_context/scope.py::
102
+ * ConversationStartRequest`).
103
+ *
104
+ * Every request that STARTS a conversation sends all three fields, no
105
+ * defaults:
106
+ *
107
+ * | `is_new` | `store` | Result |
108
+ * |----------|---------|----------------------------------------------------------|
109
+ * | true | true | Create the row with the caller's id — 409 if it exists |
110
+ * | true | false | No row. The id is correlation only (ephemeral run) |
111
+ * | false | true | Continue it — 404 if the caller doesn't own it |
112
+ * | false | false | Ephemeral run on a known id; nothing read, nothing written |
113
+ *
114
+ * `store` is the ONLY ephemeral signal; `is_new` is the caller's assertion
115
+ * about the id, never a persistence switch. `prior_messages` (the client-owned
116
+ * transcript of an ephemeral multi-turn run) is only valid with
117
+ * `store: false` — the union below makes the invalid combination
118
+ * unrepresentable, mirroring the server's 422.
119
+ *
120
+ * Continue routes (`POST /ai/conversations/{id}`) take the id from the path
121
+ * and do not carry this triple.
122
+ */
123
+ /** Recursive JSON value — the package's honest type for free-form wire bags. */
124
+ type MatrxJsonValue = string | number | boolean | null | MatrxJsonValue[] | {
125
+ [key: string]: MatrxJsonValue;
126
+ };
127
+ /** A JSON object on the wire. */
128
+ type MatrxJsonObject = {
129
+ [key: string]: MatrxJsonValue;
130
+ };
131
+ /**
132
+ * One LLM message on the request wire — `prior_messages` entries for
133
+ * stateless multi-turn runs. Mirrors aidream's `ChatMessageInput`
134
+ * (`aidream/schemas/messages.py`, `extra="allow"` — additional provider
135
+ * fields round-trip untouched).
136
+ */
137
+ interface MatrxChatMessage {
138
+ role: string;
139
+ content?: string | MatrxJsonValue[] | null;
140
+ name?: string | null;
141
+ tool_call_id?: string | null;
142
+ tool_calls?: MatrxJsonObject[] | null;
143
+ [extra: string]: MatrxJsonValue | undefined;
144
+ }
145
+ /** `is_new: true, store: true` — create the row with the caller's id. */
146
+ interface MatrxStoredConversationCreate {
147
+ conversation_id: string;
148
+ is_new: true;
149
+ store: true;
150
+ }
151
+ /** `is_new: false, store: true` — continue an owned stored conversation via a start route. */
152
+ interface MatrxStoredConversationContinue {
153
+ conversation_id: string;
154
+ is_new: false;
155
+ store: true;
156
+ }
157
+ /**
158
+ * `store: false` — ephemeral: nothing read, nothing written; the id is the
159
+ * caller's correlation handle. This is the ONLY member that may carry
160
+ * `prior_messages` (the server 422s a client transcript on a stored run).
161
+ */
162
+ interface MatrxEphemeralConversation {
163
+ conversation_id: string;
164
+ is_new: boolean;
165
+ store: false;
166
+ prior_messages?: MatrxChatMessage[];
167
+ }
168
+ /** The full conversation-start triple, one member per contract cell. */
169
+ type MatrxConversationStart = MatrxStoredConversationCreate | MatrxStoredConversationContinue | MatrxEphemeralConversation;
170
+ /** Mint a fresh client-side conversation id (the contract requires the CLIENT to mint it). */
171
+ declare function mintMatrxConversationId(): string;
172
+ /** Start a NEW stored conversation (`is_new: true, store: true`). */
173
+ declare function newStoredConversationStart(conversationId?: string): MatrxStoredConversationCreate;
174
+ /**
175
+ * Continue an EXISTING stored conversation through a start route
176
+ * (`is_new: false, store: true` — 404 when the caller doesn't own the id).
177
+ * Prefer `continueAgentConversation` (the dedicated continue route) for
178
+ * ordinary follow-up turns.
179
+ */
180
+ declare function continueStoredConversationStart(conversationId: string): MatrxStoredConversationContinue;
181
+ /**
182
+ * Start a NEW ephemeral run (`is_new: true, store: false`) — a freshly minted
183
+ * correlation id, nothing persisted.
184
+ */
185
+ declare function newEphemeralConversationStart(conversationId?: string): MatrxEphemeralConversation;
186
+ /**
187
+ * Continue an ephemeral multi-turn run (`is_new: false, store: false`): the
188
+ * CLIENT owns the transcript and replays it as `prior_messages` (ordered
189
+ * oldest-first) because the server wrote no rows to rebuild from. The server
190
+ * still owns the agent definition, model, tools, and system prompt.
191
+ */
192
+ declare function continueEphemeralConversationStart(conversationId: string, priorMessages: MatrxChatMessage[]): MatrxEphemeralConversation;
193
+
194
+ /**
195
+ * Internal request plumbing for `@ai-matrx/agents/matrx`. Not part of the
196
+ * public surface — `matrx/index.ts` deliberately does not re-export this
197
+ * module. Everything here is pure: no globals, no work at import time.
198
+ */
199
+
200
+ /**
201
+ * Options for every streaming call, riding the NDJSON kernel's contract.
202
+ * Public via `./run`'s re-export.
203
+ */
204
+ interface MatrxStreamCallOptions {
205
+ /** Abort the fetch and end the events iterator. */
206
+ signal?: AbortSignal;
207
+ /** Bounded background read-ahead (see `stream/ndjson`). */
208
+ maxReadAhead?: number;
209
+ /** Malformed NDJSON is non-fatal but must never disappear silently. */
210
+ onMalformedLine?: (issue: MatrxNdjsonIssue) => void;
211
+ /** Valid JSON with no recognized Matrx envelope. */
212
+ onUnknownEnvelope?: (value: unknown) => void;
213
+ /** Observe every valid envelope in its exact wire form. */
214
+ onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;
215
+ }
216
+ /**
217
+ * A live agent run: the server-assigned ids (from response headers, available
218
+ * BEFORE any event) and the normalized event stream. Public via `./run`.
219
+ */
220
+ interface MatrxRunHandle {
221
+ /** `X-Request-ID` — the ONLY id `POST /ai/cancel/{request_id}` accepts. */
222
+ requestId: string | null;
223
+ /** `X-Conversation-ID` — the server's conversation identity. */
224
+ conversationId: string | null;
225
+ /** Normalized `{event, data}` envelopes through the ONE wire kernel. */
226
+ events: AsyncGenerator<MatrxStreamEnvelope, void, undefined>;
227
+ /** The raw response, for hosts that need headers/status beyond the ids. */
228
+ response: Response;
229
+ }
230
+
231
+ /**
232
+ * Agent run lifecycle against the AI Matrx API — start, continue, resume,
233
+ * cancel — over the `MatrxTransport` port, with every streaming response
234
+ * parsed through the package's ONE NDJSON wire kernel (`stream/ndjson`).
235
+ *
236
+ * Server truth (verified against aidream source):
237
+ * - `POST /ai/agents/{agent_id}` — start (`aidream/api/routers/agents.py`)
238
+ * - `POST /ai/conversations/{conversation_id}` — continue (`aidream/api/routers/conversations.py`)
239
+ * - `POST /ai/conversations/{conversation_id}/resume` — resume after
240
+ * client-delegated tool suspension (same router)
241
+ * - `POST /ai/cancel/{request_id}?mode=interrupt` — cancel (`aidream/api/routers/cancel.py`)
242
+ *
243
+ * Response headers arrive before the body: `X-Conversation-ID` and
244
+ * `X-Request-ID` are surfaced on the run handle immediately. `X-Request-ID`
245
+ * is the ONLY id the server accepts for cancel — a client-local id means
246
+ * nothing to it.
247
+ *
248
+ * Host policy stays out: no retry, no store, no timeouts, no persistence
249
+ * (C10: no-persistence). Cancellation is the caller's `AbortSignal`; a client
250
+ * disconnect never stops server work (`detach_on_disconnect`).
251
+ */
252
+
253
+ /**
254
+ * Stable identity of the durable entity whose saved context owns a run —
255
+ * the server reloads the row and uses ITS scope (`ContextAnchor`,
256
+ * `aidream/services/conversation_context/scope.py`).
257
+ */
258
+ interface MatrxContextAnchor {
259
+ resource_type: string;
260
+ resource_id: string;
261
+ }
262
+ /**
263
+ * Scope and source fields shared by every scoped request
264
+ * (`ScopedRequest` / `AcceptsInjectedScope` server-side). All optional here;
265
+ * the start request narrows `organization_id` to required.
266
+ */
267
+ interface MatrxRequestScope {
268
+ organization_id?: string;
269
+ project_id?: string | null;
270
+ task_id?: string | null;
271
+ /** Active context-scope ids from the client's global picker (membership-validated server-side). */
272
+ scope_ids?: string[] | null;
273
+ /** Active scope-TYPE ids — a type-level selection with no specific scope chosen. */
274
+ active_scope_type_ids?: string[] | null;
275
+ context_anchor?: MatrxContextAnchor | null;
276
+ /** Stable application slug that initiated the request. */
277
+ source_app?: string | null;
278
+ /** Stable feature slug within the source application. */
279
+ source_feature?: string | null;
280
+ /** "user" = a person directly triggered this; "auto" = client automation; omit for API callers. */
281
+ initiation?: "user" | "auto" | null;
282
+ /** Specific connected desktop instance allowed to claim delegated local tools. */
283
+ target_instance_id?: string | null;
284
+ }
285
+ /**
286
+ * Fields shared by start/continue turn requests (tool injection, client
287
+ * capability envelope, context object). The complex bags (`tools`, `client`,
288
+ * `user`, `config_overrides`) are typed as JSON objects — their authoritative
289
+ * schemas are the server's Pydantic models and the generated API types;
290
+ * this package stays payload-agnostic about them by design.
291
+ */
292
+ interface MatrxTurnFields {
293
+ /** What the human typed (string), or structured input parts. Never smuggle machine content here. */
294
+ user_input?: string | MatrxJsonValue[] | null;
295
+ /** Per-run model/config overrides (LLMParams shape). */
296
+ config_overrides?: MatrxJsonObject | null;
297
+ debug?: boolean;
298
+ /** Additive tool specs merged into the agent's resolved tool set. */
299
+ tools?: MatrxJsonObject[];
300
+ /** When set, becomes the agent's ENTIRE tool set for the turn. */
301
+ tools_replace?: MatrxJsonObject[] | null;
302
+ /** Client capability envelope (`ClientContext`). */
303
+ client?: MatrxJsonObject | null;
304
+ /** Per-request user-level tool inclusion/exclusion overrides. */
305
+ user?: MatrxJsonObject | null;
306
+ /** Per-route context object, free-form by design. */
307
+ context?: MatrxJsonObject;
308
+ writable_variables?: string[];
309
+ allow_context_create?: boolean;
310
+ /** Request-snapshot capture override (tri-state; omit for the platform default). */
311
+ snapshot?: boolean | null;
312
+ }
313
+ /**
314
+ * `POST /ai/agents/{agent_id}` body (`AgentStartRequest` server-side).
315
+ * The conversation-start triple is required by construction; `organization_id`
316
+ * is required (the server 422s a blank one — it never manufactures an org).
317
+ * `stream` is not accepted here: this client is the streaming path and always
318
+ * sends `stream: true`.
319
+ */
320
+ type MatrxAgentStartRequest = MatrxConversationStart & Omit<MatrxRequestScope, "organization_id"> & MatrxTurnFields & {
321
+ organization_id: string;
322
+ /** Variable name → value map filling the agent's declared variables. */
323
+ variables?: MatrxJsonObject | null;
324
+ /** Run the versions table row instead of the live agent row. */
325
+ is_version?: boolean;
326
+ max_iterations?: number;
327
+ max_retries_per_iteration?: number;
328
+ };
329
+ /** `POST /ai/conversations/{id}` body (`ConversationContinueRequest` server-side). */
330
+ type MatrxConversationContinueRequest = MatrxRequestScope & MatrxTurnFields & {
331
+ /** Re-run the conversation's current persisted state (recovery after a failed turn); omit `user_input`. */
332
+ retry?: boolean;
333
+ };
334
+ /**
335
+ * `POST /ai/conversations/{id}/resume` body (`ResumeRequest` server-side) —
336
+ * the shipped durable continuation after client-delegated tool calls were
337
+ * answered via `POST /tool_results` while the original stream was gone.
338
+ * `user_request_id` is optional: when omitted the server resolves the turn
339
+ * from the conversation's newest answered client-delegated tool call.
340
+ * Re-send fresh `context` here — a resumed loop is otherwise context-blind.
341
+ */
342
+ type MatrxConversationResumeRequest = MatrxRequestScope & {
343
+ user_request_id?: string | null;
344
+ config_overrides?: MatrxJsonObject | null;
345
+ debug?: boolean;
346
+ tools?: MatrxJsonObject[];
347
+ tools_replace?: MatrxJsonObject[] | null;
348
+ client?: MatrxJsonObject | null;
349
+ user?: MatrxJsonObject | null;
350
+ context?: MatrxJsonObject;
351
+ writable_variables?: string[];
352
+ allow_context_create?: boolean;
353
+ };
354
+ /** `POST /ai/cancel/{request_id}` response (`CancelResponse` server-side). */
355
+ interface MatrxCancelResponse {
356
+ status: string;
357
+ request_id: string;
358
+ spine_executions_signalled: string[];
359
+ }
360
+ /** Start an agent run: `POST /ai/agents/{agent_id}` (NDJSON stream). */
361
+ declare function startAgentRun(transport: MatrxTransport, agentId: string, request: MatrxAgentStartRequest, options?: MatrxStreamCallOptions): Promise<MatrxRunHandle>;
362
+ /** Continue a stored conversation: `POST /ai/conversations/{id}` (NDJSON stream). */
363
+ declare function continueAgentConversation(transport: MatrxTransport, conversationId: string, request: MatrxConversationContinueRequest, options?: MatrxStreamCallOptions): Promise<MatrxRunHandle>;
364
+ /**
365
+ * Resume a suspended loop after delegated tool answers landed:
366
+ * `POST /ai/conversations/{id}/resume` (NDJSON stream). A 409
367
+ * (`resume_conflict`) means another resume holds the run claim — retrying is
368
+ * host policy.
369
+ */
370
+ declare function resumeAgentConversation(transport: MatrxTransport, conversationId: string, request?: MatrxConversationResumeRequest, options?: MatrxStreamCallOptions): Promise<MatrxRunHandle>;
371
+ /**
372
+ * Stop a running request at its next iteration boundary:
373
+ * `POST /ai/cancel/{request_id}`. Cooperative and best-effort — the in-flight
374
+ * provider call finishes by design, and everything already streamed persists.
375
+ * `mode: "interrupt"` = stop-and-fork: the tail after the last clean boundary
376
+ * persists hidden so the user's follow-up replies to what they actually saw.
377
+ * The id must be the server's `X-Request-ID`.
378
+ */
379
+ declare function cancelAgentRun(transport: MatrxTransport, requestId: string, options?: {
380
+ mode?: "cancel" | "interrupt";
381
+ signal?: AbortSignal;
382
+ }): Promise<MatrxCancelResponse>;
383
+ /**
384
+ * A run that terminated unsuccessfully: the server emitted a fatal `error`
385
+ * event, or the `user_request` completion settled `failed`/`cancelled`.
386
+ */
387
+ declare class MatrxRunError extends Error {
388
+ readonly name = "MatrxRunError";
389
+ /** The verbatim `error` event payload, when one fired. */
390
+ readonly errorPayload: Record<string, unknown> | null;
391
+ /** The `user_request` completion status (`"failed"` | `"cancelled"`), when that was the trigger. */
392
+ readonly completionStatus: string | null;
393
+ /** Text streamed before the failure — partial content never vanishes. */
394
+ readonly partialText: string;
395
+ constructor(args: {
396
+ message: string;
397
+ errorPayload?: Record<string, unknown> | null;
398
+ completionStatus?: string | null;
399
+ partialText?: string;
400
+ });
401
+ }
402
+ interface MatrxCompletedRun {
403
+ /** Accumulated `chunk` text (falls back to the completion's `result.output`). */
404
+ text: string;
405
+ requestId: string | null;
406
+ conversationId: string | null;
407
+ /** The `user_request` completion payload, verbatim, when one arrived. */
408
+ completion: Record<string, unknown> | null;
409
+ }
410
+ interface RunAgentToCompletionOptions extends MatrxStreamCallOptions {
411
+ /** Live progress: the full accumulated text after each chunk. */
412
+ onChunk?: (fullText: string) => void;
413
+ /** Every normalized envelope, before this helper interprets it. */
414
+ onEvent?: (envelope: MatrxStreamEnvelope) => void;
415
+ }
416
+ /**
417
+ * Run an agent end-to-end and resolve with its full text output — the
418
+ * package-level equivalent of the simplest existing host path
419
+ * (`useRunAgent`): accumulate `chunk` text, treat a fatal `error` event or a
420
+ * `failed`/`cancelled` `user_request` completion as a thrown `MatrxRunError`,
421
+ * and fall back to the completion's `result.output` when no text streamed.
422
+ *
423
+ * The caller still owns the conversation-start triple on `request` — a
424
+ * one-shot run typically uses `newEphemeralConversationStart()`.
425
+ */
426
+ declare function runAgentToCompletion(transport: MatrxTransport, agentId: string, request: MatrxAgentStartRequest, options?: RunAgentToCompletionOptions): Promise<MatrxCompletedRun>;
427
+
428
+ /**
429
+ * Runtime operations — the canonical reconnect & resume read surface of the
430
+ * execution spine, over the `MatrxTransport` port.
431
+ *
432
+ * Server truth (verified against aidream source,
433
+ * `aidream/api/routers/runtime_operations.py` + `aidream/services/runtime/
434
+ * reconnect.py`; mounted at bare `/runtime`):
435
+ * - `GET /runtime/operations/{request_id}` — identify by `X-Request-ID`
436
+ * - `GET /runtime/operations/by-link/{kind}/{id}` — identify by feature record
437
+ * - `GET /runtime/executions/{id}/events` — durable seq-cursored page
438
+ * - `GET /runtime/executions/{id}/events/stream` — SSE replay-then-follow,
439
+ * `id:` = per-tree seq, reconnect with `Last-Event-ID`
440
+ * - `POST /runtime/operations/{request_id}/rejoin` — replay + follow the
441
+ * ORIGINAL NDJSON response while its detached task is alive (409 when live
442
+ * delivery is unavailable — fall back to the durable lifecycle stream)
443
+ *
444
+ * The contract: identify → recover durable progress → follow live → re-query
445
+ * the final result from the feature's own record. Token text is deliberately
446
+ * never replayed on the lifecycle stream — that is what `/rejoin` is for.
447
+ *
448
+ * The SSE wire rides the package's own `stream/sse` kernel. This module owns
449
+ * ONE connection's semantics (frames → typed events, cursor advancement,
450
+ * terminal `end`); stall timers, retry budgets, and reconnect loops stay host
451
+ * policy — every yielded item carries the cursor the next attempt resumes from.
452
+ */
453
+
454
+ /** `matrx_runtime.models.ExecutionStatus` — the only progress column. */
455
+ type MatrxRuntimeExecutionStatus = "pending" | "running" | "paused" | "waiting_input" | "completed" | "failed" | "cancelled";
456
+ declare const TERMINAL_MATRX_RUNTIME_STATUSES: ReadonlySet<MatrxRuntimeExecutionStatus>;
457
+ /** One durable spine event on the wire (`OperationEvent`) — `seq` is the reconnect cursor. */
458
+ interface MatrxRuntimeOperationEvent {
459
+ seq: number | null;
460
+ /** Lifecycle vocabulary: created | started | paused | resumed | waiting_input | completed | failed | cancelled | checkpoint_saved | note. */
461
+ kind: string;
462
+ execution_id: string;
463
+ root_execution_id: string | null;
464
+ detail: MatrxJsonObject | null;
465
+ created_at: string | null;
466
+ }
467
+ /** One root execution as a reconnecting client sees it (`OperationView`). */
468
+ interface MatrxRuntimeOperationView {
469
+ execution_id: string;
470
+ /** Durable request identity — feeds `/rejoin` and no-prompt resume recovery. */
471
+ request_id: string | null;
472
+ type: string;
473
+ status: MatrxRuntimeExecutionStatus;
474
+ is_terminal: boolean;
475
+ waiting_input: boolean;
476
+ /** Decimal on the wire — may arrive as number or string; display-only. */
477
+ cost: number | string;
478
+ meters: Record<string, number | string>;
479
+ link_kind: string | null;
480
+ link_id: string | null;
481
+ error: MatrxJsonObject | null;
482
+ created_at: string | null;
483
+ started_at: string | null;
484
+ ended_at: string | null;
485
+ last_event_seq: number;
486
+ events_path: string;
487
+ stream_path: string;
488
+ }
489
+ interface MatrxOperationStatusResponse {
490
+ request_id: string;
491
+ operation_count: number;
492
+ operations: MatrxRuntimeOperationView[];
493
+ }
494
+ interface MatrxOperationsByLinkResponse {
495
+ link_kind: string;
496
+ link_id: string;
497
+ operation_count: number;
498
+ operations: MatrxRuntimeOperationView[];
499
+ }
500
+ interface MatrxOperationEventsPage {
501
+ execution_id: string;
502
+ root_execution_id: string;
503
+ events: MatrxRuntimeOperationEvent[];
504
+ /** Feeds the next page or the SSE `Last-Event-ID` — polling and push share ONE cursor. */
505
+ next_after_seq: number;
506
+ has_more: boolean;
507
+ root_status: MatrxRuntimeExecutionStatus;
508
+ root_is_terminal: boolean;
509
+ }
510
+ /**
511
+ * Where is my operation? Resolves an `X-Request-ID` to its root execution(s).
512
+ * Returns null on 404 — missing and unowned share one shape by design
513
+ * (existence is never leaked).
514
+ */
515
+ declare function getRuntimeOperationStatus(transport: MatrxTransport, requestId: string, options?: {
516
+ signal?: AbortSignal;
517
+ }): Promise<MatrxOperationStatusResponse | null>;
518
+ /**
519
+ * Operations for a feature record — e.g. `("conversation", conversationId)`,
520
+ * `("workflow", runId)`, `("agent_run", runId)`. Newest first; unowned trees
521
+ * omitted. Returns null on 404 (surface absent, or the caller owns nothing —
522
+ * one shape by design).
523
+ */
524
+ declare function getRuntimeOperationsByLink(transport: MatrxTransport, linkKind: string, linkId: string, options?: {
525
+ limit?: number;
526
+ signal?: AbortSignal;
527
+ }): Promise<MatrxOperationsByLinkResponse | null>;
528
+ /**
529
+ * Durable progress page for the whole operation TREE:
530
+ * `GET /runtime/executions/{id}/events?after_seq=…`. Pass any node id — it
531
+ * resolves to the root.
532
+ */
533
+ declare function listRuntimeOperationEvents(transport: MatrxTransport, executionId: string, options?: {
534
+ afterSeq?: number;
535
+ limit?: number;
536
+ /** Repeatable event-kind filter. */
537
+ kinds?: readonly string[];
538
+ signal?: AbortSignal;
539
+ }): Promise<MatrxOperationEventsPage>;
540
+ /**
541
+ * One item from the follow stream. Every item carries `cursor` — the highest
542
+ * event seq seen so far, which is exactly the `Last-Event-ID` a reconnect
543
+ * resumes from (host retry policy owns the reconnect loop).
544
+ */
545
+ type MatrxOperationFollowEvent = {
546
+ /** A parsed durable spine event. */
547
+ type: "event";
548
+ event: MatrxRuntimeOperationEvent;
549
+ /** The frame's SSE `id:` as an integer, when it carried one. */
550
+ seq: number | null;
551
+ cursor: number;
552
+ } | {
553
+ /**
554
+ * A frame that carried no deliverable event — a comment heartbeat, an
555
+ * unknown event name, or a malformed payload (also surfaced through
556
+ * `onMalformedFrame`). ANY parsed frame proves the wire is alive: hosts
557
+ * reset stall timers and retry budgets on it.
558
+ */
559
+ type: "liveness";
560
+ cursor: number;
561
+ } | {
562
+ /** The server's terminal frame — the root settled; the stream is over. */
563
+ type: "end";
564
+ status: MatrxRuntimeExecutionStatus | null;
565
+ cursor: number;
566
+ };
567
+ interface FollowRuntimeOperationOptions {
568
+ /** Resume cursor — the operation view's `last_event_seq` (0 = from start). */
569
+ lastEventSeq?: number;
570
+ /** Abort the follow — the generator simply ends. */
571
+ signal?: AbortSignal;
572
+ /** A frame whose payload failed to parse — never silently dropped. */
573
+ onMalformedFrame?: (frame: MatrxSseFrame, error: unknown) => void;
574
+ /** Unterminated trailing SSE text at stream end (diagnostic, never an event). */
575
+ onIncomplete?: (text: string) => void;
576
+ }
577
+ /**
578
+ * Follow ONE SSE connection of an operation's lifecycle stream:
579
+ * `GET /runtime/executions/{id}/events/stream` with `Last-Event-ID` when
580
+ * resuming past 0. Replays from the cursor, then follows live; a
581
+ * WAITING_INPUT park keeps it open (a resume re-attaches to the same
582
+ * execution and its events continue here). Ends after yielding
583
+ * `{type: "end"}` when the root settles; a server close WITHOUT an end frame
584
+ * simply ends the generator — reconnect from the last yielded `cursor` (host
585
+ * retry policy).
586
+ */
587
+ declare function followRuntimeOperationEvents(transport: MatrxTransport, executionId: string, options?: FollowRuntimeOperationOptions): AsyncGenerator<MatrxOperationFollowEvent, void, undefined>;
588
+ /**
589
+ * Rejoin the ORIGINAL NDJSON response while its detached task is still alive:
590
+ * `POST /runtime/operations/{request_id}/rejoin`. Replays the response from
591
+ * frame one, then continues live — every frame is sequence-stamped
592
+ * (`stream_seq`), so a same-page reconnect can drop frames it already
593
+ * rendered. Throws `MatrxApiError` with status 409 when live delivery is
594
+ * unavailable — fall back to `followRuntimeOperationEvents` + a final record
595
+ * re-query. The `requestId` must be the server's `X-Request-ID`.
596
+ */
597
+ declare function rejoinRuntimeOperation(transport: MatrxTransport, requestId: string, options?: MatrxStreamCallOptions): Promise<MatrxRunHandle>;
598
+
599
+ /**
600
+ * Delegated client tools — submit results and discover pending calls.
601
+ *
602
+ * Server truth (verified against aidream source,
603
+ * `aidream/api/routers/conversations.py` + `aidream/services/ai_execution/
604
+ * tool_results.py`):
605
+ * - `POST /ai/conversations/{id}/tool_results` — durable, idempotent submit.
606
+ * A delegated tool call HARD-SUSPENDS the loop; when the last outstanding
607
+ * delegated row for the user_request resolves, the response carries
608
+ * `continuation_needed: true` and the owning `user_request_id` — the signal
609
+ * to open `resumeAgentConversation`. `continuation_needed` is best-effort:
610
+ * parallel submits can both see `true`; `/resume` takes an atomic run claim
611
+ * and the loser gets a 409.
612
+ * - `GET /ai/conversations/{id}/pending_calls` — delegated calls awaiting the
613
+ * user in one conversation (rows survive disconnects and reloads).
614
+ * - `GET /ai/user/pending_calls` — every pending call for this user; an
615
+ * optional `instance_id` atomically claims them for a desktop instance.
616
+ *
617
+ * A 404 from the submit means EVERY call_id was unknown (duplicate/expired);
618
+ * partial success returns 200 with `not_found` populated. Batching, retries,
619
+ * and the resume handoff are host policy — this module is the wire.
620
+ */
621
+
622
+ /** One client tool answer (`ClientToolResult` server-side). */
623
+ interface MatrxClientToolResult {
624
+ call_id: string;
625
+ tool_name: string;
626
+ /** Tool output — inherently polymorphic; recursive JSON by design. */
627
+ output?: MatrxJsonValue | null;
628
+ is_error?: boolean;
629
+ error_message?: string | null;
630
+ /** Client-measured execution time in ms. */
631
+ duration_ms?: number | null;
632
+ }
633
+ /** `POST /tool_results` response (`ToolResultsResponse` server-side). */
634
+ interface MatrxToolResultsResponse {
635
+ resolved: string[];
636
+ already_resolved: string[];
637
+ not_found: string[];
638
+ /** True when the original stream is gone and no delegated calls remain — open `/resume`. */
639
+ continuation_needed: boolean;
640
+ user_request_id: string | null;
641
+ conversation_id: string;
642
+ }
643
+ /** One delegated call awaiting an answer (`PendingCallSummary` server-side). */
644
+ interface MatrxPendingCallSummary {
645
+ id: string;
646
+ call_id: string;
647
+ conversation_id: string;
648
+ user_request_id: string | null;
649
+ message_id: string | null;
650
+ tool_name: string;
651
+ /** Tool-call argument bag — schema is per-tool (its input_schema). */
652
+ arguments: MatrxJsonObject;
653
+ iteration: number;
654
+ created_at: string | null;
655
+ expires_at: string | null;
656
+ target_instance_id: string | null;
657
+ claimed_by_instance_id: string | null;
658
+ claim_expires_at: string | null;
659
+ execution_authorization: MatrxJsonObject | null;
660
+ }
661
+ /**
662
+ * Submit client tool results: `POST /ai/conversations/{id}/tool_results`.
663
+ * Idempotent — duplicate submits return 200 with the ids in
664
+ * `already_resolved`. Throws `MatrxApiError` (status 404) when every call_id
665
+ * was unknown or expired; the stream stays alive in that case.
666
+ */
667
+ declare function submitAgentToolResults(transport: MatrxTransport, conversationId: string, results: MatrxClientToolResult[], options?: {
668
+ instanceId?: string;
669
+ signal?: AbortSignal;
670
+ }): Promise<MatrxToolResultsResponse>;
671
+ /**
672
+ * Discover delegated calls awaiting the user in one conversation:
673
+ * `GET /ai/conversations/{id}/pending_calls`. Safe to call on every
674
+ * conversation load; a non-empty list should be surfaced exactly as if the
675
+ * original stream had delivered the `tool_delegated` events live.
676
+ */
677
+ declare function listConversationPendingToolCalls(transport: MatrxTransport, conversationId: string, options?: {
678
+ signal?: AbortSignal;
679
+ }): Promise<MatrxPendingCallSummary[]>;
680
+ /**
681
+ * Discover every delegated call awaiting this user across all conversations:
682
+ * `GET /ai/user/pending_calls`. Passing `instanceId` atomically CLAIMS the
683
+ * calls for that desktop instance — only pass it from a client that will
684
+ * actually execute them.
685
+ */
686
+ declare function listUserPendingToolCalls(transport: MatrxTransport, options?: {
687
+ instanceId?: string;
688
+ signal?: AbortSignal;
689
+ }): Promise<MatrxPendingCallSummary[]>;
690
+
691
+ export { type FollowRuntimeOperationOptions, type MatrxAgentStartRequest, MatrxApiError, type MatrxCancelResponse, type MatrxChatMessage, type MatrxClientToolResult, type MatrxCompletedRun, type MatrxContextAnchor, type MatrxConversationContinueRequest, type MatrxConversationResumeRequest, type MatrxConversationStart, type MatrxEphemeralConversation, type MatrxJsonObject, type MatrxJsonValue, type MatrxOperationEventsPage, type MatrxOperationFollowEvent, type MatrxOperationStatusResponse, type MatrxOperationsByLinkResponse, type MatrxPendingCallSummary, type MatrxRequestScope, MatrxRunError, type MatrxRunHandle, type MatrxRuntimeExecutionStatus, type MatrxRuntimeOperationEvent, type MatrxRuntimeOperationView, type MatrxStoredConversationContinue, type MatrxStoredConversationCreate, type MatrxStreamCallOptions, type MatrxToolResultsResponse, type MatrxTransport, type MatrxTransportRequest, type MatrxTurnFields, type RunAgentToCompletionOptions, TERMINAL_MATRX_RUNTIME_STATUSES, cancelAgentRun, continueAgentConversation, continueEphemeralConversationStart, continueStoredConversationStart, extractMatrxErrorCode, extractMatrxErrorMessage, followRuntimeOperationEvents, getRuntimeOperationStatus, getRuntimeOperationsByLink, listConversationPendingToolCalls, listRuntimeOperationEvents, listUserPendingToolCalls, mintMatrxConversationId, newEphemeralConversationStart, newStoredConversationStart, rejoinRuntimeOperation, resumeAgentConversation, runAgentToCompletion, startAgentRun, submitAgentToolResults };