@ai-matrx/agents 0.36.0 → 0.37.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.
Files changed (54) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/content-transfer/index.cjs +12 -12
  3. package/dist/content-transfer/index.cjs.map +1 -1
  4. package/dist/content-transfer/index.d.cts +1 -1
  5. package/dist/content-transfer/index.d.ts +1 -1
  6. package/dist/content-transfer/index.js +12 -12
  7. package/dist/content-transfer/index.js.map +1 -1
  8. package/dist/content-transfer/react/index.cjs +12 -12
  9. package/dist/content-transfer/react/index.cjs.map +1 -1
  10. package/dist/content-transfer/react/index.d.cts +1 -1
  11. package/dist/content-transfer/react/index.d.ts +1 -1
  12. package/dist/content-transfer/react/index.js +12 -12
  13. package/dist/content-transfer/react/index.js.map +1 -1
  14. package/dist/generated/api-types.cjs.map +1 -1
  15. package/dist/generated/api-types.d.cts +5 -0
  16. package/dist/generated/api-types.d.ts +5 -0
  17. package/dist/index.cjs +1458 -1220
  18. package/dist/index.cjs.map +1 -1
  19. package/dist/index.d.cts +2 -2
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +1461 -1223
  22. package/dist/index.js.map +1 -1
  23. package/dist/{keys.generated-DCtN66RS.d.cts → keys.generated-DL-5LCNz.d.cts} +4 -4
  24. package/dist/{keys.generated-DCtN66RS.d.ts → keys.generated-DL-5LCNz.d.ts} +4 -4
  25. package/dist/mandates/index.cjs +2 -2
  26. package/dist/mandates/index.cjs.map +1 -1
  27. package/dist/mandates/index.d.cts +2 -2
  28. package/dist/mandates/index.d.ts +2 -2
  29. package/dist/mandates/index.js +2 -2
  30. package/dist/mandates/index.js.map +1 -1
  31. package/dist/matrx/index.cjs +1721 -1483
  32. package/dist/matrx/index.cjs.map +1 -1
  33. package/dist/matrx/index.d.cts +376 -211
  34. package/dist/matrx/index.d.ts +376 -211
  35. package/dist/matrx/index.js +1724 -1486
  36. package/dist/matrx/index.js.map +1 -1
  37. package/dist/message-parts/index.d.cts +1 -100929
  38. package/dist/message-parts/index.d.ts +1 -100929
  39. package/dist/portable/mcp.cjs +99 -11
  40. package/dist/portable/mcp.cjs.map +1 -1
  41. package/dist/portable/mcp.js +99 -11
  42. package/dist/portable/mcp.js.map +1 -1
  43. package/dist/react/index.cjs +145 -57
  44. package/dist/react/index.cjs.map +1 -1
  45. package/dist/react/index.d.cts +3 -1
  46. package/dist/react/index.d.ts +3 -1
  47. package/dist/react/index.js +145 -57
  48. package/dist/react/index.js.map +1 -1
  49. package/generated/api-types.ts +5 -0
  50. package/mandates/snapshots/keys.0.37.0.json +653 -0
  51. package/mandates/snapshots/keys.0.37.1.json +653 -0
  52. package/package.json +4 -4
  53. package/dist/{operations-BT5kKMHl.d.cts → operations-DqOe2zob.d.cts} +34 -34
  54. package/dist/{operations-BT5kKMHl.d.ts → operations-DqOe2zob.d.ts} +34 -34
@@ -2,10 +2,10 @@ import { M as MatrxTransport, a as MatrxApiError } from '../transport-CxD0fL8p.j
2
2
  export { b as MatrxTransportRequest, e as extractMatrxErrorCode, c as extractMatrxErrorMessage } from '../transport-CxD0fL8p.js';
3
3
  import { CredentialsPort } from '@ai-matrx/data';
4
4
  import { ResilientFetchOptions } from '@ai-matrx/data/net';
5
+ import { MatrxStreamEnvelope, MatrxNdjsonIssue } from '../stream/ndjson.js';
5
6
  import { v as MatrxRuntimeOperationEvent, a as FollowRuntimeOperationToEndOptions, u as MatrxRuntimeExecutionStatus, z as MatrxStreamCallOptions, t as MatrxRunHandle, l as MatrxJsonValue, k as MatrxJsonObject } from '../operations-C3iHFcnt.js';
6
7
  export { F as FollowRuntimeOperationOptions, b as FollowRuntimeOperationToEndResult, M as MatrxAgentStartRequest, c as MatrxCancelResponse, d as MatrxChatMessage, e as MatrxCompletedRun, f as MatrxContextAnchor, g as MatrxConversationContinueRequest, h as MatrxConversationResumeRequest, i as MatrxConversationStart, j as MatrxEphemeralConversation, m as MatrxMandateStartRequest, n as MatrxOperationEventsPage, o as MatrxOperationFollowEvent, p as MatrxOperationStatusResponse, q as MatrxOperationsByLinkResponse, r as MatrxRequestScope, s as MatrxRunError, w as MatrxRuntimeOperationView, x as MatrxStoredConversationContinue, y as MatrxStoredConversationCreate, A as MatrxTurnFields, R as RunAgentToCompletionOptions, T as TERMINAL_MATRX_RUNTIME_STATUSES, B as cancelAgentRun, C as continueAgentConversation, D as continueEphemeralConversationStart, E as continueStoredConversationStart, G as followRuntimeOperationEvents, H as followRuntimeOperationToEnd, I as getRuntimeOperationStatus, J as getRuntimeOperationsByLink, K as listRuntimeOperationEvents, L as mintMatrxConversationId, N as newEphemeralConversationStart, O as newStoredConversationStart, P as rejoinRuntimeOperation, Q as resumeAgentConversation, S as runAgentToCompletion, U as startAgentRun, V as startMandateRun } from '../operations-C3iHFcnt.js';
7
- import { MatrxStreamEnvelope } from '../stream/ndjson.js';
8
- import { M as MandateKey, D as DynamicMandateKey } from '../keys.generated-DCtN66RS.js';
8
+ import { M as MandateKey, D as DynamicMandateKey } from '../keys.generated-DL-5LCNz.js';
9
9
  import '../stream/sse.js';
10
10
 
11
11
  /**
@@ -175,11 +175,21 @@ interface MatrxCallError {
175
175
  name?: string;
176
176
  /** Original exception stack. */
177
177
  stack?: string;
178
+ /** JSON-safe dump of the original thrown value. */
179
+ raw?: unknown;
178
180
  }
179
181
  /**
180
- * Classify any failure thrown by a package client call — `MatrxApiError`,
181
- * a `NetError` from the resilience layer, an org-context refusal, an abort —
182
- * into the `MatrxCallError` envelope. Never throws.
182
+ * Classify any failure thrown by a Matrx client call — `MatrxApiError`, a
183
+ * typed `BackendApiError` / `StreamTransportError`, a `NetError` from the
184
+ * resilience layer, an org-context refusal, an abort — into the
185
+ * `MatrxCallError` envelope. Never throws.
186
+ *
187
+ * Every message is laundered through `honestTransportMessage`: a bare status
188
+ * line ("HTTP 400") never reaches a person — the status rides `status`.
189
+ * A `BackendApiError` keeps its machine `code` (a dropped socket stays
190
+ * `stream_transport_lost`, so a surface reattaches instead of dead-ending)
191
+ * and its structured `details` ride `serverDetail` (the organization-hold
192
+ * body carries the caller's membership choices there).
183
193
  */
184
194
  declare function normalizeMatrxError(err: unknown): MatrxCallError;
185
195
  /**
@@ -273,6 +283,366 @@ interface CreateMatrxTransportOptions {
273
283
  */
274
284
  declare function createMatrxTransport(options: CreateMatrxTransportOptions): MatrxTransport;
275
285
 
286
+ /**
287
+ * `@ai-matrx/agents/matrx` — the AI Matrx server's error model, as every
288
+ * client reads it: `BackendApiError` (the server's `APIError` body),
289
+ * `StreamTransportError` (the socket died mid-run; the run may still finish
290
+ * and is reattachable), parsing of HTTP / stream / persisted errors, and the
291
+ * ONE sentence a person sees (`getUserMessage`, `describeBackendFailure`).
292
+ *
293
+ * Moved from matrx-frontend `lib/api/errors.ts` (chat-package independence
294
+ * P9); the app re-exports it from here. Pure: no host, no window, no env.
295
+ */
296
+ /**
297
+ * Standardized error shape returned by all backend endpoints.
298
+ * Matches the Python `APIError` Pydantic model.
299
+ */
300
+ interface BackendApiErrorData {
301
+ /** Machine-readable error code (e.g. "auth_required", "validation_error") */
302
+ error: string;
303
+ /** Developer-facing detail for debugging */
304
+ message: string;
305
+ /** Safe to display directly in the UI */
306
+ user_message: string;
307
+ /** Extra info (validation errors, etc.) */
308
+ details: unknown | null;
309
+ /** Unique request ID for support/debugging */
310
+ request_id: string;
311
+ }
312
+ /** Common backend error codes */
313
+ type BackendErrorCode = "auth_required" | "token_required" | "admin_required" | "validation_error" | "not_found" | "internal_error" | "agent_error"
314
+ /** The stream socket died mid-run; the server run may still be completing
315
+ * and is reattachable. See `StreamTransportError`. */
316
+ | "stream_transport_lost" | (string & {});
317
+ /**
318
+ * Typed error thrown by all backend API operations.
319
+ * Contains structured fields matching the Python APIError model.
320
+ *
321
+ * Usage:
322
+ * ```typescript
323
+ * try {
324
+ * await client.post(ENDPOINTS.ai.agentStart(agentId), body);
325
+ * } catch (err) {
326
+ * if (err instanceof BackendApiError) {
327
+ * // Show err.userMessage to the user
328
+ * // Log err.requestId for debugging
329
+ * // Check err.code for programmatic handling
330
+ * }
331
+ * }
332
+ * ```
333
+ */
334
+ declare class BackendApiError extends Error {
335
+ /** Machine-readable error code */
336
+ readonly code: BackendErrorCode;
337
+ /** Developer-facing detail */
338
+ readonly detail: string;
339
+ /** Safe to display directly in the UI */
340
+ readonly userMessage: string;
341
+ /** Extra info (validation errors, etc.) */
342
+ readonly details: unknown | null;
343
+ /** Unique request ID for support/debugging */
344
+ readonly requestId: string;
345
+ /** HTTP status code (if from an HTTP response) */
346
+ readonly status: number | null;
347
+ constructor(data: {
348
+ code: BackendErrorCode;
349
+ detail: string;
350
+ userMessage: string;
351
+ details?: unknown | null;
352
+ requestId?: string | undefined;
353
+ status?: number | null | undefined;
354
+ });
355
+ /** Convert to the wire format for logging */
356
+ toJSON(): BackendApiErrorData;
357
+ }
358
+ /**
359
+ * The socket carrying a live NDJSON stream broke mid-run.
360
+ *
361
+ * THE DISTINCTION THIS EXISTS TO MAKE: a backend that blows up mid-stream does
362
+ * NOT break the socket — it emits a typed `error` event and closes the body
363
+ * cleanly. So an exception escaping the body reader means the *transport* died,
364
+ * not the run. And aidream streams run `detach_on_disconnect=True`: the server
365
+ * keeps executing and persisting the turn after our connection goes away.
366
+ *
367
+ * The client therefore cannot decide locally whether the answer is lost — it
368
+ * must ASK THE SERVER. That is what `resumable` means here: "reattach by
369
+ * requestId / conversationId / durable run id and let server truth settle it",
370
+ * never "this succeeded". A server that genuinely died reports `failed` on
371
+ * reattach and the honest record replaces the optimistic copy.
372
+ *
373
+ * Consumers: `run-ai-stream.ts` (chat → `reconnectServerOperation`) and
374
+ * `adopt-foreign-stream.ts` (pipeline runs → the surface's own rejoin).
375
+ */
376
+ declare class StreamTransportError extends BackendApiError {
377
+ /** Always true — reattach and let the server settle the outcome. */
378
+ readonly resumable: true;
379
+ constructor(data: {
380
+ detail: string;
381
+ details?: unknown | null;
382
+ requestId?: string;
383
+ });
384
+ }
385
+ /**
386
+ * True when a failure is a dropped transport rather than a failed run. Use this
387
+ * instead of `instanceof` at boundaries that re-wrap errors (thunk rejections,
388
+ * `callApi` result errors), where the class identity is lost but the code
389
+ * survives.
390
+ */
391
+ declare function isStreamTransportLost(error: unknown): boolean;
392
+ /**
393
+ * Parse a non-OK HTTP response into a BackendApiError.
394
+ *
395
+ * Handles the standardized backend shape and falls back gracefully
396
+ * when the response isn't JSON or uses a legacy format.
397
+ */
398
+ declare function parseHttpError(response: Response): Promise<BackendApiError>;
399
+ /**
400
+ * Parse an already-decoded JSON error body into a BackendApiError.
401
+ *
402
+ * Exported because XHR callers (upload/download progress paths) have the
403
+ * parsed body in hand and MUST NOT hand-roll a shallower read: a private
404
+ * copy in `python-client.ts` looked only at top-level `error`/`message`, so
405
+ * FastAPI's `{"detail": {...}}` envelope — what every matrx-files 500 uses —
406
+ * degraded to the useless `code: "internal", detail: "HTTP 500"`. That is
407
+ * exactly how an upload failure with a real server-side cause reached the
408
+ * user as `Upload failed (500)` and nothing else. One parser, every transport.
409
+ */
410
+ declare function parseHttpErrorBody(body: Record<string, unknown> | null, status: number): BackendApiError;
411
+ /**
412
+ * Adapt callApi's result-style error into the same canonical error used by
413
+ * direct fetch and streaming consumers.
414
+ *
415
+ * callApi intentionally returns errors instead of throwing them, but its
416
+ * `serverDetail` contains the complete FastAPI body. Sending only
417
+ * `error.message` to a feature discards that body and turns a precise
418
+ * configuration failure into "HTTP 422". This adapter keeps one parser and
419
+ * one human-facing explanation path across both client styles.
420
+ */
421
+ declare function parseCallApiError(error: {
422
+ message: string;
423
+ status?: number;
424
+ serverDetail?: unknown;
425
+ }): BackendApiError;
426
+ /**
427
+ * Parse streaming error event data into a BackendApiError.
428
+ *
429
+ * Handles both new format (`user_message`) and legacy (`user_visible_message`).
430
+ */
431
+ declare function parseStreamError(data: unknown): BackendApiError;
432
+ /**
433
+ * Restore the canonical error shape from a durable backend run row.
434
+ *
435
+ * Provider ledgers often keep an aggregate summary plus a more specific first
436
+ * child failure. Prefer that child so a page refresh does not turn a precise
437
+ * streamed failure back into "1 request failed".
438
+ */
439
+ declare function parsePersistedBackendError(data: unknown, requestId?: string): BackendApiError | null;
440
+ /** True when a message tells the reader nothing about what actually broke. */
441
+ declare function isGenericUserMessage(message: string | null | undefined): boolean;
442
+ interface UpstreamErrorPayload {
443
+ message: string;
444
+ code: string | null;
445
+ userMessage: string | null;
446
+ requestId: string | null;
447
+ status: number | null;
448
+ }
449
+ /**
450
+ * Recover an upstream service's structured error that a downstream service
451
+ * stringified into its own message.
452
+ *
453
+ * Real example (scraper wrapping aidream):
454
+ * `aidream could not resolve GSC credential 7223…: HTTP 409 {"error":"conflict",
455
+ * "message":"Google connection 7223… has no vault credential — it needs
456
+ * re-authentication","user_message":"Something went wrong…","request_id":"9002…"}`
457
+ *
458
+ * Without this, the only actionable sentence on the whole hop is invisible.
459
+ */
460
+ declare function unwrapUpstreamError(message: string): UpstreamErrorPayload | null;
461
+ interface BackendFailureExplanation {
462
+ /** Machine code from the deepest layer that classified the failure. */
463
+ code: string;
464
+ /** The most specific human-readable cause available — never a template. */
465
+ cause: string;
466
+ /** What to headline in the UI: the cause when the server was generic. */
467
+ headline: string;
468
+ /** True when every user-facing message the server sent was a template. */
469
+ headlineWasGeneric: boolean;
470
+ /** Message chain, outermost (closest service) first. */
471
+ chain: string[];
472
+ /** Deepest request id available, for cross-service log correlation. */
473
+ requestId: string;
474
+ status: number | null;
475
+ }
476
+ /**
477
+ * THE anti-secrecy primitive: turn any thrown backend/stream failure into the
478
+ * most specific explanation the payload can support — unwrapping every nested
479
+ * upstream error and refusing to let a templated `user_message` be the answer.
480
+ *
481
+ * Every surface that reports a backend failure to a human should headline
482
+ * `explanation.headline` and always keep `cause` + `requestId` reachable.
483
+ */
484
+ declare function describeBackendFailure(error: unknown): BackendFailureExplanation;
485
+ /**
486
+ * Extract a user-visible message from any error object.
487
+ * Utility for components that just need the display string.
488
+ */
489
+ declare function getUserMessage(error: unknown): string;
490
+
491
+ /**
492
+ * `@ai-matrx/agents/matrx` — THE request pipeline every typed Matrx server call
493
+ * rides (chat package independence P9b). One implementation for every client:
494
+ * matrx-frontend's `lib/api` `callApi` and the chat package's bare-host default
495
+ * both build on it, and supply only their host facts — where the server is,
496
+ * which credential and organization ride, and where diagnostics go.
497
+ *
498
+ * What lives here (pure, no host/window/env read):
499
+ *
500
+ * - `buildMatrxRequestUrl` — path params, the legacy `/api` strip, the query;
501
+ * - `buildMatrxRequestBody` — scope injection (`organization_id` /
502
+ * `project_id` / `task_id`), the UI-only field strip, and the fail-closed
503
+ * body-vs-context organization check;
504
+ * - `bareStatusSentence` / `isBareTransportCode` / `honestTransportMessage` —
505
+ * a bare status code is never a sentence at a person;
506
+ * - `parseMatrxNdjsonResponse` — a response body as typed envelopes, a broken
507
+ * body reader classified as a resumable `StreamTransportError`;
508
+ * - `executeMatrxCall` — the JSON or NDJSON execution over the v2 → v1
509
+ * protocol fallback, with the stream callbacks and `consumeStream`;
510
+ * - `buildSafeRequestLog` / `redactUrlForRequestLog` /
511
+ * `shouldReportMatrxCallError` — the log and capture policy.
512
+ *
513
+ * The error envelope (`MatrxCallError`) and its ONE classifier
514
+ * (`normalizeMatrxError`) live in `./client`.
515
+ */
516
+
517
+ type MatrxHttpMethod = "GET" | "POST" | "PUT" | "DELETE" | "PATCH";
518
+ /**
519
+ * Every context dimension a call may carry. `organization_id`, `project_id`
520
+ * and `task_id` are injected into the body; `user_id` rides the credential and
521
+ * `conversation_id` the path or an explicit body field — never injected.
522
+ */
523
+ interface MatrxCallScope {
524
+ user_id?: string;
525
+ organization_id?: string;
526
+ project_id?: string;
527
+ task_id?: string;
528
+ conversation_id?: string;
529
+ }
530
+ interface MatrxCallResult<T = unknown> {
531
+ /** Parsed JSON response body (non-streaming calls only). */
532
+ data?: T;
533
+ /** Server-assigned request id (response header). */
534
+ requestId?: string;
535
+ /** Server-assigned conversation id (response header). */
536
+ conversationId?: string;
537
+ /** Set when the call failed with an HTTP error response. */
538
+ error?: MatrxCallError;
539
+ }
540
+ type MatrxQueryParams = Record<string, string | number | boolean>;
541
+ /**
542
+ * The full URL for one call: `{param}` segments substituted (encoded), the
543
+ * legacy `/api` prefix stripped (server routes no longer live under it), and
544
+ * the query appended.
545
+ */
546
+ declare function buildMatrxRequestUrl(baseUrl: string, pathTemplate: string, pathParams?: Record<string, string>, queryParams?: MatrxQueryParams): string;
547
+ /**
548
+ * Client capability flags that must never reach the server — the server's
549
+ * request schemas reject them.
550
+ */
551
+ declare const MATRX_UI_ONLY_BODY_FIELDS: ReadonlySet<string>;
552
+ /**
553
+ * The final request body: UI-only fields stripped, scope fields injected.
554
+ *
555
+ * A caller's `organization_id: null` (or blank) means "I have none of my own",
556
+ * never "send this for a different organization" — it is dropped and the
557
+ * scope's organization injected. A real value that disagrees with the scope
558
+ * is refused (`organization_context_mismatch`). With no scope organization
559
+ * (the org-less guest lane, an org-free read) nothing is injected for it.
560
+ * Other scope fields keep caller-wins behaviour.
561
+ */
562
+ declare function buildMatrxRequestBody(body: unknown, scope: MatrxCallScope): Record<string, unknown>;
563
+ /** True when a candidate sentence is really just the status line wearing words. */
564
+ declare function isBareTransportCode(text: string | null | undefined): boolean;
565
+ /**
566
+ * A BARE STATUS CODE IS NEVER A SENTENCE. What a person reads when the server
567
+ * answered an error with no readable message. The status itself rides
568
+ * `error.status`, which is what code branches on — this is only the words.
569
+ */
570
+ declare function bareStatusSentence(status: number): string;
571
+ /** `raw` unless it is empty or only a status line; then the status sentence. */
572
+ declare function honestTransportMessage(raw: string, status: number | undefined): string;
573
+ /** Request metadata safe to log: secret headers redacted, the body as its shape only. */
574
+ declare function buildSafeRequestLog(headers: Record<string, string>, body: unknown): {
575
+ headers: Record<string, string>;
576
+ body: Record<string, unknown>;
577
+ };
578
+ /** The URL with every query value redacted. */
579
+ declare function redactUrlForRequestLog(url: string): string;
580
+ /** False only for an HTTP status the call site declared an expected outcome. */
581
+ declare function shouldReportMatrxCallError(status: number | null | undefined, expectedErrorStatuses: readonly number[] | undefined): boolean;
582
+ interface MatrxStreamIds {
583
+ requestId: string | null;
584
+ conversationId: string | null;
585
+ }
586
+ interface MatrxStreamParse<E = MatrxStreamEnvelope> extends MatrxStreamIds {
587
+ events: AsyncGenerator<E, void, undefined>;
588
+ }
589
+ interface ParseMatrxNdjsonResponseHooks {
590
+ /** Every envelope, before the consumer sees it. */
591
+ onEvent?: (event: MatrxStreamEnvelope, ids: MatrxStreamIds) => void;
592
+ /** A broken body reader, already classified, before it is thrown. */
593
+ onTransportError?: (error: BackendApiError, ids: MatrxStreamIds) => void;
594
+ onMalformedLine?: (issue: MatrxNdjsonIssue) => void;
595
+ onUnknownEnvelope?: (value: unknown) => void;
596
+ }
597
+ /**
598
+ * A Matrx NDJSON response as typed envelopes. The ids come from headers, so
599
+ * they are available before any event. A body that breaks mid-run is a
600
+ * TRANSPORT loss (the run may still finish server-side and is reattachable) —
601
+ * thrown as `StreamTransportError`, never a failed run; an abort ends quietly.
602
+ */
603
+ declare function parseMatrxNdjsonResponse(response: Response, signal?: AbortSignal, hooks?: ParseMatrxNdjsonResponseHooks): MatrxStreamParse;
604
+ interface ExecuteMatrxCallRequest<E = MatrxStreamEnvelope> {
605
+ /** The final URL (`buildMatrxRequestUrl`). */
606
+ url: string;
607
+ method: string;
608
+ /** Every header the host binds (credential, organization, Content-Type). */
609
+ headers: Record<string, string>;
610
+ /** The assembled body (`buildMatrxRequestBody`); never sent on GET/HEAD. */
611
+ body: unknown;
612
+ /** NDJSON streaming call. */
613
+ stream?: boolean;
614
+ signal?: AbortSignal;
615
+ /** Time to response headers. Default 15_000. */
616
+ connectTimeoutMs?: number;
617
+ /** Whole-request cap for JSON calls. Default 30_000; `null` uncaps. Streams are uncapped. */
618
+ totalTimeoutMs?: number | null;
619
+ /** Fires when headers arrive, before any event. */
620
+ onStreamStart?: (requestId: string | null, conversationId: string | null) => void;
621
+ onStreamEvent?: (event: E) => void;
622
+ /**
623
+ * Take ownership of the body instead of the executor draining it (a body is
624
+ * consumed once). `onStreamEvent` is then not called; start / complete /
625
+ * error still fire.
626
+ */
627
+ consumeStream?: (response: Response, ids: MatrxStreamIds) => Promise<void>;
628
+ onStreamComplete?: (requestId: string | null, conversationId: string | null) => void;
629
+ /** Fires for an HTTP error response on a stream (thrown failures are the caller's). */
630
+ onStreamError?: (error: MatrxCallError) => void;
631
+ }
632
+ interface ExecuteMatrxCallHooks<E = MatrxStreamEnvelope> {
633
+ /** Every v2 → v1 protocol downgrade. */
634
+ onProtocolDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;
635
+ /** The host's stream parser (default `parseMatrxNdjsonResponse`). */
636
+ parseStream?: (response: Response, signal?: AbortSignal) => MatrxStreamParse<E>;
637
+ }
638
+ /**
639
+ * Execute one call over the v2 → v1 protocol fallback. An HTTP error
640
+ * response resolves as `{ error }`; a thrown failure (network, timeout,
641
+ * abort, a broken stream) propagates — the caller normalizes it with
642
+ * `normalizeMatrxError` and decides what to capture.
643
+ */
644
+ declare function executeMatrxCall<T = unknown, E = MatrxStreamEnvelope>(request: ExecuteMatrxCallRequest<E>, hooks?: ExecuteMatrxCallHooks<E>): Promise<MatrxCallResult<T>>;
645
+
276
646
  /**
277
647
  * The fail-closed organization-context kernel — ONE implementation for every
278
648
  * Matrx client transport (moved in from matrx-frontend
@@ -758,211 +1128,6 @@ declare function listUserPendingToolCalls(transport: MatrxTransport, options?: {
758
1128
  signal?: AbortSignal;
759
1129
  }): Promise<MatrxPendingCallSummary[]>;
760
1130
 
761
- /**
762
- * `@ai-matrx/agents/matrx` — the AI Matrx server's error model, as every
763
- * client reads it: `BackendApiError` (the server's `APIError` body),
764
- * `StreamTransportError` (the socket died mid-run; the run may still finish
765
- * and is reattachable), parsing of HTTP / stream / persisted errors, and the
766
- * ONE sentence a person sees (`getUserMessage`, `describeBackendFailure`).
767
- *
768
- * Moved from matrx-frontend `lib/api/errors.ts` (chat-package independence
769
- * P9); the app re-exports it from here. Pure: no host, no window, no env.
770
- */
771
- /**
772
- * Standardized error shape returned by all backend endpoints.
773
- * Matches the Python `APIError` Pydantic model.
774
- */
775
- interface BackendApiErrorData {
776
- /** Machine-readable error code (e.g. "auth_required", "validation_error") */
777
- error: string;
778
- /** Developer-facing detail for debugging */
779
- message: string;
780
- /** Safe to display directly in the UI */
781
- user_message: string;
782
- /** Extra info (validation errors, etc.) */
783
- details: unknown | null;
784
- /** Unique request ID for support/debugging */
785
- request_id: string;
786
- }
787
- /** Common backend error codes */
788
- type BackendErrorCode = "auth_required" | "token_required" | "admin_required" | "validation_error" | "not_found" | "internal_error" | "agent_error"
789
- /** The stream socket died mid-run; the server run may still be completing
790
- * and is reattachable. See `StreamTransportError`. */
791
- | "stream_transport_lost" | (string & {});
792
- /**
793
- * Typed error thrown by all backend API operations.
794
- * Contains structured fields matching the Python APIError model.
795
- *
796
- * Usage:
797
- * ```typescript
798
- * try {
799
- * await client.post(ENDPOINTS.ai.agentStart(agentId), body);
800
- * } catch (err) {
801
- * if (err instanceof BackendApiError) {
802
- * // Show err.userMessage to the user
803
- * // Log err.requestId for debugging
804
- * // Check err.code for programmatic handling
805
- * }
806
- * }
807
- * ```
808
- */
809
- declare class BackendApiError extends Error {
810
- /** Machine-readable error code */
811
- readonly code: BackendErrorCode;
812
- /** Developer-facing detail */
813
- readonly detail: string;
814
- /** Safe to display directly in the UI */
815
- readonly userMessage: string;
816
- /** Extra info (validation errors, etc.) */
817
- readonly details: unknown | null;
818
- /** Unique request ID for support/debugging */
819
- readonly requestId: string;
820
- /** HTTP status code (if from an HTTP response) */
821
- readonly status: number | null;
822
- constructor(data: {
823
- code: BackendErrorCode;
824
- detail: string;
825
- userMessage: string;
826
- details?: unknown | null;
827
- requestId?: string | undefined;
828
- status?: number | null | undefined;
829
- });
830
- /** Convert to the wire format for logging */
831
- toJSON(): BackendApiErrorData;
832
- }
833
- /**
834
- * The socket carrying a live NDJSON stream broke mid-run.
835
- *
836
- * THE DISTINCTION THIS EXISTS TO MAKE: a backend that blows up mid-stream does
837
- * NOT break the socket — it emits a typed `error` event and closes the body
838
- * cleanly. So an exception escaping the body reader means the *transport* died,
839
- * not the run. And aidream streams run `detach_on_disconnect=True`: the server
840
- * keeps executing and persisting the turn after our connection goes away.
841
- *
842
- * The client therefore cannot decide locally whether the answer is lost — it
843
- * must ASK THE SERVER. That is what `resumable` means here: "reattach by
844
- * requestId / conversationId / durable run id and let server truth settle it",
845
- * never "this succeeded". A server that genuinely died reports `failed` on
846
- * reattach and the honest record replaces the optimistic copy.
847
- *
848
- * Consumers: `run-ai-stream.ts` (chat → `reconnectServerOperation`) and
849
- * `adopt-foreign-stream.ts` (pipeline runs → the surface's own rejoin).
850
- */
851
- declare class StreamTransportError extends BackendApiError {
852
- /** Always true — reattach and let the server settle the outcome. */
853
- readonly resumable: true;
854
- constructor(data: {
855
- detail: string;
856
- details?: unknown | null;
857
- requestId?: string;
858
- });
859
- }
860
- /**
861
- * True when a failure is a dropped transport rather than a failed run. Use this
862
- * instead of `instanceof` at boundaries that re-wrap errors (thunk rejections,
863
- * `callApi` result errors), where the class identity is lost but the code
864
- * survives.
865
- */
866
- declare function isStreamTransportLost(error: unknown): boolean;
867
- /**
868
- * Parse a non-OK HTTP response into a BackendApiError.
869
- *
870
- * Handles the standardized backend shape and falls back gracefully
871
- * when the response isn't JSON or uses a legacy format.
872
- */
873
- declare function parseHttpError(response: Response): Promise<BackendApiError>;
874
- /**
875
- * Parse an already-decoded JSON error body into a BackendApiError.
876
- *
877
- * Exported because XHR callers (upload/download progress paths) have the
878
- * parsed body in hand and MUST NOT hand-roll a shallower read: a private
879
- * copy in `python-client.ts` looked only at top-level `error`/`message`, so
880
- * FastAPI's `{"detail": {...}}` envelope — what every matrx-files 500 uses —
881
- * degraded to the useless `code: "internal", detail: "HTTP 500"`. That is
882
- * exactly how an upload failure with a real server-side cause reached the
883
- * user as `Upload failed (500)` and nothing else. One parser, every transport.
884
- */
885
- declare function parseHttpErrorBody(body: Record<string, unknown> | null, status: number): BackendApiError;
886
- /**
887
- * Adapt callApi's result-style error into the same canonical error used by
888
- * direct fetch and streaming consumers.
889
- *
890
- * callApi intentionally returns errors instead of throwing them, but its
891
- * `serverDetail` contains the complete FastAPI body. Sending only
892
- * `error.message` to a feature discards that body and turns a precise
893
- * configuration failure into "HTTP 422". This adapter keeps one parser and
894
- * one human-facing explanation path across both client styles.
895
- */
896
- declare function parseCallApiError(error: {
897
- message: string;
898
- status?: number;
899
- serverDetail?: unknown;
900
- }): BackendApiError;
901
- /**
902
- * Parse streaming error event data into a BackendApiError.
903
- *
904
- * Handles both new format (`user_message`) and legacy (`user_visible_message`).
905
- */
906
- declare function parseStreamError(data: unknown): BackendApiError;
907
- /**
908
- * Restore the canonical error shape from a durable backend run row.
909
- *
910
- * Provider ledgers often keep an aggregate summary plus a more specific first
911
- * child failure. Prefer that child so a page refresh does not turn a precise
912
- * streamed failure back into "1 request failed".
913
- */
914
- declare function parsePersistedBackendError(data: unknown, requestId?: string): BackendApiError | null;
915
- /** True when a message tells the reader nothing about what actually broke. */
916
- declare function isGenericUserMessage(message: string | null | undefined): boolean;
917
- interface UpstreamErrorPayload {
918
- message: string;
919
- code: string | null;
920
- userMessage: string | null;
921
- requestId: string | null;
922
- status: number | null;
923
- }
924
- /**
925
- * Recover an upstream service's structured error that a downstream service
926
- * stringified into its own message.
927
- *
928
- * Real example (scraper wrapping aidream):
929
- * `aidream could not resolve GSC credential 7223…: HTTP 409 {"error":"conflict",
930
- * "message":"Google connection 7223… has no vault credential — it needs
931
- * re-authentication","user_message":"Something went wrong…","request_id":"9002…"}`
932
- *
933
- * Without this, the only actionable sentence on the whole hop is invisible.
934
- */
935
- declare function unwrapUpstreamError(message: string): UpstreamErrorPayload | null;
936
- interface BackendFailureExplanation {
937
- /** Machine code from the deepest layer that classified the failure. */
938
- code: string;
939
- /** The most specific human-readable cause available — never a template. */
940
- cause: string;
941
- /** What to headline in the UI: the cause when the server was generic. */
942
- headline: string;
943
- /** True when every user-facing message the server sent was a template. */
944
- headlineWasGeneric: boolean;
945
- /** Message chain, outermost (closest service) first. */
946
- chain: string[];
947
- /** Deepest request id available, for cross-service log correlation. */
948
- requestId: string;
949
- status: number | null;
950
- }
951
- /**
952
- * THE anti-secrecy primitive: turn any thrown backend/stream failure into the
953
- * most specific explanation the payload can support — unwrapping every nested
954
- * upstream error and refusing to let a templated `user_message` be the answer.
955
- *
956
- * Every surface that reports a backend failure to a human should headline
957
- * `explanation.headline` and always keep `cause` + `requestId` reachable.
958
- */
959
- declare function describeBackendFailure(error: unknown): BackendFailureExplanation;
960
- /**
961
- * Extract a user-visible message from any error object.
962
- * Utility for components that just need the display string.
963
- */
964
- declare function getUserMessage(error: unknown): string;
965
-
966
1131
  /**
967
1132
  * `@ai-matrx/agents/matrx` — every AI Matrx server endpoint path, by feature
968
1133
  * area (matching the server's router structure). Paths only, rooted at the
@@ -1664,4 +1829,4 @@ interface WarmAgentOptions extends WarmOptions {
1664
1829
  */
1665
1830
  declare function warmAgent(agentId: string, { baseUrl, isVersion, onError }: WarmAgentOptions): void;
1666
1831
 
1667
- export { type ApiTargetLogContext, BackendApiError, type BackendApiErrorData, type BackendErrorCode, type BackendFailureExplanation, type CreateMatrxTransportOptions, ENDPOINTS, type EndpointOverrideConfig, FollowRuntimeOperationToEndOptions, type FollowUnavailableRejoinOptions, MATRX_AI_API_VERSION_DEFAULT, MATRX_LIVE_STREAM_UNAVAILABLE, MATRX_RESUME_CONFLICT, MATRX_RUN_IN_PROGRESS, type MatrxAiApiVersion, MatrxApiError, type MatrxCallError, type MatrxClientSessionProvider, type MatrxClientToolResult, type MatrxFollowedOutcome, type MatrxHttpErrorLike, MatrxJsonObject, MatrxJsonValue, type MatrxLiveRunRejoin, type MatrxLiveStreamUnavailable, type MatrxPendingCallSummary, type MatrxProtocolDowngrade, type MatrxProtocolFallbackOptions, type MatrxRequestInfo, MatrxRunHandle, type MatrxRunPickup, type MatrxRunPickupSettlement, MatrxRuntimeExecutionStatus, MatrxRuntimeOperationEvent, MatrxStreamCallOptions, type MatrxToolResultsResponse, MatrxTransport, type MatrxTransportDiagnostics, type MatrxTransportTarget, OrganizationContextError, type OrganizationContextErrorCode, type OrganizationOperation, type ProviderSessionFailure, type ProviderSessionFailureVerdict, RUN_OUTPUT_KINDS, RUN_STREAM_LIFETIME_BACKSTOP_MS, RUN_WAIT_KNOB_FEATURE, type ResumeOrRejoinOptions, type ResumeOrRejoinOutcome, type RunOutputKind, type RunWait, type RunWaitKnobReader, type SettleRunPickupOptions, StreamTransportError, type UpstreamErrorPayload, V2_COVERED_AI_PATH_TEMPLATES, aiVersionPathOverrides, applyAiApiVersion, applyDesktopTargetToRequestBody, applyOrganizationContextHeader, assertOrganizationMatchesOperation, assertQueryOrganizationMatchesContext, createMatrxTransport, createOrganizationOperation, describeBackendFailure, fetchWithMatrxProtocolFallback, followUnavailableRejoin, followWorkflowRunEvents, getUserMessage, isCoveredAiPath, isGenericUserMessage, isJobOutputKind, isLiveStreamUnavailable, isResumeConflict, isStreamTransportLost, isV2Path, listConversationPendingToolCalls, listUserPendingToolCalls, logApiTarget, normalizeMatrxError, openMatrxStream, parseCallApiError, parseHttpError, parseHttpErrorBody, parsePersistedBackendError, parseStreamError, providerSessionFailureBody, readConversationOrganizationId, readLiveRunRejoin, readLiveRunRequestId, readLiveStreamUnavailable, readMatrxErrorCode, readMatrxErrorCodeFromMessage, reportProviderSessionFailure, requireOrganizationContext, resolveEndpointPath, resolveRunWaitWith, resumeOrRejoin, runJobLabel, runOutputKindFromModalities, runWaitKnobKey, runWaitTimeoutMessage, runtimeOperationRejoinPath, settleRunPickup, streamErrorText, submitAgentToolResults, toV1FallbackUrl, toV2Path, unwrapUpstreamError, warmAgent, withRunOrganization };
1832
+ export { type ApiTargetLogContext, BackendApiError, type BackendApiErrorData, type BackendErrorCode, type BackendFailureExplanation, type CreateMatrxTransportOptions, ENDPOINTS, type EndpointOverrideConfig, type ExecuteMatrxCallHooks, type ExecuteMatrxCallRequest, FollowRuntimeOperationToEndOptions, type FollowUnavailableRejoinOptions, MATRX_AI_API_VERSION_DEFAULT, MATRX_LIVE_STREAM_UNAVAILABLE, MATRX_RESUME_CONFLICT, MATRX_RUN_IN_PROGRESS, MATRX_UI_ONLY_BODY_FIELDS, type MatrxAiApiVersion, MatrxApiError, type MatrxCallError, type MatrxCallResult, type MatrxCallScope, type MatrxClientSessionProvider, type MatrxClientToolResult, type MatrxFollowedOutcome, type MatrxHttpErrorLike, type MatrxHttpMethod, MatrxJsonObject, MatrxJsonValue, type MatrxLiveRunRejoin, type MatrxLiveStreamUnavailable, type MatrxPendingCallSummary, type MatrxProtocolDowngrade, type MatrxProtocolFallbackOptions, type MatrxQueryParams, type MatrxRequestInfo, MatrxRunHandle, type MatrxRunPickup, type MatrxRunPickupSettlement, MatrxRuntimeExecutionStatus, MatrxRuntimeOperationEvent, MatrxStreamCallOptions, type MatrxStreamIds, type MatrxStreamParse, type MatrxToolResultsResponse, MatrxTransport, type MatrxTransportDiagnostics, type MatrxTransportTarget, OrganizationContextError, type OrganizationContextErrorCode, type OrganizationOperation, type ParseMatrxNdjsonResponseHooks, type ProviderSessionFailure, type ProviderSessionFailureVerdict, RUN_OUTPUT_KINDS, RUN_STREAM_LIFETIME_BACKSTOP_MS, RUN_WAIT_KNOB_FEATURE, type ResumeOrRejoinOptions, type ResumeOrRejoinOutcome, type RunOutputKind, type RunWait, type RunWaitKnobReader, type SettleRunPickupOptions, StreamTransportError, type UpstreamErrorPayload, V2_COVERED_AI_PATH_TEMPLATES, aiVersionPathOverrides, applyAiApiVersion, applyDesktopTargetToRequestBody, applyOrganizationContextHeader, assertOrganizationMatchesOperation, assertQueryOrganizationMatchesContext, bareStatusSentence, buildMatrxRequestBody, buildMatrxRequestUrl, buildSafeRequestLog, createMatrxTransport, createOrganizationOperation, describeBackendFailure, executeMatrxCall, fetchWithMatrxProtocolFallback, followUnavailableRejoin, followWorkflowRunEvents, getUserMessage, honestTransportMessage, isBareTransportCode, isCoveredAiPath, isGenericUserMessage, isJobOutputKind, isLiveStreamUnavailable, isResumeConflict, isStreamTransportLost, isV2Path, listConversationPendingToolCalls, listUserPendingToolCalls, logApiTarget, normalizeMatrxError, openMatrxStream, parseCallApiError, parseHttpError, parseHttpErrorBody, parseMatrxNdjsonResponse, parsePersistedBackendError, parseStreamError, providerSessionFailureBody, readConversationOrganizationId, readLiveRunRejoin, readLiveRunRequestId, readLiveStreamUnavailable, readMatrxErrorCode, readMatrxErrorCodeFromMessage, redactUrlForRequestLog, reportProviderSessionFailure, requireOrganizationContext, resolveEndpointPath, resolveRunWaitWith, resumeOrRejoin, runJobLabel, runOutputKindFromModalities, runWaitKnobKey, runWaitTimeoutMessage, runtimeOperationRejoinPath, settleRunPickup, shouldReportMatrxCallError, streamErrorText, submitAgentToolResults, toV1FallbackUrl, toV2Path, unwrapUpstreamError, warmAgent, withRunOrganization };