@ai-matrx/agents 0.38.1 → 0.38.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.js.map +1 -1
- package/dist/content-transfer/react/index.cjs.map +1 -1
- package/dist/content-transfer/react/index.js.map +1 -1
- package/dist/generated/api-types.cjs.map +1 -1
- package/dist/generated/api-types.d.cts +4 -4
- package/dist/generated/api-types.d.ts +4 -4
- package/dist/index.cjs +19 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +19 -18
- package/dist/index.js.map +1 -1
- package/dist/{keys.generated-DNRbtHNx.d.cts → keys.generated-BdQt09qH.d.cts} +4 -4
- package/dist/{keys.generated-DNRbtHNx.d.ts → keys.generated-BdQt09qH.d.ts} +4 -4
- package/dist/mandates/index.cjs +2 -2
- package/dist/mandates/index.cjs.map +1 -1
- package/dist/mandates/index.d.cts +2 -2
- package/dist/mandates/index.d.ts +2 -2
- package/dist/mandates/index.js +2 -2
- package/dist/mandates/index.js.map +1 -1
- package/dist/matrx/index.cjs +19 -18
- package/dist/matrx/index.cjs.map +1 -1
- package/dist/matrx/index.d.cts +1 -1
- package/dist/matrx/index.d.ts +1 -1
- package/dist/matrx/index.js +19 -18
- package/dist/matrx/index.js.map +1 -1
- package/dist/portable/mcp.cjs.map +1 -1
- package/dist/portable/mcp.js.map +1 -1
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.js.map +1 -1
- package/generated/api-types.ts +4 -4
- package/mandates/snapshots/keys.0.38.2.json +653 -0
- package/mandates/snapshots/keys.0.38.3.json +653 -0
- package/package.json +3 -3
package/dist/matrx/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../matrx/transport.ts","../../matrx/client.ts","../../matrx/backend-errors.ts","../../stream/ndjson.ts","../../matrx/org-context.ts","../../matrx/protocol.ts","../../matrx/call.ts","../../matrx/conversation.ts","../../matrx/internal.ts","../../stream/sse.ts","../../matrx/operations.ts","../../matrx/rejoin.ts","../../matrx/run.ts","../../matrx/provider-failures.ts","../../matrx/tools.ts","../../matrx/endpoints.ts","../../matrx/endpoint-path.ts","../../matrx/api-target-log.ts","../../matrx/desktop-target.ts","../../matrx/run-wait.ts","../../matrx/warm.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/matrx` — the Matrx transport port.\n *\n * The ONE seam between this package's wire semantics and a host's connection\n * policy. This package owns WHAT is said to the AI Matrx server — paths,\n * methods, JSON bodies, streaming Accept headers, the `Last-Event-ID` cursor\n * header — and the host owns HOW the connection is made:\n *\n * - base-URL / backend-channel resolution (global, sandbox override, local\n * engine, EC2-dedicated — whatever ladder the host runs);\n * - credentials (Supabase JWT `Authorization: Bearer`, guest\n * `X-Fingerprint-ID`, or the API-key lane) — NEVER implemented here;\n * - the `X-Organization-Id` context header;\n * - retry policy, network-level timeouts, and diagnostics capture.\n *\n * A host implements the port in a few lines:\n *\n * ```ts\n * const transport: MatrxTransport = {\n * fetch: (path, init) =>\n * fetch(`${baseUrl}${path}`, {\n * ...init,\n * headers: { ...init.headers, ...authHeaders() },\n * }),\n * };\n * ```\n *\n * The port is deliberately structural and `fetch`-shaped so `@ai-matrx/data`'s\n * `/api` transport can implement it without importing this package.\n */\n\n/**\n * The request this package hands the port. A strict subset of `RequestInit`,\n * so a host can spread it straight into `fetch`.\n */\nexport interface MatrxTransportRequest {\n method: \"GET\" | \"POST\";\n /**\n * Wire-semantic headers the CALL requires (`Content-Type`, `Accept`,\n * `Last-Event-ID`). The host merges its policy headers (auth, org) on top;\n * it must not drop these.\n */\n headers: Record<string, string>;\n /** Pre-serialized JSON body, present on POST calls that carry one. */\n body?: string;\n /** Caller cancellation. The host must wire it to the underlying fetch. */\n signal?: AbortSignal;\n}\n\n/**\n * The transport port. `path` is server-relative and always starts with `/`\n * (`/ai/...`, `/runtime/...`); the host prepends its resolved base URL.\n */\nexport interface MatrxTransport {\n fetch(path: string, init: MatrxTransportRequest): Promise<Response>;\n}\n\n/**\n * A non-2xx response from the Matrx API, with the server's structured error\n * body preserved and its richest human-readable message extracted.\n */\nexport class MatrxApiError extends Error {\n override readonly name = \"MatrxApiError\";\n /** HTTP status of the failed response. */\n readonly status: number;\n /** Machine code from the server body (`code`, or `detail.code`), when present. */\n readonly code: string | null;\n /** The parsed server error body, verbatim (undefined when unparsable). */\n readonly serverDetail: unknown;\n /** The request path the failure came from (server-relative). */\n readonly path: string;\n\n constructor(args: {\n status: number;\n path: string;\n serverDetail?: unknown;\n message?: string;\n }) {\n super(\n args.message ??\n extractMatrxErrorMessage(args.serverDetail) ??\n `HTTP ${args.status}`,\n );\n this.status = args.status;\n this.path = args.path;\n this.serverDetail = args.serverDetail;\n this.code = extractMatrxErrorCode(args.serverDetail);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction nonBlankString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\n/**\n * Extract the richest human-readable message from a Matrx/FastAPI error body.\n *\n * aidream 4xx validation errors look like\n * `{ error, user_message, details: [{ field, message, help }] }`; hand-raised\n * HTTPExceptions carry `{ detail: { code, message } }`; FastAPI's defaults are\n * `{ detail: string | [{ msg }] }`. Preference order: `user_message` →\n * `message` → joined `details[].message` → `detail.message` →\n * `detail` string → joined `detail[].msg`. Returns undefined for\n * unrecognized bodies so callers fall back to the bare status line.\n */\nexport function extractMatrxErrorMessage(\n serverDetail: unknown,\n): string | undefined {\n if (!isRecord(serverDetail)) return undefined;\n\n const userMessage = nonBlankString(serverDetail.user_message);\n if (userMessage) return userMessage;\n const message = nonBlankString(serverDetail.message);\n if (message) return message;\n\n if (Array.isArray(serverDetail.details)) {\n const messages = serverDetail.details\n .map((entry: unknown) => {\n if (!isRecord(entry)) return undefined;\n const detailMessage = nonBlankString(entry.message);\n if (!detailMessage) return undefined;\n const field = nonBlankString(entry.field);\n return field ? `${field}: ${detailMessage}` : detailMessage;\n })\n .filter((m): m is string => typeof m === \"string\");\n if (messages.length > 0) return messages.join(\"; \");\n }\n\n const detail = serverDetail.detail;\n if (isRecord(detail)) {\n const detailMessage =\n nonBlankString(detail.message) ?? nonBlankString(detail.user_message);\n if (detailMessage) return detailMessage;\n }\n if (typeof detail === \"string\" && detail.trim()) return detail;\n if (Array.isArray(detail)) {\n const messages = detail\n .map((entry: unknown) =>\n isRecord(entry) ? nonBlankString(entry.msg) : undefined,\n )\n .filter((m): m is string => typeof m === \"string\");\n if (messages.length > 0) return messages.join(\"; \");\n }\n return undefined;\n}\n\n/**\n * Extract the machine error code from a Matrx error body: top-level `code`,\n * else `detail.code` (the hand-raised HTTPException shape). Null when absent.\n */\nexport function extractMatrxErrorCode(serverDetail: unknown): string | null {\n if (!isRecord(serverDetail)) return null;\n const topLevel = nonBlankString(serverDetail.code);\n if (topLevel) return topLevel;\n const detail = serverDetail.detail;\n if (isRecord(detail)) {\n const nested = nonBlankString(detail.code);\n if (nested) return nested;\n }\n return null;\n}\n","/**\n * The PRODUCTION `MatrxTransport` — the full connection pipeline every Matrx\n * host used to hand-roll, moved in under C22 (THE HARD PARTS LIVE IN THE\n * PACKAGE). A host constructs it from identity alone:\n *\n * ```ts\n * const transport = createMatrxTransport({\n * baseUrl: \"https://server.app.matrxserver.com\",\n * credentials, // CredentialsPort (@ai-matrx/data)\n * organizationId: () => activeOrgId, // omit for conversation-lane calls\n * });\n * ```\n *\n * Everything else is defaulted to the proven production values:\n *\n * - **timeouts** — connect 15s (for a non-streaming FastAPI handler this is\n * effectively time-to-response), total UNCAPPED (the port cannot tell a JSON\n * call from a long-lived NDJSON/SSE stream; the connect timeout is the JSON\n * guard), via `@ai-matrx/data/net`'s `resilientFetch`;\n * - **protocol** — the AI API version transform (`applyAiApiVersion`, default\n * v2) + the loud v2 → v1 transport fallback (`./protocol`);\n * - **credentials** — read fresh from the injected `CredentialsPort` on EVERY\n * call, so a token refresh mid-run is picked up; mapped to headers by the\n * ONE `credentialToHeaders`;\n * - **org context** — the fail-closed `X-Organization-Id` binding\n * (`./org-context`): configured lanes REQUIRE an org and refuse before the\n * wire; unconfigured lanes (conversation-scoped calls, which carry org in\n * the body) send none;\n * - **error classification** — every failure normalizes through\n * `normalizeMatrxError` into the ONE `MatrxCallError` envelope;\n * - **diagnostics** — a typed sink the host wires to its capture/telemetry\n * (`onRequest`, `onError`, `onProtocolDowngrade`); wiring it is optional,\n * the transport works silently without it.\n *\n * Header merge order is part of the port contract: wire headers first\n * (`Content-Type` / `Accept` / `Last-Event-ID` — the package's), then\n * credentials, then resolver policy headers, then the org header. Policy\n * headers never carry `Content-Type` — the wire owns it, and a policy\n * `Content-Type` merged over a GET SSE call would corrupt the wire, so the\n * factory strips it defensively.\n */\n\nimport { isNetError, type CredentialsPort } from \"@ai-matrx/data\";\nimport { credentialToHeaders } from \"@ai-matrx/data\";\nimport { extractErrorMessage } from \"@ai-matrx/data/net\";\nimport { BackendApiError } from \"./backend-errors\";\nimport {\n bareStatusSentence,\n honestTransportMessage,\n isBareTransportCode,\n} from \"./call\";\nimport {\n applyOrganizationContextHeader,\n OrganizationContextError,\n requireOrganizationContext,\n} from \"./org-context\";\nimport {\n applyAiApiVersion,\n fetchWithMatrxProtocolFallback,\n MATRX_AI_API_VERSION_DEFAULT,\n type MatrxAiApiVersion,\n type MatrxProtocolDowngrade,\n} from \"./protocol\";\nimport {\n extractMatrxErrorCode,\n extractMatrxErrorMessage,\n MatrxApiError,\n type MatrxTransport,\n type MatrxTransportRequest,\n} from \"./transport\";\n\n// ─── The normalized error envelope ──────────────────────────────────────────\n\n/**\n * The ONE classified error shape for Matrx client calls — the envelope hosts\n * branch on instead of string-matching exceptions. Structurally compatible\n * with matrx-frontend's `ApiCallError` by design.\n */\nexport interface MatrxCallError {\n type:\n | \"auth_error\"\n | \"network_error\"\n | \"http_error\"\n | \"validation_error\"\n | \"abort_error\"\n | \"unknown\";\n message: string;\n /** HTTP status code, if applicable. */\n status?: number;\n /** Raw error detail from the server (the parsed error body). */\n serverDetail?: unknown;\n /** Machine code preserved through normalization (server `code`, org-context code, …). */\n code?: string;\n /** Original exception identity for diagnostics. */\n name?: string;\n /** Original exception stack. */\n stack?: string;\n /** JSON-safe dump of the original thrown value. */\n raw?: unknown;\n}\n\nfunction classifyStatus(status: number): \"validation_error\" | \"http_error\" {\n return status >= 400 && status < 500 ? \"validation_error\" : \"http_error\";\n}\n\n/**\n * Classify any failure thrown by a Matrx client call — `MatrxApiError`, a\n * typed `BackendApiError` / `StreamTransportError`, a `NetError` from the\n * resilience layer, an org-context refusal, an abort — into the\n * `MatrxCallError` envelope. Never throws.\n *\n * Every message is laundered through `honestTransportMessage`: a bare status\n * line (\"HTTP 400\") never reaches a person — the status rides `status`.\n * A `BackendApiError` keeps its machine `code` (a dropped socket stays\n * `stream_transport_lost`, so a surface reattaches instead of dead-ending)\n * and its structured `details` ride `serverDetail` (the organization-hold\n * body carries the caller's membership choices there).\n */\nexport function normalizeMatrxError(err: unknown): MatrxCallError {\n if (err instanceof OrganizationContextError) {\n return {\n type: \"validation_error\",\n message: err.message,\n code: err.code,\n name: err.name,\n ...(err.stack !== undefined ? { stack: err.stack } : {}),\n };\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return { type: \"abort_error\", message: \"Request was cancelled.\" };\n }\n\n if (err instanceof MatrxApiError) {\n return {\n type: classifyStatus(err.status),\n message: honestTransportMessage(err.message, err.status),\n status: err.status,\n serverDetail: err.serverDetail,\n ...(err.code ? { code: err.code } : {}),\n name: err.name,\n };\n }\n\n if (err instanceof BackendApiError) {\n return {\n type: \"network_error\",\n message: honestTransportMessage(\n err.detail || err.userMessage,\n err.status ?? undefined,\n ),\n code: err.code,\n name: err.name,\n ...(err.status !== null ? { status: err.status } : {}),\n ...(err.details !== null ? { serverDetail: err.details } : {}),\n };\n }\n\n if (isNetError(err)) {\n if (err.code === \"aborted\") {\n return { type: \"abort_error\", message: err.message };\n }\n if (err.code === \"http\") {\n const status = err.status ?? 0;\n return {\n type: classifyStatus(status),\n message: honestTransportMessage(err.message, status),\n status,\n };\n }\n // connect-timeout / total-timeout / heartbeat-timeout / network / offline\n return { type: \"network_error\", message: err.message };\n }\n\n if (err instanceof Error) {\n const httpMatch = err.message.match(/HTTP (\\d+):\\s*(.*)/);\n if (httpMatch) {\n const status = parseInt(httpMatch[1] as string, 10);\n return {\n type: classifyStatus(status),\n message: honestTransportMessage(httpMatch[2] ?? err.message, status),\n status,\n };\n }\n // \"HTTP 400\" with no colon: the status line itself, never the sentence.\n if (isBareTransportCode(err.message)) {\n const status = Number.parseInt(err.message.replace(/\\D+/g, \"\"), 10);\n return {\n type: classifyStatus(status),\n message: bareStatusSentence(status),\n status,\n };\n }\n return { type: \"network_error\", message: err.message };\n }\n\n return { type: \"unknown\", message: extractErrorMessage(err) };\n}\n\n// ─── The factory ────────────────────────────────────────────────────────────\n\n/**\n * A fully-resolved connection target for one call: where to send it and which\n * policy headers ride ON TOP of the wire + credential headers.\n */\nexport interface MatrxTransportTarget {\n /** Fully-qualified base URL, no trailing slash. */\n baseUrl: string;\n /**\n * Extra policy headers for this target (e.g. a resolver that carries its own\n * credential headers). `Content-Type` is stripped — the wire owns it.\n */\n policyHeaders?: Record<string, string>;\n /** Routing channel label surfaced to `onRequest` telemetry. */\n channel?: string;\n}\n\n/** Context handed to every diagnostics callback. */\nexport interface MatrxRequestInfo {\n /** The final URL (base + version-transformed path). */\n url: string;\n method: \"GET\" | \"POST\";\n /** The server-relative path as the package requested it. */\n path: string;\n /** The resolved routing channel (default \"default\"). */\n channel: string;\n /** The transport's call-site label (default \"matrxTransport\"). */\n source: string;\n}\n\n/**\n * The typed diagnostics sink — the host wires these to its telemetry/capture\n * systems; all optional, and the transport is fully functional without them.\n */\nexport interface MatrxTransportDiagnostics {\n /** Fired at the last pre-fetch moment of every call. */\n onRequest?: (info: MatrxRequestInfo) => void;\n /**\n * Fired for every thrown network failure and every non-2xx response not\n * listed in `expectedErrorStatuses`, with the classified envelope.\n */\n onError?: (error: MatrxCallError, info: MatrxRequestInfo) => void;\n /** Fired on every v2 → v1 protocol downgrade. */\n onProtocolDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n}\n\nexport interface CreateMatrxTransportOptions {\n /** Fixed base URL, no trailing slash. Exactly one of `baseUrl` / `resolveTarget`. */\n baseUrl?: string;\n /**\n * Per-call target resolver — for hosts whose base URL / policy headers are\n * dynamic (server toggles, sandbox overrides, conversation channels).\n * Resolution runs fresh on EVERY call. May throw to refuse a call loudly.\n */\n resolveTarget?: () => MatrxTransportTarget;\n /**\n * The credential source (`@ai-matrx/data`), read fresh per call so token\n * refreshes are picked up mid-run. Omit only when the resolver's\n * `policyHeaders` already carry the credentials.\n */\n credentials?: CredentialsPort;\n /**\n * The org-context binding. When configured, every call REQUIRES a valid org\n * (fail-closed `organization_context_required` before the wire) and carries\n * `X-Organization-Id`. Omit for conversation-lane transports, which send the\n * org in the body only.\n */\n organizationId?: string | (() => string | null | undefined);\n /** AI API protocol version (value or per-call getter). Default `\"v2\"`. */\n aiApiVersion?: MatrxAiApiVersion | (() => MatrxAiApiVersion);\n /** Max ms request start → response headers. Default 15_000. */\n connectTimeoutMs?: number;\n /**\n * Max ms for the whole handshake. Default `null` (uncapped) — the port\n * cannot tell a JSON call from a long-lived stream, and capping would kill\n * long streams; the connect timeout is the real JSON guard.\n */\n totalTimeoutMs?: number | null;\n /**\n * HTTP failures this transport's call class fully handles as expected\n * domain outcomes (e.g. 404 on runtime-operation identify). They still\n * reach the package client (which maps them to typed results) but are not\n * reported through `onError`.\n */\n expectedErrorStatuses?: readonly number[];\n /** Short call-site label surfaced on `MatrxRequestInfo` (default \"matrxTransport\"). */\n source?: string;\n diagnostics?: MatrxTransportDiagnostics;\n}\n\nconst PRODUCTION_CONNECT_TIMEOUT_MS = 15_000;\n\nfunction stripContentType(\n headers: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([name]) => name.toLowerCase() !== \"content-type\",\n ),\n );\n}\n\n/**\n * Build the production `MatrxTransport`. See the module doc for the pipeline;\n * every knob defaults to the proven production value.\n */\nexport function createMatrxTransport(\n options: CreateMatrxTransportOptions,\n): MatrxTransport {\n const {\n baseUrl,\n resolveTarget,\n credentials,\n organizationId,\n aiApiVersion,\n connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,\n totalTimeoutMs = null,\n expectedErrorStatuses,\n diagnostics,\n source = \"matrxTransport\",\n } = options;\n\n if ((baseUrl === undefined) === (resolveTarget === undefined)) {\n throw new Error(\n \"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`.\",\n );\n }\n\n const resolve: () => MatrxTransportTarget =\n resolveTarget ?? (() => ({ baseUrl: baseUrl as string }));\n\n const resolveVersion = (): MatrxAiApiVersion => {\n if (aiApiVersion === undefined) return MATRX_AI_API_VERSION_DEFAULT;\n return typeof aiApiVersion === \"function\" ? aiApiVersion() : aiApiVersion;\n };\n\n const resolveOrganizationId = (): string | null => {\n if (organizationId === undefined) return null;\n const candidate =\n typeof organizationId === \"function\" ? organizationId() : organizationId;\n // Fail closed: a configured org lane with no org refuses before the wire.\n return requireOrganizationContext(candidate);\n };\n\n return {\n async fetch(path: string, init: MatrxTransportRequest): Promise<Response> {\n const target = resolve();\n\n // `path` is already interpolated (`/ai/agents/<uuid>`), so the version\n // transform is the concrete-path bridge, not a template registry.\n const versionedPath = applyAiApiVersion(path, resolveVersion());\n const url = `${target.baseUrl}${versionedPath}`;\n\n // Wire headers FIRST; credentials, then resolver policy headers, then\n // the org header on top — none of them may carry Content-Type.\n const credentialHeaders = credentials\n ? credentialToHeaders(await credentials.get())\n : {};\n let headers: Record<string, string> = {\n ...init.headers,\n ...stripContentType(credentialHeaders),\n ...stripContentType(target.policyHeaders ?? {}),\n };\n const orgId = resolveOrganizationId();\n if (orgId !== null) {\n headers = applyOrganizationContextHeader(headers, orgId);\n }\n\n const info: MatrxRequestInfo = {\n url,\n method: init.method,\n path,\n channel: target.channel ?? \"default\",\n source,\n };\n diagnostics?.onRequest?.(info);\n\n let response: Response;\n try {\n ({ response } = await fetchWithMatrxProtocolFallback(\n url,\n {\n method: init.method,\n headers,\n ...(init.body !== undefined ? { body: init.body } : {}),\n },\n {\n ...(init.signal ? { signal: init.signal } : {}),\n connectTimeoutMs,\n totalTimeoutMs,\n throwOnHttpError: false,\n ...(diagnostics?.onProtocolDowngrade\n ? { onDowngrade: diagnostics.onProtocolDowngrade }\n : {}),\n },\n ));\n } catch (err) {\n diagnostics?.onError?.(normalizeMatrxError(err), info);\n throw err;\n }\n\n if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {\n // The package client consumes the original body for its\n // MatrxApiError; read the diagnostics copy from a clone so the two\n // never fight.\n const serverDetail: unknown = await response\n .clone()\n .json()\n .catch(() => undefined);\n const code = extractMatrxErrorCode(serverDetail);\n diagnostics?.onError?.(\n {\n type: classifyStatus(response.status),\n message:\n extractMatrxErrorMessage(serverDetail) ??\n `HTTP ${response.status}`,\n status: response.status,\n serverDetail,\n ...(code ? { code } : {}),\n },\n info,\n );\n }\n\n return response;\n },\n };\n}\n","/**\n * `@ai-matrx/agents/matrx` — the AI Matrx server's error model, as every\n * client reads it: `BackendApiError` (the server's `APIError` body),\n * `StreamTransportError` (the socket died mid-run; the run may still finish\n * and is reattachable), parsing of HTTP / stream / persisted errors, and the\n * ONE sentence a person sees (`getUserMessage`, `describeBackendFailure`).\n *\n * Moved from matrx-frontend `lib/api/errors.ts` (chat-package independence\n * P9); the app re-exports it from here. Pure: no host, no window, no env.\n */\n\n/**\n * Standardized error shape returned by all backend endpoints.\n * Matches the Python `APIError` Pydantic model.\n */\nexport interface BackendApiErrorData {\n /** Machine-readable error code (e.g. \"auth_required\", \"validation_error\") */\n error: string;\n /** Developer-facing detail for debugging */\n message: string;\n /** Safe to display directly in the UI */\n user_message: string;\n /** Extra info (validation errors, etc.) */\n details: unknown | null;\n /** Unique request ID for support/debugging */\n request_id: string;\n}\n\n/** Common backend error codes */\nexport type BackendErrorCode =\n | \"auth_required\"\n | \"token_required\"\n | \"admin_required\"\n | \"validation_error\"\n | \"not_found\"\n | \"internal_error\"\n | \"agent_error\"\n /** The stream socket died mid-run; the server run may still be completing\n * and is reattachable. See `StreamTransportError`. */\n | \"stream_transport_lost\"\n | (string & {});\n\n// ============================================================================\n// ERROR CLASS\n// ============================================================================\n\n/**\n * Typed error thrown by all backend API operations.\n * Contains structured fields matching the Python APIError model.\n *\n * Usage:\n * ```typescript\n * try {\n * await client.post(ENDPOINTS.ai.agentStart(agentId), body);\n * } catch (err) {\n * if (err instanceof BackendApiError) {\n * // Show err.userMessage to the user\n * // Log err.requestId for debugging\n * // Check err.code for programmatic handling\n * }\n * }\n * ```\n */\nexport class BackendApiError extends Error {\n /** Machine-readable error code */\n readonly code: BackendErrorCode;\n /** Developer-facing detail */\n readonly detail: string;\n /** Safe to display directly in the UI */\n readonly userMessage: string;\n /** Extra info (validation errors, etc.) */\n readonly details: unknown | null;\n /** Unique request ID for support/debugging */\n readonly requestId: string;\n /** HTTP status code (if from an HTTP response) */\n readonly status: number | null;\n\n constructor(data: {\n code: BackendErrorCode;\n detail: string;\n userMessage: string;\n details?: unknown | null;\n requestId?: string | undefined;\n status?: number | null | undefined;\n }) {\n super(data.userMessage);\n this.name = \"BackendApiError\";\n this.code = data.code;\n this.detail = data.detail;\n this.userMessage = data.userMessage;\n this.details = data.details ?? null;\n // MATRX-EXCEPTION: requestId is genuinely optional (constructor param);\n // \"\" means \"no request id available\" — a display/log field, not persisted.\n this.requestId = data.requestId ?? \"\";\n this.status = data.status ?? null;\n }\n\n /** Convert to the wire format for logging */\n toJSON(): BackendApiErrorData {\n return {\n error: this.code,\n message: this.detail,\n user_message: this.userMessage,\n details: this.details,\n request_id: this.requestId,\n };\n }\n}\n\n/**\n * The socket carrying a live NDJSON stream broke mid-run.\n *\n * THE DISTINCTION THIS EXISTS TO MAKE: a backend that blows up mid-stream does\n * NOT break the socket — it emits a typed `error` event and closes the body\n * cleanly. So an exception escaping the body reader means the *transport* died,\n * not the run. And aidream streams run `detach_on_disconnect=True`: the server\n * keeps executing and persisting the turn after our connection goes away.\n *\n * The client therefore cannot decide locally whether the answer is lost — it\n * must ASK THE SERVER. That is what `resumable` means here: \"reattach by\n * requestId / conversationId / durable run id and let server truth settle it\",\n * never \"this succeeded\". A server that genuinely died reports `failed` on\n * reattach and the honest record replaces the optimistic copy.\n *\n * Consumers: `run-ai-stream.ts` (chat → `reconnectServerOperation`) and\n * `adopt-foreign-stream.ts` (pipeline runs → the surface's own rejoin).\n */\nexport class StreamTransportError extends BackendApiError {\n /** Always true — reattach and let the server settle the outcome. */\n readonly resumable = true as const;\n\n constructor(data: {\n detail: string;\n details?: unknown | null;\n requestId?: string;\n }) {\n super({\n code: \"stream_transport_lost\",\n detail: data.detail,\n userMessage:\n \"The connection dropped. Your run is still going on the server — reconnecting to it now.\",\n details: data.details ?? null,\n ...(data.requestId !== undefined ? { requestId: data.requestId } : {}),\n });\n this.name = \"StreamTransportError\";\n }\n}\n\n/**\n * True when a failure is a dropped transport rather than a failed run. Use this\n * instead of `instanceof` at boundaries that re-wrap errors (thunk rejections,\n * `callApi` result errors), where the class identity is lost but the code\n * survives.\n */\nexport function isStreamTransportLost(error: unknown): boolean {\n if (error instanceof StreamTransportError) return true;\n if (error instanceof BackendApiError) {\n return error.code === \"stream_transport_lost\";\n }\n if (error && typeof error === \"object\") {\n const code = (error as { code?: unknown }).code;\n if (code === \"stream_transport_lost\") return true;\n const errorType = (error as { error_type?: unknown }).error_type;\n if (errorType === \"transport_lost\") return true;\n }\n return false;\n}\n\n// ============================================================================\n// HTTP ERROR PARSER\n// ============================================================================\n\n/**\n * Parse a non-OK HTTP response into a BackendApiError.\n *\n * Handles the standardized backend shape and falls back gracefully\n * when the response isn't JSON or uses a legacy format.\n */\nexport async function parseHttpError(\n response: Response,\n): Promise<BackendApiError> {\n const status = response.status;\n let body: Record<string, unknown> | null = null;\n\n try {\n body = await response.json();\n } catch {\n // Not JSON — try plain text\n try {\n const text = await response.text();\n return new BackendApiError({\n code: statusToCode(status),\n detail: text || `HTTP ${status}`,\n userMessage: text || `Request failed (${status})`,\n status,\n });\n } catch {\n return new BackendApiError({\n code: statusToCode(status),\n detail: `HTTP ${status}`,\n userMessage: `Request failed (${status})`,\n status,\n });\n }\n }\n\n return parseHttpErrorBody(body, status);\n}\n\n/**\n * Parse an already-decoded JSON error body into a BackendApiError.\n *\n * Exported because XHR callers (upload/download progress paths) have the\n * parsed body in hand and MUST NOT hand-roll a shallower read: a private\n * copy in `python-client.ts` looked only at top-level `error`/`message`, so\n * FastAPI's `{\"detail\": {...}}` envelope — what every matrx-files 500 uses —\n * degraded to the useless `code: \"internal\", detail: \"HTTP 500\"`. That is\n * exactly how an upload failure with a real server-side cause reached the\n * user as `Upload failed (500)` and nothing else. One parser, every transport.\n */\nexport function parseHttpErrorBody(\n body: Record<string, unknown> | null,\n status: number,\n): BackendApiError {\n if (!body) {\n return new BackendApiError({\n code: statusToCode(status),\n detail: `HTTP ${status}`,\n userMessage: `Request failed (${status})`,\n status,\n });\n }\n // Standard backend shape: { error, message, user_message, details, request_id }\n if (typeof body.error === \"string\" && typeof body.user_message === \"string\") {\n return new BackendApiError({\n code: body.error as BackendErrorCode,\n detail: (body.message as string) || `HTTP ${status}`,\n userMessage: body.user_message as string,\n details: body.details ?? null,\n requestId:\n typeof body.request_id === \"string\" ? body.request_id : undefined,\n status,\n });\n }\n\n // Legacy: nested error object with user_visible_message\n if (typeof body.error === \"object\" && body.error !== null) {\n const errorObj = body.error as Record<string, unknown>;\n return new BackendApiError({\n code:\n (errorObj.type as string) ||\n (errorObj.error as string) ||\n statusToCode(status),\n detail: (errorObj.message as string) || `HTTP ${status}`,\n userMessage:\n (errorObj.user_message as string) ||\n (errorObj.user_visible_message as string) ||\n (errorObj.message as string) ||\n `Request failed (${status})`,\n details: errorObj.details ?? null,\n requestId:\n typeof errorObj.request_id === \"string\"\n ? errorObj.request_id\n : undefined,\n status,\n });\n }\n\n // FastAPI 422 validation shape: { detail: [{ loc, msg, type }, ...] }\n if (Array.isArray(body.detail)) {\n const first = body.detail[0] as Record<string, unknown> | undefined;\n const firstMsg = first && typeof first.msg === \"string\" ? first.msg : null;\n return new BackendApiError({\n code: statusToCode(status),\n detail: firstMsg\n ? `Validation error: ${firstMsg}`\n : JSON.stringify(body.detail),\n userMessage: firstMsg || `Request failed (${status})`,\n details: body.detail,\n status,\n });\n }\n\n // FastAPI HTTPException with structured detail: { detail: { code?, error?, message?, user_message?, ... } }\n if (\n typeof body.detail === \"object\" &&\n body.detail !== null &&\n !Array.isArray(body.detail)\n ) {\n const d = body.detail as Record<string, unknown>;\n const code =\n (typeof d.code === \"string\" && d.code) ||\n (typeof d.error === \"string\" && d.error) ||\n statusToCode(status);\n const message =\n (typeof d.message === \"string\" && d.message) ||\n (typeof d.detail === \"string\" && d.detail) ||\n `HTTP ${status}`;\n return new BackendApiError({\n code: code as BackendErrorCode,\n detail: message,\n userMessage:\n (typeof d.user_message === \"string\" && d.user_message) ||\n (typeof d.user_visible_message === \"string\" &&\n d.user_visible_message) ||\n message,\n details: d.details ?? d,\n requestId: typeof d.request_id === \"string\" ? d.request_id : undefined,\n status,\n });\n }\n\n // Legacy: flat { error: string, message: string } or { detail: string }\n return new BackendApiError({\n code: typeof body.error === \"string\" ? body.error : statusToCode(status),\n detail:\n (body.message as string) ||\n (body.detail as string) ||\n (body.error as string) ||\n `HTTP ${status}`,\n userMessage:\n (body.user_message as string) ||\n (body.user_visible_message as string) ||\n (body.message as string) ||\n (body.detail as string) ||\n `Request failed (${status})`,\n details: body.details ?? null,\n requestId:\n typeof body.request_id === \"string\" ? body.request_id : undefined,\n status,\n });\n}\n\n/**\n * Adapt callApi's result-style error into the same canonical error used by\n * direct fetch and streaming consumers.\n *\n * callApi intentionally returns errors instead of throwing them, but its\n * `serverDetail` contains the complete FastAPI body. Sending only\n * `error.message` to a feature discards that body and turns a precise\n * configuration failure into \"HTTP 422\". This adapter keeps one parser and\n * one human-facing explanation path across both client styles.\n */\nexport function parseCallApiError(error: {\n message: string;\n status?: number;\n serverDetail?: unknown;\n}): BackendApiError {\n const status = error.status ?? 500;\n const body =\n error.serverDetail &&\n typeof error.serverDetail === \"object\" &&\n !Array.isArray(error.serverDetail)\n ? (error.serverDetail as Record<string, unknown>)\n : { message: error.message };\n return parseHttpErrorBody(body, status);\n}\n\n// ============================================================================\n// STREAMING ERROR PARSER\n// ============================================================================\n\n/**\n * Parse streaming error event data into a BackendApiError.\n *\n * Handles both new format (`user_message`) and legacy (`user_visible_message`).\n */\nexport function parseStreamError(data: unknown): BackendApiError {\n if (!data || typeof data !== \"object\") {\n return new BackendApiError({\n code: \"internal_error\",\n detail: typeof data === \"string\" ? data : \"Unknown streaming error\",\n userMessage: typeof data === \"string\" ? data : \"Something went wrong\",\n });\n }\n\n const obj = data as Record<string, unknown>;\n const details =\n typeof obj.details === \"object\" && obj.details !== null\n ? (obj.details as Record<string, unknown>)\n : null;\n return new BackendApiError({\n code:\n (obj.code as string) ||\n (obj.error_type as string) ||\n (obj.error as string) ||\n \"internal_error\",\n detail: (obj.message as string) || \"Streaming error\",\n userMessage:\n (obj.user_message as string) ||\n (obj.message as string) ||\n \"Something went wrong\",\n details,\n requestId:\n typeof obj.request_id === \"string\"\n ? obj.request_id\n : typeof details?.request_id === \"string\"\n ? details.request_id\n : undefined,\n });\n}\n\n/**\n * Restore the canonical error shape from a durable backend run row.\n *\n * Provider ledgers often keep an aggregate summary plus a more specific first\n * child failure. Prefer that child so a page refresh does not turn a precise\n * streamed failure back into \"1 request failed\".\n */\nexport function parsePersistedBackendError(\n data: unknown,\n requestId = \"\",\n): BackendApiError | null {\n if (!data || typeof data !== \"object\") return null;\n const error = data as Record<string, unknown>;\n const failures = Array.isArray(error.failures) ? error.failures : [];\n const firstSpecific = failures.find(\n (failure): failure is Record<string, unknown> =>\n typeof failure === \"object\" &&\n failure !== null &&\n typeof (failure as Record<string, unknown>).message === \"string\",\n );\n const summary =\n typeof error.message === \"string\"\n ? error.message\n : \"Backend operation failed\";\n const specific =\n typeof firstSpecific?.message === \"string\"\n ? firstSpecific.message\n : summary;\n const detail = specific === summary ? summary : `${summary}: ${specific}`;\n const code = typeof error.type === \"string\" ? error.type : \"internal_error\";\n // A persisted failure may carry a human-facing line the technical detail\n // cannot express — the load-bearing case being a paid result that survived\n // its persistence failure (`WritePreservedError`, D183): \"it broke\" is true\n // and \"your work is preserved and will be recovered\" is what the user needs.\n // `describeBackendFailure` still overrides a TEMPLATED one with the cause.\n const userMessage =\n typeof error.user_message === \"string\" && error.user_message\n ? error.user_message\n : detail;\n return new BackendApiError({\n code,\n detail,\n userMessage,\n details: error,\n requestId,\n });\n}\n\n// ============================================================================\n// FAILURE EXPLANATION — never let a templated non-answer be the whole story\n// ============================================================================\n\n/**\n * Server messages that carry ZERO diagnostic value. The streaming layer\n * (`matrx-connect/streaming/response.py`) emits the first one for every\n * unclassified crash — \"CanonicalGscSync failed unexpectedly. Please try\n * again or adjust your settings.\" — while the REAL cause travels in the same\n * payload's `message`. Treating those as the answer is what makes failures\n * feel secretive.\n */\nconst GENERIC_MESSAGE_PATTERNS: readonly RegExp[] = [\n /failed unexpectedly/i,\n /^\\s*something went wrong/i,\n /please try again(\\s+later)?\\.?\\s*$/i,\n /^\\s*request failed\\b/i,\n /^\\s*unknown (streaming )?error/i,\n /^\\s*internal server error\\.?\\s*$/i,\n];\n\n/** True when a message tells the reader nothing about what actually broke. */\nexport function isGenericUserMessage(\n message: string | null | undefined,\n): boolean {\n const value = (message ?? \"\").trim();\n if (!value) return true;\n return GENERIC_MESSAGE_PATTERNS.some((pattern) => pattern.test(value));\n}\n\nexport interface UpstreamErrorPayload {\n message: string;\n code: string | null;\n userMessage: string | null;\n requestId: string | null;\n status: number | null;\n}\n\n/**\n * Recover an upstream service's structured error that a downstream service\n * stringified into its own message.\n *\n * Real example (scraper wrapping aidream):\n * `aidream could not resolve GSC credential 7223…: HTTP 409 {\"error\":\"conflict\",\n * \"message\":\"Google connection 7223… has no vault credential — it needs\n * re-authentication\",\"user_message\":\"Something went wrong…\",\"request_id\":\"9002…\"}`\n *\n * Without this, the only actionable sentence on the whole hop is invisible.\n */\nexport function unwrapUpstreamError(\n message: string,\n): UpstreamErrorPayload | null {\n const start = message.indexOf(\"{\");\n const end = message.lastIndexOf(\"}\");\n if (start < 0 || end <= start) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(message.slice(start, end + 1));\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const body = parsed as Record<string, unknown>;\n const inner =\n (typeof body.message === \"string\" && body.message) ||\n (typeof body.detail === \"string\" && body.detail) ||\n \"\";\n if (!inner) return null;\n const statusMatch = /\\bHTTP (\\d{3})\\b/.exec(message.slice(0, start));\n return {\n message: inner,\n code:\n (typeof body.error_type === \"string\" && body.error_type) ||\n (typeof body.error === \"string\" && body.error) ||\n null,\n userMessage:\n typeof body.user_message === \"string\" ? body.user_message : null,\n requestId: typeof body.request_id === \"string\" ? body.request_id : null,\n status: statusMatch ? Number(statusMatch[1]) : null,\n };\n}\n\nexport interface BackendFailureExplanation {\n /** Machine code from the deepest layer that classified the failure. */\n code: string;\n /** The most specific human-readable cause available — never a template. */\n cause: string;\n /** What to headline in the UI: the cause when the server was generic. */\n headline: string;\n /** True when every user-facing message the server sent was a template. */\n headlineWasGeneric: boolean;\n /** Message chain, outermost (closest service) first. */\n chain: string[];\n /** Deepest request id available, for cross-service log correlation. */\n requestId: string;\n status: number | null;\n}\n\n/**\n * THE anti-secrecy primitive: turn any thrown backend/stream failure into the\n * most specific explanation the payload can support — unwrapping every nested\n * upstream error and refusing to let a templated `user_message` be the answer.\n *\n * Every surface that reports a backend failure to a human should headline\n * `explanation.headline` and always keep `cause` + `requestId` reachable.\n */\nexport function describeBackendFailure(\n error: unknown,\n): BackendFailureExplanation {\n const chain: string[] = [];\n let code = \"internal_error\";\n let requestId = \"\";\n let status: number | null = null;\n let userFacing: string | null = null;\n\n if (error instanceof BackendApiError) {\n code = error.code;\n requestId = error.requestId;\n status = error.status;\n userFacing = error.userMessage;\n if (error.detail) chain.push(error.detail);\n if (error.userMessage && error.userMessage !== error.detail) {\n chain.push(error.userMessage);\n }\n } else if (error instanceof Error) {\n chain.push(error.message);\n userFacing = error.message;\n } else if (typeof error === \"string\") {\n chain.push(error);\n userFacing = error;\n } else {\n chain.push(\"Unknown error\");\n }\n\n // Walk the nesting: ANY message in the chain may have stringified the\n // service above it (the technical `detail` usually does, the templated\n // `user_message` never does), so every layer gets unwrapped.\n for (let cursor = 0; cursor < chain.length && cursor < 12; cursor += 1) {\n const upstream = unwrapUpstreamError(chain[cursor] ?? \"\");\n if (!upstream || chain.includes(upstream.message)) continue;\n chain.push(upstream.message);\n if (upstream.code) code = upstream.code;\n if (upstream.requestId) requestId = upstream.requestId;\n if (upstream.status !== null) status = upstream.status;\n }\n\n const specific = [...chain]\n .reverse()\n .find((message) => !isGenericUserMessage(message));\n const cause = specific ?? chain[0] ?? \"Unknown error\";\n const headlineWasGeneric = isGenericUserMessage(userFacing);\n return {\n code,\n cause,\n headline: headlineWasGeneric ? cause : (userFacing ?? cause),\n headlineWasGeneric,\n chain,\n requestId,\n status,\n };\n}\n\n/**\n * Extract a user-visible message from any error object.\n * Utility for components that just need the display string.\n */\nexport function getUserMessage(error: unknown): string {\n if (error instanceof BackendApiError) {\n return error.userMessage;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n // A Redux thunk's `.unwrap()` rejects with a SerializedError — a plain\n // object, not an Error — whose `message` is the real reason.\n if (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as { message?: unknown }).message === \"string\" &&\n (error as { message: string }).message\n ) {\n return (error as { message: string }).message;\n }\n return \"Something went wrong\";\n}\n\n// ============================================================================\n// INTERNAL HELPERS\n// ============================================================================\n\nfunction statusToCode(status: number): BackendErrorCode {\n switch (status) {\n case 401:\n return \"auth_required\";\n case 403:\n return \"admin_required\";\n case 404:\n return \"not_found\";\n case 422:\n return \"validation_error\";\n default:\n return \"internal_error\";\n }\n}\n","/**\n * Canonical AI Matrx NDJSON wire kernel.\n *\n * This module is deliberately independent of React, Redux, Next.js, Supabase,\n * and generated application types. Every Matrx client uses it to turn the\n * backend's byte stream into the same normalized `{ event, data }` envelopes.\n * Host runtimes remain responsible for HTTP/auth errors and for deciding what\n * each event means in their state model.\n */\n\nexport interface MatrxStreamEnvelope<TData = unknown> {\n event: string;\n /** Immutable emitter segment; transport sequence is scoped to this id. */\n stream_id?: string;\n data: TData;\n /** Monotonic transport sequence from full envelopes, when supplied. */\n stream_seq?: number;\n}\n\nexport interface MatrxNdjsonIssue {\n line: string;\n error: unknown;\n /** One-based physical NDJSON line number. */\n lineNumber: number;\n /** True when an unterminated trailing fragment was parsed by `finish()`. */\n atCompletion: boolean;\n}\n\nexport interface MatrxStreamEnvelopeObservation {\n /** Exact parsed JSON value before compact/full normalization. */\n raw: unknown;\n envelope: MatrxStreamEnvelope;\n line: string;\n lineNumber: number;\n atCompletion: boolean;\n}\n\nexport interface MatrxNdjsonFramerOptions {\n /** Malformed JSON is non-fatal, but it must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx event envelope is also non-fatal. */\n onUnknownEnvelope?: (value: unknown) => void;\n /** Observe every valid envelope without changing or consuming it. */\n onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;\n}\n\nexport interface ReadMatrxNdjsonOptions extends MatrxNdjsonFramerOptions {\n signal?: AbortSignal;\n /** Maximum normalized events read ahead of the iterator consumer. */\n maxReadAhead?: number;\n}\n\nexport interface MatrxNdjsonFramer {\n /** Push a text fragment. Fragments may split JSON tokens or line endings. */\n pushText(fragment: string): MatrxStreamEnvelope[];\n /** Push a byte fragment. UTF-8 code points may span calls. */\n pushBytes(fragment: Uint8Array): MatrxStreamEnvelope[];\n /** Parse the final unterminated line and flush any pending UTF-8 bytes. */\n finish(): MatrxStreamEnvelope[];\n}\n\ntype QueueItem =\n | { kind: \"event\"; value: MatrxStreamEnvelope }\n | { kind: \"error\"; error: unknown }\n | { kind: \"done\" };\n\nexport const DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize both supported Matrx wire shapes:\n *\n * - full: `{ \"event\": \"chunk\", \"data\": { \"text\": \"...\" } }`\n * - compact chunk: `{ \"e\": \"c\", \"t\": \"...\" }`\n * - compact reasoning: `{ \"e\": \"r\", \"t\": \"...\" }`\n */\nexport function normalizeMatrxStreamEnvelope(\n value: unknown,\n): MatrxStreamEnvelope | null {\n if (!isRecord(value)) return null;\n\n if (typeof value.event === \"string\") {\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n return {\n event: value.event,\n data: value.data,\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n if (value.e === \"c\" && typeof value.t === \"string\") {\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n return {\n event: \"chunk\",\n data: { text: value.t },\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n if (value.e === \"r\" && typeof value.t === \"string\") {\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n return {\n event: \"reasoning_chunk\",\n data: { text: value.t },\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n return null;\n}\n\n/**\n * Create the transport-independent NDJSON framer used by the stream reader.\n * Browser extensions, desktop bridges, WebSockets, and tests can feed it\n * fragmented strings or bytes without constructing a `ReadableStream`.\n */\nexport function createMatrxNdjsonFramer(\n options: MatrxNdjsonFramerOptions = {},\n): MatrxNdjsonFramer {\n const decoder = new TextDecoder();\n let buffer = \"\";\n let lineNumber = 0;\n let finished = false;\n\n const assertOpen = (): void => {\n if (finished) throw new Error(\"Matrx NDJSON framer is already finished\");\n };\n\n const parseLine = (\n line: string,\n atCompletion: boolean,\n ): MatrxStreamEnvelope | null => {\n const currentLineNumber = ++lineNumber;\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed) as unknown;\n } catch (error) {\n options.onMalformedLine?.({\n line: trimmed,\n error,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return null;\n }\n\n const envelope = normalizeMatrxStreamEnvelope(parsed);\n if (!envelope) {\n options.onUnknownEnvelope?.(parsed);\n return null;\n }\n options.onValidEnvelope?.({\n raw: parsed,\n envelope,\n line: trimmed,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return envelope;\n };\n\n const pushDecodedText = (fragment: string): MatrxStreamEnvelope[] => {\n buffer += fragment;\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n const envelopes: MatrxStreamEnvelope[] = [];\n for (const line of lines) {\n const envelope = parseLine(line, false);\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n };\n\n return {\n pushText(fragment) {\n assertOpen();\n // Flush any pending byte fragment before switching to explicit text.\n return pushDecodedText(decoder.decode() + fragment);\n },\n pushBytes(fragment) {\n assertOpen();\n return pushDecodedText(decoder.decode(fragment, { stream: true }));\n },\n finish() {\n assertOpen();\n finished = true;\n const envelopes = pushDecodedText(decoder.decode());\n if (buffer.length > 0) {\n const envelope = parseLine(buffer, true);\n buffer = \"\";\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n },\n };\n}\n\nfunction readAheadLimit(value: number | undefined): number {\n const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;\n if (!Number.isSafeInteger(limit) || limit < 1) {\n throw new RangeError(\"maxReadAhead must be a positive safe integer\");\n }\n return limit;\n}\n\n/**\n * Read and normalize a Matrx NDJSON response body with bounded background\n * read-ahead. Consumer work does not stall the network until `maxReadAhead`\n * complete events are waiting; the bound prevents an abandoned or blocked\n * consumer from growing memory without limit.\n */\nexport async function* readMatrxNdjsonStream(\n body: ReadableStream<Uint8Array>,\n options: ReadMatrxNdjsonOptions = {},\n): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n const maxReadAhead = readAheadLimit(options.maxReadAhead);\n const queue: QueueItem[] = [];\n let queuedEventCount = 0;\n let wakeConsumer: (() => void) | null = null;\n let wakeProducer: (() => void) | null = null;\n let readerFinished = false;\n let consumerClosed = false;\n\n const wakeWaitingConsumer = (): void => {\n const wake = wakeConsumer;\n wakeConsumer = null;\n wake?.();\n };\n const wakeWaitingProducer = (): void => {\n const wake = wakeProducer;\n wakeProducer = null;\n wake?.();\n };\n const enqueueTerminal = (item: QueueItem): void => {\n if (consumerClosed) return;\n queue.push(item);\n wakeWaitingConsumer();\n };\n const enqueueEvent = async (value: MatrxStreamEnvelope): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n if (consumerClosed || options.signal?.aborted) return false;\n queue.push({ kind: \"event\", value });\n queuedEventCount += 1;\n wakeWaitingConsumer();\n return true;\n };\n const waitForReadCapacity = async (): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n return !consumerClosed && !options.signal?.aborted;\n };\n\n const reader = body.getReader();\n const framer = createMatrxNdjsonFramer(options);\n\n const onAbort = (): void => {\n wakeWaitingProducer();\n wakeWaitingConsumer();\n void reader.cancel(options.signal?.reason).catch(() => undefined);\n };\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (options.signal?.aborted) onAbort();\n\n const readerPromise = (async (): Promise<void> => {\n try {\n while (!options.signal?.aborted && !consumerClosed) {\n if (!(await waitForReadCapacity())) return;\n const { value, done } = await reader.read();\n if (done) break;\n for (const envelope of framer.pushBytes(value)) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n\n if (!options.signal?.aborted && !consumerClosed) {\n for (const envelope of framer.finish()) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n } catch (error) {\n const aborted =\n options.signal?.aborted ||\n consumerClosed ||\n (error instanceof Error && error.name === \"AbortError\");\n if (!aborted) enqueueTerminal({ kind: \"error\", error });\n } finally {\n readerFinished = true;\n reader.releaseLock();\n enqueueTerminal({ kind: \"done\" });\n }\n })();\n\n try {\n while (true) {\n if (queue.length === 0) {\n if (options.signal?.aborted || readerFinished) return;\n await new Promise<void>((resolve) => {\n wakeConsumer = resolve;\n });\n }\n\n const item = queue.shift();\n if (item?.kind === \"event\") queuedEventCount -= 1;\n wakeWaitingProducer();\n if (!item || item.kind === \"done\") return;\n if (item.kind === \"error\") throw item.error;\n yield item.value;\n }\n } finally {\n consumerClosed = true;\n wakeWaitingProducer();\n wakeWaitingConsumer();\n options.signal?.removeEventListener(\"abort\", onAbort);\n if (!readerFinished) {\n await reader.cancel().catch(() => undefined);\n }\n await readerPromise;\n }\n}\n","import { isUuidShape } from \"@ai-matrx/kit/uuid\";\n\n/**\n * The fail-closed organization-context kernel — ONE implementation for every\n * Matrx client transport (moved in from matrx-frontend\n * `lib/api/organization-context.ts` verbatim under C22; the host module is now\n * a re-export of this one).\n *\n * Transports resolve their authoritative organization first, then use these\n * functions to bind that exact value without guessing or defaulting. The\n * server never manufactures an org (it 422s a blank one), so the client\n * refuses before the wire: a missing or malformed org id throws\n * `OrganizationContextError` instead of sending a request that cannot succeed.\n */\n\nexport type OrganizationContextErrorCode =\n | \"organization_context_required\"\n | \"organization_context_invalid\"\n | \"organization_context_mismatch\";\n\nexport class OrganizationContextError extends Error {\n readonly code: OrganizationContextErrorCode;\n\n constructor(code: OrganizationContextErrorCode, message: string) {\n super(message);\n this.name = \"OrganizationContextError\";\n this.code = code;\n }\n}\n\ndeclare const organizationOperationBrand: unique symbol;\n\n/** A validated organization operation; construct only through the factory. */\nexport type OrganizationOperation = Readonly<{\n organization_id: string;\n readonly [organizationOperationBrand]: true;\n}>;\n\nexport function createOrganizationOperation(\n organizationId: string,\n): OrganizationOperation {\n const organization_id = requireOrganizationContext(organizationId);\n return Object.freeze({ organization_id }) as OrganizationOperation;\n}\n\nexport function assertOrganizationMatchesOperation(\n operation: OrganizationOperation,\n organizationId: string,\n): void {\n if (operation.organization_id !== requireOrganizationContext(organizationId)) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Organization ID must match the request operation.\",\n );\n }\n}\n\n/**\n * Normalize and validate the effective organization id for a request. The\n * override (an explicit per-call value) beats the selected context value.\n * Throws `organization_context_required` when neither is present and\n * `organization_context_invalid` when the candidate is not a UUID.\n */\nexport function requireOrganizationContext(\n selectedOrganizationId: string | null | undefined,\n overrideOrganizationId?: string,\n): string {\n const candidate = overrideOrganizationId ?? selectedOrganizationId;\n if (typeof candidate !== \"string\" || candidate.trim().length === 0) {\n throw new OrganizationContextError(\n \"organization_context_required\",\n \"Select an organization before sending this request.\",\n );\n }\n\n const normalized = candidate.trim();\n if (!isUuidShape(normalized)) {\n throw new OrganizationContextError(\n \"organization_context_invalid\",\n \"The selected organization ID is invalid.\",\n );\n }\n return normalized.toLowerCase();\n}\n\n/**\n * Bind `X-Organization-Id` onto a header bag. A pre-existing org header that\n * disagrees with the context org is a `organization_context_mismatch` error —\n * never silently overwritten in either direction.\n */\nexport function applyOrganizationContextHeader(\n headers: Record<string, string>,\n organizationId: string,\n): Record<string, string> {\n const normalizedOrganizationId = requireOrganizationContext(organizationId);\n for (const [name, value] of Object.entries(headers)) {\n if (\n name.toLowerCase() === \"x-organization-id\" &&\n value.trim().toLowerCase() !== normalizedOrganizationId\n ) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"X-Organization-Id must match the request context organization.\",\n );\n }\n }\n const withoutOrganizationHeader = Object.fromEntries(\n Object.entries(headers).filter(\n ([name]) => name.toLowerCase() !== \"x-organization-id\",\n ),\n );\n return {\n ...withoutOrganizationHeader,\n \"X-Organization-Id\": normalizedOrganizationId,\n };\n}\n\n/**\n * Assert that an `organization_id` query parameter (when present) matches the\n * request context organization — the query string must never smuggle a\n * different org past the header binding.\n */\nexport function assertQueryOrganizationMatchesContext(\n queryParams: Record<string, string | number | boolean> | undefined,\n organizationId: string,\n): void {\n if (!queryParams || queryParams.organization_id === undefined) return;\n const queryOrganizationId = requireOrganizationContext(\n String(queryParams.organization_id),\n );\n if (queryOrganizationId !== requireOrganizationContext(organizationId)) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Query organization_id must match the request context organization.\",\n );\n }\n}\n","/**\n * The AI API protocol-version policy — which version of the AI runtime a\n * Matrx client talks to, and the v2 → v1 transport fallback (moved in from\n * matrx-frontend `lib/api/ai-api-version.ts` + `call-api.ts::\n * fetchWithV2Fallback` under C22; server truth\n * `aidream/docs/runtime/V2_FRONTEND_MIGRATION.md`).\n *\n * Background: the Python backend exposes a `/v2` runtime-spine namespace that\n * wraps the core AI request surfaces in a request-tracking envelope. Body,\n * headers, and streaming response are BYTE-IDENTICAL to v1 — only the URL\n * differs.\n *\n * ─── The one rule that keeps burning us ─────────────────────────────────────\n * `/v2` is inserted at the FRONT of the in-app path, right before `/ai`:\n *\n * /ai/agents/{id} → /v2/ai/agents/{id} ✅ correct\n * /ai/v2/agents/… ❌ WRONG (nested) — 404s\n *\n * `toV2Path` below is the ONLY place this transform is spelled out.\n *\n * ─── Scope: ONLY the covered surfaces have a v2 form ────────────────────────\n * chat, manual, agents/{id}, conversations/{id} (+ singular aliases),\n * prompts/{id}, mandates/{key}. EVERYTHING ELSE — cancel, warm, resume,\n * fork-and-run, runtime operations, files … — has NO v2 route, and the server\n * does NOT auto-downgrade (a `/v2` request to an uncovered surface is a plain\n * 404). So the transform is a scoped allowlist, never a blanket prefix.\n */\n\nimport {\n isNetError,\n resilientFetch,\n type ResilientFetchOptions,\n} from \"@ai-matrx/data/net\";\n\nexport type MatrxAiApiVersion = \"v1\" | \"v2\";\n\n/**\n * The package-wide default AI API version — the production value every Matrx\n * client runs unless its host deliberately overrides\n * (`createMatrxTransport({ aiApiVersion })`).\n */\nexport const MATRX_AI_API_VERSION_DEFAULT: MatrxAiApiVersion = \"v2\";\n\n/**\n * The canonical v1 path TEMPLATES the v2 spine covers, `{param}` placeholders\n * intact — for hosts that route through a template registry.\n */\nexport const V2_COVERED_AI_PATH_TEMPLATES = [\n \"/ai/manual\",\n \"/ai/chat\",\n \"/ai/agents/{agent_id}\",\n \"/ai/agent/{agent_id}\", // singular alias — behaves identically\n \"/ai/conversations/{conversation_id}\",\n \"/ai/conversation/{conversation_id}\", // singular alias\n \"/ai/prompts/{prompt_id}\", // saved-prompt execution\n \"/ai/mandates/{mandate_key}\", // THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)\n] as const;\n\n/**\n * Insert `/v2` at the front of an in-app path. Idempotent, and prefix-aware:\n * a legacy `/api/` compatibility prefix (stripped server-side) is preserved so\n * `/api/ai/chat` → `/api/v2/ai/chat`.\n */\nexport function toV2Path(path: string): string {\n const withLead = path.startsWith(\"/\") ? path : `/${path}`;\n if (withLead.startsWith(\"/api/\")) {\n const rest = withLead.slice(\"/api\".length); // \"/ai/chat\"\n return rest.startsWith(\"/v2/\") ? withLead : `/api/v2${rest}`;\n }\n return withLead.startsWith(\"/v2/\") ? withLead : `/v2${withLead}`;\n}\n\n// Interpolated (concrete) forms of the covered surfaces — used to guard\n// callers that pass a real path (id already substituted). Anchored so ONLY the\n// exact shapes match: sub-paths like `/ai/agents/{id}/warm`,\n// `/ai/conversations/{id}/resume`, and `/ai/cancel/{id}` deliberately do NOT\n// match and stay on v1. The optional `/api` prefix mirrors `toV2Path`.\nconst COVERED_INTERPOLATED_PATH = [\n /^(?:\\/api)?\\/ai\\/manual$/,\n /^(?:\\/api)?\\/ai\\/chat$/,\n /^(?:\\/api)?\\/ai\\/agents\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/agent\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/conversations\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/conversation\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/prompts\\/[^/]+$/, // `/warm` etc. deliberately don't match\n /^(?:\\/api)?\\/ai\\/mandates\\/[^/]+$/, // the mandate door\n];\n\n/** Whether `path` (already interpolated) is one of the covered surfaces. */\nexport function isCoveredAiPath(path: string): boolean {\n return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));\n}\n\n/**\n * Whether an in-app path (or a full URL whose path was built by `toV2Path`)\n * targets the v2 namespace — the guard the downgrade fallback keys off.\n */\nexport function isV2Path(pathOrUrl: string): boolean {\n return /\\/v2\\/ai\\//.test(pathOrUrl);\n}\n\n/**\n * The inverse of `toV2Path` — strip the `/v2` version segment so a transport\n * failure of the v2 endpoint (network error, 404/405, 5xx BEFORE any stream\n * content) can retry the identical request on the v1 route. Works on a bare\n * path, an `/api`-prefixed path, or a full URL (the `/v2/ai/` shape is unique\n * to the version namespace). Idempotent on non-v2 input.\n */\nexport function toV1FallbackUrl(url: string): string {\n return url.replace(/\\/v2\\/ai\\//, \"/ai/\");\n}\n\n/**\n * Apply the active AI API version to an ALREADY-INTERPOLATED in-app path.\n *\n * - Covered surface + v2 → `/v2` prefix inserted.\n * - Anything else (or v1) → returned unchanged.\n *\n * Pass the in-app PATH only (no scheme/host); prepend the base URL afterward.\n */\nexport function applyAiApiVersion(\n path: string,\n version: MatrxAiApiVersion,\n): string {\n if (version !== \"v2\") return path;\n return isCoveredAiPath(path) ? toV2Path(path) : path;\n}\n\n/** One v2 → v1 downgrade, surfaced to the host's diagnostics sink. */\nexport interface MatrxProtocolDowngrade {\n /** The failed v2 URL. */\n url: string;\n /** Why the downgrade fired (thrown error text, or `HTTP <status>`). */\n reason: string;\n /** HTTP status when the trigger was a response (404/405/5xx). */\n status?: number;\n}\n\nexport interface MatrxProtocolFallbackOptions extends ResilientFetchOptions {\n /**\n * Fired on every downgrade — a sustained stream of these means a v2 surface\n * is unhealthy. The fallback also `console.warn`s unconditionally (parity\n * with the original host pipeline) so the signal never disappears silently.\n */\n onDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n}\n\n/**\n * `resilientFetch` with the v2 → v1 transport fallback. Fires ONLY when a\n * `/v2/ai/...` ENDPOINT itself fails — a network-layer throw (non-abort), a\n * 404/405 (surface not on v2), or a 5xx — always BEFORE any stream content is\n * consumed. Never on an application error (those fail identically on v1), and\n * never on a caller abort (a user cancel must not be logged as a downgrade —\n * that poisons the exact telemetry the rollout reads to judge v2 health).\n */\nexport async function fetchWithMatrxProtocolFallback(\n url: string,\n init: RequestInit,\n opts: MatrxProtocolFallbackOptions = {},\n): Promise<{ response: Response }> {\n const { onDowngrade, ...fetchOpts } = opts;\n const logDowngrade = (reason: string, status?: number) => {\n console.warn(\n `[matrx] ai_v2_downgrade → retrying on v1. v2=${url} reason=${reason}`,\n );\n onDowngrade?.({ url, reason, ...(status !== undefined ? { status } : {}) });\n };\n if (!isV2Path(url)) return resilientFetch(url, init, fetchOpts);\n let result: { response: Response };\n try {\n result = await resilientFetch(url, init, fetchOpts);\n } catch (err) {\n // resilientFetch normalizes a caller-signal abort to NetError code\n // \"aborted\" (AbortedError); a raw AbortError is checked too for safety.\n const isAbort =\n (isNetError(err) && err.code === \"aborted\") ||\n (err instanceof Error && err.name === \"AbortError\");\n if (isAbort) throw err;\n logDowngrade(String(err));\n return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);\n }\n const status = result.response.status;\n if (status === 404 || status === 405 || status >= 500) {\n logDowngrade(`HTTP ${status}`, status);\n return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);\n }\n return result;\n}\n\n/**\n * The exact-match `pathOverrides` map for `resolveEndpointPath` — keyed on the\n * canonical templates, valued at their `/v2` siblings. Empty for v1. Every call\n * that flows through the endpoint-override registry picks up v2 for the covered\n * surfaces — and ONLY the covered surfaces. (Moved from matrx-frontend\n * `lib/api/ai-api-version.ts`, chat-package independence P9.)\n */\nexport function aiVersionPathOverrides(\n version: MatrxAiApiVersion,\n): Record<string, string> {\n if (version !== \"v2\") return {};\n const map: Record<string, string> = {};\n for (const template of V2_COVERED_AI_PATH_TEMPLATES) {\n map[template] = toV2Path(template);\n }\n return map;\n}\n","/**\n * `@ai-matrx/agents/matrx` — THE request pipeline every typed Matrx server call\n * rides (chat package independence P9b). One implementation for every client:\n * matrx-frontend's `lib/api` `callApi` and the chat package's bare-host default\n * both build on it, and supply only their host facts — where the server is,\n * which credential and organization ride, and where diagnostics go.\n *\n * What lives here (pure, no host/window/env read):\n *\n * - `buildMatrxRequestUrl` — path params, the legacy `/api` strip, the query;\n * - `buildMatrxRequestBody` — scope injection (`organization_id` /\n * `project_id` / `task_id`), the UI-only field strip, and the fail-closed\n * body-vs-context organization check;\n * - `bareStatusSentence` / `isBareTransportCode` / `honestTransportMessage` —\n * a bare status code is never a sentence at a person;\n * - `parseMatrxNdjsonResponse` — a response body as typed envelopes, a broken\n * body reader classified as a resumable `StreamTransportError`;\n * - `executeMatrxCall` — the JSON or NDJSON execution over the v2 → v1\n * protocol fallback, with the stream callbacks and `consumeStream`;\n * - `sendMatrxRequest` / `readMatrxJsonResponse` — the raw-`Response` lane\n * for a host's imperative client (multipart bodies, byte downloads,\n * response-aware callers): one deadline, a caller abort kept as itself, and\n * the ONE HTTP error parser;\n * - `buildSafeRequestLog` / `redactUrlForRequestLog` /\n * `shouldReportMatrxCallError` — the log and capture policy.\n *\n * The error envelope (`MatrxCallError`) and its ONE classifier\n * (`normalizeMatrxError`) live in `./client`.\n */\n\nimport {\n readMatrxNdjsonStream,\n type MatrxNdjsonIssue,\n type MatrxStreamEnvelope,\n} from \"../stream/ndjson\";\nimport {\n BackendApiError,\n parseHttpError,\n StreamTransportError,\n} from \"./backend-errors\";\nimport type { MatrxCallError } from \"./client\";\nimport { OrganizationContextError } from \"./org-context\";\nimport {\n fetchWithMatrxProtocolFallback,\n type MatrxProtocolDowngrade,\n} from \"./protocol\";\nimport { extractMatrxErrorMessage } from \"./transport\";\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type MatrxHttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Every context dimension a call may carry. `organization_id`, `project_id`\n * and `task_id` are injected into the body; `user_id` rides the credential and\n * `conversation_id` the path or an explicit body field — never injected.\n */\nexport interface MatrxCallScope {\n user_id?: string;\n organization_id?: string;\n project_id?: string;\n task_id?: string;\n conversation_id?: string;\n}\n\nexport interface MatrxCallResult<T = unknown> {\n /** Parsed JSON response body (non-streaming calls only). */\n data?: T;\n /** Server-assigned request id (response header). */\n requestId?: string;\n /** Server-assigned conversation id (response header). */\n conversationId?: string;\n /** Set when the call failed with an HTTP error response. */\n error?: MatrxCallError;\n}\n\ntype MatrxQueryScalar = string | number | boolean;\n\n/**\n * Query values: a scalar is sent as itself, an array repeats the key (the\n * FastAPI repeatable-parameter convention), `null` / `undefined` are omitted.\n */\nexport type MatrxQueryParams = Record<\n string,\n MatrxQueryScalar | readonly MatrxQueryScalar[] | null | undefined\n>;\n\n// ─── URL ────────────────────────────────────────────────────────────────────\n\n/**\n * The full URL for one call: `{param}` segments substituted (encoded), the\n * legacy `/api` prefix stripped (server routes no longer live under it), and\n * the query appended.\n */\nexport function buildMatrxRequestUrl(\n baseUrl: string,\n pathTemplate: string,\n pathParams?: Record<string, string>,\n queryParams?: MatrxQueryParams,\n): string {\n let resolvedPath = pathTemplate;\n if (pathParams) {\n for (const [key, value] of Object.entries(pathParams)) {\n resolvedPath = resolvedPath.replace(`{${key}}`, encodeURIComponent(value));\n }\n }\n const fullPath = resolvedPath.startsWith(\"/api/\")\n ? resolvedPath.slice(4)\n : resolvedPath;\n const url = `${baseUrl}${fullPath}`;\n if (queryParams) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === null || value === undefined) continue;\n const values: readonly MatrxQueryScalar[] = Array.isArray(value)\n ? value\n : [value as MatrxQueryScalar];\n for (const entry of values) search.append(key, String(entry));\n }\n const qs = search.toString();\n if (qs) return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${qs}`;\n }\n return url;\n}\n\n// ─── Body ───────────────────────────────────────────────────────────────────\n\n/**\n * Client capability flags that must never reach the server — the server's\n * request schemas reject them.\n */\nexport const MATRX_UI_ONLY_BODY_FIELDS: ReadonlySet<string> = new Set([\n \"youtube_videos\",\n \"file_urls\",\n \"image_urls\",\n]);\n\n/**\n * The final request body: UI-only fields stripped, scope fields injected.\n *\n * A caller's `organization_id: null` (or blank) means \"I have none of my own\",\n * never \"send this for a different organization\" — it is dropped and the\n * scope's organization injected. A real value that disagrees with the scope\n * is refused (`organization_context_mismatch`). With no scope organization\n * (the org-less guest lane, an org-free read) nothing is injected for it.\n * Other scope fields keep caller-wins behaviour.\n */\nexport function buildMatrxRequestBody(\n body: unknown,\n scope: MatrxCallScope,\n): Record<string, unknown> {\n // MATRX-EXCEPTION: `body` is optional by design — a caller with no body\n // still gets scope fields injected, so `{}` is the correct start.\n const raw = (body ?? {}) as Record<string, unknown>;\n const base: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!MATRX_UI_ONLY_BODY_FIELDS.has(key)) base[key] = value;\n }\n\n if (\n base.organization_id === null ||\n (typeof base.organization_id === \"string\" &&\n base.organization_id.trim() === \"\")\n ) {\n delete base.organization_id;\n }\n\n const bodyOrganizationId = base.organization_id;\n if (\n scope.organization_id !== undefined &&\n bodyOrganizationId !== undefined &&\n (typeof bodyOrganizationId !== \"string\" ||\n bodyOrganizationId.trim() !== scope.organization_id)\n ) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Request body organization_id must match the request context organization.\",\n );\n }\n if (bodyOrganizationId !== undefined && scope.organization_id !== undefined) {\n base.organization_id = scope.organization_id;\n }\n\n const scopeFields: Record<string, unknown> = {\n ...(scope.organization_id !== undefined\n ? { organization_id: scope.organization_id }\n : {}),\n };\n if (scope.project_id !== undefined) scopeFields.project_id = scope.project_id;\n if (scope.task_id !== undefined) scopeFields.task_id = scope.task_id;\n return { ...scopeFields, ...base };\n}\n\n// ─── Honest status sentences ────────────────────────────────────────────────\n\nconst BARE_TRANSPORT_CODE =\n /^\\s*(?:HTTP|HTTP\\s*Error|Status(?:\\s*Code)?)?\\s*[:\\-]?\\s*\\d{3}\\s*[.:!]?\\s*$/i;\n\n/** True when a candidate sentence is really just the status line wearing words. */\nexport function isBareTransportCode(text: string | null | undefined): boolean {\n if (!text) return false;\n return BARE_TRANSPORT_CODE.test(text);\n}\n\n/**\n * A BARE STATUS CODE IS NEVER A SENTENCE. What a person reads when the server\n * answered an error with no readable message. The status itself rides\n * `error.status`, which is what code branches on — this is only the words.\n */\nexport function bareStatusSentence(status: number): string {\n if (status === 401 || status === 403) {\n return \"The server would not let this request through — your session may have expired, or this account may not have access here. Sign in again, and if it repeats, ask an administrator.\";\n }\n if (status === 404) {\n return \"The server has nothing at that address. Reload the page; if it repeats, report it — a client asking for something that no longer exists is a defect, not your mistake.\";\n }\n if (status === 429) {\n return \"The server is rate-limiting this request. Wait a few seconds and try again.\";\n }\n if (status >= 500) {\n return \"The server failed while answering this, and sent no explanation. Try again in a moment; if it repeats, report it with the request id above.\";\n }\n return \"The server refused this request and sent no reason with it — the missing reason is itself a defect worth reporting. Reload the page and try once more; if it repeats, report it with the request id above.\";\n}\n\n/** `raw` unless it is empty or only a status line; then the status sentence. */\nexport function honestTransportMessage(\n raw: string,\n status: number | undefined,\n): string {\n if (raw && !isBareTransportCode(raw)) return raw;\n return bareStatusSentence(status ?? 0);\n}\n\n// ─── Log + capture policy ───────────────────────────────────────────────────\n\nconst SENSITIVE_HEADER_NAME = /authorization|cookie|token|api[-_]?key/i;\n\n/** Request metadata safe to log: secret headers redacted, the body as its shape only. */\nexport function buildSafeRequestLog(\n headers: Record<string, string>,\n body: unknown,\n): { headers: Record<string, string>; body: Record<string, unknown> } {\n const safeHeaders = Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n SENSITIVE_HEADER_NAME.test(name) ? \"[REDACTED]\" : value,\n ]),\n );\n const bodyMetadata: Record<string, unknown> = Array.isArray(body)\n ? { type: \"array\", itemCount: body.length }\n : body && typeof body === \"object\"\n ? { type: \"object\", keys: Object.keys(body as Record<string, unknown>) }\n : { type: body === null ? \"null\" : typeof body };\n return { headers: safeHeaders, body: bodyMetadata };\n}\n\n/** The URL with every query value redacted. */\nexport function redactUrlForRequestLog(url: string): string {\n try {\n const parsed = new URL(url);\n for (const key of parsed.searchParams.keys()) {\n parsed.searchParams.set(key, \"[REDACTED]\");\n }\n return parsed.toString();\n } catch {\n const queryIndex = url.indexOf(\"?\");\n return queryIndex === -1 ? url : `${url.slice(0, queryIndex)}?[REDACTED]`;\n }\n}\n\n/** False only for an HTTP status the call site declared an expected outcome. */\nexport function shouldReportMatrxCallError(\n status: number | null | undefined,\n expectedErrorStatuses: readonly number[] | undefined,\n): boolean {\n return status == null || !expectedErrorStatuses?.includes(status);\n}\n\n// ─── Stream parsing ─────────────────────────────────────────────────────────\n\nexport interface MatrxStreamIds {\n requestId: string | null;\n conversationId: string | null;\n}\n\nexport interface MatrxStreamParse<E = MatrxStreamEnvelope> extends MatrxStreamIds {\n events: AsyncGenerator<E, void, undefined>;\n}\n\nexport interface ParseMatrxNdjsonResponseHooks {\n /** Every envelope, before the consumer sees it. */\n onEvent?: (event: MatrxStreamEnvelope, ids: MatrxStreamIds) => void;\n /** A broken body reader, already classified, before it is thrown. */\n onTransportError?: (error: BackendApiError, ids: MatrxStreamIds) => void;\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n onUnknownEnvelope?: (value: unknown) => void;\n}\n\n/**\n * A Matrx NDJSON response as typed envelopes. The ids come from headers, so\n * they are available before any event. A body that breaks mid-run is a\n * TRANSPORT loss (the run may still finish server-side and is reattachable) —\n * thrown as `StreamTransportError`, never a failed run; an abort ends quietly.\n */\nexport function parseMatrxNdjsonResponse(\n response: Response,\n signal?: AbortSignal,\n hooks: ParseMatrxNdjsonResponseHooks = {},\n): MatrxStreamParse {\n const ids: MatrxStreamIds = {\n requestId: response.headers.get(\"X-Request-ID\"),\n conversationId: response.headers.get(\"X-Conversation-ID\"),\n };\n async function* events(): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n if (!response.body) {\n throw new BackendApiError({\n code: \"internal_error\",\n detail: \"Response has no body\",\n userMessage: \"No response received from server\",\n });\n }\n try {\n for await (const envelope of readMatrxNdjsonStream(response.body, {\n ...(signal ? { signal } : {}),\n ...(hooks.onMalformedLine ? { onMalformedLine: hooks.onMalformedLine } : {}),\n ...(hooks.onUnknownEnvelope ? { onUnknownEnvelope: hooks.onUnknownEnvelope } : {}),\n })) {\n hooks.onEvent?.(envelope, ids);\n yield envelope;\n }\n } catch (error) {\n if (signal?.aborted || (error instanceof Error && error.name === \"AbortError\")) {\n return;\n }\n const transportError =\n error instanceof BackendApiError\n ? error\n : new StreamTransportError({\n detail:\n error instanceof Error\n ? error.message\n : \"The response stream ended unexpectedly.\",\n details: error,\n ...(ids.requestId ? { requestId: ids.requestId } : {}),\n });\n hooks.onTransportError?.(transportError, ids);\n throw transportError;\n }\n }\n return { events: events(), ...ids };\n}\n\n// ─── Execution ──────────────────────────────────────────────────────────────\n\nexport interface ExecuteMatrxCallRequest<E = MatrxStreamEnvelope> {\n /** The final URL (`buildMatrxRequestUrl`). */\n url: string;\n method: string;\n /** Every header the host binds (credential, organization, Content-Type). */\n headers: Record<string, string>;\n /** The assembled body (`buildMatrxRequestBody`); never sent on GET/HEAD. */\n body: unknown;\n /** NDJSON streaming call. */\n stream?: boolean;\n signal?: AbortSignal;\n /** Time to response headers. Default 15_000. */\n connectTimeoutMs?: number;\n /** Whole-request cap for JSON calls. Default 30_000; `null` uncaps. Streams are uncapped. */\n totalTimeoutMs?: number | null;\n /** Fires when headers arrive, before any event. */\n onStreamStart?: (requestId: string | null, conversationId: string | null) => void;\n onStreamEvent?: (event: E) => void;\n /**\n * Take ownership of the body instead of the executor draining it (a body is\n * consumed once). `onStreamEvent` is then not called; start / complete /\n * error still fire.\n */\n consumeStream?: (response: Response, ids: MatrxStreamIds) => Promise<void>;\n onStreamComplete?: (requestId: string | null, conversationId: string | null) => void;\n /** Fires for an HTTP error response on a stream (thrown failures are the caller's). */\n onStreamError?: (error: MatrxCallError) => void;\n}\n\nexport interface ExecuteMatrxCallHooks<E = MatrxStreamEnvelope> {\n /** Every v2 → v1 protocol downgrade. */\n onProtocolDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n /** The host's stream parser (default `parseMatrxNdjsonResponse`). */\n parseStream?: (response: Response, signal?: AbortSignal) => MatrxStreamParse<E>;\n}\n\nconst DEFAULT_CONNECT_TIMEOUT_MS = 15_000;\nconst DEFAULT_JSON_TOTAL_TIMEOUT_MS = 30_000;\n\nasync function httpErrorFrom(response: Response): Promise<MatrxCallError> {\n const serverDetail: unknown = await response.json().catch(() => undefined);\n return {\n type:\n response.status >= 400 && response.status < 500\n ? \"validation_error\"\n : \"http_error\",\n message:\n extractMatrxErrorMessage(serverDetail) ?? bareStatusSentence(response.status),\n status: response.status,\n serverDetail,\n };\n}\n\n/**\n * Execute one call over the v2 → v1 protocol fallback. An HTTP error\n * response resolves as `{ error }`; a thrown failure (network, timeout,\n * abort, a broken stream) propagates — the caller normalizes it with\n * `normalizeMatrxError` and decides what to capture.\n */\nexport async function executeMatrxCall<T = unknown, E = MatrxStreamEnvelope>(\n request: ExecuteMatrxCallRequest<E>,\n hooks: ExecuteMatrxCallHooks<E> = {},\n): Promise<MatrxCallResult<T>> {\n const upper = request.method.toUpperCase();\n const sendsBody = request.stream || (upper !== \"GET\" && upper !== \"HEAD\");\n const { response } = await fetchWithMatrxProtocolFallback(\n request.url,\n {\n method: request.method,\n headers: request.headers,\n ...(sendsBody ? { body: JSON.stringify(request.body) } : {}),\n },\n {\n ...(request.signal ? { signal: request.signal } : {}),\n connectTimeoutMs: request.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n totalTimeoutMs: request.stream\n ? null\n : request.totalTimeoutMs === undefined\n ? DEFAULT_JSON_TOTAL_TIMEOUT_MS\n : request.totalTimeoutMs,\n throwOnHttpError: false,\n ...(hooks.onProtocolDowngrade ? { onDowngrade: hooks.onProtocolDowngrade } : {}),\n },\n );\n\n const requestId = response.headers.get(\"X-Request-ID\");\n const conversationId = response.headers.get(\"X-Conversation-ID\");\n const idFields = {\n ...(requestId !== null ? { requestId } : {}),\n ...(conversationId !== null ? { conversationId } : {}),\n };\n\n if (!response.ok) {\n const error = await httpErrorFrom(response);\n if (request.stream) request.onStreamError?.(error);\n return { ...idFields, error };\n }\n\n if (!request.stream) {\n const data = (response.status === 204 ? undefined : await response.json()) as T;\n return { data, ...idFields };\n }\n\n if (request.consumeStream) {\n request.onStreamStart?.(requestId, conversationId);\n await request.consumeStream(response, { requestId, conversationId });\n request.onStreamComplete?.(requestId, conversationId);\n return idFields;\n }\n\n const parse =\n hooks.parseStream ??\n ((res: Response, signal?: AbortSignal) =>\n parseMatrxNdjsonResponse(res, signal) as unknown as MatrxStreamParse<E>);\n const parsed = parse(response, request.signal);\n request.onStreamStart?.(parsed.requestId, parsed.conversationId);\n for await (const event of parsed.events) {\n request.onStreamEvent?.(event);\n }\n request.onStreamComplete?.(parsed.requestId, parsed.conversationId);\n return {\n ...(parsed.requestId !== null ? { requestId: parsed.requestId } : {}),\n ...(parsed.conversationId !== null ? { conversationId: parsed.conversationId } : {}),\n };\n}\n\n// ─── Raw send ───────────────────────────────────────────────────────────────\n\nexport interface SendMatrxRequestOptions {\n /** Caller cancellation; an abort propagates as the caller's own AbortError. */\n signal?: AbortSignal;\n /**\n * Deadline (ms) from send to response headers. On expiry the call rejects\n * with a `BackendApiError` coded `request_timeout` (status 504) — never a\n * fake caller cancellation. Omit for no deadline.\n */\n timeoutMs?: number;\n}\n\n/**\n * Send one request and resolve with the raw `Response`, whatever its status.\n * The lane for an imperative host client whose bodies are not JSON (a\n * `FormData` upload), whose answers are bytes, or which reads the response\n * itself. A caller abort and a network failure propagate unchanged; only this\n * call's own deadline is classified (`request_timeout`).\n */\nexport async function sendMatrxRequest(\n url: string,\n init: RequestInit = {},\n options: SendMatrxRequestOptions = {},\n): Promise<Response> {\n const callerSignal = options.signal ?? init.signal ?? undefined;\n if (options.timeoutMs === undefined) {\n return fetch(url, { ...init, ...(callerSignal ? { signal: callerSignal } : {}) });\n }\n const controller = new AbortController();\n const onCallerAbort = (): void => controller.abort(callerSignal?.reason);\n if (callerSignal) {\n if (callerSignal.aborted) controller.abort(callerSignal.reason);\n else callerSignal.addEventListener(\"abort\", onCallerAbort, { once: true });\n }\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs);\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (timedOut) {\n throw new BackendApiError({\n code: \"request_timeout\",\n detail: `${init.method ?? \"GET\"} ${url} exceeded ${options.timeoutMs}ms`,\n userMessage: \"The request timed out — please retry.\",\n status: 504,\n });\n }\n throw error;\n } finally {\n clearTimeout(timer);\n callerSignal?.removeEventListener(\"abort\", onCallerAbort);\n }\n}\n\n/**\n * A response's JSON body, or the ONE classified `BackendApiError`\n * (`parseHttpError`) for a non-2xx answer. A 204 resolves `null`.\n */\nexport async function readMatrxJsonResponse<T>(response: Response): Promise<T> {\n if (!response.ok) throw await parseHttpError(response);\n if (response.status === 204) return null as T;\n return (await response.json()) as T;\n}\n","/**\n * The conversation-start contract — client-minted `conversation_id`, `is_new`,\n * `store` — typed exactly per the cross-repo System of Record\n * (`common-docs/systems/agents/conversation-start-contract/FEATURE.md`;\n * server truth `aidream/services/conversation_context/scope.py::\n * ConversationStartRequest`).\n *\n * Every request that STARTS a conversation sends all three fields, no\n * defaults:\n *\n * | `is_new` | `store` | Result |\n * |----------|---------|----------------------------------------------------------|\n * | true | true | Create the row with the caller's id — 409 if it exists |\n * | true | false | No row. The id is correlation only (ephemeral run) |\n * | false | true | Continue it — 404 if the caller doesn't own it |\n * | false | false | Ephemeral run on a known id; nothing read, nothing written |\n *\n * `store` is the ONLY ephemeral signal; `is_new` is the caller's assertion\n * about the id, never a persistence switch. `prior_messages` (the client-owned\n * transcript of an ephemeral multi-turn run) is only valid with\n * `store: false` — the union below makes the invalid combination\n * unrepresentable, mirroring the server's 422.\n *\n * Continue routes (`POST /ai/conversations/{id}`) take the id from the path\n * and do not carry this triple.\n */\n\n/** Recursive JSON value — the package's honest type for free-form wire bags. */\nexport type MatrxJsonValue =\n | string\n | number\n | boolean\n | null\n | MatrxJsonValue[]\n | { [key: string]: MatrxJsonValue };\n\n/** A JSON object on the wire. */\nexport type MatrxJsonObject = { [key: string]: MatrxJsonValue };\n\n/**\n * One LLM message on the request wire — `prior_messages` entries for\n * stateless multi-turn runs. Mirrors aidream's `ChatMessageInput`\n * (`aidream/schemas/messages.py`, `extra=\"allow\"` — additional provider\n * fields round-trip untouched).\n */\nexport interface MatrxChatMessage {\n role: string;\n content?: string | MatrxJsonValue[] | null;\n name?: string | null;\n tool_call_id?: string | null;\n tool_calls?: MatrxJsonObject[] | null;\n [extra: string]: MatrxJsonValue | undefined;\n}\n\n/** `is_new: true, store: true` — create the row with the caller's id. */\nexport interface MatrxStoredConversationCreate {\n conversation_id: string;\n is_new: true;\n store: true;\n}\n\n/** `is_new: false, store: true` — continue an owned stored conversation via a start route. */\nexport interface MatrxStoredConversationContinue {\n conversation_id: string;\n is_new: false;\n store: true;\n}\n\n/**\n * `store: false` — ephemeral: nothing read, nothing written; the id is the\n * caller's correlation handle. This is the ONLY member that may carry\n * `prior_messages` (the server 422s a client transcript on a stored run).\n */\nexport interface MatrxEphemeralConversation {\n conversation_id: string;\n is_new: boolean;\n store: false;\n prior_messages?: MatrxChatMessage[];\n}\n\n/** The full conversation-start triple, one member per contract cell. */\nexport type MatrxConversationStart =\n | MatrxStoredConversationCreate\n | MatrxStoredConversationContinue\n | MatrxEphemeralConversation;\n\n/** Mint a fresh client-side conversation id (the contract requires the CLIENT to mint it). */\nexport function mintMatrxConversationId(): string {\n return crypto.randomUUID();\n}\n\n/** Start a NEW stored conversation (`is_new: true, store: true`). */\nexport function newStoredConversationStart(\n conversationId?: string,\n): MatrxStoredConversationCreate {\n return {\n conversation_id: conversationId ?? mintMatrxConversationId(),\n is_new: true,\n store: true,\n };\n}\n\n/**\n * Continue an EXISTING stored conversation through a start route\n * (`is_new: false, store: true` — 404 when the caller doesn't own the id).\n * Prefer `continueAgentConversation` (the dedicated continue route) for\n * ordinary follow-up turns.\n */\nexport function continueStoredConversationStart(\n conversationId: string,\n): MatrxStoredConversationContinue {\n return { conversation_id: conversationId, is_new: false, store: true };\n}\n\n/**\n * Start a NEW ephemeral run (`is_new: true, store: false`) — a freshly minted\n * correlation id, nothing persisted.\n */\nexport function newEphemeralConversationStart(\n conversationId?: string,\n): MatrxEphemeralConversation {\n return {\n conversation_id: conversationId ?? mintMatrxConversationId(),\n is_new: true,\n store: false,\n };\n}\n\n/**\n * Continue an ephemeral multi-turn run (`is_new: false, store: false`): the\n * CLIENT owns the transcript and replays it as `prior_messages` (ordered\n * oldest-first) because the server wrote no rows to rebuild from. The server\n * still owns the agent definition, model, tools, and system prompt.\n */\nexport function continueEphemeralConversationStart(\n conversationId: string,\n priorMessages: MatrxChatMessage[],\n): MatrxEphemeralConversation {\n return {\n conversation_id: conversationId,\n is_new: false,\n store: false,\n prior_messages: priorMessages,\n };\n}\n","/**\n * Internal request plumbing for `@ai-matrx/agents/matrx`. Not part of the\n * public surface — `matrx/index.ts` deliberately does not re-export this\n * module. Everything here is pure: no globals, no work at import time.\n */\n\nimport {\n readMatrxNdjsonStream,\n type MatrxNdjsonIssue,\n type MatrxStreamEnvelope,\n type MatrxStreamEnvelopeObservation,\n} from \"../stream/ndjson\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\n/** Encode one path segment (an id) safely into a server-relative path. */\nexport function encodePathSegment(value: string): string {\n return encodeURIComponent(value);\n}\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined;\n\n/**\n * Build a query string. Array values repeat the key (`kind=a&kind=b` — the\n * FastAPI repeatable-parameter convention); undefined values are omitted.\n * Returns \"\" or a string starting with \"?\".\n */\nexport function buildQuery(params: Record<string, QueryValue>): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const entry of value) search.append(key, entry);\n } else {\n search.append(key, String(value));\n }\n }\n const encoded = search.toString();\n return encoded ? `?${encoded}` : \"\";\n}\n\nasync function readServerDetail(response: Response): Promise<unknown> {\n try {\n return (await response.json()) as unknown;\n } catch {\n return undefined;\n }\n}\n\nasync function throwApiError(path: string, response: Response): Promise<never> {\n throw new MatrxApiError({\n status: response.status,\n path,\n serverDetail: await readServerDetail(response),\n });\n}\n\nexport interface JsonRequestOptions {\n method: \"GET\" | \"POST\";\n body?: unknown;\n signal?: AbortSignal;\n}\n\n/**\n * Execute a JSON request through the transport. Throws `MatrxApiError` on a\n * non-2xx response; resolves with the parsed JSON body otherwise.\n */\nexport async function requestJson<T>(\n transport: MatrxTransport,\n path: string,\n options: JsonRequestOptions,\n): Promise<T> {\n const hasBody = options.method !== \"GET\" && options.body !== undefined;\n const response = await transport.fetch(path, {\n method: options.method,\n headers: hasBody ? { \"Content-Type\": \"application/json\" } : {},\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) return throwApiError(path, response);\n return (await response.json()) as T;\n}\n\n/**\n * Options for every streaming call, riding the NDJSON kernel's contract.\n * Public via `./run`'s re-export.\n */\nexport interface MatrxStreamCallOptions {\n /** Abort the fetch and end the events iterator. */\n signal?: AbortSignal;\n /** Bounded background read-ahead (see `stream/ndjson`). */\n maxReadAhead?: number;\n /** Malformed NDJSON is non-fatal but must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx envelope. */\n onUnknownEnvelope?: (value: unknown) => void;\n /** Observe every valid envelope in its exact wire form. */\n onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;\n}\n\n/**\n * A live agent run: the server-assigned ids (from response headers, available\n * BEFORE any event) and the normalized event stream. Public via `./run`.\n */\nexport interface MatrxRunHandle {\n /** `X-Request-ID` — the ONLY id `POST /ai/cancel/{request_id}` accepts. */\n requestId: string | null;\n /** `X-Conversation-ID` — the server's conversation identity. */\n conversationId: string | null;\n /** Normalized `{event, data}` envelopes through the ONE wire kernel. */\n events: AsyncGenerator<MatrxStreamEnvelope, void, undefined>;\n /** The raw response, for hosts that need headers/status beyond the ids. */\n response: Response;\n}\n\n/**\n * Wrap a validated streaming Response into the run handle — the ONE place\n * the id headers are read and the NDJSON kernel is attached (`./run` and\n * `./operations`' rejoin share it).\n */\nexport function toRunHandle(\n response: Response,\n options: MatrxStreamCallOptions,\n): MatrxRunHandle {\n return {\n requestId: response.headers.get(\"X-Request-ID\"),\n conversationId: response.headers.get(\"X-Conversation-ID\"),\n events: readMatrxNdjsonStream(response.body as ReadableStream<Uint8Array>, {\n ...(options.signal ? { signal: options.signal } : {}),\n ...(options.maxReadAhead !== undefined\n ? { maxReadAhead: options.maxReadAhead }\n : {}),\n ...(options.onMalformedLine\n ? { onMalformedLine: options.onMalformedLine }\n : {}),\n ...(options.onUnknownEnvelope\n ? { onUnknownEnvelope: options.onUnknownEnvelope }\n : {}),\n ...(options.onValidEnvelope\n ? { onValidEnvelope: options.onValidEnvelope }\n : {}),\n }),\n response,\n };\n}\n\nexport interface StreamRequestOptions {\n method: \"GET\" | \"POST\";\n body?: unknown;\n /** Extra wire-semantic headers (`Accept`, `Last-Event-ID`). */\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\n/**\n * Execute a streaming request. Throws `MatrxApiError` on a non-2xx response\n * (reading the error body as JSON when possible) or when a 2xx response\n * carries no body; resolves with the validated `Response` otherwise.\n */\nexport async function requestStream(\n transport: MatrxTransport,\n path: string,\n options: StreamRequestOptions,\n): Promise<Response> {\n const hasBody = options.method !== \"GET\" && options.body !== undefined;\n const response = await transport.fetch(path, {\n method: options.method,\n headers: {\n ...(hasBody ? { \"Content-Type\": \"application/json\" } : {}),\n ...options.headers,\n },\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) return throwApiError(path, response);\n if (!response.body) {\n throw new MatrxApiError({\n status: response.status,\n path,\n serverDetail: { code: \"missing_response_body\" },\n message: \"The streaming response carried no body.\",\n });\n }\n return response;\n}\n","/**\n * `@ai-matrx/agents/stream/sse` — the Matrx SSE frame kernel.\n *\n * Two Matrx clients hand-rolled the identical `text/event-stream` framing —\n * the same separator regex, the same field parsing, the same CRLF incident —\n * for the durable rejoin endpoints (`/runtime/.../events/stream`,\n * `/runs/.../events/stream`). This module is that framing extracted ONCE, as a\n * pure incremental parser, so a host keeps only what is genuinely host policy:\n * the fetch, the stall timer, the retry budget, and what each event MEANS.\n *\n * Contract, mirroring `stream/ndjson`:\n * - Pure and effect-free: no fetch, no timers, no globals. Importing this\n * module performs no work.\n * - Incremental across arbitrary chunk boundaries: a frame split anywhere —\n * mid-line, mid-separator, mid-UTF-8 when using the byte reader — parses\n * identically to one delivered whole.\n * - All three SSE line terminators (`\\r\\n`, `\\n`, `\\r`) and all three frame\n * separators are handled — the CRLF-vs-LF divergence that bit production is\n * covered by construction and by test.\n * - Comment-only frames (heartbeats, `:` lines) ARE emitted (with\n * `data === null`) because hosts use any parsed frame as liveness proof to\n * reset stall timers and retry budgets. Frames with data join multi-line\n * `data:` fields with `\\n` per the SSE spec.\n * - `id:` is surfaced raw AND, when it is a safe integer, as `seq` — the\n * `Last-Event-ID` cursor both Matrx rejoin endpoints use for durable replay.\n * Cursor ADVANCEMENT (`seq > cursor`) stays host-side, next to the retry.\n */\n\nexport interface MatrxSseFrame {\n /** `event:` field; the SSE default \"message\" when absent. */\n event: string;\n /** `id:` field, raw, when present. */\n id: string | null;\n /**\n * `id:` parsed as a non-negative safe integer, else null. Matrx rejoin\n * streams use integer ids as the `Last-Event-ID` replay cursor.\n */\n seq: number | null;\n /**\n * Joined `data:` lines (`\\n`-separated per spec), or null for a frame with\n * no data field at all (e.g. a comment-only heartbeat). An empty-string\n * data field is `\"\"`, not null.\n */\n data: string | null;\n}\n\nconst FRAME_SEPARATOR = /\\r\\n\\r\\n|\\n\\n|\\r\\r/;\nconst LINE_SEPARATOR = /\\r\\n|\\n|\\r/;\n\n/** Parse ONE complete frame's text (no trailing separator). */\nexport function parseMatrxSseFrame(frame: string): MatrxSseFrame {\n let event = \"message\";\n let id: string | null = null;\n const dataLines: string[] = [];\n let sawData = false;\n\n for (const line of frame.split(LINE_SEPARATOR)) {\n if (line.startsWith(\":\")) continue;\n if (line.startsWith(\"event:\")) event = line.slice(6).trim();\n else if (line.startsWith(\"data:\")) {\n sawData = true;\n dataLines.push(line.slice(5).replace(/^ /, \"\"));\n } else if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n }\n\n const seqCandidate = id !== null && id !== \"\" ? Number(id) : NaN;\n const seq =\n Number.isSafeInteger(seqCandidate) && seqCandidate >= 0\n ? seqCandidate\n : null;\n\n return { event, id, seq, data: sawData ? dataLines.join(\"\\n\") : null };\n}\n\nexport interface MatrxSseFramer {\n /** Feed a decoded text chunk; returns every frame it completed. */\n push(chunk: string): MatrxSseFrame[];\n /**\n * Signal end of input. A non-empty trailing buffer is an UNTERMINATED frame:\n * per the SSE spec it was never dispatched, so it is returned separately for\n * the host to treat as diagnostic, never as a delivered event.\n */\n flush(): { incomplete: string | null };\n}\n\n/** Incremental SSE framer over already-decoded text. */\nexport function createMatrxSseFramer(): MatrxSseFramer {\n let buffer = \"\";\n return {\n push(chunk: string): MatrxSseFrame[] {\n buffer += chunk;\n const frames: MatrxSseFrame[] = [];\n for (;;) {\n const sep = FRAME_SEPARATOR.exec(buffer);\n if (sep === null) break;\n // A lone trailing `\\r` could be the first half of `\\r\\n\\r\\n`'s final\n // newline — but the separator regex only matched what is already\n // complete, so the slice below is always safe.\n const frame = buffer.slice(0, sep.index);\n buffer = buffer.slice(sep.index + sep[0].length);\n frames.push(parseMatrxSseFrame(frame));\n }\n return frames;\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return { incomplete: rest.length > 0 ? rest : null };\n },\n };\n}\n\nexport interface ReadMatrxSseOptions {\n /**\n * Called with any unterminated trailing text at stream end (a frame the\n * server never finished — diagnostic, not a delivered event).\n */\n onIncomplete?: (text: string) => void;\n}\n\n/**\n * Async-iterate the frames of a byte stream (e.g. `response.body`), handling\n * split UTF-8 across chunk boundaries. Cancellation follows the reader: abort\n * the fetch and the iterator ends; a transport error after complete frames\n * were yielded surfaces AFTER those frames, with its original cause.\n */\nexport async function* readMatrxSseStream(\n stream: ReadableStream<Uint8Array>,\n options: ReadMatrxSseOptions = {},\n): AsyncGenerator<MatrxSseFrame, void, undefined> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const framer = createMatrxSseFramer();\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n const frames = framer.push(decoder.decode(value, { stream: true }));\n for (const frame of frames) yield frame;\n }\n const tail = framer.push(decoder.decode());\n for (const frame of tail) yield frame;\n const { incomplete } = framer.flush();\n if (incomplete !== null) options.onIncomplete?.(incomplete);\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * Runtime operations — the canonical reconnect & resume read surface of the\n * execution spine, over the `MatrxTransport` port.\n *\n * Server truth (verified against aidream source,\n * `aidream/api/routers/runtime_operations.py` + `aidream/services/runtime/\n * reconnect.py`; mounted at bare `/runtime`):\n * - `GET /runtime/operations/{request_id}` — identify by `X-Request-ID`\n * - `GET /runtime/operations/by-link/{kind}/{id}` — identify by feature record\n * - `GET /runtime/executions/{id}/events` — durable seq-cursored page\n * - `GET /runtime/executions/{id}/events/stream` — SSE replay-then-follow,\n * `id:` = per-tree seq, reconnect with `Last-Event-ID`\n * - `POST /runtime/operations/{request_id}/rejoin` — replay + follow the\n * ORIGINAL NDJSON response while its detached task is alive (409 when live\n * delivery is unavailable — fall back to the durable lifecycle stream)\n *\n * The contract: identify → recover durable progress → follow live → re-query\n * the final result from the feature's own record. Token text is deliberately\n * never replayed on the lifecycle stream — that is what `/rejoin` is for.\n *\n * The SSE wire rides the package's own `stream/sse` kernel. This module owns\n * ONE connection's semantics (frames → typed events, cursor advancement,\n * terminal `end`); stall timers, retry budgets, and reconnect loops stay host\n * policy — every yielded item carries the cursor the next attempt resumes from.\n */\n\nimport { readMatrxSseStream, type MatrxSseFrame } from \"../stream/sse\";\nimport type { MatrxJsonObject } from \"./conversation\";\nimport {\n encodePathSegment,\n buildQuery,\n requestJson,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\n// ─── Wire types (mirroring `aidream/services/runtime/reconnect.py`) ─────────\n\n/** `matrx_runtime.models.ExecutionStatus` — the only progress column. */\nexport type MatrxRuntimeExecutionStatus =\n | \"pending\"\n | \"running\"\n | \"paused\"\n | \"waiting_input\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport const TERMINAL_MATRX_RUNTIME_STATUSES: ReadonlySet<MatrxRuntimeExecutionStatus> =\n new Set([\"completed\", \"failed\", \"cancelled\"]);\n\nconst RUNTIME_STATUSES: ReadonlySet<string> = new Set([\n \"pending\",\n \"running\",\n \"paused\",\n \"waiting_input\",\n \"completed\",\n \"failed\",\n \"cancelled\",\n]);\n\n/** One durable spine event on the wire (`OperationEvent`) — `seq` is the reconnect cursor. */\nexport interface MatrxRuntimeOperationEvent {\n seq: number | null;\n /** Lifecycle vocabulary: created | started | paused | resumed | waiting_input | completed | failed | cancelled | checkpoint_saved | note. */\n kind: string;\n execution_id: string;\n root_execution_id: string | null;\n detail: MatrxJsonObject | null;\n created_at: string | null;\n}\n\n/** One root execution as a reconnecting client sees it (`OperationView`). */\nexport interface MatrxRuntimeOperationView {\n execution_id: string;\n /** Durable request identity — feeds `/rejoin` and no-prompt resume recovery. */\n request_id: string | null;\n type: string;\n status: MatrxRuntimeExecutionStatus;\n is_terminal: boolean;\n waiting_input: boolean;\n /** Decimal on the wire — may arrive as number or string; display-only. */\n cost: number | string;\n meters: Record<string, number | string>;\n link_kind: string | null;\n link_id: string | null;\n error: MatrxJsonObject | null;\n created_at: string | null;\n started_at: string | null;\n ended_at: string | null;\n last_event_seq: number;\n events_path: string;\n stream_path: string;\n}\n\nexport interface MatrxOperationStatusResponse {\n request_id: string;\n operation_count: number;\n operations: MatrxRuntimeOperationView[];\n}\n\nexport interface MatrxOperationsByLinkResponse {\n link_kind: string;\n link_id: string;\n operation_count: number;\n operations: MatrxRuntimeOperationView[];\n}\n\nexport interface MatrxOperationEventsPage {\n execution_id: string;\n root_execution_id: string;\n events: MatrxRuntimeOperationEvent[];\n /** Feeds the next page or the SSE `Last-Event-ID` — polling and push share ONE cursor. */\n next_after_seq: number;\n has_more: boolean;\n root_status: MatrxRuntimeExecutionStatus;\n root_is_terminal: boolean;\n}\n\n// ─── Identify + durable progress ────────────────────────────────────────────\n\n/**\n * Where is my operation? Resolves an `X-Request-ID` to its root execution(s).\n * Returns null on 404 — missing and unowned share one shape by design\n * (existence is never leaked).\n */\nexport async function getRuntimeOperationStatus(\n transport: MatrxTransport,\n requestId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<MatrxOperationStatusResponse | null> {\n try {\n return await requestJson<MatrxOperationStatusResponse>(\n transport,\n `/runtime/operations/${encodePathSegment(requestId)}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n } catch (error) {\n if (error instanceof MatrxApiError && error.status === 404) return null;\n throw error;\n }\n}\n\n/**\n * Operations for a feature record — e.g. `(\"conversation\", conversationId)`,\n * `(\"workflow\", runId)`, `(\"agent_run\", runId)`. Newest first; unowned trees\n * omitted. Returns null on 404 (surface absent, or the caller owns nothing —\n * one shape by design).\n */\nexport async function getRuntimeOperationsByLink(\n transport: MatrxTransport,\n linkKind: string,\n linkId: string,\n options: { limit?: number; signal?: AbortSignal } = {},\n): Promise<MatrxOperationsByLinkResponse | null> {\n const query = buildQuery(\n options.limit !== undefined ? { limit: options.limit } : {},\n );\n try {\n return await requestJson<MatrxOperationsByLinkResponse>(\n transport,\n `/runtime/operations/by-link/${encodePathSegment(linkKind)}/${encodePathSegment(linkId)}${query}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n } catch (error) {\n if (error instanceof MatrxApiError && error.status === 404) return null;\n throw error;\n }\n}\n\n/**\n * Durable progress page for the whole operation TREE:\n * `GET /runtime/executions/{id}/events?after_seq=…`. Pass any node id — it\n * resolves to the root.\n */\nexport function listRuntimeOperationEvents(\n transport: MatrxTransport,\n executionId: string,\n options: {\n afterSeq?: number;\n limit?: number;\n /** Repeatable event-kind filter. */\n kinds?: readonly string[];\n signal?: AbortSignal;\n } = {},\n): Promise<MatrxOperationEventsPage> {\n const query = buildQuery({\n ...(options.afterSeq !== undefined ? { after_seq: options.afterSeq } : {}),\n ...(options.limit !== undefined ? { limit: options.limit } : {}),\n ...(options.kinds !== undefined ? { kind: options.kinds } : {}),\n });\n return requestJson<MatrxOperationEventsPage>(\n transport,\n `/runtime/executions/${encodePathSegment(executionId)}/events${query}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n}\n\n// ─── SSE follow (replay-then-follow with Last-Event-ID) ─────────────────────\n\n/**\n * One item from the follow stream. Every item carries `cursor` — the highest\n * event seq seen so far, which is exactly the `Last-Event-ID` a reconnect\n * resumes from (host retry policy owns the reconnect loop).\n */\nexport type MatrxOperationFollowEvent =\n | {\n /** A parsed durable spine event. */\n type: \"event\";\n event: MatrxRuntimeOperationEvent;\n /** The frame's SSE `id:` as an integer, when it carried one. */\n seq: number | null;\n cursor: number;\n }\n | {\n /**\n * A frame that carried no deliverable event — a comment heartbeat, an\n * unknown event name, or a malformed payload (also surfaced through\n * `onMalformedFrame`). ANY parsed frame proves the wire is alive: hosts\n * reset stall timers and retry budgets on it.\n */\n type: \"liveness\";\n cursor: number;\n }\n | {\n /** The server's terminal frame — the root settled; the stream is over. */\n type: \"end\";\n status: MatrxRuntimeExecutionStatus | null;\n cursor: number;\n };\n\nexport interface FollowRuntimeOperationOptions {\n /** Resume cursor — the operation view's `last_event_seq` (0 = from start). */\n lastEventSeq?: number;\n /** Abort the follow — the generator simply ends. */\n signal?: AbortSignal;\n /** A frame whose payload failed to parse — never silently dropped. */\n onMalformedFrame?: (frame: MatrxSseFrame, error: unknown) => void;\n /** Unterminated trailing SSE text at stream end (diagnostic, never an event). */\n onIncomplete?: (text: string) => void;\n}\n\nfunction parseEndStatus(data: string | null): MatrxRuntimeExecutionStatus | null {\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as unknown;\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n typeof (parsed as { status?: unknown }).status === \"string\"\n ) {\n const status = (parsed as { status: string }).status;\n return RUNTIME_STATUSES.has(status)\n ? (status as MatrxRuntimeExecutionStatus)\n : null;\n }\n } catch {\n // malformed end payload — still terminal\n }\n return null;\n}\n\n/**\n * Follow ONE SSE connection of an operation's lifecycle stream:\n * `GET /runtime/executions/{id}/events/stream` with `Last-Event-ID` when\n * resuming past 0. Replays from the cursor, then follows live; a\n * WAITING_INPUT park keeps it open (a resume re-attaches to the same\n * execution and its events continue here). Ends after yielding\n * `{type: \"end\"}` when the root settles; a server close WITHOUT an end frame\n * simply ends the generator — reconnect from the last yielded `cursor` (host\n * retry policy).\n */\nexport async function* followRuntimeOperationEvents(\n transport: MatrxTransport,\n executionId: string,\n options: FollowRuntimeOperationOptions = {},\n): AsyncGenerator<MatrxOperationFollowEvent, void, undefined> {\n let cursor = options.lastEventSeq ?? 0;\n\n const headers: Record<string, string> = { Accept: \"text/event-stream\" };\n if (cursor > 0) headers[\"Last-Event-ID\"] = String(cursor);\n\n const response = await requestStream(\n transport,\n `/runtime/executions/${encodePathSegment(executionId)}/events/stream`,\n {\n method: \"GET\",\n headers,\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n\n const frames = readMatrxSseStream(\n response.body as ReadableStream<Uint8Array>,\n options.onIncomplete ? { onIncomplete: options.onIncomplete } : {},\n );\n\n for await (const frame of frames) {\n if (frame.event === \"end\") {\n yield { type: \"end\", status: parseEndStatus(frame.data), cursor };\n return;\n }\n if (frame.event === \"execution_event\" && frame.data !== null) {\n let event: MatrxRuntimeOperationEvent;\n try {\n event = JSON.parse(frame.data) as MatrxRuntimeOperationEvent;\n } catch (error) {\n options.onMalformedFrame?.(frame, error);\n yield { type: \"liveness\", cursor };\n continue;\n }\n if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;\n yield { type: \"event\", event, seq: frame.seq, cursor };\n continue;\n }\n // Comment heartbeats, unknown event names, data-less frames: liveness.\n yield { type: \"liveness\", cursor };\n }\n}\n\n// ─── Follow to end (the production reconnect policy) ────────────────────────\n\nexport interface FollowRuntimeOperationToEndOptions {\n /** Resume cursor — the operation view's `last_event_seq` (0 = from start). */\n lastEventSeq?: number;\n /** Caller teardown — aborting resolves with `ended: false`. */\n signal?: AbortSignal;\n /**\n * The server pings every ~15s, so a wire that is open but silent past this\n * is dead (buffering proxy, idle-killed connection) — abort the attempt and\n * retry rather than hanging forever. Default 45_000.\n */\n stallTimeoutMs?: number;\n /**\n * Consecutive failed attempts before giving up. A single-server deployment\n * deliberately drains for 60s, then starts a new container — the default\n * budget (60 × 2s) keeps following for ~three minutes so the runtime ledger\n * can bridge that handoff. ANY parsed frame resets the budget. Default 60.\n */\n reconnectLimit?: number;\n /** Delay between attempts. Default 2_000. */\n reconnectDelayMs?: number;\n /** Fired per durable spine event (lifecycle transitions + notes). */\n onEvent: (event: MatrxRuntimeOperationEvent, seq: number | null) => void;\n /** A failed attempt (never silently swallowed when provided). */\n onAttemptError?: (error: unknown) => void;\n /** A frame whose payload failed to parse (the ledger heals gaps on reconnect). */\n onMalformedFrame?: (frame: MatrxSseFrame, error: unknown) => void;\n}\n\nexport interface FollowRuntimeOperationToEndResult {\n /** True when the server sent the terminal `end` frame. */\n ended: boolean;\n /** The root status carried on the `end` frame (when `ended`). */\n status: MatrxRuntimeExecutionStatus | null;\n}\n\n/**\n * Follow an operation's lifecycle stream TO ITS END — the full production\n * reconnect policy over `followRuntimeOperationEvents`: replay-then-follow\n * with bounded reconnects, a stall watchdog, and durable `Last-Event-ID`\n * cursor advancement across attempts.\n *\n * Resolves `{ended: true, status}` on the server's `end` frame (the operation\n * settled); `{ended: false}` when the caller aborted or every reconnect\n * attempt failed. A WAITING_INPUT park keeps the stream open by design — a\n * resume re-attaches to the same execution and its events continue arriving\n * on the same cursor. Any parsed frame — comment heartbeats included —\n * proves the wire is alive and resets both the stall timer and the retry\n * budget.\n */\nexport async function followRuntimeOperationToEnd(\n transport: MatrxTransport,\n executionId: string,\n options: FollowRuntimeOperationToEndOptions,\n): Promise<FollowRuntimeOperationToEndResult> {\n const stallTimeoutMs = options.stallTimeoutMs ?? 45_000;\n const reconnectLimit = options.reconnectLimit ?? 60;\n const reconnectDelayMs = options.reconnectDelayMs ?? 2_000;\n const outer = options.signal;\n\n let cursor = options.lastEventSeq ?? 0;\n let failures = 0;\n\n while (!outer?.aborted && failures < reconnectLimit) {\n const attempt = new AbortController();\n const onOuterAbort = () => attempt.abort();\n outer?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\n let stallTimer: ReturnType<typeof setTimeout> | null = null;\n const armStall = () => {\n if (stallTimer !== null) clearTimeout(stallTimer);\n stallTimer = setTimeout(() => attempt.abort(), stallTimeoutMs);\n };\n\n try {\n const items = followRuntimeOperationEvents(transport, executionId, {\n lastEventSeq: cursor,\n signal: attempt.signal,\n ...(options.onMalformedFrame\n ? { onMalformedFrame: options.onMalformedFrame }\n : {}),\n });\n\n armStall();\n for await (const item of items) {\n armStall();\n failures = 0;\n cursor = item.cursor;\n if (item.type === \"end\") {\n return { ended: true, status: item.status };\n }\n if (item.type === \"event\") {\n options.onEvent(item.event, item.seq);\n }\n }\n // Server closed without an `end` frame (e.g. process restart). Retry —\n // `Last-Event-ID` replays anything missed from the durable ledger.\n failures += 1;\n } catch (error) {\n if (outer?.aborted) break;\n failures += 1;\n options.onAttemptError?.(error);\n } finally {\n if (stallTimer !== null) clearTimeout(stallTimer);\n outer?.removeEventListener(\"abort\", onOuterAbort);\n }\n\n if (!outer?.aborted && failures < reconnectLimit) {\n await new Promise((r) => setTimeout(r, reconnectDelayMs));\n }\n }\n\n return { ended: false, status: null };\n}\n\n// ─── NDJSON rejoin (replay the original response) ───────────────────────────\n\n/**\n * Rejoin the ORIGINAL NDJSON response while its detached task is still alive:\n * `POST /runtime/operations/{request_id}/rejoin`. Replays the response from\n * frame one, then continues live — every frame is sequence-stamped\n * (`stream_seq`), so a same-page reconnect can drop frames it already\n * rendered. Throws `MatrxApiError` with status 409 when live delivery is\n * unavailable — fall back to `followRuntimeOperationEvents` + a final record\n * re-query. The `requestId` must be the server's `X-Request-ID`.\n */\nexport async function rejoinRuntimeOperation(\n transport: MatrxTransport,\n requestId: string,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n const response = await requestStream(\n transport,\n `/runtime/operations/${encodePathSegment(requestId)}/rejoin`,\n {\n method: \"POST\",\n // The route takes no body model; the reference client posts an empty\n // JSON object. Match it so proxies see an ordinary JSON POST.\n body: {},\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n return toRunHandle(response, options);\n}\n","/**\n * Resume-or-rejoin — the ONE client behavior for \"pick a run back up\".\n *\n * Server truth (aidream `services/runtime/FEATURE.md` § \"A live run is\n * REJOINED, never resumed beside itself\"; `reconnect.run_in_progress_error`):\n * - Every resume / retry / continue door asked to resume a run that is STILL\n * LIVE answers `409` with, at the ROOT of the error body,\n * `{error, code: \"run_in_progress\", live_request_id, rejoin_path, message,\n * …extras}` (extras: `run_id` for workflow / SEO / comparison, `arm_index` /\n * `arm`, `analysis_id`). The client follows `rejoin_path` — never a URL it\n * builds — because a door outside the spine (SEO collections) answers\n * `live_request_id: null` with its own `/seo/collections/{run_id}/rejoin`.\n * - Chat/conversation resume answers `code: \"resume_conflict\"` — even when the\n * body ALSO names `live_request_id` + `rejoin_path` — and it is ALWAYS host\n * retry, never a rejoin: the claim holder is usually the turn that is still\n * SUSPENDING, and rejoining it replays that turn from frame one (duplicate\n * text) while the person's continuation never runs. Only\n * `code: run_in_progress` rejoins.\n * - The envelope RESERVES `request_id` for the refusing call's own id — the\n * live run is read from `live_request_id`, never `request_id` (reading it\n * rejoined a request that did not exist: 404, 2026-10-01).\n * - A rejoin answers `409 live_stream_unavailable` when there is no journal to\n * replay (resumed workflow legs, comparison arms). Then: a body naming a\n * workflow `run_id` → follow `GET /runs/{run_id}/events/stream` (the workflow\n * SSE, which also carries the node_stream media frames); otherwise follow the\n * durable lifecycle (`followRuntimeOperationToEnd`).\n *\n * Resume and rejoin are work on an EXISTING run, so they carry THAT run's\n * organization (`organizationId`), never whatever the session has selected.\n */\n\nimport type { MatrxStreamEnvelope } from \"../stream/ndjson\";\nimport { readMatrxSseStream } from \"../stream/sse\";\nimport {\n encodePathSegment,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport {\n followRuntimeOperationToEnd,\n getRuntimeOperationStatus,\n type FollowRuntimeOperationToEndOptions,\n type MatrxRuntimeExecutionStatus,\n type MatrxRuntimeOperationEvent,\n} from \"./operations\";\nimport { requireOrganizationContext } from \"./org-context\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\nexport const MATRX_RUN_IN_PROGRESS = \"run_in_progress\";\nexport const MATRX_RESUME_CONFLICT = \"resume_conflict\";\nexport const MATRX_LIVE_STREAM_UNAVAILABLE = \"live_stream_unavailable\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction nonBlank(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value : null;\n}\n\n/**\n * Any error carrying an HTTP status and the parsed server body —\n * `MatrxApiError`, matrx-frontend's `ApiCallError`, or a host's own shape.\n */\nexport interface MatrxHttpErrorLike {\n status?: unknown;\n serverDetail?: unknown;\n}\n\n/** The places a structured detail can sit: FastAPI `detail`, envelope `details`, envelope top level. */\nfunction detailCandidates(body: unknown): Record<string, unknown>[] {\n if (!isRecord(body)) return [];\n const out: Record<string, unknown>[] = [];\n if (isRecord(body.detail)) out.push(body.detail);\n if (isRecord(body.details)) out.push(body.details);\n out.push(body);\n return out;\n}\n\nfunction statusOf(error: unknown): number | null {\n if (!isRecord(error) && !(error instanceof Error)) return null;\n const status = (error as MatrxHttpErrorLike).status;\n return typeof status === \"number\" ? status : null;\n}\n\nfunction bodyOf(error: unknown): unknown {\n if (!isRecord(error) && !(error instanceof Error)) return undefined;\n return (error as MatrxHttpErrorLike).serverDetail;\n}\n\n/**\n * The machine code of a Matrx HTTP error: `code` (or the envelope's hoisted\n * `error`) from `detail`, `details`, or the top level. Null when absent.\n */\nexport function readMatrxErrorCode(error: unknown): string | null {\n for (const candidate of detailCandidates(bodyOf(error))) {\n const code = nonBlank(candidate.code);\n if (code) return code;\n }\n for (const candidate of detailCandidates(bodyOf(error))) {\n const code = nonBlank(candidate.error);\n if (code) return code;\n }\n return null;\n}\n\n/** Codes the server may carry only as a message prefix (`\"resume_conflict: …\"`). */\nconst PREFIXED_ERROR_CODES = [\n \"resume_conflict\",\n \"not_resumable\",\n \"outstanding_delegated_calls\",\n \"user_request_not_found\",\n \"run_in_flight\",\n] as const;\n\n/**\n * The machine code a server message carries as a PREFIX\n * (`\"resume_conflict: another run is live\"` → `resume_conflict`), for envelope\n * variants that pass the message but map `error` to a generic status word.\n * Only the known resume/turn-lock codes match; null for anything else.\n */\nexport function readMatrxErrorCodeFromMessage(\n message: string | null | undefined,\n): string | null {\n if (typeof message !== \"string\") return null;\n for (const code of PREFIXED_ERROR_CODES) {\n if (message.startsWith(`${code}:`)) return code;\n }\n return null;\n}\n\n/**\n * The conversation's own organization id, for scoping a resume/rejoin to the\n * RUN's organization instead of the session's selection. Transport-agnostic:\n * the host injects `read` (a supabase select, a REST call, …) returning the raw\n * `organization_id` (or throwing). Null — with `onUnreadable(reason)` — when it\n * is missing or unreadable, so the caller keeps the active organization and\n * says so.\n */\nexport async function readConversationOrganizationId(\n conversationId: string,\n read: (conversationId: string) => Promise<unknown>,\n onUnreadable?: (reason: string | null) => void,\n): Promise<string | null> {\n try {\n const value = await read(conversationId);\n if (typeof value === \"string\" && value.trim()) return value;\n onUnreadable?.(null);\n } catch (error) {\n onUnreadable?.(error instanceof Error ? error.message : String(error));\n }\n return null;\n}\n\n/** Where to rejoin a live run, read from a resume door's 409. */\nexport interface MatrxLiveRunRejoin {\n /** The live request (`GET /runtime/operations/{id}`); null for doors outside the spine (SEO). */\n liveRequestId: string | null;\n /** Server-relative path to `POST` for the NDJSON replay-then-follow. Always from the body when present. */\n rejoinPath: string;\n /** `run_id` extra (workflow / SEO / comparison), when present. */\n runId: string | null;\n /** The refusal's code — always `run_in_progress` (chat's `resume_conflict` is retried, never rejoined). */\n code: string;\n /** The refusal body (root of the envelope), for door-specific extras (`arm_index`, `analysis_id`, …). */\n body: Record<string, unknown>;\n}\n\nfunction firstString(candidates: Record<string, unknown>[], key: string): string | null {\n for (const candidate of candidates) {\n const value = nonBlank(candidate[key]);\n if (value) return value.trim();\n }\n return null;\n}\n\n/**\n * The rejoin target of a live-run refusal: `409` with `code: run_in_progress`.\n * Null for every other error — a genuine failure is never mistaken for a live\n * run, and chat's `resume_conflict` is never a rejoin even when its body names\n * one (the host retries the resume so the continuation runs). Reads\n * `rejoin_path` from the body first; derives the runtime rejoin from\n * `live_request_id` only when the body names no path. Never reads\n * `request_id`.\n */\nexport function readLiveRunRejoin(error: unknown): MatrxLiveRunRejoin | null {\n if (statusOf(error) !== 409) return null;\n const candidates = detailCandidates(bodyOf(error));\n if (candidates.length === 0) return null;\n const code = readMatrxErrorCode(error);\n if (code !== MATRX_RUN_IN_PROGRESS) return null;\n const liveRequestId = firstString(candidates, \"live_request_id\");\n const pathFromBody = firstString(candidates, \"rejoin_path\");\n const rejoinPath =\n pathFromBody && pathFromBody.startsWith(\"/\")\n ? pathFromBody\n : liveRequestId\n ? runtimeOperationRejoinPath(liveRequestId)\n : null;\n if (!rejoinPath) return null;\n const root = bodyOf(error);\n return {\n liveRequestId,\n rejoinPath,\n runId: firstString(candidates, \"run_id\"),\n code,\n body: isRecord(root) ? root : {},\n };\n}\n\n/**\n * The request id of a run that is STILL LIVE, read from a resume door's\n * refusal (`live_request_id` — never the envelope's own `request_id`). Null\n * for every other error, and for a live refusal outside the spine (SEO) —\n * follow `readLiveRunRejoin(error).rejoinPath` instead.\n */\nexport function readLiveRunRequestId(error: unknown): string | null {\n return readLiveRunRejoin(error)?.liveRequestId ?? null;\n}\n\n/**\n * `409 resume_conflict` — another run holds the conversation's claim (usually\n * the turn still suspending); retry the resume with the host's backoff so the\n * continuation runs. Never a rejoin, even when the body names a live run.\n */\nexport function isResumeConflict(error: unknown): boolean {\n return (\n statusOf(error) === 409 &&\n readMatrxErrorCode(error) === MATRX_RESUME_CONFLICT\n );\n}\n\n/** `409 live_stream_unavailable` — the rejoin journal is gone; follow the durable lifecycle instead. */\nexport function isLiveStreamUnavailable(error: unknown): boolean {\n return (\n statusOf(error) === 409 &&\n readMatrxErrorCode(error) === MATRX_LIVE_STREAM_UNAVAILABLE\n );\n}\n\n/**\n * The server-relative rejoin path — for hosts whose stream pipeline takes a\n * URL instead of a transport (prepend the resolved base URL).\n */\nexport function runtimeOperationRejoinPath(requestId: string): string {\n return `/runtime/operations/${encodePathSegment(requestId)}/rejoin`;\n}\n\n/**\n * The text to show for a stream `error` event: the server's `user_message`\n * first (it is written for the person — e.g. \"OpenAI refused this request:\n * the platform's OpenAI account is out of credit.\"), then `message`. Accepts\n * the `{event, data}` envelope or its `data` payload. Null when neither is\n * present — the host supplies its own fallback; it must never REPLACE a\n * message the server sent.\n */\nexport function streamErrorText(eventOrPayload: unknown): string | null {\n if (!isRecord(eventOrPayload)) return null;\n const payload =\n typeof eventOrPayload.event === \"string\" && isRecord(eventOrPayload.data)\n ? eventOrPayload.data\n : eventOrPayload;\n return nonBlank(payload.user_message) ?? nonBlank(payload.message);\n}\n\n/**\n * Open any Matrx NDJSON stream by path (`POST`, optional JSON body) — for\n * feature doors outside the agent lifecycle (`/podcast/resume/{run_id}`, …)\n * so their streams ride the same transport and wire kernel as every run.\n */\nexport async function openMatrxStream(\n transport: MatrxTransport,\n path: string,\n options: MatrxStreamCallOptions & { body?: unknown } = {},\n): Promise<MatrxRunHandle> {\n const response = await requestStream(transport, path, {\n method: \"POST\",\n ...(options.body !== undefined ? { body: options.body } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return toRunHandle(response, options);\n}\n\n/**\n * Bind a run's organization onto every call as `X-Organization-Id`. Host\n * policy headers still merge on top; the package's own `createMatrxTransport`\n * refuses a disagreeing org (`organization_context_mismatch`) rather than\n * silently swapping it, so a host must not force the SESSION org onto a\n * resume/rejoin transport.\n */\nexport function withRunOrganization(\n transport: MatrxTransport,\n organizationId: string,\n): MatrxTransport {\n const orgId = requireOrganizationContext(organizationId);\n return {\n fetch: (path, init) =>\n transport.fetch(path, {\n ...init,\n headers: { ...init.headers, \"X-Organization-Id\": orgId },\n }),\n };\n}\n\n/**\n * Follow a workflow run's SSE (`GET /runs/{run_id}/events/stream`) — the\n * rejoin fallback for workflow legs with no stream journal. Delivers every\n * parsed event (durable run events with their seq; ephemeral `node_stream`\n * frames — including `kind: \"media\"` — with seq null). One connection, no\n * reconnect policy: resolves `{ended: true}` on the server's `end` frame,\n * `{ended: false}` when the wire closes or the caller aborts.\n */\nexport async function followWorkflowRunEvents(\n transport: MatrxTransport,\n runId: string,\n options: {\n onEvent: (event: Record<string, unknown>, seq: number | null) => void;\n lastEventId?: number | null;\n signal?: AbortSignal;\n },\n): Promise<{ ended: boolean }> {\n const headers: Record<string, string> = { Accept: \"text/event-stream\" };\n if (options.lastEventId) headers[\"Last-Event-ID\"] = String(options.lastEventId);\n let response: Response;\n try {\n response = await requestStream(\n transport,\n `/runs/${encodePathSegment(runId)}/events/stream`,\n {\n method: \"GET\",\n headers,\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n } catch (error) {\n if (options.signal?.aborted) return { ended: false };\n throw error;\n }\n try {\n for await (const frame of readMatrxSseStream(\n response.body as ReadableStream<Uint8Array>,\n )) {\n if (frame.event === \"end\") return { ended: true };\n if (frame.data === null) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(frame.data);\n } catch {\n continue;\n }\n if (!isRecord(parsed)) continue;\n options.onEvent(parsed, parsed.event === \"node_stream\" ? null : frame.seq);\n }\n } catch (error) {\n if (!options.signal?.aborted) throw error;\n }\n return { ended: false };\n}\n\nexport type ResumeOrRejoinOutcome =\n /** The resume door ran the run; its stream was delivered to `onEnvelope`. */\n | { kind: \"resumed\"; requestId: string | null }\n /** The run was live; its stream (from `rejoin_path`) was replayed + followed into `onEnvelope`. */\n | { kind: \"rejoined\"; rejoin: MatrxLiveRunRejoin }\n /**\n * The run was live but had no journal to replay; the durable lifecycle was\n * followed instead. Re-query the feature's record for the result.\n * `ended: false` = the follow gave up (or no operation was found).\n */\n | {\n kind: \"followed\";\n rejoin: MatrxLiveRunRejoin;\n executionId: string | null;\n ended: boolean;\n status: MatrxRuntimeExecutionStatus | null;\n }\n /** No journal, and the run is a workflow: its run SSE was followed into `onWorkflowEvent`. */\n | { kind: \"followed_workflow\"; rejoin: MatrxLiveRunRejoin; runId: string; ended: boolean }\n /** `409 resume_conflict` (named live run or not) — retry with the host's backoff policy. */\n | { kind: \"resume_conflict\"; error: MatrxApiError };\n\nexport interface ResumeOrRejoinOptions\n extends Omit<MatrxStreamCallOptions, \"signal\"> {\n /** Every NDJSON envelope — from the resume stream OR the rejoined stream. */\n onEnvelope: (envelope: MatrxStreamEnvelope) => void;\n /** THE RUN'S organization (from its durable record) — bound on every call. */\n organizationId?: string | null;\n signal?: AbortSignal;\n /** Fired the moment a live run is detected, before the rejoin opens (reset replay-sensitive state). */\n onRejoin?: (rejoin: MatrxLiveRunRejoin) => void;\n /** Durable lifecycle events while following (the no-journal fallback). */\n onOperationEvent?: (event: MatrxRuntimeOperationEvent) => void;\n /** Workflow run SSE events (the no-journal fallback for a workflow `run_id`). */\n onWorkflowEvent?: (event: Record<string, unknown>, seq: number | null) => void;\n /** Tuning for the durable follow (stall / reconnect policy). */\n follow?: Omit<\n FollowRuntimeOperationToEndOptions,\n \"onEvent\" | \"signal\" | \"lastEventSeq\"\n >;\n}\n\nasync function drain(\n handle: MatrxRunHandle,\n onEnvelope: (envelope: MatrxStreamEnvelope) => void,\n): Promise<void> {\n for await (const envelope of handle.events) onEnvelope(envelope);\n}\n\n/**\n * Resume a run — or, when the server says it is still live, REJOIN it.\n *\n * Calls `resumeCall` (the feature's resume door) and pipes its stream into\n * `onEnvelope`. On a live-run refusal (`run_in_progress`) it follows the body's `rejoin_path`\n * into the SAME handler under the same organization; when the rejoin has no\n * journal (`live_stream_unavailable`) it follows the workflow run SSE (body\n * names a workflow `run_id`) or the durable lifecycle. Never runs a live run a\n * second time. Every `resume_conflict` comes back as an outcome; any other\n * error is thrown.\n */\nexport async function resumeOrRejoin(\n transport: MatrxTransport,\n resumeCall: (\n transport: MatrxTransport,\n options: MatrxStreamCallOptions,\n ) => Promise<MatrxRunHandle>,\n options: ResumeOrRejoinOptions,\n): Promise<ResumeOrRejoinOutcome> {\n const {\n onEnvelope,\n organizationId,\n onRejoin,\n onOperationEvent,\n onWorkflowEvent,\n follow,\n ...rest\n } = options;\n const bound = organizationId\n ? withRunOrganization(transport, organizationId)\n : transport;\n const streamOptions: MatrxStreamCallOptions = {\n ...rest,\n ...(options.signal ? { signal: options.signal } : {}),\n };\n const signalOnly = options.signal ? { signal: options.signal } : {};\n\n let rejoin: MatrxLiveRunRejoin;\n try {\n const handle = await resumeCall(bound, streamOptions);\n await drain(handle, onEnvelope);\n return { kind: \"resumed\", requestId: handle.requestId };\n } catch (error) {\n const target = readLiveRunRejoin(error);\n if (!target) {\n if (error instanceof MatrxApiError && isResumeConflict(error)) {\n return { kind: \"resume_conflict\", error };\n }\n throw error;\n }\n rejoin = target;\n }\n\n onRejoin?.(rejoin);\n let unavailable: MatrxLiveStreamUnavailable;\n try {\n const handle = await openMatrxStream(bound, rejoin.rejoinPath, {\n ...streamOptions,\n // The rejoin routes take no body model; the reference client posts {}.\n body: {},\n });\n await drain(handle, onEnvelope);\n return { kind: \"rejoined\", rejoin };\n } catch (error) {\n const read = readLiveStreamUnavailable(error);\n if (!read) throw error;\n unavailable = read;\n }\n\n // `bound` already carries the run's organization.\n return followUnavailableRejoin(bound, rejoin, unavailable, {\n ...signalOnly,\n ...(onOperationEvent ? { onOperationEvent } : {}),\n ...(onWorkflowEvent ? { onWorkflowEvent } : {}),\n ...(follow ? { follow } : {}),\n });\n}\n\n/** What a `409 live_stream_unavailable` rejoin answer names: a workflow `run_id`, when it has one. */\nexport interface MatrxLiveStreamUnavailable {\n runId: string | null;\n}\n\n/**\n * Read a rejoin's `409 live_stream_unavailable` (the journal is gone). Null\n * for every other error. For hosts that open the rejoin stream themselves —\n * hand the result to `followUnavailableRejoin`.\n */\nexport function readLiveStreamUnavailable(\n error: unknown,\n): MatrxLiveStreamUnavailable | null {\n if (!isLiveStreamUnavailable(error)) return null;\n return { runId: firstString(detailCandidates(bodyOf(error)), \"run_id\") };\n}\n\nexport type MatrxFollowedOutcome = Extract<\n ResumeOrRejoinOutcome,\n { kind: \"followed\" | \"followed_workflow\" }\n>;\n\nexport interface FollowUnavailableRejoinOptions {\n /** THE RUN'S organization; omit when `transport` is already bound to it. */\n organizationId?: string | null;\n signal?: AbortSignal;\n onOperationEvent?: (event: MatrxRuntimeOperationEvent) => void;\n onWorkflowEvent?: (event: Record<string, unknown>, seq: number | null) => void;\n follow?: Omit<\n FollowRuntimeOperationToEndOptions,\n \"onEvent\" | \"signal\" | \"lastEventSeq\"\n >;\n}\n\n/**\n * The no-journal fallback of a rejoin — the SAME branch `resumeOrRejoin`\n * takes, exported for hosts whose rejoin stream rides their own wire (the\n * extension's offscreen fetch, the desktop's request loop). A workflow\n * `run_id` (from the unavailable body, else the refusal) on a runtime rejoin\n * → follow the workflow run SSE; otherwise read the live operation and\n * follow it to its end. Settle the result with `settleRunPickup`.\n */\nexport async function followUnavailableRejoin(\n transport: MatrxTransport,\n rejoin: MatrxLiveRunRejoin,\n unavailable: MatrxLiveStreamUnavailable,\n options: FollowUnavailableRejoinOptions = {},\n): Promise<MatrxFollowedOutcome> {\n const bound = options.organizationId\n ? withRunOrganization(transport, options.organizationId)\n : transport;\n const signalOnly = options.signal ? { signal: options.signal } : {};\n\n const runId = unavailable.runId ?? rejoin.runId;\n if (runId && rejoin.rejoinPath.startsWith(\"/runtime/operations/\")) {\n const result = await followWorkflowRunEvents(bound, runId, {\n ...signalOnly,\n onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq),\n });\n return { kind: \"followed_workflow\", rejoin, runId, ended: result.ended };\n }\n\n const liveRequestId = rejoin.liveRequestId;\n const statusView = liveRequestId\n ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly)\n : null;\n const operation =\n statusView?.operations.find((op) => !op.is_terminal) ??\n statusView?.operations[0] ??\n null;\n if (!operation) {\n return { kind: \"followed\", rejoin, executionId: null, ended: false, status: null };\n }\n if (operation.is_terminal) {\n return {\n kind: \"followed\",\n rejoin,\n executionId: operation.execution_id,\n ended: true,\n status: operation.status,\n };\n }\n const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {\n ...options.follow,\n lastEventSeq: operation.last_event_seq,\n ...signalOnly,\n onEvent: (event) => options.onOperationEvent?.(event),\n });\n return {\n kind: \"followed\",\n rejoin,\n executionId: operation.execution_id,\n ended: result.ended,\n status: result.status,\n };\n}\n\n/**\n * The parts of a pick-up result `settleRunPickup` reads — every\n * `ResumeOrRejoinOutcome` is one, and so is a host's own follow result.\n */\nexport type MatrxRunPickup =\n | { kind: \"resumed\" | \"rejoined\" }\n | { kind: \"resume_conflict\" }\n | {\n kind: \"followed\";\n executionId: string | null;\n ended: boolean;\n status: MatrxRuntimeExecutionStatus | null;\n }\n | { kind: \"followed_workflow\"; ended: boolean };\n\nexport type MatrxRunPickupSettlement =\n /** The turn arrived on a stream the host already rendered — nothing to reload. */\n | { state: \"streamed\" }\n /** Bare `resume_conflict` — retry with the host's backoff. */\n | { state: \"retry\" }\n /**\n * The run is over (or no live operation remains): the SAVED turn was\n * reloaded — that is the answer to show, never an empty bubble and never a\n * failure the run did not have. `status` null = unknown (workflow / none\n * found); `reloaded: false` = the reload itself threw (`error`).\n */\n | {\n state: \"settled\";\n status: MatrxRuntimeExecutionStatus | null;\n reloaded: boolean;\n error?: unknown;\n }\n /** The follow gave up while the run may still be live; `onStillRunning` (default: reload what is saved) ran. */\n | { state: \"still_running\"; reloaded: boolean; error?: unknown };\n\nexport interface SettleRunPickupOptions {\n /** Re-read the feature's saved record (the conversation's messages) into the screen. */\n reloadSavedTurn: () => Promise<void> | void;\n /**\n * The follow gave up on a run that may still be live. Default: reload what\n * is saved now. A host with its own patient recovery (the web app's\n * dropped-stream poll) passes it here instead.\n */\n onStillRunning?: () => Promise<void> | void;\n}\n\nasync function attempt(run: () => Promise<void> | void): Promise<{ reloaded: boolean; error?: unknown }> {\n try {\n await run();\n return { reloaded: true };\n } catch (error) {\n return { reloaded: false, error };\n }\n}\n\n/**\n * THE one mapping from a pick-up result to what the screen does, shared by\n * every chat client so a live run that cannot replay ends the same way\n * everywhere: streamed → done; bare conflict → retry; followed to its end\n * (or nothing live left to follow) → reload the saved turn and report the\n * run's real status; follow gave up → still running (never \"failed\").\n */\nexport async function settleRunPickup(\n pickup: MatrxRunPickup,\n options: SettleRunPickupOptions,\n): Promise<MatrxRunPickupSettlement> {\n switch (pickup.kind) {\n case \"resumed\":\n case \"rejoined\":\n return { state: \"streamed\" };\n case \"resume_conflict\":\n return { state: \"retry\" };\n case \"followed_workflow\":\n case \"followed\": {\n const status = pickup.kind === \"followed\" ? pickup.status : null;\n // No operation left on the spine = the turn already settled; its saved\n // record is the truth.\n const nothingLive = pickup.kind === \"followed\" && pickup.executionId === null;\n if (pickup.ended || nothingLive) {\n return { state: \"settled\", status, ...(await attempt(options.reloadSavedTurn)) };\n }\n return {\n state: \"still_running\",\n ...(await attempt(options.onStillRunning ?? options.reloadSavedTurn)),\n };\n }\n }\n}\n","/**\n * Agent run lifecycle against the AI Matrx API — start, continue, resume,\n * cancel — over the `MatrxTransport` port, with every streaming response\n * parsed through the package's ONE NDJSON wire kernel (`stream/ndjson`).\n *\n * Server truth (verified against aidream source):\n * - `POST /ai/agents/{agent_id}` — start (`aidream/api/routers/agents.py`)\n * - `POST /ai/conversations/{conversation_id}` — continue (`aidream/api/routers/conversations.py`)\n * - `POST /ai/conversations/{conversation_id}/resume` — resume after\n * client-delegated tool suspension (same router)\n * - `POST /ai/cancel/{request_id}?mode=interrupt` — cancel (`aidream/api/routers/cancel.py`)\n *\n * Response headers arrive before the body: `X-Conversation-ID` and\n * `X-Request-ID` are surfaced on the run handle immediately. `X-Request-ID`\n * is the ONLY id the server accepts for cancel — a client-local id means\n * nothing to it.\n *\n * Host policy stays out: no retry, no store, no timeouts, no persistence\n * (C10: no-persistence). Cancellation is the caller's `AbortSignal`; a client\n * disconnect never stops server work (`detach_on_disconnect`).\n */\n\nimport type { MatrxStreamEnvelope } from \"../stream/ndjson\";\nimport type {\n MatrxConversationStart,\n MatrxJsonObject,\n MatrxJsonValue,\n} from \"./conversation\";\nimport {\n encodePathSegment,\n buildQuery,\n requestJson,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\nimport { streamErrorText } from \"./rejoin\";\n\nexport type { MatrxRunHandle, MatrxStreamCallOptions } from \"./internal\";\n\n// ─── Request shapes (mirroring the server's Pydantic models) ────────────────\n\n/**\n * Stable identity of the durable entity whose saved context owns a run —\n * the server reloads the row and uses ITS scope (`ContextAnchor`,\n * `aidream/services/conversation_context/scope.py`).\n */\nexport interface MatrxContextAnchor {\n resource_type: string;\n resource_id: string;\n}\n\n/**\n * Scope and source fields shared by every scoped request\n * (`ScopedRequest` / `AcceptsInjectedScope` server-side). All optional here;\n * the start request narrows `organization_id` to required.\n */\nexport interface MatrxRequestScope {\n organization_id?: string;\n project_id?: string | null;\n task_id?: string | null;\n /** Active context-scope ids from the client's global picker (membership-validated server-side). */\n scope_ids?: string[] | null;\n /** Active scope-TYPE ids — a type-level selection with no specific scope chosen. */\n active_scope_type_ids?: string[] | null;\n context_anchor?: MatrxContextAnchor | null;\n /** Stable application slug that initiated the request. */\n source_app?: string | null;\n /** Stable feature slug within the source application. */\n source_feature?: string | null;\n /** \"user\" = a person directly triggered this; \"auto\" = client automation; omit for API callers. */\n initiation?: \"user\" | \"auto\" | null;\n /** Specific connected desktop instance allowed to claim delegated local tools. */\n target_instance_id?: string | null;\n}\n\n/**\n * Fields shared by start/continue turn requests (tool injection, client\n * capability envelope, context object). The complex bags (`tools`, `client`,\n * `user`, `config_overrides`) are typed as JSON objects — their authoritative\n * schemas are the server's Pydantic models and the generated API types;\n * this package stays payload-agnostic about them by design.\n */\nexport interface MatrxTurnFields {\n /** What the human typed (string), or structured input parts. Never smuggle machine content here. */\n user_input?: string | MatrxJsonValue[] | null;\n /** Per-run model/config overrides (LLMParams shape). */\n config_overrides?: MatrxJsonObject | null;\n debug?: boolean;\n /** Additive tool specs merged into the agent's resolved tool set. */\n tools?: MatrxJsonObject[];\n /** When set, becomes the agent's ENTIRE tool set for the turn. */\n tools_replace?: MatrxJsonObject[] | null;\n /** Client capability envelope (`ClientContext`). */\n client?: MatrxJsonObject | null;\n /** Per-request user-level tool inclusion/exclusion overrides. */\n user?: MatrxJsonObject | null;\n /** Per-route context object, free-form by design. */\n context?: MatrxJsonObject;\n writable_variables?: string[];\n allow_context_create?: boolean;\n /** Request-snapshot capture override (tri-state; omit for the platform default). */\n snapshot?: boolean | null;\n}\n\n/**\n * `POST /ai/agents/{agent_id}` body (`AgentStartRequest` server-side).\n * The conversation-start triple is required by construction; `organization_id`\n * is required (the server 422s a blank one — it never manufactures an org).\n * `stream` is not accepted here: this client is the streaming path and always\n * sends `stream: true`.\n */\nexport type MatrxAgentStartRequest = MatrxConversationStart &\n Omit<MatrxRequestScope, \"organization_id\"> &\n MatrxTurnFields & {\n organization_id: string;\n /** Variable name → value map filling the agent's declared variables. */\n variables?: MatrxJsonObject | null;\n /** Run the versions table row instead of the live agent row. */\n is_version?: boolean;\n max_iterations?: number;\n max_retries_per_iteration?: number;\n };\n\n/**\n * `POST /ai/mandates/{mandate_key}` uses the exact saved-agent start body.\n * The server resolves the mandate's holder, binding, and configuration; a\n * client must offer only the declared variables and human input here.\n */\nexport type MatrxMandateStartRequest = MatrxAgentStartRequest;\n\n/** `POST /ai/conversations/{id}` body (`ConversationContinueRequest` server-side). */\nexport type MatrxConversationContinueRequest = MatrxRequestScope &\n MatrxTurnFields & {\n /** Re-run the conversation's current persisted state (recovery after a failed turn); omit `user_input`. */\n retry?: boolean;\n };\n\n/**\n * `POST /ai/conversations/{id}/resume` body (`ResumeRequest` server-side) —\n * the shipped durable continuation after client-delegated tool calls were\n * answered via `POST /tool_results` while the original stream was gone.\n * `user_request_id` is optional: when omitted the server resolves the turn\n * from the conversation's newest answered client-delegated tool call.\n * Re-send fresh `context` here — a resumed loop is otherwise context-blind.\n */\nexport type MatrxConversationResumeRequest = MatrxRequestScope & {\n user_request_id?: string | null;\n config_overrides?: MatrxJsonObject | null;\n debug?: boolean;\n tools?: MatrxJsonObject[];\n tools_replace?: MatrxJsonObject[] | null;\n client?: MatrxJsonObject | null;\n user?: MatrxJsonObject | null;\n context?: MatrxJsonObject;\n writable_variables?: string[];\n allow_context_create?: boolean;\n};\n\n/** `POST /ai/cancel/{request_id}` response (`CancelResponse` server-side). */\nexport interface MatrxCancelResponse {\n status: string;\n request_id: string;\n spine_executions_signalled: string[];\n}\n\n// ─── The run handle ─────────────────────────────────────────────────────────\n// `MatrxStreamCallOptions`, `MatrxRunHandle`, and the handle constructor live\n// in ./internal so `./operations`' rejoin shares the exact same construction.\n\nasync function streamCall(\n transport: MatrxTransport,\n path: string,\n body: object,\n options: MatrxStreamCallOptions,\n): Promise<MatrxRunHandle> {\n const response = await requestStream(transport, path, {\n method: \"POST\",\n // This client IS the streaming path — `stream: true` always, last so a\n // caller-supplied value can never flip the response off NDJSON.\n body: { ...body, stream: true },\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return toRunHandle(response, options);\n}\n\n// ─── Lifecycle calls ────────────────────────────────────────────────────────\n\n/** Start an agent run: `POST /ai/agents/{agent_id}` (NDJSON stream). */\nexport function startAgentRun(\n transport: MatrxTransport,\n agentId: string,\n request: MatrxAgentStartRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/agents/${encodePathSegment(agentId)}`,\n request,\n options,\n );\n}\n\n/**\n * Start a declared mandate: `POST /ai/mandates/{mandate_key}` (NDJSON\n * stream). This is deliberately separate from `startAgentRun`: callers name\n * the mandate and never resolve or echo its holder/configuration themselves.\n */\nexport function startMandateRun(\n transport: MatrxTransport,\n mandateKey: string,\n request: MatrxMandateStartRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/mandates/${encodePathSegment(mandateKey)}`,\n request,\n options,\n );\n}\n\n/** Continue a stored conversation: `POST /ai/conversations/{id}` (NDJSON stream). */\nexport function continueAgentConversation(\n transport: MatrxTransport,\n conversationId: string,\n request: MatrxConversationContinueRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}`,\n request,\n options,\n );\n}\n\n/**\n * Resume a suspended loop after delegated tool answers landed:\n * `POST /ai/conversations/{id}/resume` (NDJSON stream). A 409\n * (`resume_conflict`) means another resume holds the run claim — retrying is\n * host policy.\n */\nexport function resumeAgentConversation(\n transport: MatrxTransport,\n conversationId: string,\n request: MatrxConversationResumeRequest = {},\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/resume`,\n request,\n options,\n );\n}\n\n/**\n * Stop a running request at its next iteration boundary:\n * `POST /ai/cancel/{request_id}`. Cooperative and best-effort — the in-flight\n * provider call finishes by design, and everything already streamed persists.\n * `mode: \"interrupt\"` = stop-and-fork: the tail after the last clean boundary\n * persists hidden so the user's follow-up replies to what they actually saw.\n * The id must be the server's `X-Request-ID`.\n */\nexport function cancelAgentRun(\n transport: MatrxTransport,\n requestId: string,\n options: { mode?: \"cancel\" | \"interrupt\"; signal?: AbortSignal } = {},\n): Promise<MatrxCancelResponse> {\n const query = buildQuery(\n options.mode === \"interrupt\" ? { mode: \"interrupt\" } : {},\n );\n return requestJson<MatrxCancelResponse>(\n transport,\n `/ai/cancel/${encodePathSegment(requestId)}${query}`,\n {\n method: \"POST\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n// ─── End-to-end convenience: run to completion ──────────────────────────────\n\n/**\n * A run that terminated unsuccessfully: the server emitted a fatal `error`\n * event, or the `user_request` completion settled `failed`/`cancelled`.\n */\nexport class MatrxRunError extends Error {\n override readonly name = \"MatrxRunError\";\n /** The verbatim `error` event payload, when one fired. */\n readonly errorPayload: Record<string, unknown> | null;\n /** The `user_request` completion status (`\"failed\"` | `\"cancelled\"`), when that was the trigger. */\n readonly completionStatus: string | null;\n /** Text streamed before the failure — partial content never vanishes. */\n readonly partialText: string;\n\n constructor(args: {\n message: string;\n errorPayload?: Record<string, unknown> | null;\n completionStatus?: string | null;\n partialText?: string;\n }) {\n super(args.message);\n this.errorPayload = args.errorPayload ?? null;\n this.completionStatus = args.completionStatus ?? null;\n this.partialText = args.partialText ?? \"\";\n }\n}\n\nexport interface MatrxCompletedRun {\n /** Accumulated `chunk` text (falls back to the completion's `result.output`). */\n text: string;\n requestId: string | null;\n conversationId: string | null;\n /** The `user_request` completion payload, verbatim, when one arrived. */\n completion: Record<string, unknown> | null;\n}\n\nexport interface RunAgentToCompletionOptions extends MatrxStreamCallOptions {\n /** Live progress: the full accumulated text after each chunk. */\n onChunk?: (fullText: string) => void;\n /** Every normalized envelope, before this helper interprets it. */\n onEvent?: (envelope: MatrxStreamEnvelope) => void;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(value: unknown, key: string): string | null {\n if (!isRecord(value)) return null;\n const field = value[key];\n return typeof field === \"string\" && field ? field : null;\n}\n\n/**\n * Run an agent end-to-end and resolve with its full text output — the\n * package-level equivalent of the simplest existing host path\n * (`useRunAgent`): accumulate `chunk` text, treat a fatal `error` event or a\n * `failed`/`cancelled` `user_request` completion as a thrown `MatrxRunError`,\n * and fall back to the completion's `result.output` when no text streamed.\n *\n * The caller still owns the conversation-start triple on `request` — a\n * one-shot run typically uses `newEphemeralConversationStart()`.\n */\nexport async function runAgentToCompletion(\n transport: MatrxTransport,\n agentId: string,\n request: MatrxAgentStartRequest,\n options: RunAgentToCompletionOptions = {},\n): Promise<MatrxCompletedRun> {\n const handle = await startAgentRun(transport, agentId, request, options);\n\n let text = \"\";\n let completion: Record<string, unknown> | null = null;\n let failure: MatrxRunError | null = null;\n\n for await (const envelope of handle.events) {\n options.onEvent?.(envelope);\n\n if (envelope.event === \"chunk\") {\n const chunk = stringField(envelope.data, \"text\");\n if (chunk !== null) {\n text += chunk;\n options.onChunk?.(text);\n }\n continue;\n }\n\n if (envelope.event === \"error\" && failure === null) {\n const payload = isRecord(envelope.data) ? envelope.data : null;\n failure = new MatrxRunError({\n message: streamErrorText(payload) ?? \"The agent run failed\",\n errorPayload: payload,\n partialText: text,\n });\n continue;\n }\n\n if (envelope.event !== \"completion\" || !isRecord(envelope.data)) continue;\n // `init`/`completion` pairs exist for five operations; the terminal\n // outcome of the run is the `user_request` completion (STREAM-CONTRACT\n // §3.2 — always present, always last).\n if (envelope.data.operation !== \"user_request\") continue;\n\n completion = envelope.data;\n const status = envelope.data.status;\n if ((status === \"failed\" || status === \"cancelled\") && failure === null) {\n const result = isRecord(envelope.data.result) ? envelope.data.result : null;\n failure = new MatrxRunError({\n message:\n stringField(result, \"error\") ??\n stringField(result, \"user_message\") ??\n `The agent run ${status}`,\n completionStatus: status,\n partialText: text,\n });\n }\n }\n\n if (failure) throw failure;\n\n if (!text && completion) {\n const result = completion.result;\n const output = stringField(result, \"output\");\n if (output !== null) text = output;\n }\n\n return {\n text,\n requestId: handle.requestId,\n conversationId: handle.conversationId,\n completion,\n };\n}\n","/**\n * Browser-held provider sessions report their failures through the server.\n *\n * Realtime voice (OpenAI / xAI) and Cartesia TTS run browser → provider\n * directly on an ephemeral token from the token broker, so a provider refusal\n * (e.g. the platform's account is out of credit) never touches the server —\n * the operator would never hear of it, and the person would see raw provider\n * text. Every client calls `reportProviderSessionFailure` from the session's\n * error handler and shows the returned `user_message`.\n *\n * Server truth: `POST /broker/provider-failures`\n * (`aidream/api/routers/token_broker.py`; body `ProviderSessionFailureReport`\n * in `aidream/services/token_broker/models.py` — `extra=\"forbid\"`, allow-listed\n * providers, bounded text; identity and organization come from the session).\n */\n\nimport { requestJson } from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\n\n/** The providers whose sessions a browser holds directly (server allow-list). */\nexport type MatrxClientSessionProvider = \"openai\" | \"xai\" | \"cartesia\";\n\nexport interface ProviderSessionFailure {\n provider: MatrxClientSessionProvider;\n model?: string | null;\n /** HTTP status the provider answered, when the failure was an HTTP answer. */\n status_code?: number | null;\n /** The provider's own error type/code (`insufficient_quota`, …). */\n error_type?: string | null;\n /** The provider's text, verbatim — classified server-side, never shown. */\n message: string;\n}\n\n/** `ProviderSessionFailureVerdict` — what to show, and whether reconnecting can help. */\nexport interface ProviderSessionFailureVerdict {\n error_type: string;\n retryable: boolean;\n /** The sentence to show the person (never the provider's raw text). */\n user_message: string;\n}\n\nconst clip = (value: string, max: number): string =>\n value.length > max ? value.slice(0, max) : value;\n\n/** The body the server accepts — bounded exactly as its model bounds it. */\nexport function providerSessionFailureBody(\n failure: ProviderSessionFailure,\n): Record<string, string | number> {\n const message =\n failure.message?.trim() ||\n failure.error_type?.trim() ||\n (failure.status_code ? `HTTP ${failure.status_code}` : \"provider session failed\");\n const body: Record<string, string | number> = {\n provider: failure.provider,\n message: clip(message, 4000),\n };\n if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);\n if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);\n if (\n typeof failure.status_code === \"number\" &&\n Number.isInteger(failure.status_code) &&\n failure.status_code >= 100 &&\n failure.status_code <= 599\n ) {\n body.status_code = failure.status_code;\n }\n return body;\n}\n\n/**\n * Report a browser-held provider session failure and get the sentence to\n * show. Resolves null (and warns) when the report itself could not be made —\n * the caller then shows its own fallback; it never throws from an error\n * handler.\n */\nexport async function reportProviderSessionFailure(\n transport: MatrxTransport,\n failure: ProviderSessionFailure,\n options: { signal?: AbortSignal } = {},\n): Promise<ProviderSessionFailureVerdict | null> {\n try {\n return await requestJson<ProviderSessionFailureVerdict>(\n transport,\n \"/broker/provider-failures\",\n {\n method: \"POST\",\n body: providerSessionFailureBody(failure),\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n } catch (error) {\n console.warn(\n `[provider-failures] could not report a ${failure.provider} session failure`,\n error,\n );\n return null;\n }\n}\n","/**\n * Delegated client tools — submit results and discover pending calls.\n *\n * Server truth (verified against aidream source,\n * `aidream/api/routers/conversations.py` + `aidream/services/ai_execution/\n * tool_results.py`):\n * - `POST /ai/conversations/{id}/tool_results` — durable, idempotent submit.\n * A delegated tool call HARD-SUSPENDS the loop; when the last outstanding\n * delegated row for the user_request resolves, the response carries\n * `continuation_needed: true` and the owning `user_request_id` — the signal\n * to open `resumeAgentConversation`. `continuation_needed` is best-effort:\n * parallel submits can both see `true`; `/resume` takes an atomic run claim\n * and the loser gets a 409.\n * - `GET /ai/conversations/{id}/pending_calls` — delegated calls awaiting the\n * user in one conversation (rows survive disconnects and reloads).\n * - `GET /ai/user/pending_calls` — every pending call for this user; an\n * optional `instance_id` atomically claims them for a desktop instance.\n *\n * A 404 from the submit means EVERY call_id was unknown (duplicate/expired);\n * partial success returns 200 with `not_found` populated. Batching, retries,\n * and the resume handoff are host policy — this module is the wire.\n */\n\nimport type { MatrxJsonObject, MatrxJsonValue } from \"./conversation\";\nimport { encodePathSegment, buildQuery, requestJson } from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\n\n/** One client tool answer (`ClientToolResult` server-side). */\nexport interface MatrxClientToolResult {\n call_id: string;\n tool_name: string;\n /** Tool output — inherently polymorphic; recursive JSON by design. */\n output?: MatrxJsonValue | null;\n is_error?: boolean;\n error_message?: string | null;\n /** Client-measured execution time in ms. */\n duration_ms?: number | null;\n}\n\n/** `POST /tool_results` response (`ToolResultsResponse` server-side). */\nexport interface MatrxToolResultsResponse {\n resolved: string[];\n already_resolved: string[];\n not_found: string[];\n /** True when the original stream is gone and no delegated calls remain — open `/resume`. */\n continuation_needed: boolean;\n user_request_id: string | null;\n conversation_id: string;\n}\n\n/** One delegated call awaiting an answer (`PendingCallSummary` server-side). */\nexport interface MatrxPendingCallSummary {\n id: string;\n call_id: string;\n conversation_id: string;\n user_request_id: string | null;\n message_id: string | null;\n tool_name: string;\n /** Tool-call argument bag — schema is per-tool (its input_schema). */\n arguments: MatrxJsonObject;\n iteration: number;\n created_at: string | null;\n expires_at: string | null;\n target_instance_id: string | null;\n claimed_by_instance_id: string | null;\n claim_expires_at: string | null;\n execution_authorization: MatrxJsonObject | null;\n}\n\n/**\n * Submit client tool results: `POST /ai/conversations/{id}/tool_results`.\n * Idempotent — duplicate submits return 200 with the ids in\n * `already_resolved`. Throws `MatrxApiError` (status 404) when every call_id\n * was unknown or expired; the stream stays alive in that case.\n */\nexport function submitAgentToolResults(\n transport: MatrxTransport,\n conversationId: string,\n results: MatrxClientToolResult[],\n options: { instanceId?: string; signal?: AbortSignal } = {},\n): Promise<MatrxToolResultsResponse> {\n return requestJson<MatrxToolResultsResponse>(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/tool_results`,\n {\n method: \"POST\",\n body: {\n results,\n ...(options.instanceId !== undefined\n ? { instance_id: options.instanceId }\n : {}),\n },\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n/**\n * Discover delegated calls awaiting the user in one conversation:\n * `GET /ai/conversations/{id}/pending_calls`. Safe to call on every\n * conversation load; a non-empty list should be surfaced exactly as if the\n * original stream had delivered the `tool_delegated` events live.\n */\nexport function listConversationPendingToolCalls(\n transport: MatrxTransport,\n conversationId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<MatrxPendingCallSummary[]> {\n return requestJson<MatrxPendingCallSummary[]>(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/pending_calls`,\n {\n method: \"GET\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n/**\n * Discover every delegated call awaiting this user across all conversations:\n * `GET /ai/user/pending_calls`. Passing `instanceId` atomically CLAIMS the\n * calls for that desktop instance — only pass it from a client that will\n * actually execute them.\n */\nexport function listUserPendingToolCalls(\n transport: MatrxTransport,\n options: { instanceId?: string; signal?: AbortSignal } = {},\n): Promise<MatrxPendingCallSummary[]> {\n const query = buildQuery(\n options.instanceId !== undefined ? { instance_id: options.instanceId } : {},\n );\n return requestJson<MatrxPendingCallSummary[]>(\n transport,\n `/ai/user/pending_calls${query}`,\n {\n method: \"GET\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n","/**\n * `@ai-matrx/agents/matrx` — every AI Matrx server endpoint path, by feature\n * area (matching the server's router structure). Paths only, rooted at the\n * host (`/ai/...`, `/health`); the HOST owns the base URL.\n *\n * Moved from matrx-frontend `lib/api/endpoints.ts` (chat-package independence\n * P9); the app re-exports it. The production origin and the per-environment\n * base URLs stay in the host (they are environment values).\n */\n\n\nimport type { DynamicMandateKey, MandateKey } from \"../mandates\";\n\n/**\n * All backend API endpoint paths.\n *\n * Organized by feature area matching the backend router structure.\n * Use these constants everywhere instead of hardcoded strings.\n *\n * Auth tiers:\n * - Public: No auth required\n * - Guest OK: Fingerprint or JWT token\n * - Authenticated: Valid JWT token required\n * - Admin: Valid JWT token + admin role\n */\nexport const ENDPOINTS = {\n /** AI endpoints — chat, agents, conversations */\n ai: {\n /**\n * POST — Manual-mode execution (Builder + ephemeral conversations).\n * POST /ai/manual\n *\n * Accepts full message history in `messages` on every call. Used by:\n * • Builder — reads the LIVE agent definition (incl. unsaved edits) and\n * sends it as the system instruction + priming messages.\n * • Ephemeral conversations (turn 2+) — no DB row exists, so the client\n * is the source of truth for history; sends it with each turn.\n *\n * `conversation_id` is optional in the body (for labeling/storage only);\n * pair with `is_new:false, store:false` for fully stateless runs.\n *\n * NOTE: this replaces the legacy `/ai/chat` endpoint. The canonical\n * client-side vocabulary is `manual` (see ConversationInvocation.routing\n * .apiEndpointMode). The legacy `chat` alias below stays for one\n * migration cycle.\n */\n manual: \"/ai/manual\" as const,\n\n /** @deprecated Use `ENDPOINTS.ai.manual`. Kept for one migration cycle. */\n chat: \"/ai/manual\" as const,\n\n /**\n * POST — Start a new agent conversation (Guest OK)\n * POST /ai/agents/{agentId}\n * Never send conversation_id — the server generates it and returns it in the stream.\n */\n agentStart: (agentId: string) => `/ai/agents/${agentId}` as const,\n\n /**\n * POST — THE MANDATE DOOR. Start a new conversation by MANDATE KEY, not by\n * agent id (Guest OK).\n * POST /ai/mandates/{mandateKey}\n *\n * Body is the SAME `AgentStartRequest` as `agentStart`. The server resolves\n * the principal (bearer/fingerprint) → system default → org binding → user\n * binding, applies the binding's `config_overrides`, provision consumption\n * and variable mapping, and then runs the IDENTICAL downstream pipeline\n * (`_run_mandated_agent` → `_run_agent`). A rebind therefore changes which\n * agent answers with NO client deploy — which is the entire point.\n *\n * Never send mandate-derived `config_overrides` on this path: the server\n * treats request config as the EXPLICIT layer that WINS over the binding,\n * so echoing a client-resolved binding back would re-fork resolution.\n *\n * 404 `{code: \"mandate_unfulfilled\"}` when the mandate cannot be resolved —\n * surfaced verbatim, never swallowed into a client-side re-resolve.\n */\n mandateStart: (\n /**\n * 🚨 TYPED, NEVER `string` (V-L6a, 2026-09-17). This is the execute path\n * itself: a stale key here becomes `404 mandate_unfulfilled` on a live\n * surface, so the compiler holds it. `DynamicMandateKey` covers the\n * DB-authored `app.*` / `shortcut.*` jobs that legitimately run here.\n */\n mandateKey: MandateKey | DynamicMandateKey,\n ) => `/ai/mandates/${mandateKey}` as const,\n\n /**\n * POST — Continue any existing conversation (Guest OK)\n * POST /ai/conversations/{conversationId}\n * Conversation ID in URL. Just send user_input in the body.\n */\n conversationContinue: (conversationId: string) =>\n `/ai/conversations/${conversationId}` as const,\n\n /**\n * POST — Pre-warm a conversation's server cache. No body. No auth.\n * POST /ai/conversations/{conversationId}/warm\n * Fire when user navigates to a conversation page.\n */\n conversationWarm: (conversationId: string) =>\n `/ai/conversations/${conversationId}/warm` as const,\n\n /**\n * POST — Pre-warm an agent's server cache. No auth. (public endpoint)\n * POST /ai/agents/{agentId}/warm\n * Optional body: `{ source: \"prompt\" | \"builtin\" | \"prompt_version\" | \"builtin_version\" }`\n */\n agentWarm: (agentId: string) => `/ai/agents/${agentId}/warm` as const,\n\n /**\n * POST — Start a new prompt conversation (Guest OK)\n * POST /ai/prompts/{promptId}\n * Body: PromptStartRequest — user_input, variables, stream, debug, client_tools, etc.\n * Never send conversation_id — the server generates it and returns it in the stream.\n */\n promptStart: (promptId: string) => `/ai/prompts/${promptId}` as const,\n\n /**\n * POST — Pre-warm a prompt's server cache. No auth. (public endpoint)\n * POST /ai/prompts/{promptId}/warm\n * Optional body: `{ source: string | null }`\n */\n promptWarm: (promptId: string) => `/ai/prompts/${promptId}/warm` as const,\n\n /**\n * POST — Start a new block-streaming agent session (Guest OK)\n * POST /ai/agents-blocks/{agentId}\n * Same as agentStart but emits 'content_block' NDJSON events instead of raw 'chunk' events.\n */\n agentBlocksStart: (agentId: string) =>\n `/ai/agents-blocks/${agentId}` as const,\n\n /**\n * POST — Pre-warm a block-streaming agent (Public)\n * POST /ai/agents-blocks/{agentId}/warm\n * Optional body: `{ source: \"prompt\" | \"builtin\" | \"prompt_version\" | \"builtin_version\" }`\n */\n agentBlocksWarm: (agentId: string) =>\n `/ai/agents-blocks/${agentId}/warm` as const,\n\n /**\n * POST — Execute a prompt app using its pinned prompt version (Guest OK)\n * POST /ai/apps/{appId}\n * The backend resolves the pinned prompt version — the client never sees prompt secrets.\n */\n appExecute: (appId: string) => `/ai/apps/${appId}` as const,\n\n /**\n * POST — Pre-warm a prompt app's pinned version into cache (Public, no auth)\n * POST /ai/apps/{appId}/warm\n * Fire when the prompt app page loads so execution is instant.\n */\n appWarm: (appId: string) => `/ai/apps/${appId}/warm` as const,\n\n /** POST — Cancel a running request by request_id (Authenticated) */\n cancel: (requestId: string) => `/ai/cancel/${requestId}` as const,\n },\n\n /** Block processing test endpoints — Guest OK */\n blockProcessing: {\n /** POST — Process raw text/markdown → structured blocks (JSON response) */\n process: \"/utilities/block-processing/process\" as const,\n /** POST — Process raw text/markdown → block events (NDJSON stream, simulates live agent) */\n processStream: \"/utilities/block-processing/process/stream\" as const,\n },\n\n /** CX-data endpoints — conversation/message data (Authenticated) */\n cx: {\n /**\n * GET — Snapshot of \"what the model is currently seeing\" for a conversation.\n * GET /cx/conversations/{conversationId}/context-state\n * Initial hydration for the Model Context tab; live updates come via\n * CONTEXT_STATE / CONTEXT_TRIMMED stream events after each turn.\n */\n contextState: (conversationId: string) =>\n `/cx/conversations/${conversationId}/context-state` as const,\n },\n\n /** CMS server work — authenticated. CMS row CRUD stays direct-to-Supabase. */\n cms: {\n /** POST — Canonical matrx-content-guard validation before CMS writes. */\n validate: \"/cms/validate\" as const,\n /**\n * POST — THE decision door for a queued content exception\n * (`features/approvals/cms-door.ts`). The exception id is the idempotency\n * key; the server finds its queue row and replays the ordinary human write\n * path. Nothing else decides these — the CMS's own review route is gone.\n */\n approveException: (exceptionId: string) =>\n `/cms/exceptions/${encodeURIComponent(exceptionId)}/approve` as const,\n rejectException: (exceptionId: string) =>\n `/cms/exceptions/${encodeURIComponent(exceptionId)}/reject` as const,\n },\n\n /** Tool testing endpoints — Authenticated */\n tools: {\n /** GET — List available tools (?category=) */\n testList: \"/tools/test/list\",\n /** GET — Get tool details by name */\n testDetail: (toolName: string) => `/tools/test/${toolName}` as const,\n /** POST — Create/reuse test session */\n testSession: \"/tools/test/session\",\n /** POST — Execute tool test with streaming */\n testExecute: \"/tools/test/execute\",\n },\n\n /** Scraper endpoints — Authenticated */\n scraper: {\n /** POST — Quick scrape URLs */\n quickScrape: \"/scraper/quick-scrape\",\n /** POST — Search keywords */\n search: \"/scraper/search\",\n /** POST — Search and scrape combined */\n searchAndScrape: \"/scraper/search-and-scrape\",\n /** POST — Search and scrape with limits */\n searchAndScrapeLimited: \"/scraper/search-and-scrape-limited\",\n /** POST — Connectivity check */\n micCheck: \"/scraper/mic-check\",\n },\n\n /** Utility endpoints — Guest OK */\n utilities: {\n /** @deprecated Use ENDPOINTS.pdf.extractText instead */\n pdfExtractText: \"/utilities/pdf/extract-text\",\n },\n\n /**\n * PDF extraction, manipulation, and document management — Authenticated.\n * Most JSON endpoints accept a unified source via `MediaRef` (preferred for\n * cloud files via `cld_id`), `file`, `url`, or `local_path`. See\n * `features/pdf-extractor/types.ts` for the full type re-exports.\n *\n * NOTE: list/detail endpoints below are kept for backwards compatibility\n * but the workspace now reads `processed_documents` directly from Supabase\n * for the sidebar list and the on-click detail (the old `extracted_documents`\n * facade view was retired 2026-06-11). Loading hundreds of full `content`\n * rows from Python was making the window take 2+ minutes to open.\n */\n pdf: {\n // ── Lifecycle ─────────────────────────────────────────────────────────\n /**\n * POST — Compress PDF (multipart file upload). Query params:\n * - `level` (1..5): minimum quality tier. 1=lossless, 5=max compression.\n * - `max_size_mb` (optional float): absolute upper bound on output size;\n * when set, the server escalates `level` one tier at a time until the\n * output fits (or tier 5 is reached). Omit for \"honour level exactly.\"\n * Response headers include `X-Compression-Level-Used` and\n * `X-Compression-Cap-Satisfied` so the caller can see what actually ran.\n */\n compress: \"/utilities/pdf/compress\" as const,\n /** POST — Single-file text extraction (stateless multipart, NDJSON streaming).\n * Emits `pdf_extract_started` / `pdf_page_extracted` / `pdf_extract_complete`\n * data events; the complete event carries the old `{ filename, text_content }`\n * body. Consume via `streamPdfExtractText` (features/pdf-extractor/service/streamPdf.ts). */\n extractText: \"/utilities/pdf/extract-text\" as const,\n /** POST — Batch extraction with NDJSON streaming (saves to DB + storage). */\n batchExtract: \"/utilities/pdf/batch-extract\" as const,\n /**\n * POST — Phone-scanner assembly (NDJSON streaming): ordered photos\n * (optional quad + rotation) + PDFs → ONE user-visible PDF, extracted\n * + handed to the content pipeline. Terminal `data` event carries\n * `{ file_id, doc_id, page_count }`.\n */\n fromImages: \"/utilities/pdf/from-images\" as const,\n\n // ── New `MediaRef`-based JSON endpoints (matrx-utils) ─────────────────\n /** POST — Text extraction from a remote source (MediaRef / url; NDJSON streaming,\n * same events as `extractText`). Consume via `streamPdfExtractTextRemote`. */\n extractTextRemote: \"/utilities/pdf/extract-text-remote\" as const,\n /** POST — Table extraction. Returns `PdfResult`. */\n extractTables: \"/utilities/pdf/extract-tables\" as const,\n /** POST — Extract pages into a new PDF. Returns PDF blob. */\n extractPages: \"/utilities/pdf/extract-pages\" as const,\n /** POST — Crop pages (with `crop_box`). Returns PDF blob. */\n cropPages: \"/utilities/pdf/crop-pages\" as const,\n /** POST — Rotate pages. Returns PDF blob. */\n rotatePages: \"/utilities/pdf/rotate-pages\" as const,\n /** POST — Delete pages. Returns PDF blob. */\n deletePages: \"/utilities/pdf/delete-pages\" as const,\n /** POST — Merge multiple PDFs. Returns PDF blob. */\n merge: \"/utilities/pdf/merge\" as const,\n /** POST — Split PDF into parts (`parts` or `max_pages_per_part`). Returns ZIP blob. */\n split: \"/utilities/pdf/split\" as const,\n\n // ── AI pipelines (streaming JSONL) ────────────────────────────────────\n /** POST — Process a PDF with AI agents (single-pass / chunk / reassembly). Streams JSONL. */\n processWithAi: \"/utilities/pdf/process-with-ai\" as const,\n /** POST — Full pipeline: extract → chunk → AI → reassembly. Streams JSONL with `PdfPipelineOptions`. */\n fullPipeline: \"/utilities/pdf/full-pipeline\" as const,\n /** POST — AI content cleaning on an already-extracted document (NDJSON streaming). */\n cleanContent: (docId: string) =>\n `/utilities/pdf/clean-content/${docId}` as const,\n\n // ── Document management (server-side; prefer direct Supabase reads) ──\n /** @deprecated — Read `processed_documents` directly from Supabase with metadata-only projection. */\n documents: \"/utilities/pdf/documents\" as const,\n /** @deprecated — Read `processed_documents` directly from Supabase. */\n document: (docId: string) => `/utilities/pdf/documents/${docId}` as const,\n\n // ── Phase 2 — render & advanced page ops ──────────────────────────────\n /** POST — Render one page to an image blob (PNG/JPEG/WebP/TIFF). */\n renderPage: \"/utilities/pdf/render-page\" as const,\n /** POST — Render every page; returns a ZIP of per-page images. */\n renderAll: \"/utilities/pdf/render-all\" as const,\n /** POST — Cover thumbnail at `max_side` px. */\n renderThumbnail: \"/utilities/pdf/render-thumbnail\" as const,\n /** POST — Reorder pages by `new_order`. Returns PDF blob. */\n reorderPages: \"/utilities/pdf/reorder-pages\" as const,\n /** POST — Insert pages from `source_*` into target. Returns PDF blob. */\n insertPages: \"/utilities/pdf/insert-pages\" as const,\n /** POST — Duplicate pages inline (`count` copies). Returns PDF blob. */\n duplicatePages: \"/utilities/pdf/duplicate-pages\" as const,\n /** GET — Studio preset catalog. Returns `PdfStudioCatalog`. */\n studioPresets: \"/utilities/pdf/studio/presets\" as const,\n /** POST — Studio dispatcher; image blob or ZIP depending on preset. */\n studioRender: \"/utilities/pdf/studio/render\" as const,\n\n // ── Phase 3 — layout analysis ─────────────────────────────────────────\n /** POST — Detect headers / footers / watermarks / recurring side notes. Returns `RepeatedRegionsReport`. */\n detectRepeatedRegions: \"/utilities/pdf/detect-repeated-regions\" as const,\n /** POST — Detect + strip repeated regions from per-page text. Returns `StripRepeatedRegionsResultSchema`. */\n stripRepeatedRegions: \"/utilities/pdf/strip-repeated-regions\" as const,\n /** POST — Classify every page (cover / TOC / body / exhibit / signature / billing / ...). Returns `LayoutClassificationReport`. */\n classifyPages: \"/utilities/pdf/classify-pages\" as const,\n /** POST — Multi-column → linear reading order. Returns `ReadingOrderReport`. */\n extractReadingOrder: \"/utilities/pdf/extract-reading-order\" as const,\n\n // ── Phase 4 — redaction & privacy ─────────────────────────────────────\n /** GET — Builtin redaction pattern catalog (SSN / email / phone / MRN / ...). */\n redactPatterns: \"/utilities/pdf/redact/patterns\" as const,\n /** POST — Redact one or more page-anchored rectangles. PDF blob or persisted JSON. */\n redactRegions: \"/utilities/pdf/redact-regions\" as const,\n /** POST — Redact every regex match (builtin id or raw pattern). PDF blob or persisted JSON. */\n redactPattern: \"/utilities/pdf/redact-pattern\" as const,\n /** POST — Detect repeated regions then redact selected/all. PDF blob or persisted JSON. */\n redactRepeatedRegions: \"/utilities/pdf/redact-repeated-regions\" as const,\n /** POST — Wipe /Info + XMP metadata + thumbnails. */\n stripMetadata: \"/utilities/pdf/strip-metadata\" as const,\n /** POST — Granular composite scrub (metadata / attachments / JS / flatten). */\n scrub: \"/utilities/pdf/scrub\" as const,\n /** POST — Bake annotations + widgets into page content. */\n flattenAnnotations: \"/utilities/pdf/flatten-annotations\" as const,\n },\n\n /**\n * Per-page AI extraction — fan out an agent across pages of a document and\n * persist structured results anchored to source page numbers. See\n * `features/page-extraction/FEATURE.md` for the data model.\n */\n pageExtraction: {\n /** POST — Run extraction across pages (NDJSON streaming, per-page events). */\n runStream: \"/page-extraction/runs/stream\" as const,\n /** POST — Retry one failed page-run (replaces its results). */\n retryPageRun: (pageRunId: string) =>\n `/page-extraction/page-runs/${pageRunId}/retry` as const,\n /** POST — Cancel an in-flight run. */\n cancelRun: (runId: string) =>\n `/page-extraction/runs/${runId}/cancel` as const,\n },\n\n /** Test/admin endpoints — Admin only */\n tests: {\n /** GET/POST — Example endpoints */\n examples: \"/tests/examples\",\n /** GET — Stream text test */\n streamText: \"/tests/stream/text\",\n },\n\n /** Builtin agent endpoints — Authenticated */\n builtinAgents: {\n /** POST — Categorize a single prompt (streaming) */\n categorize: \"/ai/builtin-agents/categorize\" as const,\n /** POST — Categorize a single prompt (sync, no streaming) */\n categorizeSync: \"/ai/builtin-agents/categorize/sync\" as const,\n },\n\n /** Media processing endpoints — Authenticated */\n media: {\n /**\n * POST — Upload podcast video → extract cover frame, render podcast\n * variants, returns URLs + Asset envelope. Image-only uploads now go\n * through {@link ENDPOINTS.assets.upload} with `preset=\"podcast\"`.\n */\n uploadPodcastVideo: \"/media/podcast/upload-video\" as const,\n /**\n * POST — stream the spoken transcript of a captioned YouTube video as\n * text. Body: `{ youtube_url }`. Reuses the \"YouTube Video Transcription\n * Analysis\" agent server-side (quiet run, no chat clutter). Streams NDJSON:\n * the transcript arrives as chunk text (`accumulatedText`); a captionless\n * video yields a non-fatal warning + empty text so callers stay honest.\n */\n youtubeTranscript: \"/media/youtube/transcript\" as const,\n },\n\n /**\n * Content-processing orchestrator — the interactive counterpart to the\n * automatic post-upload hook. Triggers extract→clean→chunk→embed→NER for an\n * already-uploaded `cld_files` row and streams typed progress (NDJSON). The\n * terminal `data` event carries a `ContentProcessingResult`\n * (`signature: \"ContentProcessingResult\"`) with `status` + `processed_document_id`.\n * Today's content types: `\"pdf\"` (default) and `\"office\"` (docx/pptx/xlsx —\n * pure-python extraction, no LibreOffice/OCR; already-clean markdown so the\n * LLM clean stage is skipped). The extracted text itself is NOT in the\n * stream — read `docproc.processed_documents.content` directly via\n * `docprocDb(supabase)` (canonical direct-Supabase read) once the run\n * completes.\n */\n contentProcessing: {\n process: (cldFileId: string) => `/content-processing/${cldFileId}` as const,\n },\n\n /**\n * Unified asset (image / media) upload + render-variants pipeline.\n *\n * One endpoint family handles every media upload in the platform. The\n * server renders preset variants (cover, OG, thumbnail, avatar sizes,\n * favicons, etc.) and returns the canonical {@link Asset} envelope —\n * see `features/files/types.ts` for the wire shape.\n *\n * Preset → variant key map (high level):\n * - raw → only `original`\n * - podcast → cover_url (3000²), cover_sd_url (1400²) + social baseline\n * - social → og_url, square_url, portrait_url, story_url, yt_thumbnail_url + baseline\n * - web → hero_url, og_url, card_url, touch_icon_url, pwa_icon_url, thumbnail_url + baseline\n * - email → header_url, square_url (no baseline)\n * - logo → logo_lg_url, logo_md_url, logo_sm_url + baseline\n * - avatar → avatar_xl/lg/md/sm/xs_url (no baseline)\n * - favicon → favicon_android/apple_touch/32/16_url (no baseline)\n *\n * Authenticated. See `features/files/api/assets.ts` for the typed\n * client wrapper.\n */\n assets: {\n /** POST — multipart upload + render preset variants. */\n upload: \"/assets\" as const,\n /** GET — read the canonical Asset envelope for an upload's master file. */\n detail: (fileId: string) => `/assets/${fileId}` as const,\n /** PATCH — change sharing / metadata. */\n patch: (fileId: string) => `/assets/${fileId}` as const,\n /** POST — render more variants (idempotent). */\n addVariants: (fileId: string) => `/assets/${fileId}/variants` as const,\n /** GET — list every server-known preset. */\n presets: \"/assets/presets\" as const,\n /**\n * GET — convert any cld_files row to an Asset envelope. The\n * click-to-render primitive: hand any file_id, get back URLs +\n * variants the FE can render directly.\n */\n forFile: (fileId: string) => `/files/${fileId}/asset` as const,\n /**\n * POST — no-persist preview rendering (E.16, matrx-utils v1.1.0).\n * Accepts a `MediaRef` source + variants[]. Returns either base64\n * `data_url` (≤256 KB) or a 5-min `ephemeral_url`. Replaces the\n * deleted Next.js Sharp route at app/api/images/studio/process.\n */\n preview: \"/assets/preview\" as const,\n /**\n * POST — multipart variant of {@link preview}. Render directly without\n * a prior `cld_files` row. Useful for Image Studio drag-and-drop\n * preview before commit-to-save.\n */\n previewMultipart: \"/assets/preview/multipart\" as const,\n /**\n * POST — no-persist PDF compression (E.17). Accepts a `MediaRef` source.\n * Returns `data_url` (≤256 KB) or a 5-min `ephemeral_url`.\n * Replaces the deleted Next.js route at app/api/pdf/compress.\n */\n pdfCompress: \"/assets/pdf-compress\" as const,\n /** POST — multipart variant of {@link pdfCompress}. */\n pdfCompressMultipart: \"/assets/pdf-compress/multipart\" as const,\n },\n\n /** Health endpoints — Public (aligned with types/python-generated OpenAPI) */\n health: {\n /** GET — Basic health check */\n check: \"/health\",\n /** GET — Detailed health with component status */\n detailed: \"/health/detailed\",\n /** GET — Liveness (process up; no I/O) */\n live: \"/health/live\",\n /** GET — Readiness (deps initialized; use for deploy probes) */\n ready: \"/health/ready\",\n },\n\n /** Research endpoints — Authenticated */\n research: {\n /** POST — Initialize research config */\n init: \"/research/init\",\n /** GET — List templates */\n templatesList: \"/research/templates/list\",\n /** POST — Create template */\n templatesCreate: \"/research/templates\",\n /** GET — Template detail */\n templateDetail: (templateId: string) =>\n `/research/templates/${templateId}` as const,\n /** GET — Extension scrape queue */\n extensionScrapeQueue: \"/research/extension/scrape-queue\",\n /** GET — Research state / PATCH — Update config */\n state: (projectId: string) => `/research/${projectId}` as const,\n /** POST — Suggest setup */\n suggest: (projectId: string) => `/research/${projectId}/suggest` as const,\n /** POST — Run full pipeline (streaming) */\n run: (projectId: string) => `/research/${projectId}/run` as const,\n /** POST — Trigger search (streaming) */\n search: (projectId: string) => `/research/${projectId}/search` as const,\n /** POST — Trigger scrape (streaming) */\n scrape: (projectId: string) => `/research/${projectId}/scrape` as const,\n /** POST — Analyze all sources (streaming) */\n analyzeAll: (projectId: string) =>\n `/research/${projectId}/analyze-all` as const,\n /** POST — Synthesize */\n synthesize: (projectId: string) =>\n `/research/${projectId}/synthesize` as const,\n /** GET — Keywords */\n keywords: (projectId: string) => `/research/${projectId}/keywords` as const,\n /** GET — Sources */\n sources: (projectId: string) => `/research/${projectId}/sources` as const,\n /** GET — Tags */\n tags: (projectId: string) => `/research/${projectId}/tags` as const,\n /** GET/POST — Document */\n document: (projectId: string) => `/research/${projectId}/document` as const,\n /** GET — Costs */\n costs: (projectId: string) => `/research/${projectId}/costs` as const,\n },\n\n /**\n * ACTION REQUESTS — `platform.action_request`. An agent asks the person it\n * works for for ONE thing; they answer on `/q/<token>` and the parked turn\n * resumes.\n *\n * All three sit on aidream's PUBLIC router at the BARE prefix (no `/api`,\n * no version), because the person tapping them has no account in the general\n * case. They are POSTs deliberately — the token would otherwise sit in a URL,\n * which means in the access log and in every proxy between here and it.\n *\n * Reached ONLY from `features/action-requests/service.ts` (server lane): the\n * `Authorization` header is what separates a signed-in completion from a\n * bearer one, so the decision to send it belongs where the session cookie is.\n */\n actionRequests: {\n /** POST — what the page draws. MUTATES NOTHING. */\n open: \"/action-requests/open\" as const,\n /** POST — the answer. */\n complete: \"/action-requests/complete\" as const,\n /** POST — \"text me a new link\". Rate-limited in the database. */\n remint: \"/action-requests/remint\" as const,\n },\n} as const;\n","/**\n * `@ai-matrx/agents/matrx` — the single primitive that transforms a server\n * endpoint PATH (never the base URL) before it is sent: an exact per-path\n * override, else a global version prefix. Moved from matrx-frontend\n * `lib/api/resolve-endpoint-path.ts` (chat-package independence P9).\n */\n// Both layers default to off (null / empty), so an untouched app behaves\n// identically to before this primitive existed.\n\nexport interface EndpointOverrideConfig {\n /**\n * Global leading version segment applied to every path that has no exact\n * pathOverride. `null` / empty → no version transform. The value may be\n * given with or without a leading slash (\"v2\" and \"/v2\" both work).\n */\n apiVersion?: string | null;\n\n /**\n * Exact-match canonical-path → replacement-path map. Keys are the path\n * template exactly as written in `ENDPOINTS` / the generated schema\n * (including any `{param}` segments). Wins over `apiVersion`.\n */\n pathOverrides?: Record<string, string>;\n}\n\n/** Normalize a path fragment to a single leading slash, no trailing slash. */\nfunction normalizeLeadingSlash(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n const withLead = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return withLead.length > 1 && withLead.endsWith(\"/\")\n ? withLead.slice(0, -1)\n : withLead;\n}\n\n/**\n * Resolve the final path for a canonical endpoint path, applying any active\n * override layers. Pure — given the same inputs it always returns the same\n * path. Callers prepend the resolved base URL themselves.\n *\n * @param canonicalPath The path exactly as declared in ENDPOINTS / the schema.\n * @param config The active override layers (read from Redux).\n */\nexport function resolveEndpointPath(\n canonicalPath: string,\n config?: EndpointOverrideConfig | null,\n): string {\n if (!config) return canonicalPath;\n\n // Layer 1 — exact path override wins outright.\n const override = config.pathOverrides?.[canonicalPath];\n if (override && override.trim()) {\n return normalizeLeadingSlash(override);\n }\n\n // Layer 2 — global version prefix.\n const version = config.apiVersion?.trim();\n if (version) {\n const prefix = normalizeLeadingSlash(version);\n const path = canonicalPath.startsWith(\"/\")\n ? canonicalPath\n : `/${canonicalPath}`;\n return `${prefix}${path}`;\n }\n\n return canonicalPath;\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/log-api-target.ts` (chat-package independence P9). */\n/**\n * lib/api/log-api-target.ts\n *\n * ONE place that logs the *final, resolved* destination of every outbound\n * backend call — at the last moment, after every layer of server-address\n * resolution has run and the URL can no longer change before `fetch()`.\n *\n * Why this exists:\n * We have several independent resolution layers — `selectResolvedBaseUrl`\n * (apiConfigSlice), the EC2 / sandbox override channel in\n * `resolve-base-url.ts`, per-call `forceBaseUrl` / `baseUrlOverride`, and\n * the env-var fallback in `python-client.ts`. A bug in any one of them can\n * silently send traffic to the wrong host (or to the sandbox URL, which is\n * reserved for a single rare case). This logger makes the actual target of\n * EVERY call visible in the console so misrouting is impossible to miss.\n *\n * Call this immediately before the `fetch()` / `resilientFetch()` /\n * `XMLHttpRequest.open()` that uses the URL — never earlier.\n */\n\nexport interface ApiTargetLogContext {\n /** Short label of the call site, e.g. \"callApi\", \"python-client.postJson\". */\n source: string;\n /** HTTP method when known. */\n method?: string;\n /**\n * Resolution channel when the call site knows it — \"global\" / \"override\" /\n * \"ec2-dedicated\" / \"force\" / \"env-fallback\". Surfaces sandbox routing.\n */\n channel?: string;\n /** The active server environment key from apiConfigSlice, when available. */\n activeServer?: string;\n /** Anything else worth seeing (conversationId, requestId, etc.). */\n [extra: string]: unknown;\n}\n\n/**\n * Hosts that should almost never appear as an API target. If a resolved URL\n * points at one of these, the log is escalated to a hard `console.error` so it\n * stands out — the sandbox server is reserved for a single, rare case.\n */\nconst SUSPECT_HOST_FRAGMENTS = [\"sandbox\"] as const;\n\nfunction looksSuspect(url: string): boolean {\n const lower = url.toLowerCase();\n return SUSPECT_HOST_FRAGMENTS.some((frag) => lower.includes(frag));\n}\n\n/**\n * Log the final resolved target URL for an outbound backend call.\n *\n * Normal calls log at `console.info` with a green tag. Calls whose host looks\n * like a sandbox/override target log at `console.error` with a red tag so they\n * are impossible to miss while hunting a misrouting bug.\n */\nexport function logApiTarget(url: string, context: ApiTargetLogContext): void {\n const { source, method, channel, activeServer, ...extra } = context;\n\n let origin = url;\n try {\n origin = new URL(url).origin;\n } catch {\n /* relative or malformed — log the raw string */\n }\n\n const suspect = looksSuspect(url);\n const tag = suspect ? \"🚨 API TARGET (SANDBOX?)\" : \"📡 API TARGET\";\n const style = suspect\n ? \"font-weight:bold;color:#fff;background:#c0392b;padding:1px 4px;border-radius:3px;\"\n : \"font-weight:bold;color:#fff;background:#16a085;padding:1px 4px;border-radius:3px;\";\n\n const meta: Record<string, unknown> = {\n origin,\n fullUrl: url,\n source,\n };\n if (method) meta.method = method;\n if (channel) meta.channel = channel;\n if (activeServer) meta.activeServer = activeServer;\n for (const [k, v] of Object.entries(extra)) {\n if (v !== undefined) meta[k] = v;\n }\n\n const log = suspect ? console.error : console.info;\n log(\n `%c${tag}%c ${method ? method + \" \" : \"\"}${url}`,\n style,\n \"color:inherit;\",\n meta,\n );\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/desktop-target-request.ts` (chat-package independence P9). */\nconst DESKTOP_NATIVE_CAPABILITY = \"desktop-native\";\n\ntype MutableRecord = Record<string, unknown>;\n\n/**\n * Stamp the admin desktop-target preference onto a request body — but ONLY\n * when the body already declares a live `desktop-native` capability.\n *\n * The preference (Settings → Admin Server, `adminPreferences.\n * desktopTargetInstanceId`, persisted local-only) may DIRECT delegation to a\n * specific desktop; it must never DECLARE one. Fabricating the capability\n * here used to override the presence gate in `desktop-native.provider.ts`,\n * so a stale preference silently rode every AI turn: the server stamped\n * `target_instance_id` onto delegated tool calls while the smart-input\n * indicator truthfully showed no desktop bound, and browser-executed tools\n * (war_room_*, ui-first) 404'd their own /tool_results (submission-binding\n * check) and wedged the turn.\n */\nexport function applyDesktopTargetToRequestBody(\n body: unknown,\n targetInstanceId: string | null | undefined,\n): void {\n if (!targetInstanceId || !isRecord(body)) return;\n\n const existingClient = isRecord(body.client) ? body.client : null;\n const existingState =\n existingClient && isRecord(existingClient.state)\n ? existingClient.state\n : null;\n const existingDesktopState =\n existingState && isRecord(existingState[DESKTOP_NATIVE_CAPABILITY])\n ? existingState[DESKTOP_NATIVE_CAPABILITY]\n : null;\n\n // No live desktop-native envelope on this request → the presence gate said\n // no desktop is online (or the caller never built a client envelope).\n // Silently skipping is correct: targeting a desktop that isn't declared\n // delegates calls into a void.\n if (!existingClient || !existingState || !existingDesktopState) return;\n\n body.target_instance_id ??= targetInstanceId;\n existingDesktopState.target_instance_id ??= targetInstanceId;\n}\n\nfunction isRecord(value: unknown): value is MutableRecord {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n","/**\n * `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/run-wait.ts` (chat-package\n * independence P9). The knob read is injected (`resolveRunWaitWith`); the host wraps it.\n */\n/**\n * How long a client waits for the server to START answering a run — per output\n * kind, as an organization knob.\n *\n * 🚨 THE DEFECT (2026-09-22). Pressing Run in the agent builder on an image\n * agent (\"Product Photo Studio\", Gemini 3.1 Flash Image) died on the client with\n * \"Connection timed out after 15000ms\". The builder's manual path was the only\n * agent stream path carrying a fixed 15-second `connectTimeoutMs`, and that\n * timer does not measure a TCP connect: aidream's prepared-streaming routes\n * (`create_prepared_streaming_response`) finish request PREPARATION — auth, the\n * request lane, conversation create, resolving attached files — BEFORE the\n * response headers go out. A busy server or a draining deploy pushed prep past\n * 15 s, the client aborted, and aborting before the headers dropped the server\n * run with it (conversation created, no messages).\n *\n * THE RULE. A generation is a job, not a request with a stopwatch:\n * - Once the stream is open there is NO wall-clock cap — the server heartbeat\n * (every 5 s) keeps the watchdog fed and the run ends on the stream's own\n * `end` event.\n * - The one cap that remains — \"the server never started answering\" — is an\n * organization knob per output kind (`agents.run_wait.<kind>_seconds`),\n * with generous agent-set defaults registered in the knob table, never a\n * constant here.\n * - When that cap is actually hit, the person is told the truth: which model,\n * how long we waited, and that the server may still be working — with a\n * door to the conversation, because the run can finish without us.\n *\n * If the knob snapshot cannot be read the wait falls back to the stream\n * lifetime backstop (announced loudly), never to a number nobody chose.\n */\n\nimport { formatDurationSeconds } from \"@ai-matrx/kit/format\";\n\n\n/** What a run produces. Anything but text is a job (seconds to minutes). */\n/** Every output kind a run can wait on — one `<kind>_seconds` knob each. */\nexport const RUN_OUTPUT_KINDS = [\"text\", \"image\", \"video\", \"audio\"] as const;\nexport type RunOutputKind = (typeof RUN_OUTPUT_KINDS)[number];\n\nexport const RUN_WAIT_KNOB_FEATURE = \"agents.run_wait\";\n\n/**\n * Stream lifetime backstop — the same 24 hours the agent run path\n * (`runAiStream`) has always used. It is the ceiling for a stream that keeps\n * heartbeating forever, not a wait anyone tunes; the heartbeat watchdog is the\n * real liveness check. Also the first-response wait when the knob cannot be\n * read (setTimeout's own ceiling is ~24.8 days, so this stays safe).\n */\nexport const RUN_STREAM_LIFETIME_BACKSTOP_MS = 24 * 60 * 60 * 1000;\n\nexport function isJobOutputKind(kind: RunOutputKind): boolean {\n return kind !== \"text\";\n}\n\n/**\n * The output kind from a model's declared output modalities (the parsed\n * `capabilities.output` list). Video outranks image outranks audio: a model\n * that can emit several is waited on as its slowest.\n */\nexport function runOutputKindFromModalities(\n output: readonly string[] | null | undefined,\n): RunOutputKind {\n const set = new Set((output ?? []).map((m) => m.toLowerCase()));\n if (set.has(\"video\")) return \"video\";\n if (set.has(\"image\")) return \"image\";\n if (set.has(\"audio\")) return \"audio\";\n return \"text\";\n}\n\nexport function runWaitKnobKey(kind: RunOutputKind): string {\n return `${kind}_seconds`;\n}\n\nexport interface RunWait {\n /** Milliseconds the client waits for the stream to open. */\n firstResponseMs: number;\n /** Seconds as configured, or null when the knob could not be read. */\n seconds: number | null;\n kind: RunOutputKind;\n}\n\n/**\n * Resolve the first-response wait for one run from the organization's knob.\n * Never throws — a run is never refused because a setting could not load; the\n * failure is announced and the wait becomes the lifetime backstop.\n */\n/**\n * Reads one settings-register knob for an organization (and person). The HOST\n * supplies it — matrx-frontend: `ensureEffectiveKnob` (lib/scoped-config).\n */\nexport type RunWaitKnobReader = (\n organizationId: string,\n userId: string | null,\n knob: { feature: string; key: string },\n) => Promise<unknown>;\n\nexport async function resolveRunWaitWith(\n readKnob: RunWaitKnobReader,\n organizationId: string | null | undefined,\n userId: string | null | undefined,\n kind: RunOutputKind,\n): Promise<RunWait> {\n const key = runWaitKnobKey(kind);\n if (!organizationId) {\n // The organization-less guest lane has no organization setting to read.\n // It waits on the lifetime backstop — no invented first-response limit.\n return { firstResponseMs: RUN_STREAM_LIFETIME_BACKSTOP_MS, seconds: null, kind };\n }\n try {\n const raw = await readKnob(organizationId, userId ?? null, {\n feature: RUN_WAIT_KNOB_FEATURE,\n key,\n });\n const seconds = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(seconds) || seconds <= 0) {\n throw new Error(`it resolves to ${JSON.stringify(raw)}, not a number of seconds`);\n }\n return { firstResponseMs: Math.round(seconds * 1000), seconds, kind };\n } catch (error) {\n console.error(\n `[run-wait] The \"${RUN_WAIT_KNOB_FEATURE}.${key}\" setting could not be read — ` +\n `${error instanceof Error ? error.message : String(error)}. This run waits ` +\n \"for the server without a first-response limit (the 24-hour stream backstop) \" +\n \"instead of inventing one. Remedy: seed the knob (matrx-frontend \" +\n \"migrations/agents_run_wait_knobs.sql) or fix the knob snapshot read.\",\n );\n return {\n firstResponseMs: RUN_STREAM_LIFETIME_BACKSTOP_MS,\n seconds: null,\n kind,\n };\n }\n}\n\nconst KIND_NOUN: Record<RunOutputKind, string> = {\n text: \"a reply\",\n image: \"an image\",\n video: \"a video\",\n audio: \"audio\",\n};\n\n/** \"Generating an image with Gemini 3.1 Flash Image\" — the job's working line. */\nexport function runJobLabel(kind: RunOutputKind, modelLabel: string | null): string {\n const what =\n kind === \"text\" ? \"Writing a reply\" : `Generating ${KIND_NOUN[kind]}`;\n return modelLabel ? `${what} with ${modelLabel}` : what;\n}\n\n/**\n * The honest sentence for a first-response timeout. The server may still\n * finish the run, so the sentence says so and the caller attaches a door to\n * the conversation.\n */\nexport function runWaitTimeoutMessage(\n kind: RunOutputKind,\n modelLabel: string | null,\n seconds: number | null,\n): string {\n const waited =\n seconds != null\n ? // An exact limit an admin configured, so both tiers: \"1 minute 30 seconds\".\n `within ${formatDurationSeconds(seconds, { style: \"long\", parts: 2, round: \"nearest\" })}`\n : \"in time\";\n const who = modelLabel ? ` (${modelLabel})` : \"\";\n return (\n `The server did not start ${kind === \"text\" ? \"answering\" : `generating ${KIND_NOUN[kind]}`}` +\n `${who} ${waited}, so this page stopped waiting. The run may still finish on ` +\n \"the server — open the conversation to check before running it again. \" +\n \"An organization admin can lengthen this wait in the organization's configuration settings.\"\n );\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/warm-helpers.ts` (chat-package independence P9). */\n/**\n * Warm-helper utilities — centralized fire-and-forget pre-warm POSTs to the\n * backend so the next real request finds the resource already cached.\n *\n * Every warm call across the app should go through these helpers. Hand-rolled\n * `fetch(${BACKEND_URLS.production}${ENDPOINTS.ai.agentWarm(id)})` was the old\n * pattern and is being phased out: it ignores the in-header server picker,\n * silently swallows errors, and duplicates the URL-resolution logic at every\n * callsite.\n *\n * Server vs client:\n * - Server callers (page.tsx server components) cannot read the picker —\n * they pass an explicit `baseUrl` (typically `BACKEND_URLS.production`).\n * - Conversation warming is intentionally not exposed here: it requires an\n * authenticated owner and must happen only after client session hydration.\n *\n * Errors are intentionally swallowed — warm is best-effort. Telemetry can be\n * added by listening on the optional `onError` callback.\n */\n\nimport { ENDPOINTS } from \"./endpoints\";\n\ninterface WarmOptions {\n /**\n * Resolved backend URL. Server callers typically pass `BACKEND_URLS.production`,\n * which is `string | undefined` when the env var isn't configured — accepted\n * here (not coerced to `\"\"` at the call site) because the warm functions\n * below already no-op on a falsy `baseUrl`.\n */\n baseUrl: string | undefined;\n /** Optional callback for telemetry; warm failures never throw. */\n onError?: (err: unknown) => void;\n}\n\ninterface WarmAgentOptions extends WarmOptions {\n /** True when the path id is an agx_version id, not an agx_agent id. */\n isVersion?: boolean;\n}\n\n/**\n * POST /ai/agents/{agentId}/warm — preloads the agent's execution payload.\n * Body is `{ \"is_version\": true }` when `isVersion` is true; otherwise omitted.\n * Public route, no auth.\n */\nexport function warmAgent(\n agentId: string,\n { baseUrl, isVersion, onError }: WarmAgentOptions,\n): void {\n if (!baseUrl || !agentId) return;\n const url = `${baseUrl}${ENDPOINTS.ai.agentWarm(agentId)}`;\n const body = isVersion ? JSON.stringify({ is_version: true }) : undefined;\n fetch(\n url,\n body\n ? {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body,\n keepalive: true,\n }\n : { method: \"POST\", keepalive: true },\n ).catch((err) => {\n onError?.(err);\n });\n}\n"],"mappings":"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","names":["isNetError","isRecord","status","isNetError","attempt","isRecord","result","isRecord","isRecord"]}
|
|
1
|
+
{"version":3,"sources":["../../matrx/transport.ts","../../matrx/client.ts","../../matrx/backend-errors.ts","../../stream/ndjson.ts","../../matrx/org-context.ts","../../matrx/protocol.ts","../../matrx/call.ts","../../matrx/conversation.ts","../../matrx/internal.ts","../../stream/sse.ts","../../matrx/operations.ts","../../matrx/rejoin.ts","../../matrx/run.ts","../../matrx/provider-failures.ts","../../matrx/tools.ts","../../matrx/endpoints.ts","../../matrx/endpoint-path.ts","../../matrx/api-target-log.ts","../../matrx/desktop-target.ts","../../matrx/run-wait.ts","../../matrx/warm.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/matrx` — the Matrx transport port.\n *\n * The ONE seam between this package's wire semantics and a host's connection\n * policy. This package owns WHAT is said to the AI Matrx server — paths,\n * methods, JSON bodies, streaming Accept headers, the `Last-Event-ID` cursor\n * header — and the host owns HOW the connection is made:\n *\n * - base-URL / backend-channel resolution (global, sandbox override, local\n * engine, EC2-dedicated — whatever ladder the host runs);\n * - credentials (Supabase JWT `Authorization: Bearer`, guest\n * `X-Fingerprint-ID`, or the API-key lane) — NEVER implemented here;\n * - the `X-Organization-Id` context header;\n * - retry policy, network-level timeouts, and diagnostics capture.\n *\n * A host implements the port in a few lines:\n *\n * ```ts\n * const transport: MatrxTransport = {\n * fetch: (path, init) =>\n * fetch(`${baseUrl}${path}`, {\n * ...init,\n * headers: { ...init.headers, ...authHeaders() },\n * }),\n * };\n * ```\n *\n * The port is deliberately structural and `fetch`-shaped so `@ai-matrx/data`'s\n * `/api` transport can implement it without importing this package.\n */\n\n/**\n * The request this package hands the port. A strict subset of `RequestInit`,\n * so a host can spread it straight into `fetch`.\n */\nexport interface MatrxTransportRequest {\n method: \"GET\" | \"POST\";\n /**\n * Wire-semantic headers the CALL requires (`Content-Type`, `Accept`,\n * `Last-Event-ID`). The host merges its policy headers (auth, org) on top;\n * it must not drop these.\n */\n headers: Record<string, string>;\n /** Pre-serialized JSON body, present on POST calls that carry one. */\n body?: string;\n /** Caller cancellation. The host must wire it to the underlying fetch. */\n signal?: AbortSignal;\n}\n\n/**\n * The transport port. `path` is server-relative and always starts with `/`\n * (`/ai/...`, `/runtime/...`); the host prepends its resolved base URL.\n */\nexport interface MatrxTransport {\n fetch(path: string, init: MatrxTransportRequest): Promise<Response>;\n}\n\n/**\n * A non-2xx response from the Matrx API, with the server's structured error\n * body preserved and its richest human-readable message extracted.\n */\nexport class MatrxApiError extends Error {\n override readonly name = \"MatrxApiError\";\n /** HTTP status of the failed response. */\n readonly status: number;\n /** Machine code from the server body (`code`, or `detail.code`), when present. */\n readonly code: string | null;\n /** The parsed server error body, verbatim (undefined when unparsable). */\n readonly serverDetail: unknown;\n /** The request path the failure came from (server-relative). */\n readonly path: string;\n\n constructor(args: {\n status: number;\n path: string;\n serverDetail?: unknown;\n message?: string;\n }) {\n super(\n args.message ??\n extractMatrxErrorMessage(args.serverDetail) ??\n `HTTP ${args.status}`,\n );\n this.status = args.status;\n this.path = args.path;\n this.serverDetail = args.serverDetail;\n this.code = extractMatrxErrorCode(args.serverDetail);\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction nonBlankString(value: unknown): string | undefined {\n return typeof value === \"string\" && value.trim() ? value : undefined;\n}\n\n/**\n * Extract the richest human-readable message from a Matrx/FastAPI error body.\n *\n * aidream 4xx validation errors look like\n * `{ error, user_message, details: [{ field, message, help }] }`; hand-raised\n * HTTPExceptions carry `{ detail: { code, message } }`; FastAPI's defaults are\n * `{ detail: string | [{ msg }] }`. Preference order: `user_message` →\n * `message` → joined `details[].message` → `detail.message` →\n * `detail` string → joined `detail[].msg`. Returns undefined for\n * unrecognized bodies so callers fall back to the bare status line.\n */\nexport function extractMatrxErrorMessage(\n serverDetail: unknown,\n): string | undefined {\n if (!isRecord(serverDetail)) return undefined;\n\n const userMessage = nonBlankString(serverDetail.user_message);\n if (userMessage) return userMessage;\n const message = nonBlankString(serverDetail.message);\n if (message) return message;\n\n if (Array.isArray(serverDetail.details)) {\n const messages = serverDetail.details\n .map((entry: unknown) => {\n if (!isRecord(entry)) return undefined;\n const detailMessage = nonBlankString(entry.message);\n if (!detailMessage) return undefined;\n const field = nonBlankString(entry.field);\n return field ? `${field}: ${detailMessage}` : detailMessage;\n })\n .filter((m): m is string => typeof m === \"string\");\n if (messages.length > 0) return messages.join(\"; \");\n }\n\n const detail = serverDetail.detail;\n if (isRecord(detail)) {\n const detailMessage =\n nonBlankString(detail.message) ?? nonBlankString(detail.user_message);\n if (detailMessage) return detailMessage;\n }\n if (typeof detail === \"string\" && detail.trim()) return detail;\n if (Array.isArray(detail)) {\n const messages = detail\n .map((entry: unknown) =>\n isRecord(entry) ? nonBlankString(entry.msg) : undefined,\n )\n .filter((m): m is string => typeof m === \"string\");\n if (messages.length > 0) return messages.join(\"; \");\n }\n return undefined;\n}\n\n/**\n * Extract the machine error code from a Matrx error body: top-level `code`,\n * else `detail.code` (the hand-raised HTTPException shape). Null when absent.\n */\nexport function extractMatrxErrorCode(serverDetail: unknown): string | null {\n if (!isRecord(serverDetail)) return null;\n const topLevel = nonBlankString(serverDetail.code);\n if (topLevel) return topLevel;\n const detail = serverDetail.detail;\n if (isRecord(detail)) {\n const nested = nonBlankString(detail.code);\n if (nested) return nested;\n }\n return null;\n}\n","/**\n * The PRODUCTION `MatrxTransport` — the full connection pipeline every Matrx\n * host used to hand-roll, moved in under C22 (THE HARD PARTS LIVE IN THE\n * PACKAGE). A host constructs it from identity alone:\n *\n * ```ts\n * const transport = createMatrxTransport({\n * baseUrl: \"https://server.app.matrxserver.com\",\n * credentials, // CredentialsPort (@ai-matrx/data)\n * organizationId: () => activeOrgId, // omit for conversation-lane calls\n * });\n * ```\n *\n * Everything else is defaulted to the proven production values:\n *\n * - **timeouts** — connect 15s (for a non-streaming FastAPI handler this is\n * effectively time-to-response), total UNCAPPED (the port cannot tell a JSON\n * call from a long-lived NDJSON/SSE stream; the connect timeout is the JSON\n * guard), via `@ai-matrx/data/net`'s `resilientFetch`;\n * - **protocol** — the AI API version transform (`applyAiApiVersion`, default\n * v2) + the loud v2 → v1 transport fallback (`./protocol`);\n * - **credentials** — read fresh from the injected `CredentialsPort` on EVERY\n * call, so a token refresh mid-run is picked up; mapped to headers by the\n * ONE `credentialToHeaders`;\n * - **org context** — the fail-closed `X-Organization-Id` binding\n * (`./org-context`): configured lanes REQUIRE an org and refuse before the\n * wire; unconfigured lanes (conversation-scoped calls, which carry org in\n * the body) send none;\n * - **error classification** — every failure normalizes through\n * `normalizeMatrxError` into the ONE `MatrxCallError` envelope;\n * - **diagnostics** — a typed sink the host wires to its capture/telemetry\n * (`onRequest`, `onError`, `onProtocolDowngrade`); wiring it is optional,\n * the transport works silently without it.\n *\n * Header merge order is part of the port contract: wire headers first\n * (`Content-Type` / `Accept` / `Last-Event-ID` — the package's), then\n * credentials, then resolver policy headers, then the org header. Policy\n * headers never carry `Content-Type` — the wire owns it, and a policy\n * `Content-Type` merged over a GET SSE call would corrupt the wire, so the\n * factory strips it defensively.\n */\n\nimport { isNetError, type CredentialsPort } from \"@ai-matrx/data\";\nimport { credentialToHeaders } from \"@ai-matrx/data\";\nimport { extractErrorMessage } from \"@ai-matrx/data/net\";\nimport { BackendApiError } from \"./backend-errors\";\nimport {\n bareStatusSentence,\n honestTransportMessage,\n isBareTransportCode,\n} from \"./call\";\nimport {\n applyOrganizationContextHeader,\n OrganizationContextError,\n requireOrganizationContext,\n} from \"./org-context\";\nimport {\n applyAiApiVersion,\n fetchWithMatrxProtocolFallback,\n MATRX_AI_API_VERSION_DEFAULT,\n type MatrxAiApiVersion,\n type MatrxProtocolDowngrade,\n} from \"./protocol\";\nimport {\n extractMatrxErrorCode,\n extractMatrxErrorMessage,\n MatrxApiError,\n type MatrxTransport,\n type MatrxTransportRequest,\n} from \"./transport\";\n\n// ─── The normalized error envelope ──────────────────────────────────────────\n\n/**\n * The ONE classified error shape for Matrx client calls — the envelope hosts\n * branch on instead of string-matching exceptions. Structurally compatible\n * with matrx-frontend's `ApiCallError` by design.\n */\nexport interface MatrxCallError {\n type:\n | \"auth_error\"\n | \"network_error\"\n | \"http_error\"\n | \"validation_error\"\n | \"abort_error\"\n | \"unknown\";\n message: string;\n /** HTTP status code, if applicable. */\n status?: number;\n /** Raw error detail from the server (the parsed error body). */\n serverDetail?: unknown;\n /** Machine code preserved through normalization (server `code`, org-context code, …). */\n code?: string;\n /** Original exception identity for diagnostics. */\n name?: string;\n /** Original exception stack. */\n stack?: string;\n /** JSON-safe dump of the original thrown value. */\n raw?: unknown;\n}\n\nfunction classifyStatus(status: number): \"validation_error\" | \"http_error\" {\n return status >= 400 && status < 500 ? \"validation_error\" : \"http_error\";\n}\n\n/**\n * Classify any failure thrown by a Matrx client call — `MatrxApiError`, a\n * typed `BackendApiError` / `StreamTransportError`, a `NetError` from the\n * resilience layer, an org-context refusal, an abort — into the\n * `MatrxCallError` envelope. Never throws.\n *\n * Every message is laundered through `honestTransportMessage`: a bare status\n * line (\"HTTP 400\") never reaches a person — the status rides `status`.\n * A `BackendApiError` keeps its machine `code` (a dropped socket stays\n * `stream_transport_lost`, so a surface reattaches instead of dead-ending)\n * and its structured `details` ride `serverDetail` (the organization-hold\n * body carries the caller's membership choices there).\n */\nexport function normalizeMatrxError(err: unknown): MatrxCallError {\n if (err instanceof OrganizationContextError) {\n return {\n type: \"validation_error\",\n message: err.message,\n code: err.code,\n name: err.name,\n ...(err.stack !== undefined ? { stack: err.stack } : {}),\n };\n }\n\n if (err instanceof DOMException && err.name === \"AbortError\") {\n return { type: \"abort_error\", message: \"Request was cancelled.\" };\n }\n\n if (err instanceof MatrxApiError) {\n return {\n type: classifyStatus(err.status),\n message: honestTransportMessage(err.message, err.status),\n status: err.status,\n serverDetail: err.serverDetail,\n ...(err.code ? { code: err.code } : {}),\n name: err.name,\n };\n }\n\n if (err instanceof BackendApiError) {\n return {\n type: \"network_error\",\n message: honestTransportMessage(\n err.detail || err.userMessage,\n err.status ?? undefined,\n ),\n code: err.code,\n name: err.name,\n ...(err.status !== null ? { status: err.status } : {}),\n ...(err.details !== null ? { serverDetail: err.details } : {}),\n };\n }\n\n if (isNetError(err)) {\n if (err.code === \"aborted\") {\n return { type: \"abort_error\", message: err.message };\n }\n if (err.code === \"http\") {\n const status = err.status ?? 0;\n return {\n type: classifyStatus(status),\n message: honestTransportMessage(err.message, status),\n status,\n };\n }\n // connect-timeout / total-timeout / heartbeat-timeout / network / offline\n return { type: \"network_error\", message: err.message };\n }\n\n if (err instanceof Error) {\n const httpMatch = err.message.match(/HTTP (\\d+):\\s*(.*)/);\n if (httpMatch) {\n const status = parseInt(httpMatch[1] as string, 10);\n return {\n type: classifyStatus(status),\n message: honestTransportMessage(httpMatch[2] ?? err.message, status),\n status,\n };\n }\n // \"HTTP 400\" with no colon: the status line itself, never the sentence.\n if (isBareTransportCode(err.message)) {\n const status = Number.parseInt(err.message.replace(/\\D+/g, \"\"), 10);\n return {\n type: classifyStatus(status),\n message: bareStatusSentence(status),\n status,\n };\n }\n return { type: \"network_error\", message: err.message };\n }\n\n return { type: \"unknown\", message: extractErrorMessage(err) };\n}\n\n// ─── The factory ────────────────────────────────────────────────────────────\n\n/**\n * A fully-resolved connection target for one call: where to send it and which\n * policy headers ride ON TOP of the wire + credential headers.\n */\nexport interface MatrxTransportTarget {\n /** Fully-qualified base URL, no trailing slash. */\n baseUrl: string;\n /**\n * Extra policy headers for this target (e.g. a resolver that carries its own\n * credential headers). `Content-Type` is stripped — the wire owns it.\n */\n policyHeaders?: Record<string, string>;\n /** Routing channel label surfaced to `onRequest` telemetry. */\n channel?: string;\n}\n\n/** Context handed to every diagnostics callback. */\nexport interface MatrxRequestInfo {\n /** The final URL (base + version-transformed path). */\n url: string;\n method: \"GET\" | \"POST\";\n /** The server-relative path as the package requested it. */\n path: string;\n /** The resolved routing channel (default \"default\"). */\n channel: string;\n /** The transport's call-site label (default \"matrxTransport\"). */\n source: string;\n}\n\n/**\n * The typed diagnostics sink — the host wires these to its telemetry/capture\n * systems; all optional, and the transport is fully functional without them.\n */\nexport interface MatrxTransportDiagnostics {\n /** Fired at the last pre-fetch moment of every call. */\n onRequest?: (info: MatrxRequestInfo) => void;\n /**\n * Fired for every thrown network failure and every non-2xx response not\n * listed in `expectedErrorStatuses`, with the classified envelope.\n */\n onError?: (error: MatrxCallError, info: MatrxRequestInfo) => void;\n /** Fired on every v2 → v1 protocol downgrade. */\n onProtocolDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n}\n\nexport interface CreateMatrxTransportOptions {\n /** Fixed base URL, no trailing slash. Exactly one of `baseUrl` / `resolveTarget`. */\n baseUrl?: string;\n /**\n * Per-call target resolver — for hosts whose base URL / policy headers are\n * dynamic (server toggles, sandbox overrides, conversation channels).\n * Resolution runs fresh on EVERY call. May throw to refuse a call loudly.\n */\n resolveTarget?: () => MatrxTransportTarget;\n /**\n * The credential source (`@ai-matrx/data`), read fresh per call so token\n * refreshes are picked up mid-run. Omit only when the resolver's\n * `policyHeaders` already carry the credentials.\n */\n credentials?: CredentialsPort;\n /**\n * The org-context binding. When configured, every call REQUIRES a valid org\n * (fail-closed `organization_context_required` before the wire) and carries\n * `X-Organization-Id`. Omit for conversation-lane transports, which send the\n * org in the body only.\n */\n organizationId?: string | (() => string | null | undefined);\n /** AI API protocol version (value or per-call getter). Default `\"v2\"`. */\n aiApiVersion?: MatrxAiApiVersion | (() => MatrxAiApiVersion);\n /** Max ms request start → response headers. Default 15_000. */\n connectTimeoutMs?: number;\n /**\n * Max ms for the whole handshake. Default `null` (uncapped) — the port\n * cannot tell a JSON call from a long-lived stream, and capping would kill\n * long streams; the connect timeout is the real JSON guard.\n */\n totalTimeoutMs?: number | null;\n /**\n * HTTP failures this transport's call class fully handles as expected\n * domain outcomes (e.g. 404 on runtime-operation identify). They still\n * reach the package client (which maps them to typed results) but are not\n * reported through `onError`.\n */\n expectedErrorStatuses?: readonly number[];\n /** Short call-site label surfaced on `MatrxRequestInfo` (default \"matrxTransport\"). */\n source?: string;\n diagnostics?: MatrxTransportDiagnostics;\n}\n\nconst PRODUCTION_CONNECT_TIMEOUT_MS = 15_000;\n\nfunction stripContentType(\n headers: Record<string, string>,\n): Record<string, string> {\n return Object.fromEntries(\n Object.entries(headers).filter(\n ([name]) => name.toLowerCase() !== \"content-type\",\n ),\n );\n}\n\n/**\n * Build the production `MatrxTransport`. See the module doc for the pipeline;\n * every knob defaults to the proven production value.\n */\nexport function createMatrxTransport(\n options: CreateMatrxTransportOptions,\n): MatrxTransport {\n const {\n baseUrl,\n resolveTarget,\n credentials,\n organizationId,\n aiApiVersion,\n connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,\n totalTimeoutMs = null,\n expectedErrorStatuses,\n diagnostics,\n source = \"matrxTransport\",\n } = options;\n\n if ((baseUrl === undefined) === (resolveTarget === undefined)) {\n throw new Error(\n \"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`.\",\n );\n }\n\n const resolve: () => MatrxTransportTarget =\n resolveTarget ?? (() => ({ baseUrl: baseUrl as string }));\n\n const resolveVersion = (): MatrxAiApiVersion => {\n if (aiApiVersion === undefined) return MATRX_AI_API_VERSION_DEFAULT;\n return typeof aiApiVersion === \"function\" ? aiApiVersion() : aiApiVersion;\n };\n\n const resolveOrganizationId = (): string | null => {\n if (organizationId === undefined) return null;\n const candidate =\n typeof organizationId === \"function\" ? organizationId() : organizationId;\n // Fail closed: a configured org lane with no org refuses before the wire.\n return requireOrganizationContext(candidate);\n };\n\n return {\n async fetch(path: string, init: MatrxTransportRequest): Promise<Response> {\n const target = resolve();\n\n // `path` is already interpolated (`/ai/agents/<uuid>`), so the version\n // transform is the concrete-path bridge, not a template registry.\n const versionedPath = applyAiApiVersion(path, resolveVersion());\n const url = `${target.baseUrl}${versionedPath}`;\n\n // Wire headers FIRST; credentials, then resolver policy headers, then\n // the org header on top — none of them may carry Content-Type.\n const credentialHeaders = credentials\n ? credentialToHeaders(await credentials.get())\n : {};\n let headers: Record<string, string> = {\n ...init.headers,\n ...stripContentType(credentialHeaders),\n ...stripContentType(target.policyHeaders ?? {}),\n };\n const orgId = resolveOrganizationId();\n if (orgId !== null) {\n headers = applyOrganizationContextHeader(headers, orgId);\n }\n\n const info: MatrxRequestInfo = {\n url,\n method: init.method,\n path,\n channel: target.channel ?? \"default\",\n source,\n };\n diagnostics?.onRequest?.(info);\n\n let response: Response;\n try {\n ({ response } = await fetchWithMatrxProtocolFallback(\n url,\n {\n method: init.method,\n headers,\n ...(init.body !== undefined ? { body: init.body } : {}),\n },\n {\n ...(init.signal ? { signal: init.signal } : {}),\n connectTimeoutMs,\n totalTimeoutMs,\n throwOnHttpError: false,\n ...(diagnostics?.onProtocolDowngrade\n ? { onDowngrade: diagnostics.onProtocolDowngrade }\n : {}),\n },\n ));\n } catch (err) {\n diagnostics?.onError?.(normalizeMatrxError(err), info);\n throw err;\n }\n\n if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {\n // The package client consumes the original body for its\n // MatrxApiError; read the diagnostics copy from a clone so the two\n // never fight.\n const serverDetail: unknown = await response\n .clone()\n .json()\n .catch(() => undefined);\n const code = extractMatrxErrorCode(serverDetail);\n diagnostics?.onError?.(\n {\n type: classifyStatus(response.status),\n message:\n extractMatrxErrorMessage(serverDetail) ??\n `HTTP ${response.status}`,\n status: response.status,\n serverDetail,\n ...(code ? { code } : {}),\n },\n info,\n );\n }\n\n return response;\n },\n };\n}\n","/**\n * `@ai-matrx/agents/matrx` — the AI Matrx server's error model, as every\n * client reads it: `BackendApiError` (the server's `APIError` body),\n * `StreamTransportError` (the socket died mid-run; the run may still finish\n * and is reattachable), parsing of HTTP / stream / persisted errors, and the\n * ONE sentence a person sees (`getUserMessage`, `describeBackendFailure`).\n *\n * Moved from matrx-frontend `lib/api/errors.ts` (chat-package independence\n * P9); the app re-exports it from here. Pure: no host, no window, no env.\n */\n\n/**\n * Standardized error shape returned by all backend endpoints.\n * Matches the Python `APIError` Pydantic model.\n */\nexport interface BackendApiErrorData {\n /** Machine-readable error code (e.g. \"auth_required\", \"validation_error\") */\n error: string;\n /** Developer-facing detail for debugging */\n message: string;\n /** Safe to display directly in the UI */\n user_message: string;\n /** Extra info (validation errors, etc.) */\n details: unknown | null;\n /** Unique request ID for support/debugging */\n request_id: string;\n}\n\n/** Common backend error codes */\nexport type BackendErrorCode =\n | \"auth_required\"\n | \"token_required\"\n | \"admin_required\"\n | \"validation_error\"\n | \"not_found\"\n | \"internal_error\"\n | \"agent_error\"\n /** The stream socket died mid-run; the server run may still be completing\n * and is reattachable. See `StreamTransportError`. */\n | \"stream_transport_lost\"\n | (string & {});\n\n// ============================================================================\n// ERROR CLASS\n// ============================================================================\n\n/**\n * Typed error thrown by all backend API operations.\n * Contains structured fields matching the Python APIError model.\n *\n * Usage:\n * ```typescript\n * try {\n * await client.post(ENDPOINTS.ai.agentStart(agentId), body);\n * } catch (err) {\n * if (err instanceof BackendApiError) {\n * // Show err.userMessage to the user\n * // Log err.requestId for debugging\n * // Check err.code for programmatic handling\n * }\n * }\n * ```\n */\nexport class BackendApiError extends Error {\n /** Machine-readable error code */\n readonly code: BackendErrorCode;\n /** Developer-facing detail */\n readonly detail: string;\n /** Safe to display directly in the UI */\n readonly userMessage: string;\n /** Extra info (validation errors, etc.) */\n readonly details: unknown | null;\n /** Unique request ID for support/debugging */\n readonly requestId: string;\n /** HTTP status code (if from an HTTP response) */\n readonly status: number | null;\n\n constructor(data: {\n code: BackendErrorCode;\n detail: string;\n userMessage: string;\n details?: unknown | null;\n requestId?: string | undefined;\n status?: number | null | undefined;\n }) {\n super(data.userMessage);\n this.name = \"BackendApiError\";\n this.code = data.code;\n this.detail = data.detail;\n this.userMessage = data.userMessage;\n this.details = data.details ?? null;\n // MATRX-EXCEPTION: requestId is genuinely optional (constructor param);\n // \"\" means \"no request id available\" — a display/log field, not persisted.\n this.requestId = data.requestId ?? \"\";\n this.status = data.status ?? null;\n }\n\n /** Convert to the wire format for logging */\n toJSON(): BackendApiErrorData {\n return {\n error: this.code,\n message: this.detail,\n user_message: this.userMessage,\n details: this.details,\n request_id: this.requestId,\n };\n }\n}\n\n/**\n * The socket carrying a live NDJSON stream broke mid-run.\n *\n * THE DISTINCTION THIS EXISTS TO MAKE: a backend that blows up mid-stream does\n * NOT break the socket — it emits a typed `error` event and closes the body\n * cleanly. So an exception escaping the body reader means the *transport* died,\n * not the run. And aidream streams run `detach_on_disconnect=True`: the server\n * keeps executing and persisting the turn after our connection goes away.\n *\n * The client therefore cannot decide locally whether the answer is lost — it\n * must ASK THE SERVER. That is what `resumable` means here: \"reattach by\n * requestId / conversationId / durable run id and let server truth settle it\",\n * never \"this succeeded\". A server that genuinely died reports `failed` on\n * reattach and the honest record replaces the optimistic copy.\n *\n * Consumers: `run-ai-stream.ts` (chat → `reconnectServerOperation`) and\n * `adopt-foreign-stream.ts` (pipeline runs → the surface's own rejoin).\n */\nexport class StreamTransportError extends BackendApiError {\n /** Always true — reattach and let the server settle the outcome. */\n readonly resumable = true as const;\n\n constructor(data: {\n detail: string;\n details?: unknown | null;\n requestId?: string;\n }) {\n super({\n code: \"stream_transport_lost\",\n detail: data.detail,\n userMessage:\n \"The connection dropped. Your run is still going on the server — reconnecting to it now.\",\n details: data.details ?? null,\n ...(data.requestId !== undefined ? { requestId: data.requestId } : {}),\n });\n this.name = \"StreamTransportError\";\n }\n}\n\n/**\n * True when a failure is a dropped transport rather than a failed run. Use this\n * instead of `instanceof` at boundaries that re-wrap errors (thunk rejections,\n * `callApi` result errors), where the class identity is lost but the code\n * survives.\n */\nexport function isStreamTransportLost(error: unknown): boolean {\n if (error instanceof StreamTransportError) return true;\n if (error instanceof BackendApiError) {\n return error.code === \"stream_transport_lost\";\n }\n if (error && typeof error === \"object\") {\n const code = (error as { code?: unknown }).code;\n if (code === \"stream_transport_lost\") return true;\n const errorType = (error as { error_type?: unknown }).error_type;\n if (errorType === \"transport_lost\") return true;\n }\n return false;\n}\n\n// ============================================================================\n// HTTP ERROR PARSER\n// ============================================================================\n\n/**\n * Parse a non-OK HTTP response into a BackendApiError.\n *\n * Handles the standardized backend shape and falls back gracefully\n * when the response isn't JSON or uses a legacy format.\n */\nexport async function parseHttpError(\n response: Response,\n): Promise<BackendApiError> {\n const status = response.status;\n let text: string;\n\n try {\n // A Response body can only be read once. Capture it before deciding\n // whether the backend sent a structured error or plain text.\n text = await response.text();\n } catch {\n return new BackendApiError({\n code: statusToCode(status),\n detail: `HTTP ${status}`,\n userMessage: `Request failed (${status})`,\n status,\n });\n }\n\n let body: Record<string, unknown> | null;\n try {\n body = JSON.parse(text) as Record<string, unknown> | null;\n } catch {\n return new BackendApiError({\n code: statusToCode(status),\n detail: text || `HTTP ${status}`,\n userMessage: text || `Request failed (${status})`,\n status,\n });\n }\n return parseHttpErrorBody(body, status);\n}\n\n/**\n * Parse an already-decoded JSON error body into a BackendApiError.\n *\n * Exported because XHR callers (upload/download progress paths) have the\n * parsed body in hand and MUST NOT hand-roll a shallower read: a private\n * copy in `python-client.ts` looked only at top-level `error`/`message`, so\n * FastAPI's `{\"detail\": {...}}` envelope — what every matrx-files 500 uses —\n * degraded to the useless `code: \"internal\", detail: \"HTTP 500\"`. That is\n * exactly how an upload failure with a real server-side cause reached the\n * user as `Upload failed (500)` and nothing else. One parser, every transport.\n */\nexport function parseHttpErrorBody(\n body: Record<string, unknown> | null,\n status: number,\n): BackendApiError {\n if (!body) {\n return new BackendApiError({\n code: statusToCode(status),\n detail: `HTTP ${status}`,\n userMessage: `Request failed (${status})`,\n status,\n });\n }\n // Standard backend shape: { error, message, user_message, details, request_id }\n if (typeof body.error === \"string\" && typeof body.user_message === \"string\") {\n return new BackendApiError({\n code: body.error as BackendErrorCode,\n detail: (body.message as string) || `HTTP ${status}`,\n userMessage: body.user_message as string,\n details: body.details ?? null,\n requestId:\n typeof body.request_id === \"string\" ? body.request_id : undefined,\n status,\n });\n }\n\n // Legacy: nested error object with user_visible_message\n if (typeof body.error === \"object\" && body.error !== null) {\n const errorObj = body.error as Record<string, unknown>;\n return new BackendApiError({\n code:\n (errorObj.type as string) ||\n (errorObj.error as string) ||\n statusToCode(status),\n detail: (errorObj.message as string) || `HTTP ${status}`,\n userMessage:\n (errorObj.user_message as string) ||\n (errorObj.user_visible_message as string) ||\n (errorObj.message as string) ||\n `Request failed (${status})`,\n details: errorObj.details ?? null,\n requestId:\n typeof errorObj.request_id === \"string\"\n ? errorObj.request_id\n : undefined,\n status,\n });\n }\n\n // FastAPI 422 validation shape: { detail: [{ loc, msg, type }, ...] }\n if (Array.isArray(body.detail)) {\n const first = body.detail[0] as Record<string, unknown> | undefined;\n const firstMsg = first && typeof first.msg === \"string\" ? first.msg : null;\n return new BackendApiError({\n code: statusToCode(status),\n detail: firstMsg\n ? `Validation error: ${firstMsg}`\n : JSON.stringify(body.detail),\n userMessage: firstMsg || `Request failed (${status})`,\n details: body.detail,\n status,\n });\n }\n\n // FastAPI HTTPException with structured detail: { detail: { code?, error?, message?, user_message?, ... } }\n if (\n typeof body.detail === \"object\" &&\n body.detail !== null &&\n !Array.isArray(body.detail)\n ) {\n const d = body.detail as Record<string, unknown>;\n const code =\n (typeof d.code === \"string\" && d.code) ||\n (typeof d.error === \"string\" && d.error) ||\n statusToCode(status);\n const message =\n (typeof d.message === \"string\" && d.message) ||\n (typeof d.detail === \"string\" && d.detail) ||\n `HTTP ${status}`;\n return new BackendApiError({\n code: code as BackendErrorCode,\n detail: message,\n userMessage:\n (typeof d.user_message === \"string\" && d.user_message) ||\n (typeof d.user_visible_message === \"string\" &&\n d.user_visible_message) ||\n message,\n details: d.details ?? d,\n requestId: typeof d.request_id === \"string\" ? d.request_id : undefined,\n status,\n });\n }\n\n // Legacy: flat { error: string, message: string } or { detail: string }\n return new BackendApiError({\n code: typeof body.error === \"string\" ? body.error : statusToCode(status),\n detail:\n (body.message as string) ||\n (body.detail as string) ||\n (body.error as string) ||\n `HTTP ${status}`,\n userMessage:\n (body.user_message as string) ||\n (body.user_visible_message as string) ||\n (body.message as string) ||\n (body.detail as string) ||\n `Request failed (${status})`,\n details: body.details ?? null,\n requestId:\n typeof body.request_id === \"string\" ? body.request_id : undefined,\n status,\n });\n}\n\n/**\n * Adapt callApi's result-style error into the same canonical error used by\n * direct fetch and streaming consumers.\n *\n * callApi intentionally returns errors instead of throwing them, but its\n * `serverDetail` contains the complete FastAPI body. Sending only\n * `error.message` to a feature discards that body and turns a precise\n * configuration failure into \"HTTP 422\". This adapter keeps one parser and\n * one human-facing explanation path across both client styles.\n */\nexport function parseCallApiError(error: {\n message: string;\n status?: number;\n serverDetail?: unknown;\n}): BackendApiError {\n const status = error.status ?? 500;\n const body =\n error.serverDetail &&\n typeof error.serverDetail === \"object\" &&\n !Array.isArray(error.serverDetail)\n ? (error.serverDetail as Record<string, unknown>)\n : { message: error.message };\n return parseHttpErrorBody(body, status);\n}\n\n// ============================================================================\n// STREAMING ERROR PARSER\n// ============================================================================\n\n/**\n * Parse streaming error event data into a BackendApiError.\n *\n * Handles both new format (`user_message`) and legacy (`user_visible_message`).\n */\nexport function parseStreamError(data: unknown): BackendApiError {\n if (!data || typeof data !== \"object\") {\n return new BackendApiError({\n code: \"internal_error\",\n detail: typeof data === \"string\" ? data : \"Unknown streaming error\",\n userMessage: typeof data === \"string\" ? data : \"Something went wrong\",\n });\n }\n\n const obj = data as Record<string, unknown>;\n const details =\n typeof obj.details === \"object\" && obj.details !== null\n ? (obj.details as Record<string, unknown>)\n : null;\n return new BackendApiError({\n code:\n (obj.code as string) ||\n (obj.error_type as string) ||\n (obj.error as string) ||\n \"internal_error\",\n detail: (obj.message as string) || \"Streaming error\",\n userMessage:\n (obj.user_message as string) ||\n (obj.message as string) ||\n \"Something went wrong\",\n details,\n requestId:\n typeof obj.request_id === \"string\"\n ? obj.request_id\n : typeof details?.request_id === \"string\"\n ? details.request_id\n : undefined,\n });\n}\n\n/**\n * Restore the canonical error shape from a durable backend run row.\n *\n * Provider ledgers often keep an aggregate summary plus a more specific first\n * child failure. Prefer that child so a page refresh does not turn a precise\n * streamed failure back into \"1 request failed\".\n */\nexport function parsePersistedBackendError(\n data: unknown,\n requestId = \"\",\n): BackendApiError | null {\n if (!data || typeof data !== \"object\") return null;\n const error = data as Record<string, unknown>;\n const failures = Array.isArray(error.failures) ? error.failures : [];\n const firstSpecific = failures.find(\n (failure): failure is Record<string, unknown> =>\n typeof failure === \"object\" &&\n failure !== null &&\n typeof (failure as Record<string, unknown>).message === \"string\",\n );\n const summary =\n typeof error.message === \"string\"\n ? error.message\n : \"Backend operation failed\";\n const specific =\n typeof firstSpecific?.message === \"string\"\n ? firstSpecific.message\n : summary;\n const detail = specific === summary ? summary : `${summary}: ${specific}`;\n const code = typeof error.type === \"string\" ? error.type : \"internal_error\";\n // A persisted failure may carry a human-facing line the technical detail\n // cannot express — the load-bearing case being a paid result that survived\n // its persistence failure (`WritePreservedError`, D183): \"it broke\" is true\n // and \"your work is preserved and will be recovered\" is what the user needs.\n // `describeBackendFailure` still overrides a TEMPLATED one with the cause.\n const userMessage =\n typeof error.user_message === \"string\" && error.user_message\n ? error.user_message\n : detail;\n return new BackendApiError({\n code,\n detail,\n userMessage,\n details: error,\n requestId,\n });\n}\n\n// ============================================================================\n// FAILURE EXPLANATION — never let a templated non-answer be the whole story\n// ============================================================================\n\n/**\n * Server messages that carry ZERO diagnostic value. The streaming layer\n * (`matrx-connect/streaming/response.py`) emits the first one for every\n * unclassified crash — \"CanonicalGscSync failed unexpectedly. Please try\n * again or adjust your settings.\" — while the REAL cause travels in the same\n * payload's `message`. Treating those as the answer is what makes failures\n * feel secretive.\n */\nconst GENERIC_MESSAGE_PATTERNS: readonly RegExp[] = [\n /failed unexpectedly/i,\n /^\\s*something went wrong/i,\n /please try again(\\s+later)?\\.?\\s*$/i,\n /^\\s*request failed\\b/i,\n /^\\s*unknown (streaming )?error/i,\n /^\\s*internal server error\\.?\\s*$/i,\n];\n\n/** True when a message tells the reader nothing about what actually broke. */\nexport function isGenericUserMessage(\n message: string | null | undefined,\n): boolean {\n const value = (message ?? \"\").trim();\n if (!value) return true;\n return GENERIC_MESSAGE_PATTERNS.some((pattern) => pattern.test(value));\n}\n\nexport interface UpstreamErrorPayload {\n message: string;\n code: string | null;\n userMessage: string | null;\n requestId: string | null;\n status: number | null;\n}\n\n/**\n * Recover an upstream service's structured error that a downstream service\n * stringified into its own message.\n *\n * Real example (scraper wrapping aidream):\n * `aidream could not resolve GSC credential 7223…: HTTP 409 {\"error\":\"conflict\",\n * \"message\":\"Google connection 7223… has no vault credential — it needs\n * re-authentication\",\"user_message\":\"Something went wrong…\",\"request_id\":\"9002…\"}`\n *\n * Without this, the only actionable sentence on the whole hop is invisible.\n */\nexport function unwrapUpstreamError(\n message: string,\n): UpstreamErrorPayload | null {\n const start = message.indexOf(\"{\");\n const end = message.lastIndexOf(\"}\");\n if (start < 0 || end <= start) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(message.slice(start, end + 1));\n } catch {\n return null;\n }\n if (typeof parsed !== \"object\" || parsed === null) return null;\n const body = parsed as Record<string, unknown>;\n const inner =\n (typeof body.message === \"string\" && body.message) ||\n (typeof body.detail === \"string\" && body.detail) ||\n \"\";\n if (!inner) return null;\n const statusMatch = /\\bHTTP (\\d{3})\\b/.exec(message.slice(0, start));\n return {\n message: inner,\n code:\n (typeof body.error_type === \"string\" && body.error_type) ||\n (typeof body.error === \"string\" && body.error) ||\n null,\n userMessage:\n typeof body.user_message === \"string\" ? body.user_message : null,\n requestId: typeof body.request_id === \"string\" ? body.request_id : null,\n status: statusMatch ? Number(statusMatch[1]) : null,\n };\n}\n\nexport interface BackendFailureExplanation {\n /** Machine code from the deepest layer that classified the failure. */\n code: string;\n /** The most specific human-readable cause available — never a template. */\n cause: string;\n /** What to headline in the UI: the cause when the server was generic. */\n headline: string;\n /** True when every user-facing message the server sent was a template. */\n headlineWasGeneric: boolean;\n /** Message chain, outermost (closest service) first. */\n chain: string[];\n /** Deepest request id available, for cross-service log correlation. */\n requestId: string;\n status: number | null;\n}\n\n/**\n * THE anti-secrecy primitive: turn any thrown backend/stream failure into the\n * most specific explanation the payload can support — unwrapping every nested\n * upstream error and refusing to let a templated `user_message` be the answer.\n *\n * Every surface that reports a backend failure to a human should headline\n * `explanation.headline` and always keep `cause` + `requestId` reachable.\n */\nexport function describeBackendFailure(\n error: unknown,\n): BackendFailureExplanation {\n const chain: string[] = [];\n let code = \"internal_error\";\n let requestId = \"\";\n let status: number | null = null;\n let userFacing: string | null = null;\n\n if (error instanceof BackendApiError) {\n code = error.code;\n requestId = error.requestId;\n status = error.status;\n userFacing = error.userMessage;\n if (error.detail) chain.push(error.detail);\n if (error.userMessage && error.userMessage !== error.detail) {\n chain.push(error.userMessage);\n }\n } else if (error instanceof Error) {\n chain.push(error.message);\n userFacing = error.message;\n } else if (typeof error === \"string\") {\n chain.push(error);\n userFacing = error;\n } else {\n chain.push(\"Unknown error\");\n }\n\n // Walk the nesting: ANY message in the chain may have stringified the\n // service above it (the technical `detail` usually does, the templated\n // `user_message` never does), so every layer gets unwrapped.\n for (let cursor = 0; cursor < chain.length && cursor < 12; cursor += 1) {\n const upstream = unwrapUpstreamError(chain[cursor] ?? \"\");\n if (!upstream || chain.includes(upstream.message)) continue;\n chain.push(upstream.message);\n if (upstream.code) code = upstream.code;\n if (upstream.requestId) requestId = upstream.requestId;\n if (upstream.status !== null) status = upstream.status;\n }\n\n const specific = [...chain]\n .reverse()\n .find((message) => !isGenericUserMessage(message));\n const cause = specific ?? chain[0] ?? \"Unknown error\";\n const headlineWasGeneric = isGenericUserMessage(userFacing);\n return {\n code,\n cause,\n headline: headlineWasGeneric ? cause : (userFacing ?? cause),\n headlineWasGeneric,\n chain,\n requestId,\n status,\n };\n}\n\n/**\n * Extract a user-visible message from any error object.\n * Utility for components that just need the display string.\n */\nexport function getUserMessage(error: unknown): string {\n if (error instanceof BackendApiError) {\n return error.userMessage;\n }\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n // A Redux thunk's `.unwrap()` rejects with a SerializedError — a plain\n // object, not an Error — whose `message` is the real reason.\n if (\n typeof error === \"object\" &&\n error !== null &&\n typeof (error as { message?: unknown }).message === \"string\" &&\n (error as { message: string }).message\n ) {\n return (error as { message: string }).message;\n }\n return \"Something went wrong\";\n}\n\n// ============================================================================\n// INTERNAL HELPERS\n// ============================================================================\n\nfunction statusToCode(status: number): BackendErrorCode {\n switch (status) {\n case 401:\n return \"auth_required\";\n case 403:\n return \"admin_required\";\n case 404:\n return \"not_found\";\n case 422:\n return \"validation_error\";\n default:\n return \"internal_error\";\n }\n}\n","/**\n * Canonical AI Matrx NDJSON wire kernel.\n *\n * This module is deliberately independent of React, Redux, Next.js, Supabase,\n * and generated application types. Every Matrx client uses it to turn the\n * backend's byte stream into the same normalized `{ event, data }` envelopes.\n * Host runtimes remain responsible for HTTP/auth errors and for deciding what\n * each event means in their state model.\n */\n\nexport interface MatrxStreamEnvelope<TData = unknown> {\n event: string;\n /** Immutable emitter segment; transport sequence is scoped to this id. */\n stream_id?: string;\n data: TData;\n /** Monotonic transport sequence from full envelopes, when supplied. */\n stream_seq?: number;\n}\n\nexport interface MatrxNdjsonIssue {\n line: string;\n error: unknown;\n /** One-based physical NDJSON line number. */\n lineNumber: number;\n /** True when an unterminated trailing fragment was parsed by `finish()`. */\n atCompletion: boolean;\n}\n\nexport interface MatrxStreamEnvelopeObservation {\n /** Exact parsed JSON value before compact/full normalization. */\n raw: unknown;\n envelope: MatrxStreamEnvelope;\n line: string;\n lineNumber: number;\n atCompletion: boolean;\n}\n\nexport interface MatrxNdjsonFramerOptions {\n /** Malformed JSON is non-fatal, but it must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx event envelope is also non-fatal. */\n onUnknownEnvelope?: (value: unknown) => void;\n /** Observe every valid envelope without changing or consuming it. */\n onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;\n}\n\nexport interface ReadMatrxNdjsonOptions extends MatrxNdjsonFramerOptions {\n signal?: AbortSignal;\n /** Maximum normalized events read ahead of the iterator consumer. */\n maxReadAhead?: number;\n}\n\nexport interface MatrxNdjsonFramer {\n /** Push a text fragment. Fragments may split JSON tokens or line endings. */\n pushText(fragment: string): MatrxStreamEnvelope[];\n /** Push a byte fragment. UTF-8 code points may span calls. */\n pushBytes(fragment: Uint8Array): MatrxStreamEnvelope[];\n /** Parse the final unterminated line and flush any pending UTF-8 bytes. */\n finish(): MatrxStreamEnvelope[];\n}\n\ntype QueueItem =\n | { kind: \"event\"; value: MatrxStreamEnvelope }\n | { kind: \"error\"; error: unknown }\n | { kind: \"done\" };\n\nexport const DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize both supported Matrx wire shapes:\n *\n * - full: `{ \"event\": \"chunk\", \"data\": { \"text\": \"...\" } }`\n * - compact chunk: `{ \"e\": \"c\", \"t\": \"...\" }`\n * - compact reasoning: `{ \"e\": \"r\", \"t\": \"...\" }`\n */\nexport function normalizeMatrxStreamEnvelope(\n value: unknown,\n): MatrxStreamEnvelope | null {\n if (!isRecord(value)) return null;\n\n if (typeof value.event === \"string\") {\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n return {\n event: value.event,\n data: value.data,\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n if (value.e === \"c\" && typeof value.t === \"string\") {\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n return {\n event: \"chunk\",\n data: { text: value.t },\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n if (value.e === \"r\" && typeof value.t === \"string\") {\n const streamId = typeof value.stream_id === \"string\" ? value.stream_id : undefined;\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n return {\n event: \"reasoning_chunk\",\n data: { text: value.t },\n ...(streamId === undefined ? {} : { stream_id: streamId }),\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n return null;\n}\n\n/**\n * Create the transport-independent NDJSON framer used by the stream reader.\n * Browser extensions, desktop bridges, WebSockets, and tests can feed it\n * fragmented strings or bytes without constructing a `ReadableStream`.\n */\nexport function createMatrxNdjsonFramer(\n options: MatrxNdjsonFramerOptions = {},\n): MatrxNdjsonFramer {\n const decoder = new TextDecoder();\n let buffer = \"\";\n let lineNumber = 0;\n let finished = false;\n\n const assertOpen = (): void => {\n if (finished) throw new Error(\"Matrx NDJSON framer is already finished\");\n };\n\n const parseLine = (\n line: string,\n atCompletion: boolean,\n ): MatrxStreamEnvelope | null => {\n const currentLineNumber = ++lineNumber;\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed) as unknown;\n } catch (error) {\n options.onMalformedLine?.({\n line: trimmed,\n error,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return null;\n }\n\n const envelope = normalizeMatrxStreamEnvelope(parsed);\n if (!envelope) {\n options.onUnknownEnvelope?.(parsed);\n return null;\n }\n options.onValidEnvelope?.({\n raw: parsed,\n envelope,\n line: trimmed,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return envelope;\n };\n\n const pushDecodedText = (fragment: string): MatrxStreamEnvelope[] => {\n buffer += fragment;\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n const envelopes: MatrxStreamEnvelope[] = [];\n for (const line of lines) {\n const envelope = parseLine(line, false);\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n };\n\n return {\n pushText(fragment) {\n assertOpen();\n // Flush any pending byte fragment before switching to explicit text.\n return pushDecodedText(decoder.decode() + fragment);\n },\n pushBytes(fragment) {\n assertOpen();\n return pushDecodedText(decoder.decode(fragment, { stream: true }));\n },\n finish() {\n assertOpen();\n finished = true;\n const envelopes = pushDecodedText(decoder.decode());\n if (buffer.length > 0) {\n const envelope = parseLine(buffer, true);\n buffer = \"\";\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n },\n };\n}\n\nfunction readAheadLimit(value: number | undefined): number {\n const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;\n if (!Number.isSafeInteger(limit) || limit < 1) {\n throw new RangeError(\"maxReadAhead must be a positive safe integer\");\n }\n return limit;\n}\n\n/**\n * Read and normalize a Matrx NDJSON response body with bounded background\n * read-ahead. Consumer work does not stall the network until `maxReadAhead`\n * complete events are waiting; the bound prevents an abandoned or blocked\n * consumer from growing memory without limit.\n */\nexport async function* readMatrxNdjsonStream(\n body: ReadableStream<Uint8Array>,\n options: ReadMatrxNdjsonOptions = {},\n): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n const maxReadAhead = readAheadLimit(options.maxReadAhead);\n const queue: QueueItem[] = [];\n let queuedEventCount = 0;\n let wakeConsumer: (() => void) | null = null;\n let wakeProducer: (() => void) | null = null;\n let readerFinished = false;\n let consumerClosed = false;\n\n const wakeWaitingConsumer = (): void => {\n const wake = wakeConsumer;\n wakeConsumer = null;\n wake?.();\n };\n const wakeWaitingProducer = (): void => {\n const wake = wakeProducer;\n wakeProducer = null;\n wake?.();\n };\n const enqueueTerminal = (item: QueueItem): void => {\n if (consumerClosed) return;\n queue.push(item);\n wakeWaitingConsumer();\n };\n const enqueueEvent = async (value: MatrxStreamEnvelope): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n if (consumerClosed || options.signal?.aborted) return false;\n queue.push({ kind: \"event\", value });\n queuedEventCount += 1;\n wakeWaitingConsumer();\n return true;\n };\n const waitForReadCapacity = async (): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n return !consumerClosed && !options.signal?.aborted;\n };\n\n const reader = body.getReader();\n const framer = createMatrxNdjsonFramer(options);\n\n const onAbort = (): void => {\n wakeWaitingProducer();\n wakeWaitingConsumer();\n void reader.cancel(options.signal?.reason).catch(() => undefined);\n };\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (options.signal?.aborted) onAbort();\n\n const readerPromise = (async (): Promise<void> => {\n try {\n while (!options.signal?.aborted && !consumerClosed) {\n if (!(await waitForReadCapacity())) return;\n const { value, done } = await reader.read();\n if (done) break;\n for (const envelope of framer.pushBytes(value)) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n\n if (!options.signal?.aborted && !consumerClosed) {\n for (const envelope of framer.finish()) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n } catch (error) {\n const aborted =\n options.signal?.aborted ||\n consumerClosed ||\n (error instanceof Error && error.name === \"AbortError\");\n if (!aborted) enqueueTerminal({ kind: \"error\", error });\n } finally {\n readerFinished = true;\n reader.releaseLock();\n enqueueTerminal({ kind: \"done\" });\n }\n })();\n\n try {\n while (true) {\n if (queue.length === 0) {\n if (options.signal?.aborted || readerFinished) return;\n await new Promise<void>((resolve) => {\n wakeConsumer = resolve;\n });\n }\n\n const item = queue.shift();\n if (item?.kind === \"event\") queuedEventCount -= 1;\n wakeWaitingProducer();\n if (!item || item.kind === \"done\") return;\n if (item.kind === \"error\") throw item.error;\n yield item.value;\n }\n } finally {\n consumerClosed = true;\n wakeWaitingProducer();\n wakeWaitingConsumer();\n options.signal?.removeEventListener(\"abort\", onAbort);\n if (!readerFinished) {\n await reader.cancel().catch(() => undefined);\n }\n await readerPromise;\n }\n}\n","import { isUuidShape } from \"@ai-matrx/kit/uuid\";\n\n/**\n * The fail-closed organization-context kernel — ONE implementation for every\n * Matrx client transport (moved in from matrx-frontend\n * `lib/api/organization-context.ts` verbatim under C22; the host module is now\n * a re-export of this one).\n *\n * Transports resolve their authoritative organization first, then use these\n * functions to bind that exact value without guessing or defaulting. The\n * server never manufactures an org (it 422s a blank one), so the client\n * refuses before the wire: a missing or malformed org id throws\n * `OrganizationContextError` instead of sending a request that cannot succeed.\n */\n\nexport type OrganizationContextErrorCode =\n | \"organization_context_required\"\n | \"organization_context_invalid\"\n | \"organization_context_mismatch\";\n\nexport class OrganizationContextError extends Error {\n readonly code: OrganizationContextErrorCode;\n\n constructor(code: OrganizationContextErrorCode, message: string) {\n super(message);\n this.name = \"OrganizationContextError\";\n this.code = code;\n }\n}\n\ndeclare const organizationOperationBrand: unique symbol;\n\n/** A validated organization operation; construct only through the factory. */\nexport type OrganizationOperation = Readonly<{\n organization_id: string;\n readonly [organizationOperationBrand]: true;\n}>;\n\nexport function createOrganizationOperation(\n organizationId: string,\n): OrganizationOperation {\n const organization_id = requireOrganizationContext(organizationId);\n return Object.freeze({ organization_id }) as OrganizationOperation;\n}\n\nexport function assertOrganizationMatchesOperation(\n operation: OrganizationOperation,\n organizationId: string,\n): void {\n if (operation.organization_id !== requireOrganizationContext(organizationId)) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Organization ID must match the request operation.\",\n );\n }\n}\n\n/**\n * Normalize and validate the effective organization id for a request. The\n * override (an explicit per-call value) beats the selected context value.\n * Throws `organization_context_required` when neither is present and\n * `organization_context_invalid` when the candidate is not a UUID.\n */\nexport function requireOrganizationContext(\n selectedOrganizationId: string | null | undefined,\n overrideOrganizationId?: string,\n): string {\n const candidate = overrideOrganizationId ?? selectedOrganizationId;\n if (typeof candidate !== \"string\" || candidate.trim().length === 0) {\n throw new OrganizationContextError(\n \"organization_context_required\",\n \"Select an organization before sending this request.\",\n );\n }\n\n const normalized = candidate.trim();\n if (!isUuidShape(normalized)) {\n throw new OrganizationContextError(\n \"organization_context_invalid\",\n \"The selected organization ID is invalid.\",\n );\n }\n return normalized.toLowerCase();\n}\n\n/**\n * Bind `X-Organization-Id` onto a header bag. A pre-existing org header that\n * disagrees with the context org is a `organization_context_mismatch` error —\n * never silently overwritten in either direction.\n */\nexport function applyOrganizationContextHeader(\n headers: Record<string, string>,\n organizationId: string,\n): Record<string, string> {\n const normalizedOrganizationId = requireOrganizationContext(organizationId);\n for (const [name, value] of Object.entries(headers)) {\n if (\n name.toLowerCase() === \"x-organization-id\" &&\n value.trim().toLowerCase() !== normalizedOrganizationId\n ) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"X-Organization-Id must match the request context organization.\",\n );\n }\n }\n const withoutOrganizationHeader = Object.fromEntries(\n Object.entries(headers).filter(\n ([name]) => name.toLowerCase() !== \"x-organization-id\",\n ),\n );\n return {\n ...withoutOrganizationHeader,\n \"X-Organization-Id\": normalizedOrganizationId,\n };\n}\n\n/**\n * Assert that an `organization_id` query parameter (when present) matches the\n * request context organization — the query string must never smuggle a\n * different org past the header binding.\n */\nexport function assertQueryOrganizationMatchesContext(\n queryParams: Record<string, string | number | boolean> | undefined,\n organizationId: string,\n): void {\n if (!queryParams || queryParams.organization_id === undefined) return;\n const queryOrganizationId = requireOrganizationContext(\n String(queryParams.organization_id),\n );\n if (queryOrganizationId !== requireOrganizationContext(organizationId)) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Query organization_id must match the request context organization.\",\n );\n }\n}\n","/**\n * The AI API protocol-version policy — which version of the AI runtime a\n * Matrx client talks to, and the v2 → v1 transport fallback (moved in from\n * matrx-frontend `lib/api/ai-api-version.ts` + `call-api.ts::\n * fetchWithV2Fallback` under C22; server truth\n * `aidream/docs/runtime/V2_FRONTEND_MIGRATION.md`).\n *\n * Background: the Python backend exposes a `/v2` runtime-spine namespace that\n * wraps the core AI request surfaces in a request-tracking envelope. Body,\n * headers, and streaming response are BYTE-IDENTICAL to v1 — only the URL\n * differs.\n *\n * ─── The one rule that keeps burning us ─────────────────────────────────────\n * `/v2` is inserted at the FRONT of the in-app path, right before `/ai`:\n *\n * /ai/agents/{id} → /v2/ai/agents/{id} ✅ correct\n * /ai/v2/agents/… ❌ WRONG (nested) — 404s\n *\n * `toV2Path` below is the ONLY place this transform is spelled out.\n *\n * ─── Scope: ONLY the covered surfaces have a v2 form ────────────────────────\n * chat, manual, agents/{id}, conversations/{id} (+ singular aliases),\n * prompts/{id}, mandates/{key}. EVERYTHING ELSE — cancel, warm, resume,\n * fork-and-run, runtime operations, files … — has NO v2 route, and the server\n * does NOT auto-downgrade (a `/v2` request to an uncovered surface is a plain\n * 404). So the transform is a scoped allowlist, never a blanket prefix.\n */\n\nimport {\n isNetError,\n resilientFetch,\n type ResilientFetchOptions,\n} from \"@ai-matrx/data/net\";\n\nexport type MatrxAiApiVersion = \"v1\" | \"v2\";\n\n/**\n * The package-wide default AI API version — the production value every Matrx\n * client runs unless its host deliberately overrides\n * (`createMatrxTransport({ aiApiVersion })`).\n */\nexport const MATRX_AI_API_VERSION_DEFAULT: MatrxAiApiVersion = \"v2\";\n\n/**\n * The canonical v1 path TEMPLATES the v2 spine covers, `{param}` placeholders\n * intact — for hosts that route through a template registry.\n */\nexport const V2_COVERED_AI_PATH_TEMPLATES = [\n \"/ai/manual\",\n \"/ai/chat\",\n \"/ai/agents/{agent_id}\",\n \"/ai/agent/{agent_id}\", // singular alias — behaves identically\n \"/ai/conversations/{conversation_id}\",\n \"/ai/conversation/{conversation_id}\", // singular alias\n \"/ai/prompts/{prompt_id}\", // saved-prompt execution\n \"/ai/mandates/{mandate_key}\", // THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)\n] as const;\n\n/**\n * Insert `/v2` at the front of an in-app path. Idempotent, and prefix-aware:\n * a legacy `/api/` compatibility prefix (stripped server-side) is preserved so\n * `/api/ai/chat` → `/api/v2/ai/chat`.\n */\nexport function toV2Path(path: string): string {\n const withLead = path.startsWith(\"/\") ? path : `/${path}`;\n if (withLead.startsWith(\"/api/\")) {\n const rest = withLead.slice(\"/api\".length); // \"/ai/chat\"\n return rest.startsWith(\"/v2/\") ? withLead : `/api/v2${rest}`;\n }\n return withLead.startsWith(\"/v2/\") ? withLead : `/v2${withLead}`;\n}\n\n// Interpolated (concrete) forms of the covered surfaces — used to guard\n// callers that pass a real path (id already substituted). Anchored so ONLY the\n// exact shapes match: sub-paths like `/ai/agents/{id}/warm`,\n// `/ai/conversations/{id}/resume`, and `/ai/cancel/{id}` deliberately do NOT\n// match and stay on v1. The optional `/api` prefix mirrors `toV2Path`.\nconst COVERED_INTERPOLATED_PATH = [\n /^(?:\\/api)?\\/ai\\/manual$/,\n /^(?:\\/api)?\\/ai\\/chat$/,\n /^(?:\\/api)?\\/ai\\/agents\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/agent\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/conversations\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/conversation\\/[^/]+$/,\n /^(?:\\/api)?\\/ai\\/prompts\\/[^/]+$/, // `/warm` etc. deliberately don't match\n /^(?:\\/api)?\\/ai\\/mandates\\/[^/]+$/, // the mandate door\n];\n\n/** Whether `path` (already interpolated) is one of the covered surfaces. */\nexport function isCoveredAiPath(path: string): boolean {\n return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));\n}\n\n/**\n * Whether an in-app path (or a full URL whose path was built by `toV2Path`)\n * targets the v2 namespace — the guard the downgrade fallback keys off.\n */\nexport function isV2Path(pathOrUrl: string): boolean {\n return /\\/v2\\/ai\\//.test(pathOrUrl);\n}\n\n/**\n * The inverse of `toV2Path` — strip the `/v2` version segment so a transport\n * failure of the v2 endpoint (network error, 404/405, 5xx BEFORE any stream\n * content) can retry the identical request on the v1 route. Works on a bare\n * path, an `/api`-prefixed path, or a full URL (the `/v2/ai/` shape is unique\n * to the version namespace). Idempotent on non-v2 input.\n */\nexport function toV1FallbackUrl(url: string): string {\n return url.replace(/\\/v2\\/ai\\//, \"/ai/\");\n}\n\n/**\n * Apply the active AI API version to an ALREADY-INTERPOLATED in-app path.\n *\n * - Covered surface + v2 → `/v2` prefix inserted.\n * - Anything else (or v1) → returned unchanged.\n *\n * Pass the in-app PATH only (no scheme/host); prepend the base URL afterward.\n */\nexport function applyAiApiVersion(\n path: string,\n version: MatrxAiApiVersion,\n): string {\n if (version !== \"v2\") return path;\n return isCoveredAiPath(path) ? toV2Path(path) : path;\n}\n\n/** One v2 → v1 downgrade, surfaced to the host's diagnostics sink. */\nexport interface MatrxProtocolDowngrade {\n /** The failed v2 URL. */\n url: string;\n /** Why the downgrade fired (thrown error text, or `HTTP <status>`). */\n reason: string;\n /** HTTP status when the trigger was a response (404/405/5xx). */\n status?: number;\n}\n\nexport interface MatrxProtocolFallbackOptions extends ResilientFetchOptions {\n /**\n * Fired on every downgrade — a sustained stream of these means a v2 surface\n * is unhealthy. The fallback also `console.warn`s unconditionally (parity\n * with the original host pipeline) so the signal never disappears silently.\n */\n onDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n}\n\n/**\n * `resilientFetch` with the v2 → v1 transport fallback. Fires ONLY when a\n * `/v2/ai/...` ENDPOINT itself fails — a network-layer throw (non-abort), a\n * 404/405 (surface not on v2), or a 5xx — always BEFORE any stream content is\n * consumed. Never on an application error (those fail identically on v1), and\n * never on a caller abort (a user cancel must not be logged as a downgrade —\n * that poisons the exact telemetry the rollout reads to judge v2 health).\n */\nexport async function fetchWithMatrxProtocolFallback(\n url: string,\n init: RequestInit,\n opts: MatrxProtocolFallbackOptions = {},\n): Promise<{ response: Response }> {\n const { onDowngrade, ...fetchOpts } = opts;\n const logDowngrade = (reason: string, status?: number) => {\n console.warn(\n `[matrx] ai_v2_downgrade → retrying on v1. v2=${url} reason=${reason}`,\n );\n onDowngrade?.({ url, reason, ...(status !== undefined ? { status } : {}) });\n };\n if (!isV2Path(url)) return resilientFetch(url, init, fetchOpts);\n let result: { response: Response };\n try {\n result = await resilientFetch(url, init, fetchOpts);\n } catch (err) {\n // resilientFetch normalizes a caller-signal abort to NetError code\n // \"aborted\" (AbortedError); a raw AbortError is checked too for safety.\n const isAbort =\n (isNetError(err) && err.code === \"aborted\") ||\n (err instanceof Error && err.name === \"AbortError\");\n if (isAbort) throw err;\n logDowngrade(String(err));\n return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);\n }\n const status = result.response.status;\n if (status === 404 || status === 405 || status >= 500) {\n logDowngrade(`HTTP ${status}`, status);\n return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);\n }\n return result;\n}\n\n/**\n * The exact-match `pathOverrides` map for `resolveEndpointPath` — keyed on the\n * canonical templates, valued at their `/v2` siblings. Empty for v1. Every call\n * that flows through the endpoint-override registry picks up v2 for the covered\n * surfaces — and ONLY the covered surfaces. (Moved from matrx-frontend\n * `lib/api/ai-api-version.ts`, chat-package independence P9.)\n */\nexport function aiVersionPathOverrides(\n version: MatrxAiApiVersion,\n): Record<string, string> {\n if (version !== \"v2\") return {};\n const map: Record<string, string> = {};\n for (const template of V2_COVERED_AI_PATH_TEMPLATES) {\n map[template] = toV2Path(template);\n }\n return map;\n}\n","/**\n * `@ai-matrx/agents/matrx` — THE request pipeline every typed Matrx server call\n * rides (chat package independence P9b). One implementation for every client:\n * matrx-frontend's `lib/api` `callApi` and the chat package's bare-host default\n * both build on it, and supply only their host facts — where the server is,\n * which credential and organization ride, and where diagnostics go.\n *\n * What lives here (pure, no host/window/env read):\n *\n * - `buildMatrxRequestUrl` — path params, the legacy `/api` strip, the query;\n * - `buildMatrxRequestBody` — scope injection (`organization_id` /\n * `project_id` / `task_id`), the UI-only field strip, and the fail-closed\n * body-vs-context organization check;\n * - `bareStatusSentence` / `isBareTransportCode` / `honestTransportMessage` —\n * a bare status code is never a sentence at a person;\n * - `parseMatrxNdjsonResponse` — a response body as typed envelopes, a broken\n * body reader classified as a resumable `StreamTransportError`;\n * - `executeMatrxCall` — the JSON or NDJSON execution over the v2 → v1\n * protocol fallback, with the stream callbacks and `consumeStream`;\n * - `sendMatrxRequest` / `readMatrxJsonResponse` — the raw-`Response` lane\n * for a host's imperative client (multipart bodies, byte downloads,\n * response-aware callers): one deadline, a caller abort kept as itself, and\n * the ONE HTTP error parser;\n * - `buildSafeRequestLog` / `redactUrlForRequestLog` /\n * `shouldReportMatrxCallError` — the log and capture policy.\n *\n * The error envelope (`MatrxCallError`) and its ONE classifier\n * (`normalizeMatrxError`) live in `./client`.\n */\n\nimport {\n readMatrxNdjsonStream,\n type MatrxNdjsonIssue,\n type MatrxStreamEnvelope,\n} from \"../stream/ndjson\";\nimport {\n BackendApiError,\n parseHttpError,\n StreamTransportError,\n} from \"./backend-errors\";\nimport type { MatrxCallError } from \"./client\";\nimport { OrganizationContextError } from \"./org-context\";\nimport {\n fetchWithMatrxProtocolFallback,\n type MatrxProtocolDowngrade,\n} from \"./protocol\";\nimport { extractMatrxErrorMessage } from \"./transport\";\n\n// ─── Types ──────────────────────────────────────────────────────────────────\n\nexport type MatrxHttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Every context dimension a call may carry. `organization_id`, `project_id`\n * and `task_id` are injected into the body; `user_id` rides the credential and\n * `conversation_id` the path or an explicit body field — never injected.\n */\nexport interface MatrxCallScope {\n user_id?: string;\n organization_id?: string;\n project_id?: string;\n task_id?: string;\n conversation_id?: string;\n}\n\nexport interface MatrxCallResult<T = unknown> {\n /** Parsed JSON response body (non-streaming calls only). */\n data?: T;\n /** Server-assigned request id (response header). */\n requestId?: string;\n /** Server-assigned conversation id (response header). */\n conversationId?: string;\n /** Set when the call failed with an HTTP error response. */\n error?: MatrxCallError;\n}\n\ntype MatrxQueryScalar = string | number | boolean;\n\n/**\n * Query values: a scalar is sent as itself, an array repeats the key (the\n * FastAPI repeatable-parameter convention), `null` / `undefined` are omitted.\n */\nexport type MatrxQueryParams = Record<\n string,\n MatrxQueryScalar | readonly MatrxQueryScalar[] | null | undefined\n>;\n\n// ─── URL ────────────────────────────────────────────────────────────────────\n\n/**\n * The full URL for one call: `{param}` segments substituted (encoded), the\n * legacy `/api` prefix stripped (server routes no longer live under it), and\n * the query appended.\n */\nexport function buildMatrxRequestUrl(\n baseUrl: string,\n pathTemplate: string,\n pathParams?: Record<string, string>,\n queryParams?: MatrxQueryParams,\n): string {\n let resolvedPath = pathTemplate;\n if (pathParams) {\n for (const [key, value] of Object.entries(pathParams)) {\n resolvedPath = resolvedPath.replace(`{${key}}`, encodeURIComponent(value));\n }\n }\n const fullPath = resolvedPath.startsWith(\"/api/\")\n ? resolvedPath.slice(4)\n : resolvedPath;\n const url = `${baseUrl}${fullPath}`;\n if (queryParams) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(queryParams)) {\n if (value === null || value === undefined) continue;\n const values: readonly MatrxQueryScalar[] = Array.isArray(value)\n ? value\n : [value as MatrxQueryScalar];\n for (const entry of values) search.append(key, String(entry));\n }\n const qs = search.toString();\n if (qs) return `${url}${url.includes(\"?\") ? \"&\" : \"?\"}${qs}`;\n }\n return url;\n}\n\n// ─── Body ───────────────────────────────────────────────────────────────────\n\n/**\n * Client capability flags that must never reach the server — the server's\n * request schemas reject them.\n */\nexport const MATRX_UI_ONLY_BODY_FIELDS: ReadonlySet<string> = new Set([\n \"youtube_videos\",\n \"file_urls\",\n \"image_urls\",\n]);\n\n/**\n * The final request body: UI-only fields stripped, scope fields injected.\n *\n * A caller's `organization_id: null` (or blank) means \"I have none of my own\",\n * never \"send this for a different organization\" — it is dropped and the\n * scope's organization injected. A real value that disagrees with the scope\n * is refused (`organization_context_mismatch`). With no scope organization\n * (the org-less guest lane, an org-free read) nothing is injected for it.\n * Other scope fields keep caller-wins behaviour.\n */\nexport function buildMatrxRequestBody(\n body: unknown,\n scope: MatrxCallScope,\n): Record<string, unknown> {\n // MATRX-EXCEPTION: `body` is optional by design — a caller with no body\n // still gets scope fields injected, so `{}` is the correct start.\n const raw = (body ?? {}) as Record<string, unknown>;\n const base: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (!MATRX_UI_ONLY_BODY_FIELDS.has(key)) base[key] = value;\n }\n\n if (\n base.organization_id === null ||\n (typeof base.organization_id === \"string\" &&\n base.organization_id.trim() === \"\")\n ) {\n delete base.organization_id;\n }\n\n const bodyOrganizationId = base.organization_id;\n if (\n scope.organization_id !== undefined &&\n bodyOrganizationId !== undefined &&\n (typeof bodyOrganizationId !== \"string\" ||\n bodyOrganizationId.trim() !== scope.organization_id)\n ) {\n throw new OrganizationContextError(\n \"organization_context_mismatch\",\n \"Request body organization_id must match the request context organization.\",\n );\n }\n if (bodyOrganizationId !== undefined && scope.organization_id !== undefined) {\n base.organization_id = scope.organization_id;\n }\n\n const scopeFields: Record<string, unknown> = {\n ...(scope.organization_id !== undefined\n ? { organization_id: scope.organization_id }\n : {}),\n };\n if (scope.project_id !== undefined) scopeFields.project_id = scope.project_id;\n if (scope.task_id !== undefined) scopeFields.task_id = scope.task_id;\n return { ...scopeFields, ...base };\n}\n\n// ─── Honest status sentences ────────────────────────────────────────────────\n\nconst BARE_TRANSPORT_CODE =\n /^\\s*(?:HTTP|HTTP\\s*Error|Status(?:\\s*Code)?)?\\s*[:\\-]?\\s*\\d{3}\\s*[.:!]?\\s*$/i;\n\n/** True when a candidate sentence is really just the status line wearing words. */\nexport function isBareTransportCode(text: string | null | undefined): boolean {\n if (!text) return false;\n return BARE_TRANSPORT_CODE.test(text);\n}\n\n/**\n * A BARE STATUS CODE IS NEVER A SENTENCE. What a person reads when the server\n * answered an error with no readable message. The status itself rides\n * `error.status`, which is what code branches on — this is only the words.\n */\nexport function bareStatusSentence(status: number): string {\n if (status === 401 || status === 403) {\n return \"The server would not let this request through — your session may have expired, or this account may not have access here. Sign in again, and if it repeats, ask an administrator.\";\n }\n if (status === 404) {\n return \"The server has nothing at that address. Reload the page; if it repeats, report it — a client asking for something that no longer exists is a defect, not your mistake.\";\n }\n if (status === 429) {\n return \"The server is rate-limiting this request. Wait a few seconds and try again.\";\n }\n if (status >= 500) {\n return \"The server failed while answering this, and sent no explanation. Try again in a moment; if it repeats, report it with the request id above.\";\n }\n return \"The server refused this request and sent no reason with it — the missing reason is itself a defect worth reporting. Reload the page and try once more; if it repeats, report it with the request id above.\";\n}\n\n/** `raw` unless it is empty or only a status line; then the status sentence. */\nexport function honestTransportMessage(\n raw: string,\n status: number | undefined,\n): string {\n if (raw && !isBareTransportCode(raw)) return raw;\n return bareStatusSentence(status ?? 0);\n}\n\n// ─── Log + capture policy ───────────────────────────────────────────────────\n\nconst SENSITIVE_HEADER_NAME = /authorization|cookie|token|api[-_]?key/i;\n\n/** Request metadata safe to log: secret headers redacted, the body as its shape only. */\nexport function buildSafeRequestLog(\n headers: Record<string, string>,\n body: unknown,\n): { headers: Record<string, string>; body: Record<string, unknown> } {\n const safeHeaders = Object.fromEntries(\n Object.entries(headers).map(([name, value]) => [\n name,\n SENSITIVE_HEADER_NAME.test(name) ? \"[REDACTED]\" : value,\n ]),\n );\n const bodyMetadata: Record<string, unknown> = Array.isArray(body)\n ? { type: \"array\", itemCount: body.length }\n : body && typeof body === \"object\"\n ? { type: \"object\", keys: Object.keys(body as Record<string, unknown>) }\n : { type: body === null ? \"null\" : typeof body };\n return { headers: safeHeaders, body: bodyMetadata };\n}\n\n/** The URL with every query value redacted. */\nexport function redactUrlForRequestLog(url: string): string {\n try {\n const parsed = new URL(url);\n for (const key of parsed.searchParams.keys()) {\n parsed.searchParams.set(key, \"[REDACTED]\");\n }\n return parsed.toString();\n } catch {\n const queryIndex = url.indexOf(\"?\");\n return queryIndex === -1 ? url : `${url.slice(0, queryIndex)}?[REDACTED]`;\n }\n}\n\n/** False only for an HTTP status the call site declared an expected outcome. */\nexport function shouldReportMatrxCallError(\n status: number | null | undefined,\n expectedErrorStatuses: readonly number[] | undefined,\n): boolean {\n return status == null || !expectedErrorStatuses?.includes(status);\n}\n\n// ─── Stream parsing ─────────────────────────────────────────────────────────\n\nexport interface MatrxStreamIds {\n requestId: string | null;\n conversationId: string | null;\n}\n\nexport interface MatrxStreamParse<E = MatrxStreamEnvelope> extends MatrxStreamIds {\n events: AsyncGenerator<E, void, undefined>;\n}\n\nexport interface ParseMatrxNdjsonResponseHooks {\n /** Every envelope, before the consumer sees it. */\n onEvent?: (event: MatrxStreamEnvelope, ids: MatrxStreamIds) => void;\n /** A broken body reader, already classified, before it is thrown. */\n onTransportError?: (error: BackendApiError, ids: MatrxStreamIds) => void;\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n onUnknownEnvelope?: (value: unknown) => void;\n}\n\n/**\n * A Matrx NDJSON response as typed envelopes. The ids come from headers, so\n * they are available before any event. A body that breaks mid-run is a\n * TRANSPORT loss (the run may still finish server-side and is reattachable) —\n * thrown as `StreamTransportError`, never a failed run; an abort ends quietly.\n */\nexport function parseMatrxNdjsonResponse(\n response: Response,\n signal?: AbortSignal,\n hooks: ParseMatrxNdjsonResponseHooks = {},\n): MatrxStreamParse {\n const ids: MatrxStreamIds = {\n requestId: response.headers.get(\"X-Request-ID\"),\n conversationId: response.headers.get(\"X-Conversation-ID\"),\n };\n async function* events(): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n if (!response.body) {\n throw new BackendApiError({\n code: \"internal_error\",\n detail: \"Response has no body\",\n userMessage: \"No response received from server\",\n });\n }\n try {\n for await (const envelope of readMatrxNdjsonStream(response.body, {\n ...(signal ? { signal } : {}),\n ...(hooks.onMalformedLine ? { onMalformedLine: hooks.onMalformedLine } : {}),\n ...(hooks.onUnknownEnvelope ? { onUnknownEnvelope: hooks.onUnknownEnvelope } : {}),\n })) {\n hooks.onEvent?.(envelope, ids);\n yield envelope;\n }\n } catch (error) {\n if (signal?.aborted || (error instanceof Error && error.name === \"AbortError\")) {\n return;\n }\n const transportError =\n error instanceof BackendApiError\n ? error\n : new StreamTransportError({\n detail:\n error instanceof Error\n ? error.message\n : \"The response stream ended unexpectedly.\",\n details: error,\n ...(ids.requestId ? { requestId: ids.requestId } : {}),\n });\n hooks.onTransportError?.(transportError, ids);\n throw transportError;\n }\n }\n return { events: events(), ...ids };\n}\n\n// ─── Execution ──────────────────────────────────────────────────────────────\n\nexport interface ExecuteMatrxCallRequest<E = MatrxStreamEnvelope> {\n /** The final URL (`buildMatrxRequestUrl`). */\n url: string;\n method: string;\n /** Every header the host binds (credential, organization, Content-Type). */\n headers: Record<string, string>;\n /** The assembled body (`buildMatrxRequestBody`); never sent on GET/HEAD. */\n body: unknown;\n /** NDJSON streaming call. */\n stream?: boolean;\n signal?: AbortSignal;\n /** Time to response headers. Default 15_000. */\n connectTimeoutMs?: number;\n /** Whole-request cap for JSON calls. Default 30_000; `null` uncaps. Streams are uncapped. */\n totalTimeoutMs?: number | null;\n /** Fires when headers arrive, before any event. */\n onStreamStart?: (requestId: string | null, conversationId: string | null) => void;\n onStreamEvent?: (event: E) => void;\n /**\n * Take ownership of the body instead of the executor draining it (a body is\n * consumed once). `onStreamEvent` is then not called; start / complete /\n * error still fire.\n */\n consumeStream?: (response: Response, ids: MatrxStreamIds) => Promise<void>;\n onStreamComplete?: (requestId: string | null, conversationId: string | null) => void;\n /** Fires for an HTTP error response on a stream (thrown failures are the caller's). */\n onStreamError?: (error: MatrxCallError) => void;\n}\n\nexport interface ExecuteMatrxCallHooks<E = MatrxStreamEnvelope> {\n /** Every v2 → v1 protocol downgrade. */\n onProtocolDowngrade?: (downgrade: MatrxProtocolDowngrade) => void;\n /** The host's stream parser (default `parseMatrxNdjsonResponse`). */\n parseStream?: (response: Response, signal?: AbortSignal) => MatrxStreamParse<E>;\n}\n\nconst DEFAULT_CONNECT_TIMEOUT_MS = 15_000;\nconst DEFAULT_JSON_TOTAL_TIMEOUT_MS = 30_000;\n\nasync function httpErrorFrom(response: Response): Promise<MatrxCallError> {\n const serverDetail: unknown = await response.json().catch(() => undefined);\n return {\n type:\n response.status >= 400 && response.status < 500\n ? \"validation_error\"\n : \"http_error\",\n message:\n extractMatrxErrorMessage(serverDetail) ?? bareStatusSentence(response.status),\n status: response.status,\n serverDetail,\n };\n}\n\n/**\n * Execute one call over the v2 → v1 protocol fallback. An HTTP error\n * response resolves as `{ error }`; a thrown failure (network, timeout,\n * abort, a broken stream) propagates — the caller normalizes it with\n * `normalizeMatrxError` and decides what to capture.\n */\nexport async function executeMatrxCall<T = unknown, E = MatrxStreamEnvelope>(\n request: ExecuteMatrxCallRequest<E>,\n hooks: ExecuteMatrxCallHooks<E> = {},\n): Promise<MatrxCallResult<T>> {\n const upper = request.method.toUpperCase();\n const sendsBody = request.stream || (upper !== \"GET\" && upper !== \"HEAD\");\n const { response } = await fetchWithMatrxProtocolFallback(\n request.url,\n {\n method: request.method,\n headers: request.headers,\n ...(sendsBody ? { body: JSON.stringify(request.body) } : {}),\n },\n {\n ...(request.signal ? { signal: request.signal } : {}),\n connectTimeoutMs: request.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,\n totalTimeoutMs: request.stream\n ? null\n : request.totalTimeoutMs === undefined\n ? DEFAULT_JSON_TOTAL_TIMEOUT_MS\n : request.totalTimeoutMs,\n throwOnHttpError: false,\n ...(hooks.onProtocolDowngrade ? { onDowngrade: hooks.onProtocolDowngrade } : {}),\n },\n );\n\n const requestId = response.headers.get(\"X-Request-ID\");\n const conversationId = response.headers.get(\"X-Conversation-ID\");\n const idFields = {\n ...(requestId !== null ? { requestId } : {}),\n ...(conversationId !== null ? { conversationId } : {}),\n };\n\n if (!response.ok) {\n const error = await httpErrorFrom(response);\n if (request.stream) request.onStreamError?.(error);\n return { ...idFields, error };\n }\n\n if (!request.stream) {\n const data = (response.status === 204 ? undefined : await response.json()) as T;\n return { data, ...idFields };\n }\n\n if (request.consumeStream) {\n request.onStreamStart?.(requestId, conversationId);\n await request.consumeStream(response, { requestId, conversationId });\n request.onStreamComplete?.(requestId, conversationId);\n return idFields;\n }\n\n const parse =\n hooks.parseStream ??\n ((res: Response, signal?: AbortSignal) =>\n parseMatrxNdjsonResponse(res, signal) as unknown as MatrxStreamParse<E>);\n const parsed = parse(response, request.signal);\n request.onStreamStart?.(parsed.requestId, parsed.conversationId);\n for await (const event of parsed.events) {\n request.onStreamEvent?.(event);\n }\n request.onStreamComplete?.(parsed.requestId, parsed.conversationId);\n return {\n ...(parsed.requestId !== null ? { requestId: parsed.requestId } : {}),\n ...(parsed.conversationId !== null ? { conversationId: parsed.conversationId } : {}),\n };\n}\n\n// ─── Raw send ───────────────────────────────────────────────────────────────\n\nexport interface SendMatrxRequestOptions {\n /** Caller cancellation; an abort propagates as the caller's own AbortError. */\n signal?: AbortSignal;\n /**\n * Deadline (ms) from send to response headers. On expiry the call rejects\n * with a `BackendApiError` coded `request_timeout` (status 504) — never a\n * fake caller cancellation. Omit for no deadline.\n */\n timeoutMs?: number;\n}\n\n/**\n * Send one request and resolve with the raw `Response`, whatever its status.\n * The lane for an imperative host client whose bodies are not JSON (a\n * `FormData` upload), whose answers are bytes, or which reads the response\n * itself. A caller abort and a network failure propagate unchanged; only this\n * call's own deadline is classified (`request_timeout`).\n */\nexport async function sendMatrxRequest(\n url: string,\n init: RequestInit = {},\n options: SendMatrxRequestOptions = {},\n): Promise<Response> {\n const callerSignal = options.signal ?? init.signal ?? undefined;\n if (options.timeoutMs === undefined) {\n return fetch(url, { ...init, ...(callerSignal ? { signal: callerSignal } : {}) });\n }\n const controller = new AbortController();\n const onCallerAbort = (): void => controller.abort(callerSignal?.reason);\n if (callerSignal) {\n if (callerSignal.aborted) controller.abort(callerSignal.reason);\n else callerSignal.addEventListener(\"abort\", onCallerAbort, { once: true });\n }\n let timedOut = false;\n const timer = setTimeout(() => {\n timedOut = true;\n controller.abort();\n }, options.timeoutMs);\n try {\n return await fetch(url, { ...init, signal: controller.signal });\n } catch (error) {\n if (timedOut) {\n throw new BackendApiError({\n code: \"request_timeout\",\n detail: `${init.method ?? \"GET\"} ${url} exceeded ${options.timeoutMs}ms`,\n userMessage: \"The request timed out — please retry.\",\n status: 504,\n });\n }\n throw error;\n } finally {\n clearTimeout(timer);\n callerSignal?.removeEventListener(\"abort\", onCallerAbort);\n }\n}\n\n/**\n * A response's JSON body, or the ONE classified `BackendApiError`\n * (`parseHttpError`) for a non-2xx answer. A 204 resolves `null`.\n */\nexport async function readMatrxJsonResponse<T>(response: Response): Promise<T> {\n if (!response.ok) throw await parseHttpError(response);\n if (response.status === 204) return null as T;\n return (await response.json()) as T;\n}\n","/**\n * The conversation-start contract — client-minted `conversation_id`, `is_new`,\n * `store` — typed exactly per the cross-repo System of Record\n * (`common-docs/systems/agents/conversation-start-contract/FEATURE.md`;\n * server truth `aidream/services/conversation_context/scope.py::\n * ConversationStartRequest`).\n *\n * Every request that STARTS a conversation sends all three fields, no\n * defaults:\n *\n * | `is_new` | `store` | Result |\n * |----------|---------|----------------------------------------------------------|\n * | true | true | Create the row with the caller's id — 409 if it exists |\n * | true | false | No row. The id is correlation only (ephemeral run) |\n * | false | true | Continue it — 404 if the caller doesn't own it |\n * | false | false | Ephemeral run on a known id; nothing read, nothing written |\n *\n * `store` is the ONLY ephemeral signal; `is_new` is the caller's assertion\n * about the id, never a persistence switch. `prior_messages` (the client-owned\n * transcript of an ephemeral multi-turn run) is only valid with\n * `store: false` — the union below makes the invalid combination\n * unrepresentable, mirroring the server's 422.\n *\n * Continue routes (`POST /ai/conversations/{id}`) take the id from the path\n * and do not carry this triple.\n */\n\n/** Recursive JSON value — the package's honest type for free-form wire bags. */\nexport type MatrxJsonValue =\n | string\n | number\n | boolean\n | null\n | MatrxJsonValue[]\n | { [key: string]: MatrxJsonValue };\n\n/** A JSON object on the wire. */\nexport type MatrxJsonObject = { [key: string]: MatrxJsonValue };\n\n/**\n * One LLM message on the request wire — `prior_messages` entries for\n * stateless multi-turn runs. Mirrors aidream's `ChatMessageInput`\n * (`aidream/schemas/messages.py`, `extra=\"allow\"` — additional provider\n * fields round-trip untouched).\n */\nexport interface MatrxChatMessage {\n role: string;\n content?: string | MatrxJsonValue[] | null;\n name?: string | null;\n tool_call_id?: string | null;\n tool_calls?: MatrxJsonObject[] | null;\n [extra: string]: MatrxJsonValue | undefined;\n}\n\n/** `is_new: true, store: true` — create the row with the caller's id. */\nexport interface MatrxStoredConversationCreate {\n conversation_id: string;\n is_new: true;\n store: true;\n}\n\n/** `is_new: false, store: true` — continue an owned stored conversation via a start route. */\nexport interface MatrxStoredConversationContinue {\n conversation_id: string;\n is_new: false;\n store: true;\n}\n\n/**\n * `store: false` — ephemeral: nothing read, nothing written; the id is the\n * caller's correlation handle. This is the ONLY member that may carry\n * `prior_messages` (the server 422s a client transcript on a stored run).\n */\nexport interface MatrxEphemeralConversation {\n conversation_id: string;\n is_new: boolean;\n store: false;\n prior_messages?: MatrxChatMessage[];\n}\n\n/** The full conversation-start triple, one member per contract cell. */\nexport type MatrxConversationStart =\n | MatrxStoredConversationCreate\n | MatrxStoredConversationContinue\n | MatrxEphemeralConversation;\n\n/** Mint a fresh client-side conversation id (the contract requires the CLIENT to mint it). */\nexport function mintMatrxConversationId(): string {\n return crypto.randomUUID();\n}\n\n/** Start a NEW stored conversation (`is_new: true, store: true`). */\nexport function newStoredConversationStart(\n conversationId?: string,\n): MatrxStoredConversationCreate {\n return {\n conversation_id: conversationId ?? mintMatrxConversationId(),\n is_new: true,\n store: true,\n };\n}\n\n/**\n * Continue an EXISTING stored conversation through a start route\n * (`is_new: false, store: true` — 404 when the caller doesn't own the id).\n * Prefer `continueAgentConversation` (the dedicated continue route) for\n * ordinary follow-up turns.\n */\nexport function continueStoredConversationStart(\n conversationId: string,\n): MatrxStoredConversationContinue {\n return { conversation_id: conversationId, is_new: false, store: true };\n}\n\n/**\n * Start a NEW ephemeral run (`is_new: true, store: false`) — a freshly minted\n * correlation id, nothing persisted.\n */\nexport function newEphemeralConversationStart(\n conversationId?: string,\n): MatrxEphemeralConversation {\n return {\n conversation_id: conversationId ?? mintMatrxConversationId(),\n is_new: true,\n store: false,\n };\n}\n\n/**\n * Continue an ephemeral multi-turn run (`is_new: false, store: false`): the\n * CLIENT owns the transcript and replays it as `prior_messages` (ordered\n * oldest-first) because the server wrote no rows to rebuild from. The server\n * still owns the agent definition, model, tools, and system prompt.\n */\nexport function continueEphemeralConversationStart(\n conversationId: string,\n priorMessages: MatrxChatMessage[],\n): MatrxEphemeralConversation {\n return {\n conversation_id: conversationId,\n is_new: false,\n store: false,\n prior_messages: priorMessages,\n };\n}\n","/**\n * Internal request plumbing for `@ai-matrx/agents/matrx`. Not part of the\n * public surface — `matrx/index.ts` deliberately does not re-export this\n * module. Everything here is pure: no globals, no work at import time.\n */\n\nimport {\n readMatrxNdjsonStream,\n type MatrxNdjsonIssue,\n type MatrxStreamEnvelope,\n type MatrxStreamEnvelopeObservation,\n} from \"../stream/ndjson\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\n/** Encode one path segment (an id) safely into a server-relative path. */\nexport function encodePathSegment(value: string): string {\n return encodeURIComponent(value);\n}\n\nexport type QueryValue =\n | string\n | number\n | boolean\n | readonly string[]\n | undefined;\n\n/**\n * Build a query string. Array values repeat the key (`kind=a&kind=b` — the\n * FastAPI repeatable-parameter convention); undefined values are omitted.\n * Returns \"\" or a string starting with \"?\".\n */\nexport function buildQuery(params: Record<string, QueryValue>): string {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined) continue;\n if (Array.isArray(value)) {\n for (const entry of value) search.append(key, entry);\n } else {\n search.append(key, String(value));\n }\n }\n const encoded = search.toString();\n return encoded ? `?${encoded}` : \"\";\n}\n\nasync function readServerDetail(response: Response): Promise<unknown> {\n try {\n return (await response.json()) as unknown;\n } catch {\n return undefined;\n }\n}\n\nasync function throwApiError(path: string, response: Response): Promise<never> {\n throw new MatrxApiError({\n status: response.status,\n path,\n serverDetail: await readServerDetail(response),\n });\n}\n\nexport interface JsonRequestOptions {\n method: \"GET\" | \"POST\";\n body?: unknown;\n signal?: AbortSignal;\n}\n\n/**\n * Execute a JSON request through the transport. Throws `MatrxApiError` on a\n * non-2xx response; resolves with the parsed JSON body otherwise.\n */\nexport async function requestJson<T>(\n transport: MatrxTransport,\n path: string,\n options: JsonRequestOptions,\n): Promise<T> {\n const hasBody = options.method !== \"GET\" && options.body !== undefined;\n const response = await transport.fetch(path, {\n method: options.method,\n headers: hasBody ? { \"Content-Type\": \"application/json\" } : {},\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) return throwApiError(path, response);\n return (await response.json()) as T;\n}\n\n/**\n * Options for every streaming call, riding the NDJSON kernel's contract.\n * Public via `./run`'s re-export.\n */\nexport interface MatrxStreamCallOptions {\n /** Abort the fetch and end the events iterator. */\n signal?: AbortSignal;\n /** Bounded background read-ahead (see `stream/ndjson`). */\n maxReadAhead?: number;\n /** Malformed NDJSON is non-fatal but must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx envelope. */\n onUnknownEnvelope?: (value: unknown) => void;\n /** Observe every valid envelope in its exact wire form. */\n onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;\n}\n\n/**\n * A live agent run: the server-assigned ids (from response headers, available\n * BEFORE any event) and the normalized event stream. Public via `./run`.\n */\nexport interface MatrxRunHandle {\n /** `X-Request-ID` — the ONLY id `POST /ai/cancel/{request_id}` accepts. */\n requestId: string | null;\n /** `X-Conversation-ID` — the server's conversation identity. */\n conversationId: string | null;\n /** Normalized `{event, data}` envelopes through the ONE wire kernel. */\n events: AsyncGenerator<MatrxStreamEnvelope, void, undefined>;\n /** The raw response, for hosts that need headers/status beyond the ids. */\n response: Response;\n}\n\n/**\n * Wrap a validated streaming Response into the run handle — the ONE place\n * the id headers are read and the NDJSON kernel is attached (`./run` and\n * `./operations`' rejoin share it).\n */\nexport function toRunHandle(\n response: Response,\n options: MatrxStreamCallOptions,\n): MatrxRunHandle {\n return {\n requestId: response.headers.get(\"X-Request-ID\"),\n conversationId: response.headers.get(\"X-Conversation-ID\"),\n events: readMatrxNdjsonStream(response.body as ReadableStream<Uint8Array>, {\n ...(options.signal ? { signal: options.signal } : {}),\n ...(options.maxReadAhead !== undefined\n ? { maxReadAhead: options.maxReadAhead }\n : {}),\n ...(options.onMalformedLine\n ? { onMalformedLine: options.onMalformedLine }\n : {}),\n ...(options.onUnknownEnvelope\n ? { onUnknownEnvelope: options.onUnknownEnvelope }\n : {}),\n ...(options.onValidEnvelope\n ? { onValidEnvelope: options.onValidEnvelope }\n : {}),\n }),\n response,\n };\n}\n\nexport interface StreamRequestOptions {\n method: \"GET\" | \"POST\";\n body?: unknown;\n /** Extra wire-semantic headers (`Accept`, `Last-Event-ID`). */\n headers?: Record<string, string>;\n signal?: AbortSignal;\n}\n\n/**\n * Execute a streaming request. Throws `MatrxApiError` on a non-2xx response\n * (reading the error body as JSON when possible) or when a 2xx response\n * carries no body; resolves with the validated `Response` otherwise.\n */\nexport async function requestStream(\n transport: MatrxTransport,\n path: string,\n options: StreamRequestOptions,\n): Promise<Response> {\n const hasBody = options.method !== \"GET\" && options.body !== undefined;\n const response = await transport.fetch(path, {\n method: options.method,\n headers: {\n ...(hasBody ? { \"Content-Type\": \"application/json\" } : {}),\n ...options.headers,\n },\n ...(hasBody ? { body: JSON.stringify(options.body) } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) return throwApiError(path, response);\n if (!response.body) {\n throw new MatrxApiError({\n status: response.status,\n path,\n serverDetail: { code: \"missing_response_body\" },\n message: \"The streaming response carried no body.\",\n });\n }\n return response;\n}\n","/**\n * `@ai-matrx/agents/stream/sse` — the Matrx SSE frame kernel.\n *\n * Two Matrx clients hand-rolled the identical `text/event-stream` framing —\n * the same separator regex, the same field parsing, the same CRLF incident —\n * for the durable rejoin endpoints (`/runtime/.../events/stream`,\n * `/runs/.../events/stream`). This module is that framing extracted ONCE, as a\n * pure incremental parser, so a host keeps only what is genuinely host policy:\n * the fetch, the stall timer, the retry budget, and what each event MEANS.\n *\n * Contract, mirroring `stream/ndjson`:\n * - Pure and effect-free: no fetch, no timers, no globals. Importing this\n * module performs no work.\n * - Incremental across arbitrary chunk boundaries: a frame split anywhere —\n * mid-line, mid-separator, mid-UTF-8 when using the byte reader — parses\n * identically to one delivered whole.\n * - All three SSE line terminators (`\\r\\n`, `\\n`, `\\r`) and all three frame\n * separators are handled — the CRLF-vs-LF divergence that bit production is\n * covered by construction and by test.\n * - Comment-only frames (heartbeats, `:` lines) ARE emitted (with\n * `data === null`) because hosts use any parsed frame as liveness proof to\n * reset stall timers and retry budgets. Frames with data join multi-line\n * `data:` fields with `\\n` per the SSE spec.\n * - `id:` is surfaced raw AND, when it is a safe integer, as `seq` — the\n * `Last-Event-ID` cursor both Matrx rejoin endpoints use for durable replay.\n * Cursor ADVANCEMENT (`seq > cursor`) stays host-side, next to the retry.\n */\n\nexport interface MatrxSseFrame {\n /** `event:` field; the SSE default \"message\" when absent. */\n event: string;\n /** `id:` field, raw, when present. */\n id: string | null;\n /**\n * `id:` parsed as a non-negative safe integer, else null. Matrx rejoin\n * streams use integer ids as the `Last-Event-ID` replay cursor.\n */\n seq: number | null;\n /**\n * Joined `data:` lines (`\\n`-separated per spec), or null for a frame with\n * no data field at all (e.g. a comment-only heartbeat). An empty-string\n * data field is `\"\"`, not null.\n */\n data: string | null;\n}\n\nconst FRAME_SEPARATOR = /\\r\\n\\r\\n|\\n\\n|\\r\\r/;\nconst LINE_SEPARATOR = /\\r\\n|\\n|\\r/;\n\n/** Parse ONE complete frame's text (no trailing separator). */\nexport function parseMatrxSseFrame(frame: string): MatrxSseFrame {\n let event = \"message\";\n let id: string | null = null;\n const dataLines: string[] = [];\n let sawData = false;\n\n for (const line of frame.split(LINE_SEPARATOR)) {\n if (line.startsWith(\":\")) continue;\n if (line.startsWith(\"event:\")) event = line.slice(6).trim();\n else if (line.startsWith(\"data:\")) {\n sawData = true;\n dataLines.push(line.slice(5).replace(/^ /, \"\"));\n } else if (line.startsWith(\"id:\")) id = line.slice(3).trim();\n }\n\n const seqCandidate = id !== null && id !== \"\" ? Number(id) : NaN;\n const seq =\n Number.isSafeInteger(seqCandidate) && seqCandidate >= 0\n ? seqCandidate\n : null;\n\n return { event, id, seq, data: sawData ? dataLines.join(\"\\n\") : null };\n}\n\nexport interface MatrxSseFramer {\n /** Feed a decoded text chunk; returns every frame it completed. */\n push(chunk: string): MatrxSseFrame[];\n /**\n * Signal end of input. A non-empty trailing buffer is an UNTERMINATED frame:\n * per the SSE spec it was never dispatched, so it is returned separately for\n * the host to treat as diagnostic, never as a delivered event.\n */\n flush(): { incomplete: string | null };\n}\n\n/** Incremental SSE framer over already-decoded text. */\nexport function createMatrxSseFramer(): MatrxSseFramer {\n let buffer = \"\";\n return {\n push(chunk: string): MatrxSseFrame[] {\n buffer += chunk;\n const frames: MatrxSseFrame[] = [];\n for (;;) {\n const sep = FRAME_SEPARATOR.exec(buffer);\n if (sep === null) break;\n // A lone trailing `\\r` could be the first half of `\\r\\n\\r\\n`'s final\n // newline — but the separator regex only matched what is already\n // complete, so the slice below is always safe.\n const frame = buffer.slice(0, sep.index);\n buffer = buffer.slice(sep.index + sep[0].length);\n frames.push(parseMatrxSseFrame(frame));\n }\n return frames;\n },\n flush() {\n const rest = buffer;\n buffer = \"\";\n return { incomplete: rest.length > 0 ? rest : null };\n },\n };\n}\n\nexport interface ReadMatrxSseOptions {\n /**\n * Called with any unterminated trailing text at stream end (a frame the\n * server never finished — diagnostic, not a delivered event).\n */\n onIncomplete?: (text: string) => void;\n}\n\n/**\n * Async-iterate the frames of a byte stream (e.g. `response.body`), handling\n * split UTF-8 across chunk boundaries. Cancellation follows the reader: abort\n * the fetch and the iterator ends; a transport error after complete frames\n * were yielded surfaces AFTER those frames, with its original cause.\n */\nexport async function* readMatrxSseStream(\n stream: ReadableStream<Uint8Array>,\n options: ReadMatrxSseOptions = {},\n): AsyncGenerator<MatrxSseFrame, void, undefined> {\n const reader = stream.getReader();\n const decoder = new TextDecoder();\n const framer = createMatrxSseFramer();\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n const frames = framer.push(decoder.decode(value, { stream: true }));\n for (const frame of frames) yield frame;\n }\n const tail = framer.push(decoder.decode());\n for (const frame of tail) yield frame;\n const { incomplete } = framer.flush();\n if (incomplete !== null) options.onIncomplete?.(incomplete);\n } finally {\n reader.releaseLock();\n }\n}\n","/**\n * Runtime operations — the canonical reconnect & resume read surface of the\n * execution spine, over the `MatrxTransport` port.\n *\n * Server truth (verified against aidream source,\n * `aidream/api/routers/runtime_operations.py` + `aidream/services/runtime/\n * reconnect.py`; mounted at bare `/runtime`):\n * - `GET /runtime/operations/{request_id}` — identify by `X-Request-ID`\n * - `GET /runtime/operations/by-link/{kind}/{id}` — identify by feature record\n * - `GET /runtime/executions/{id}/events` — durable seq-cursored page\n * - `GET /runtime/executions/{id}/events/stream` — SSE replay-then-follow,\n * `id:` = per-tree seq, reconnect with `Last-Event-ID`\n * - `POST /runtime/operations/{request_id}/rejoin` — replay + follow the\n * ORIGINAL NDJSON response while its detached task is alive (409 when live\n * delivery is unavailable — fall back to the durable lifecycle stream)\n *\n * The contract: identify → recover durable progress → follow live → re-query\n * the final result from the feature's own record. Token text is deliberately\n * never replayed on the lifecycle stream — that is what `/rejoin` is for.\n *\n * The SSE wire rides the package's own `stream/sse` kernel. This module owns\n * ONE connection's semantics (frames → typed events, cursor advancement,\n * terminal `end`); stall timers, retry budgets, and reconnect loops stay host\n * policy — every yielded item carries the cursor the next attempt resumes from.\n */\n\nimport { readMatrxSseStream, type MatrxSseFrame } from \"../stream/sse\";\nimport type { MatrxJsonObject } from \"./conversation\";\nimport {\n encodePathSegment,\n buildQuery,\n requestJson,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\n// ─── Wire types (mirroring `aidream/services/runtime/reconnect.py`) ─────────\n\n/** `matrx_runtime.models.ExecutionStatus` — the only progress column. */\nexport type MatrxRuntimeExecutionStatus =\n | \"pending\"\n | \"running\"\n | \"paused\"\n | \"waiting_input\"\n | \"completed\"\n | \"failed\"\n | \"cancelled\";\n\nexport const TERMINAL_MATRX_RUNTIME_STATUSES: ReadonlySet<MatrxRuntimeExecutionStatus> =\n new Set([\"completed\", \"failed\", \"cancelled\"]);\n\nconst RUNTIME_STATUSES: ReadonlySet<string> = new Set([\n \"pending\",\n \"running\",\n \"paused\",\n \"waiting_input\",\n \"completed\",\n \"failed\",\n \"cancelled\",\n]);\n\n/** One durable spine event on the wire (`OperationEvent`) — `seq` is the reconnect cursor. */\nexport interface MatrxRuntimeOperationEvent {\n seq: number | null;\n /** Lifecycle vocabulary: created | started | paused | resumed | waiting_input | completed | failed | cancelled | checkpoint_saved | note. */\n kind: string;\n execution_id: string;\n root_execution_id: string | null;\n detail: MatrxJsonObject | null;\n created_at: string | null;\n}\n\n/** One root execution as a reconnecting client sees it (`OperationView`). */\nexport interface MatrxRuntimeOperationView {\n execution_id: string;\n /** Durable request identity — feeds `/rejoin` and no-prompt resume recovery. */\n request_id: string | null;\n type: string;\n status: MatrxRuntimeExecutionStatus;\n is_terminal: boolean;\n waiting_input: boolean;\n /** Decimal on the wire — may arrive as number or string; display-only. */\n cost: number | string;\n meters: Record<string, number | string>;\n link_kind: string | null;\n link_id: string | null;\n error: MatrxJsonObject | null;\n created_at: string | null;\n started_at: string | null;\n ended_at: string | null;\n last_event_seq: number;\n events_path: string;\n stream_path: string;\n}\n\nexport interface MatrxOperationStatusResponse {\n request_id: string;\n operation_count: number;\n operations: MatrxRuntimeOperationView[];\n}\n\nexport interface MatrxOperationsByLinkResponse {\n link_kind: string;\n link_id: string;\n operation_count: number;\n operations: MatrxRuntimeOperationView[];\n}\n\nexport interface MatrxOperationEventsPage {\n execution_id: string;\n root_execution_id: string;\n events: MatrxRuntimeOperationEvent[];\n /** Feeds the next page or the SSE `Last-Event-ID` — polling and push share ONE cursor. */\n next_after_seq: number;\n has_more: boolean;\n root_status: MatrxRuntimeExecutionStatus;\n root_is_terminal: boolean;\n}\n\n// ─── Identify + durable progress ────────────────────────────────────────────\n\n/**\n * Where is my operation? Resolves an `X-Request-ID` to its root execution(s).\n * Returns null on 404 — missing and unowned share one shape by design\n * (existence is never leaked).\n */\nexport async function getRuntimeOperationStatus(\n transport: MatrxTransport,\n requestId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<MatrxOperationStatusResponse | null> {\n try {\n return await requestJson<MatrxOperationStatusResponse>(\n transport,\n `/runtime/operations/${encodePathSegment(requestId)}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n } catch (error) {\n if (error instanceof MatrxApiError && error.status === 404) return null;\n throw error;\n }\n}\n\n/**\n * Operations for a feature record — e.g. `(\"conversation\", conversationId)`,\n * `(\"workflow\", runId)`, `(\"agent_run\", runId)`. Newest first; unowned trees\n * omitted. Returns null on 404 (surface absent, or the caller owns nothing —\n * one shape by design).\n */\nexport async function getRuntimeOperationsByLink(\n transport: MatrxTransport,\n linkKind: string,\n linkId: string,\n options: { limit?: number; signal?: AbortSignal } = {},\n): Promise<MatrxOperationsByLinkResponse | null> {\n const query = buildQuery(\n options.limit !== undefined ? { limit: options.limit } : {},\n );\n try {\n return await requestJson<MatrxOperationsByLinkResponse>(\n transport,\n `/runtime/operations/by-link/${encodePathSegment(linkKind)}/${encodePathSegment(linkId)}${query}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n } catch (error) {\n if (error instanceof MatrxApiError && error.status === 404) return null;\n throw error;\n }\n}\n\n/**\n * Durable progress page for the whole operation TREE:\n * `GET /runtime/executions/{id}/events?after_seq=…`. Pass any node id — it\n * resolves to the root.\n */\nexport function listRuntimeOperationEvents(\n transport: MatrxTransport,\n executionId: string,\n options: {\n afterSeq?: number;\n limit?: number;\n /** Repeatable event-kind filter. */\n kinds?: readonly string[];\n signal?: AbortSignal;\n } = {},\n): Promise<MatrxOperationEventsPage> {\n const query = buildQuery({\n ...(options.afterSeq !== undefined ? { after_seq: options.afterSeq } : {}),\n ...(options.limit !== undefined ? { limit: options.limit } : {}),\n ...(options.kinds !== undefined ? { kind: options.kinds } : {}),\n });\n return requestJson<MatrxOperationEventsPage>(\n transport,\n `/runtime/executions/${encodePathSegment(executionId)}/events${query}`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n}\n\n// ─── SSE follow (replay-then-follow with Last-Event-ID) ─────────────────────\n\n/**\n * One item from the follow stream. Every item carries `cursor` — the highest\n * event seq seen so far, which is exactly the `Last-Event-ID` a reconnect\n * resumes from (host retry policy owns the reconnect loop).\n */\nexport type MatrxOperationFollowEvent =\n | {\n /** A parsed durable spine event. */\n type: \"event\";\n event: MatrxRuntimeOperationEvent;\n /** The frame's SSE `id:` as an integer, when it carried one. */\n seq: number | null;\n cursor: number;\n }\n | {\n /**\n * A frame that carried no deliverable event — a comment heartbeat, an\n * unknown event name, or a malformed payload (also surfaced through\n * `onMalformedFrame`). ANY parsed frame proves the wire is alive: hosts\n * reset stall timers and retry budgets on it.\n */\n type: \"liveness\";\n cursor: number;\n }\n | {\n /** The server's terminal frame — the root settled; the stream is over. */\n type: \"end\";\n status: MatrxRuntimeExecutionStatus | null;\n cursor: number;\n };\n\nexport interface FollowRuntimeOperationOptions {\n /** Resume cursor — the operation view's `last_event_seq` (0 = from start). */\n lastEventSeq?: number;\n /** Abort the follow — the generator simply ends. */\n signal?: AbortSignal;\n /** A frame whose payload failed to parse — never silently dropped. */\n onMalformedFrame?: (frame: MatrxSseFrame, error: unknown) => void;\n /** Unterminated trailing SSE text at stream end (diagnostic, never an event). */\n onIncomplete?: (text: string) => void;\n}\n\nfunction parseEndStatus(data: string | null): MatrxRuntimeExecutionStatus | null {\n if (data === null) return null;\n try {\n const parsed = JSON.parse(data) as unknown;\n if (\n typeof parsed === \"object\" &&\n parsed !== null &&\n typeof (parsed as { status?: unknown }).status === \"string\"\n ) {\n const status = (parsed as { status: string }).status;\n return RUNTIME_STATUSES.has(status)\n ? (status as MatrxRuntimeExecutionStatus)\n : null;\n }\n } catch {\n // malformed end payload — still terminal\n }\n return null;\n}\n\n/**\n * Follow ONE SSE connection of an operation's lifecycle stream:\n * `GET /runtime/executions/{id}/events/stream` with `Last-Event-ID` when\n * resuming past 0. Replays from the cursor, then follows live; a\n * WAITING_INPUT park keeps it open (a resume re-attaches to the same\n * execution and its events continue here). Ends after yielding\n * `{type: \"end\"}` when the root settles; a server close WITHOUT an end frame\n * simply ends the generator — reconnect from the last yielded `cursor` (host\n * retry policy).\n */\nexport async function* followRuntimeOperationEvents(\n transport: MatrxTransport,\n executionId: string,\n options: FollowRuntimeOperationOptions = {},\n): AsyncGenerator<MatrxOperationFollowEvent, void, undefined> {\n let cursor = options.lastEventSeq ?? 0;\n\n const headers: Record<string, string> = { Accept: \"text/event-stream\" };\n if (cursor > 0) headers[\"Last-Event-ID\"] = String(cursor);\n\n const response = await requestStream(\n transport,\n `/runtime/executions/${encodePathSegment(executionId)}/events/stream`,\n {\n method: \"GET\",\n headers,\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n\n const frames = readMatrxSseStream(\n response.body as ReadableStream<Uint8Array>,\n options.onIncomplete ? { onIncomplete: options.onIncomplete } : {},\n );\n\n for await (const frame of frames) {\n if (frame.event === \"end\") {\n yield { type: \"end\", status: parseEndStatus(frame.data), cursor };\n return;\n }\n if (frame.event === \"execution_event\" && frame.data !== null) {\n let event: MatrxRuntimeOperationEvent;\n try {\n event = JSON.parse(frame.data) as MatrxRuntimeOperationEvent;\n } catch (error) {\n options.onMalformedFrame?.(frame, error);\n yield { type: \"liveness\", cursor };\n continue;\n }\n if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;\n yield { type: \"event\", event, seq: frame.seq, cursor };\n continue;\n }\n // Comment heartbeats, unknown event names, data-less frames: liveness.\n yield { type: \"liveness\", cursor };\n }\n}\n\n// ─── Follow to end (the production reconnect policy) ────────────────────────\n\nexport interface FollowRuntimeOperationToEndOptions {\n /** Resume cursor — the operation view's `last_event_seq` (0 = from start). */\n lastEventSeq?: number;\n /** Caller teardown — aborting resolves with `ended: false`. */\n signal?: AbortSignal;\n /**\n * The server pings every ~15s, so a wire that is open but silent past this\n * is dead (buffering proxy, idle-killed connection) — abort the attempt and\n * retry rather than hanging forever. Default 45_000.\n */\n stallTimeoutMs?: number;\n /**\n * Consecutive failed attempts before giving up. A single-server deployment\n * deliberately drains for 60s, then starts a new container — the default\n * budget (60 × 2s) keeps following for ~three minutes so the runtime ledger\n * can bridge that handoff. ANY parsed frame resets the budget. Default 60.\n */\n reconnectLimit?: number;\n /** Delay between attempts. Default 2_000. */\n reconnectDelayMs?: number;\n /** Fired per durable spine event (lifecycle transitions + notes). */\n onEvent: (event: MatrxRuntimeOperationEvent, seq: number | null) => void;\n /** A failed attempt (never silently swallowed when provided). */\n onAttemptError?: (error: unknown) => void;\n /** A frame whose payload failed to parse (the ledger heals gaps on reconnect). */\n onMalformedFrame?: (frame: MatrxSseFrame, error: unknown) => void;\n}\n\nexport interface FollowRuntimeOperationToEndResult {\n /** True when the server sent the terminal `end` frame. */\n ended: boolean;\n /** The root status carried on the `end` frame (when `ended`). */\n status: MatrxRuntimeExecutionStatus | null;\n}\n\n/**\n * Follow an operation's lifecycle stream TO ITS END — the full production\n * reconnect policy over `followRuntimeOperationEvents`: replay-then-follow\n * with bounded reconnects, a stall watchdog, and durable `Last-Event-ID`\n * cursor advancement across attempts.\n *\n * Resolves `{ended: true, status}` on the server's `end` frame (the operation\n * settled); `{ended: false}` when the caller aborted or every reconnect\n * attempt failed. A WAITING_INPUT park keeps the stream open by design — a\n * resume re-attaches to the same execution and its events continue arriving\n * on the same cursor. Any parsed frame — comment heartbeats included —\n * proves the wire is alive and resets both the stall timer and the retry\n * budget.\n */\nexport async function followRuntimeOperationToEnd(\n transport: MatrxTransport,\n executionId: string,\n options: FollowRuntimeOperationToEndOptions,\n): Promise<FollowRuntimeOperationToEndResult> {\n const stallTimeoutMs = options.stallTimeoutMs ?? 45_000;\n const reconnectLimit = options.reconnectLimit ?? 60;\n const reconnectDelayMs = options.reconnectDelayMs ?? 2_000;\n const outer = options.signal;\n\n let cursor = options.lastEventSeq ?? 0;\n let failures = 0;\n\n while (!outer?.aborted && failures < reconnectLimit) {\n const attempt = new AbortController();\n const onOuterAbort = () => attempt.abort();\n outer?.addEventListener(\"abort\", onOuterAbort, { once: true });\n\n let stallTimer: ReturnType<typeof setTimeout> | null = null;\n const armStall = () => {\n if (stallTimer !== null) clearTimeout(stallTimer);\n stallTimer = setTimeout(() => attempt.abort(), stallTimeoutMs);\n };\n\n try {\n const items = followRuntimeOperationEvents(transport, executionId, {\n lastEventSeq: cursor,\n signal: attempt.signal,\n ...(options.onMalformedFrame\n ? { onMalformedFrame: options.onMalformedFrame }\n : {}),\n });\n\n armStall();\n for await (const item of items) {\n armStall();\n failures = 0;\n cursor = item.cursor;\n if (item.type === \"end\") {\n return { ended: true, status: item.status };\n }\n if (item.type === \"event\") {\n options.onEvent(item.event, item.seq);\n }\n }\n // Server closed without an `end` frame (e.g. process restart). Retry —\n // `Last-Event-ID` replays anything missed from the durable ledger.\n failures += 1;\n } catch (error) {\n if (outer?.aborted) break;\n failures += 1;\n options.onAttemptError?.(error);\n } finally {\n if (stallTimer !== null) clearTimeout(stallTimer);\n outer?.removeEventListener(\"abort\", onOuterAbort);\n }\n\n if (!outer?.aborted && failures < reconnectLimit) {\n await new Promise((r) => setTimeout(r, reconnectDelayMs));\n }\n }\n\n return { ended: false, status: null };\n}\n\n// ─── NDJSON rejoin (replay the original response) ───────────────────────────\n\n/**\n * Rejoin the ORIGINAL NDJSON response while its detached task is still alive:\n * `POST /runtime/operations/{request_id}/rejoin`. Replays the response from\n * frame one, then continues live — every frame is sequence-stamped\n * (`stream_seq`), so a same-page reconnect can drop frames it already\n * rendered. Throws `MatrxApiError` with status 409 when live delivery is\n * unavailable — fall back to `followRuntimeOperationEvents` + a final record\n * re-query. The `requestId` must be the server's `X-Request-ID`.\n */\nexport async function rejoinRuntimeOperation(\n transport: MatrxTransport,\n requestId: string,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n const response = await requestStream(\n transport,\n `/runtime/operations/${encodePathSegment(requestId)}/rejoin`,\n {\n method: \"POST\",\n // The route takes no body model; the reference client posts an empty\n // JSON object. Match it so proxies see an ordinary JSON POST.\n body: {},\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n return toRunHandle(response, options);\n}\n","/**\n * Resume-or-rejoin — the ONE client behavior for \"pick a run back up\".\n *\n * Server truth (aidream `services/runtime/FEATURE.md` § \"A live run is\n * REJOINED, never resumed beside itself\"; `reconnect.run_in_progress_error`):\n * - Every resume / retry / continue door asked to resume a run that is STILL\n * LIVE answers `409` with, at the ROOT of the error body,\n * `{error, code: \"run_in_progress\", live_request_id, rejoin_path, message,\n * …extras}` (extras: `run_id` for workflow / SEO / comparison, `arm_index` /\n * `arm`, `analysis_id`). The client follows `rejoin_path` — never a URL it\n * builds — because a door outside the spine (SEO collections) answers\n * `live_request_id: null` with its own `/seo/collections/{run_id}/rejoin`.\n * - Chat/conversation resume answers `code: \"resume_conflict\"` — even when the\n * body ALSO names `live_request_id` + `rejoin_path` — and it is ALWAYS host\n * retry, never a rejoin: the claim holder is usually the turn that is still\n * SUSPENDING, and rejoining it replays that turn from frame one (duplicate\n * text) while the person's continuation never runs. Only\n * `code: run_in_progress` rejoins.\n * - The envelope RESERVES `request_id` for the refusing call's own id — the\n * live run is read from `live_request_id`, never `request_id` (reading it\n * rejoined a request that did not exist: 404, 2026-10-01).\n * - A rejoin answers `409 live_stream_unavailable` when there is no journal to\n * replay (resumed workflow legs, comparison arms). Then: a body naming a\n * workflow `run_id` → follow `GET /runs/{run_id}/events/stream` (the workflow\n * SSE, which also carries the node_stream media frames); otherwise follow the\n * durable lifecycle (`followRuntimeOperationToEnd`).\n *\n * Resume and rejoin are work on an EXISTING run, so they carry THAT run's\n * organization (`organizationId`), never whatever the session has selected.\n */\n\nimport type { MatrxStreamEnvelope } from \"../stream/ndjson\";\nimport { readMatrxSseStream } from \"../stream/sse\";\nimport {\n encodePathSegment,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport {\n followRuntimeOperationToEnd,\n getRuntimeOperationStatus,\n type FollowRuntimeOperationToEndOptions,\n type MatrxRuntimeExecutionStatus,\n type MatrxRuntimeOperationEvent,\n} from \"./operations\";\nimport { requireOrganizationContext } from \"./org-context\";\nimport { MatrxApiError, type MatrxTransport } from \"./transport\";\n\nexport const MATRX_RUN_IN_PROGRESS = \"run_in_progress\";\nexport const MATRX_RESUME_CONFLICT = \"resume_conflict\";\nexport const MATRX_LIVE_STREAM_UNAVAILABLE = \"live_stream_unavailable\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction nonBlank(value: unknown): string | null {\n return typeof value === \"string\" && value.trim() ? value : null;\n}\n\n/**\n * Any error carrying an HTTP status and the parsed server body —\n * `MatrxApiError`, matrx-frontend's `ApiCallError`, or a host's own shape.\n */\nexport interface MatrxHttpErrorLike {\n status?: unknown;\n serverDetail?: unknown;\n}\n\n/** The places a structured detail can sit: FastAPI `detail`, envelope `details`, envelope top level. */\nfunction detailCandidates(body: unknown): Record<string, unknown>[] {\n if (!isRecord(body)) return [];\n const out: Record<string, unknown>[] = [];\n if (isRecord(body.detail)) out.push(body.detail);\n if (isRecord(body.details)) out.push(body.details);\n out.push(body);\n return out;\n}\n\nfunction statusOf(error: unknown): number | null {\n if (!isRecord(error) && !(error instanceof Error)) return null;\n const status = (error as MatrxHttpErrorLike).status;\n return typeof status === \"number\" ? status : null;\n}\n\nfunction bodyOf(error: unknown): unknown {\n if (!isRecord(error) && !(error instanceof Error)) return undefined;\n return (error as MatrxHttpErrorLike).serverDetail;\n}\n\n/**\n * The machine code of a Matrx HTTP error: `code` (or the envelope's hoisted\n * `error`) from `detail`, `details`, or the top level. Null when absent.\n */\nexport function readMatrxErrorCode(error: unknown): string | null {\n for (const candidate of detailCandidates(bodyOf(error))) {\n const code = nonBlank(candidate.code);\n if (code) return code;\n }\n for (const candidate of detailCandidates(bodyOf(error))) {\n const code = nonBlank(candidate.error);\n if (code) return code;\n }\n return null;\n}\n\n/** Codes the server may carry only as a message prefix (`\"resume_conflict: …\"`). */\nconst PREFIXED_ERROR_CODES = [\n \"resume_conflict\",\n \"not_resumable\",\n \"outstanding_delegated_calls\",\n \"user_request_not_found\",\n \"run_in_flight\",\n] as const;\n\n/**\n * The machine code a server message carries as a PREFIX\n * (`\"resume_conflict: another run is live\"` → `resume_conflict`), for envelope\n * variants that pass the message but map `error` to a generic status word.\n * Only the known resume/turn-lock codes match; null for anything else.\n */\nexport function readMatrxErrorCodeFromMessage(\n message: string | null | undefined,\n): string | null {\n if (typeof message !== \"string\") return null;\n for (const code of PREFIXED_ERROR_CODES) {\n if (message.startsWith(`${code}:`)) return code;\n }\n return null;\n}\n\n/**\n * The conversation's own organization id, for scoping a resume/rejoin to the\n * RUN's organization instead of the session's selection. Transport-agnostic:\n * the host injects `read` (a supabase select, a REST call, …) returning the raw\n * `organization_id` (or throwing). Null — with `onUnreadable(reason)` — when it\n * is missing or unreadable, so the caller keeps the active organization and\n * says so.\n */\nexport async function readConversationOrganizationId(\n conversationId: string,\n read: (conversationId: string) => Promise<unknown>,\n onUnreadable?: (reason: string | null) => void,\n): Promise<string | null> {\n try {\n const value = await read(conversationId);\n if (typeof value === \"string\" && value.trim()) return value;\n onUnreadable?.(null);\n } catch (error) {\n onUnreadable?.(error instanceof Error ? error.message : String(error));\n }\n return null;\n}\n\n/** Where to rejoin a live run, read from a resume door's 409. */\nexport interface MatrxLiveRunRejoin {\n /** The live request (`GET /runtime/operations/{id}`); null for doors outside the spine (SEO). */\n liveRequestId: string | null;\n /** Server-relative path to `POST` for the NDJSON replay-then-follow. Always from the body when present. */\n rejoinPath: string;\n /** `run_id` extra (workflow / SEO / comparison), when present. */\n runId: string | null;\n /** The refusal's code — always `run_in_progress` (chat's `resume_conflict` is retried, never rejoined). */\n code: string;\n /** The refusal body (root of the envelope), for door-specific extras (`arm_index`, `analysis_id`, …). */\n body: Record<string, unknown>;\n}\n\nfunction firstString(candidates: Record<string, unknown>[], key: string): string | null {\n for (const candidate of candidates) {\n const value = nonBlank(candidate[key]);\n if (value) return value.trim();\n }\n return null;\n}\n\n/**\n * The rejoin target of a live-run refusal: `409` with `code: run_in_progress`.\n * Null for every other error — a genuine failure is never mistaken for a live\n * run, and chat's `resume_conflict` is never a rejoin even when its body names\n * one (the host retries the resume so the continuation runs). Reads\n * `rejoin_path` from the body first; derives the runtime rejoin from\n * `live_request_id` only when the body names no path. Never reads\n * `request_id`.\n */\nexport function readLiveRunRejoin(error: unknown): MatrxLiveRunRejoin | null {\n if (statusOf(error) !== 409) return null;\n const candidates = detailCandidates(bodyOf(error));\n if (candidates.length === 0) return null;\n const code = readMatrxErrorCode(error);\n if (code !== MATRX_RUN_IN_PROGRESS) return null;\n const liveRequestId = firstString(candidates, \"live_request_id\");\n const pathFromBody = firstString(candidates, \"rejoin_path\");\n const rejoinPath =\n pathFromBody && pathFromBody.startsWith(\"/\")\n ? pathFromBody\n : liveRequestId\n ? runtimeOperationRejoinPath(liveRequestId)\n : null;\n if (!rejoinPath) return null;\n const root = bodyOf(error);\n return {\n liveRequestId,\n rejoinPath,\n runId: firstString(candidates, \"run_id\"),\n code,\n body: isRecord(root) ? root : {},\n };\n}\n\n/**\n * The request id of a run that is STILL LIVE, read from a resume door's\n * refusal (`live_request_id` — never the envelope's own `request_id`). Null\n * for every other error, and for a live refusal outside the spine (SEO) —\n * follow `readLiveRunRejoin(error).rejoinPath` instead.\n */\nexport function readLiveRunRequestId(error: unknown): string | null {\n return readLiveRunRejoin(error)?.liveRequestId ?? null;\n}\n\n/**\n * `409 resume_conflict` — another run holds the conversation's claim (usually\n * the turn still suspending); retry the resume with the host's backoff so the\n * continuation runs. Never a rejoin, even when the body names a live run.\n */\nexport function isResumeConflict(error: unknown): boolean {\n return (\n statusOf(error) === 409 &&\n readMatrxErrorCode(error) === MATRX_RESUME_CONFLICT\n );\n}\n\n/** `409 live_stream_unavailable` — the rejoin journal is gone; follow the durable lifecycle instead. */\nexport function isLiveStreamUnavailable(error: unknown): boolean {\n return (\n statusOf(error) === 409 &&\n readMatrxErrorCode(error) === MATRX_LIVE_STREAM_UNAVAILABLE\n );\n}\n\n/**\n * The server-relative rejoin path — for hosts whose stream pipeline takes a\n * URL instead of a transport (prepend the resolved base URL).\n */\nexport function runtimeOperationRejoinPath(requestId: string): string {\n return `/runtime/operations/${encodePathSegment(requestId)}/rejoin`;\n}\n\n/**\n * The text to show for a stream `error` event: the server's `user_message`\n * first (it is written for the person — e.g. \"OpenAI refused this request:\n * the platform's OpenAI account is out of credit.\"), then `message`. Accepts\n * the `{event, data}` envelope or its `data` payload. Null when neither is\n * present — the host supplies its own fallback; it must never REPLACE a\n * message the server sent.\n */\nexport function streamErrorText(eventOrPayload: unknown): string | null {\n if (!isRecord(eventOrPayload)) return null;\n const payload =\n typeof eventOrPayload.event === \"string\" && isRecord(eventOrPayload.data)\n ? eventOrPayload.data\n : eventOrPayload;\n return nonBlank(payload.user_message) ?? nonBlank(payload.message);\n}\n\n/**\n * Open any Matrx NDJSON stream by path (`POST`, optional JSON body) — for\n * feature doors outside the agent lifecycle (`/podcast/resume/{run_id}`, …)\n * so their streams ride the same transport and wire kernel as every run.\n */\nexport async function openMatrxStream(\n transport: MatrxTransport,\n path: string,\n options: MatrxStreamCallOptions & { body?: unknown } = {},\n): Promise<MatrxRunHandle> {\n const response = await requestStream(transport, path, {\n method: \"POST\",\n ...(options.body !== undefined ? { body: options.body } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return toRunHandle(response, options);\n}\n\n/**\n * Bind a run's organization onto every call as `X-Organization-Id`. Host\n * policy headers still merge on top; the package's own `createMatrxTransport`\n * refuses a disagreeing org (`organization_context_mismatch`) rather than\n * silently swapping it, so a host must not force the SESSION org onto a\n * resume/rejoin transport.\n */\nexport function withRunOrganization(\n transport: MatrxTransport,\n organizationId: string,\n): MatrxTransport {\n const orgId = requireOrganizationContext(organizationId);\n return {\n fetch: (path, init) =>\n transport.fetch(path, {\n ...init,\n headers: { ...init.headers, \"X-Organization-Id\": orgId },\n }),\n };\n}\n\n/**\n * Follow a workflow run's SSE (`GET /runs/{run_id}/events/stream`) — the\n * rejoin fallback for workflow legs with no stream journal. Delivers every\n * parsed event (durable run events with their seq; ephemeral `node_stream`\n * frames — including `kind: \"media\"` — with seq null). One connection, no\n * reconnect policy: resolves `{ended: true}` on the server's `end` frame,\n * `{ended: false}` when the wire closes or the caller aborts.\n */\nexport async function followWorkflowRunEvents(\n transport: MatrxTransport,\n runId: string,\n options: {\n onEvent: (event: Record<string, unknown>, seq: number | null) => void;\n lastEventId?: number | null;\n signal?: AbortSignal;\n },\n): Promise<{ ended: boolean }> {\n const headers: Record<string, string> = { Accept: \"text/event-stream\" };\n if (options.lastEventId) headers[\"Last-Event-ID\"] = String(options.lastEventId);\n let response: Response;\n try {\n response = await requestStream(\n transport,\n `/runs/${encodePathSegment(runId)}/events/stream`,\n {\n method: \"GET\",\n headers,\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n } catch (error) {\n if (options.signal?.aborted) return { ended: false };\n throw error;\n }\n try {\n for await (const frame of readMatrxSseStream(\n response.body as ReadableStream<Uint8Array>,\n )) {\n if (frame.event === \"end\") return { ended: true };\n if (frame.data === null) continue;\n let parsed: unknown;\n try {\n parsed = JSON.parse(frame.data);\n } catch {\n continue;\n }\n if (!isRecord(parsed)) continue;\n options.onEvent(parsed, parsed.event === \"node_stream\" ? null : frame.seq);\n }\n } catch (error) {\n if (!options.signal?.aborted) throw error;\n }\n return { ended: false };\n}\n\nexport type ResumeOrRejoinOutcome =\n /** The resume door ran the run; its stream was delivered to `onEnvelope`. */\n | { kind: \"resumed\"; requestId: string | null }\n /** The run was live; its stream (from `rejoin_path`) was replayed + followed into `onEnvelope`. */\n | { kind: \"rejoined\"; rejoin: MatrxLiveRunRejoin }\n /**\n * The run was live but had no journal to replay; the durable lifecycle was\n * followed instead. Re-query the feature's record for the result.\n * `ended: false` = the follow gave up (or no operation was found).\n */\n | {\n kind: \"followed\";\n rejoin: MatrxLiveRunRejoin;\n executionId: string | null;\n ended: boolean;\n status: MatrxRuntimeExecutionStatus | null;\n }\n /** No journal, and the run is a workflow: its run SSE was followed into `onWorkflowEvent`. */\n | { kind: \"followed_workflow\"; rejoin: MatrxLiveRunRejoin; runId: string; ended: boolean }\n /** `409 resume_conflict` (named live run or not) — retry with the host's backoff policy. */\n | { kind: \"resume_conflict\"; error: MatrxApiError };\n\nexport interface ResumeOrRejoinOptions\n extends Omit<MatrxStreamCallOptions, \"signal\"> {\n /** Every NDJSON envelope — from the resume stream OR the rejoined stream. */\n onEnvelope: (envelope: MatrxStreamEnvelope) => void;\n /** THE RUN'S organization (from its durable record) — bound on every call. */\n organizationId?: string | null;\n signal?: AbortSignal;\n /** Fired the moment a live run is detected, before the rejoin opens (reset replay-sensitive state). */\n onRejoin?: (rejoin: MatrxLiveRunRejoin) => void;\n /** Durable lifecycle events while following (the no-journal fallback). */\n onOperationEvent?: (event: MatrxRuntimeOperationEvent) => void;\n /** Workflow run SSE events (the no-journal fallback for a workflow `run_id`). */\n onWorkflowEvent?: (event: Record<string, unknown>, seq: number | null) => void;\n /** Tuning for the durable follow (stall / reconnect policy). */\n follow?: Omit<\n FollowRuntimeOperationToEndOptions,\n \"onEvent\" | \"signal\" | \"lastEventSeq\"\n >;\n}\n\nasync function drain(\n handle: MatrxRunHandle,\n onEnvelope: (envelope: MatrxStreamEnvelope) => void,\n): Promise<void> {\n for await (const envelope of handle.events) onEnvelope(envelope);\n}\n\n/**\n * Resume a run — or, when the server says it is still live, REJOIN it.\n *\n * Calls `resumeCall` (the feature's resume door) and pipes its stream into\n * `onEnvelope`. On a live-run refusal (`run_in_progress`) it follows the body's `rejoin_path`\n * into the SAME handler under the same organization; when the rejoin has no\n * journal (`live_stream_unavailable`) it follows the workflow run SSE (body\n * names a workflow `run_id`) or the durable lifecycle. Never runs a live run a\n * second time. Every `resume_conflict` comes back as an outcome; any other\n * error is thrown.\n */\nexport async function resumeOrRejoin(\n transport: MatrxTransport,\n resumeCall: (\n transport: MatrxTransport,\n options: MatrxStreamCallOptions,\n ) => Promise<MatrxRunHandle>,\n options: ResumeOrRejoinOptions,\n): Promise<ResumeOrRejoinOutcome> {\n const {\n onEnvelope,\n organizationId,\n onRejoin,\n onOperationEvent,\n onWorkflowEvent,\n follow,\n ...rest\n } = options;\n const bound = organizationId\n ? withRunOrganization(transport, organizationId)\n : transport;\n const streamOptions: MatrxStreamCallOptions = {\n ...rest,\n ...(options.signal ? { signal: options.signal } : {}),\n };\n const signalOnly = options.signal ? { signal: options.signal } : {};\n\n let rejoin: MatrxLiveRunRejoin;\n try {\n const handle = await resumeCall(bound, streamOptions);\n await drain(handle, onEnvelope);\n return { kind: \"resumed\", requestId: handle.requestId };\n } catch (error) {\n const target = readLiveRunRejoin(error);\n if (!target) {\n if (error instanceof MatrxApiError && isResumeConflict(error)) {\n return { kind: \"resume_conflict\", error };\n }\n throw error;\n }\n rejoin = target;\n }\n\n onRejoin?.(rejoin);\n let unavailable: MatrxLiveStreamUnavailable;\n try {\n const handle = await openMatrxStream(bound, rejoin.rejoinPath, {\n ...streamOptions,\n // The rejoin routes take no body model; the reference client posts {}.\n body: {},\n });\n await drain(handle, onEnvelope);\n return { kind: \"rejoined\", rejoin };\n } catch (error) {\n const read = readLiveStreamUnavailable(error);\n if (!read) throw error;\n unavailable = read;\n }\n\n // `bound` already carries the run's organization.\n return followUnavailableRejoin(bound, rejoin, unavailable, {\n ...signalOnly,\n ...(onOperationEvent ? { onOperationEvent } : {}),\n ...(onWorkflowEvent ? { onWorkflowEvent } : {}),\n ...(follow ? { follow } : {}),\n });\n}\n\n/** What a `409 live_stream_unavailable` rejoin answer names: a workflow `run_id`, when it has one. */\nexport interface MatrxLiveStreamUnavailable {\n runId: string | null;\n}\n\n/**\n * Read a rejoin's `409 live_stream_unavailable` (the journal is gone). Null\n * for every other error. For hosts that open the rejoin stream themselves —\n * hand the result to `followUnavailableRejoin`.\n */\nexport function readLiveStreamUnavailable(\n error: unknown,\n): MatrxLiveStreamUnavailable | null {\n if (!isLiveStreamUnavailable(error)) return null;\n return { runId: firstString(detailCandidates(bodyOf(error)), \"run_id\") };\n}\n\nexport type MatrxFollowedOutcome = Extract<\n ResumeOrRejoinOutcome,\n { kind: \"followed\" | \"followed_workflow\" }\n>;\n\nexport interface FollowUnavailableRejoinOptions {\n /** THE RUN'S organization; omit when `transport` is already bound to it. */\n organizationId?: string | null;\n signal?: AbortSignal;\n onOperationEvent?: (event: MatrxRuntimeOperationEvent) => void;\n onWorkflowEvent?: (event: Record<string, unknown>, seq: number | null) => void;\n follow?: Omit<\n FollowRuntimeOperationToEndOptions,\n \"onEvent\" | \"signal\" | \"lastEventSeq\"\n >;\n}\n\n/**\n * The no-journal fallback of a rejoin — the SAME branch `resumeOrRejoin`\n * takes, exported for hosts whose rejoin stream rides their own wire (the\n * extension's offscreen fetch, the desktop's request loop). A workflow\n * `run_id` (from the unavailable body, else the refusal) on a runtime rejoin\n * → follow the workflow run SSE; otherwise read the live operation and\n * follow it to its end. Settle the result with `settleRunPickup`.\n */\nexport async function followUnavailableRejoin(\n transport: MatrxTransport,\n rejoin: MatrxLiveRunRejoin,\n unavailable: MatrxLiveStreamUnavailable,\n options: FollowUnavailableRejoinOptions = {},\n): Promise<MatrxFollowedOutcome> {\n const bound = options.organizationId\n ? withRunOrganization(transport, options.organizationId)\n : transport;\n const signalOnly = options.signal ? { signal: options.signal } : {};\n\n const runId = unavailable.runId ?? rejoin.runId;\n if (runId && rejoin.rejoinPath.startsWith(\"/runtime/operations/\")) {\n const result = await followWorkflowRunEvents(bound, runId, {\n ...signalOnly,\n onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq),\n });\n return { kind: \"followed_workflow\", rejoin, runId, ended: result.ended };\n }\n\n const liveRequestId = rejoin.liveRequestId;\n const statusView = liveRequestId\n ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly)\n : null;\n const operation =\n statusView?.operations.find((op) => !op.is_terminal) ??\n statusView?.operations[0] ??\n null;\n if (!operation) {\n return { kind: \"followed\", rejoin, executionId: null, ended: false, status: null };\n }\n if (operation.is_terminal) {\n return {\n kind: \"followed\",\n rejoin,\n executionId: operation.execution_id,\n ended: true,\n status: operation.status,\n };\n }\n const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {\n ...options.follow,\n lastEventSeq: operation.last_event_seq,\n ...signalOnly,\n onEvent: (event) => options.onOperationEvent?.(event),\n });\n return {\n kind: \"followed\",\n rejoin,\n executionId: operation.execution_id,\n ended: result.ended,\n status: result.status,\n };\n}\n\n/**\n * The parts of a pick-up result `settleRunPickup` reads — every\n * `ResumeOrRejoinOutcome` is one, and so is a host's own follow result.\n */\nexport type MatrxRunPickup =\n | { kind: \"resumed\" | \"rejoined\" }\n | { kind: \"resume_conflict\" }\n | {\n kind: \"followed\";\n executionId: string | null;\n ended: boolean;\n status: MatrxRuntimeExecutionStatus | null;\n }\n | { kind: \"followed_workflow\"; ended: boolean };\n\nexport type MatrxRunPickupSettlement =\n /** The turn arrived on a stream the host already rendered — nothing to reload. */\n | { state: \"streamed\" }\n /** Bare `resume_conflict` — retry with the host's backoff. */\n | { state: \"retry\" }\n /**\n * The run is over (or no live operation remains): the SAVED turn was\n * reloaded — that is the answer to show, never an empty bubble and never a\n * failure the run did not have. `status` null = unknown (workflow / none\n * found); `reloaded: false` = the reload itself threw (`error`).\n */\n | {\n state: \"settled\";\n status: MatrxRuntimeExecutionStatus | null;\n reloaded: boolean;\n error?: unknown;\n }\n /** The follow gave up while the run may still be live; `onStillRunning` (default: reload what is saved) ran. */\n | { state: \"still_running\"; reloaded: boolean; error?: unknown };\n\nexport interface SettleRunPickupOptions {\n /** Re-read the feature's saved record (the conversation's messages) into the screen. */\n reloadSavedTurn: () => Promise<void> | void;\n /**\n * The follow gave up on a run that may still be live. Default: reload what\n * is saved now. A host with its own patient recovery (the web app's\n * dropped-stream poll) passes it here instead.\n */\n onStillRunning?: () => Promise<void> | void;\n}\n\nasync function attempt(run: () => Promise<void> | void): Promise<{ reloaded: boolean; error?: unknown }> {\n try {\n await run();\n return { reloaded: true };\n } catch (error) {\n return { reloaded: false, error };\n }\n}\n\n/**\n * THE one mapping from a pick-up result to what the screen does, shared by\n * every chat client so a live run that cannot replay ends the same way\n * everywhere: streamed → done; bare conflict → retry; followed to its end\n * (or nothing live left to follow) → reload the saved turn and report the\n * run's real status; follow gave up → still running (never \"failed\").\n */\nexport async function settleRunPickup(\n pickup: MatrxRunPickup,\n options: SettleRunPickupOptions,\n): Promise<MatrxRunPickupSettlement> {\n switch (pickup.kind) {\n case \"resumed\":\n case \"rejoined\":\n return { state: \"streamed\" };\n case \"resume_conflict\":\n return { state: \"retry\" };\n case \"followed_workflow\":\n case \"followed\": {\n const status = pickup.kind === \"followed\" ? pickup.status : null;\n // No operation left on the spine = the turn already settled; its saved\n // record is the truth.\n const nothingLive = pickup.kind === \"followed\" && pickup.executionId === null;\n if (pickup.ended || nothingLive) {\n return { state: \"settled\", status, ...(await attempt(options.reloadSavedTurn)) };\n }\n return {\n state: \"still_running\",\n ...(await attempt(options.onStillRunning ?? options.reloadSavedTurn)),\n };\n }\n }\n}\n","/**\n * Agent run lifecycle against the AI Matrx API — start, continue, resume,\n * cancel — over the `MatrxTransport` port, with every streaming response\n * parsed through the package's ONE NDJSON wire kernel (`stream/ndjson`).\n *\n * Server truth (verified against aidream source):\n * - `POST /ai/agents/{agent_id}` — start (`aidream/api/routers/agents.py`)\n * - `POST /ai/conversations/{conversation_id}` — continue (`aidream/api/routers/conversations.py`)\n * - `POST /ai/conversations/{conversation_id}/resume` — resume after\n * client-delegated tool suspension (same router)\n * - `POST /ai/cancel/{request_id}?mode=interrupt` — cancel (`aidream/api/routers/cancel.py`)\n *\n * Response headers arrive before the body: `X-Conversation-ID` and\n * `X-Request-ID` are surfaced on the run handle immediately. `X-Request-ID`\n * is the ONLY id the server accepts for cancel — a client-local id means\n * nothing to it.\n *\n * Host policy stays out: no retry, no store, no timeouts, no persistence\n * (C10: no-persistence). Cancellation is the caller's `AbortSignal`; a client\n * disconnect never stops server work (`detach_on_disconnect`).\n */\n\nimport type { MatrxStreamEnvelope } from \"../stream/ndjson\";\nimport type {\n MatrxConversationStart,\n MatrxJsonObject,\n MatrxJsonValue,\n} from \"./conversation\";\nimport {\n encodePathSegment,\n buildQuery,\n requestJson,\n requestStream,\n toRunHandle,\n type MatrxRunHandle,\n type MatrxStreamCallOptions,\n} from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\nimport { streamErrorText } from \"./rejoin\";\n\nexport type { MatrxRunHandle, MatrxStreamCallOptions } from \"./internal\";\n\n// ─── Request shapes (mirroring the server's Pydantic models) ────────────────\n\n/**\n * Stable identity of the durable entity whose saved context owns a run —\n * the server reloads the row and uses ITS scope (`ContextAnchor`,\n * `aidream/services/conversation_context/scope.py`).\n */\nexport interface MatrxContextAnchor {\n resource_type: string;\n resource_id: string;\n}\n\n/**\n * Scope and source fields shared by every scoped request\n * (`ScopedRequest` / `AcceptsInjectedScope` server-side). All optional here;\n * the start request narrows `organization_id` to required.\n */\nexport interface MatrxRequestScope {\n organization_id?: string;\n project_id?: string | null;\n task_id?: string | null;\n /** Active context-scope ids from the client's global picker (membership-validated server-side). */\n scope_ids?: string[] | null;\n /** Active scope-TYPE ids — a type-level selection with no specific scope chosen. */\n active_scope_type_ids?: string[] | null;\n context_anchor?: MatrxContextAnchor | null;\n /** Stable application slug that initiated the request. */\n source_app?: string | null;\n /** Stable feature slug within the source application. */\n source_feature?: string | null;\n /** \"user\" = a person directly triggered this; \"auto\" = client automation; omit for API callers. */\n initiation?: \"user\" | \"auto\" | null;\n /** Specific connected desktop instance allowed to claim delegated local tools. */\n target_instance_id?: string | null;\n}\n\n/**\n * Fields shared by start/continue turn requests (tool injection, client\n * capability envelope, context object). The complex bags (`tools`, `client`,\n * `user`, `config_overrides`) are typed as JSON objects — their authoritative\n * schemas are the server's Pydantic models and the generated API types;\n * this package stays payload-agnostic about them by design.\n */\nexport interface MatrxTurnFields {\n /** What the human typed (string), or structured input parts. Never smuggle machine content here. */\n user_input?: string | MatrxJsonValue[] | null;\n /** Per-run model/config overrides (LLMParams shape). */\n config_overrides?: MatrxJsonObject | null;\n debug?: boolean;\n /** Additive tool specs merged into the agent's resolved tool set. */\n tools?: MatrxJsonObject[];\n /** When set, becomes the agent's ENTIRE tool set for the turn. */\n tools_replace?: MatrxJsonObject[] | null;\n /** Client capability envelope (`ClientContext`). */\n client?: MatrxJsonObject | null;\n /** Per-request user-level tool inclusion/exclusion overrides. */\n user?: MatrxJsonObject | null;\n /** Per-route context object, free-form by design. */\n context?: MatrxJsonObject;\n writable_variables?: string[];\n allow_context_create?: boolean;\n /** Request-snapshot capture override (tri-state; omit for the platform default). */\n snapshot?: boolean | null;\n}\n\n/**\n * `POST /ai/agents/{agent_id}` body (`AgentStartRequest` server-side).\n * The conversation-start triple is required by construction; `organization_id`\n * is required (the server 422s a blank one — it never manufactures an org).\n * `stream` is not accepted here: this client is the streaming path and always\n * sends `stream: true`.\n */\nexport type MatrxAgentStartRequest = MatrxConversationStart &\n Omit<MatrxRequestScope, \"organization_id\"> &\n MatrxTurnFields & {\n organization_id: string;\n /** Variable name → value map filling the agent's declared variables. */\n variables?: MatrxJsonObject | null;\n /** Run the versions table row instead of the live agent row. */\n is_version?: boolean;\n max_iterations?: number;\n max_retries_per_iteration?: number;\n };\n\n/**\n * `POST /ai/mandates/{mandate_key}` uses the exact saved-agent start body.\n * The server resolves the mandate's holder, binding, and configuration; a\n * client must offer only the declared variables and human input here.\n */\nexport type MatrxMandateStartRequest = MatrxAgentStartRequest;\n\n/** `POST /ai/conversations/{id}` body (`ConversationContinueRequest` server-side). */\nexport type MatrxConversationContinueRequest = MatrxRequestScope &\n MatrxTurnFields & {\n /** Re-run the conversation's current persisted state (recovery after a failed turn); omit `user_input`. */\n retry?: boolean;\n };\n\n/**\n * `POST /ai/conversations/{id}/resume` body (`ResumeRequest` server-side) —\n * the shipped durable continuation after client-delegated tool calls were\n * answered via `POST /tool_results` while the original stream was gone.\n * `user_request_id` is optional: when omitted the server resolves the turn\n * from the conversation's newest answered client-delegated tool call.\n * Re-send fresh `context` here — a resumed loop is otherwise context-blind.\n */\nexport type MatrxConversationResumeRequest = MatrxRequestScope & {\n user_request_id?: string | null;\n config_overrides?: MatrxJsonObject | null;\n debug?: boolean;\n tools?: MatrxJsonObject[];\n tools_replace?: MatrxJsonObject[] | null;\n client?: MatrxJsonObject | null;\n user?: MatrxJsonObject | null;\n context?: MatrxJsonObject;\n writable_variables?: string[];\n allow_context_create?: boolean;\n};\n\n/** `POST /ai/cancel/{request_id}` response (`CancelResponse` server-side). */\nexport interface MatrxCancelResponse {\n status: string;\n request_id: string;\n spine_executions_signalled: string[];\n}\n\n// ─── The run handle ─────────────────────────────────────────────────────────\n// `MatrxStreamCallOptions`, `MatrxRunHandle`, and the handle constructor live\n// in ./internal so `./operations`' rejoin shares the exact same construction.\n\nasync function streamCall(\n transport: MatrxTransport,\n path: string,\n body: object,\n options: MatrxStreamCallOptions,\n): Promise<MatrxRunHandle> {\n const response = await requestStream(transport, path, {\n method: \"POST\",\n // This client IS the streaming path — `stream: true` always, last so a\n // caller-supplied value can never flip the response off NDJSON.\n body: { ...body, stream: true },\n ...(options.signal ? { signal: options.signal } : {}),\n });\n return toRunHandle(response, options);\n}\n\n// ─── Lifecycle calls ────────────────────────────────────────────────────────\n\n/** Start an agent run: `POST /ai/agents/{agent_id}` (NDJSON stream). */\nexport function startAgentRun(\n transport: MatrxTransport,\n agentId: string,\n request: MatrxAgentStartRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/agents/${encodePathSegment(agentId)}`,\n request,\n options,\n );\n}\n\n/**\n * Start a declared mandate: `POST /ai/mandates/{mandate_key}` (NDJSON\n * stream). This is deliberately separate from `startAgentRun`: callers name\n * the mandate and never resolve or echo its holder/configuration themselves.\n */\nexport function startMandateRun(\n transport: MatrxTransport,\n mandateKey: string,\n request: MatrxMandateStartRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/mandates/${encodePathSegment(mandateKey)}`,\n request,\n options,\n );\n}\n\n/** Continue a stored conversation: `POST /ai/conversations/{id}` (NDJSON stream). */\nexport function continueAgentConversation(\n transport: MatrxTransport,\n conversationId: string,\n request: MatrxConversationContinueRequest,\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}`,\n request,\n options,\n );\n}\n\n/**\n * Resume a suspended loop after delegated tool answers landed:\n * `POST /ai/conversations/{id}/resume` (NDJSON stream). A 409\n * (`resume_conflict`) means another resume holds the run claim — retrying is\n * host policy.\n */\nexport function resumeAgentConversation(\n transport: MatrxTransport,\n conversationId: string,\n request: MatrxConversationResumeRequest = {},\n options: MatrxStreamCallOptions = {},\n): Promise<MatrxRunHandle> {\n return streamCall(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/resume`,\n request,\n options,\n );\n}\n\n/**\n * Stop a running request at its next iteration boundary:\n * `POST /ai/cancel/{request_id}`. Cooperative and best-effort — the in-flight\n * provider call finishes by design, and everything already streamed persists.\n * `mode: \"interrupt\"` = stop-and-fork: the tail after the last clean boundary\n * persists hidden so the user's follow-up replies to what they actually saw.\n * The id must be the server's `X-Request-ID`.\n */\nexport function cancelAgentRun(\n transport: MatrxTransport,\n requestId: string,\n options: { mode?: \"cancel\" | \"interrupt\"; signal?: AbortSignal } = {},\n): Promise<MatrxCancelResponse> {\n const query = buildQuery(\n options.mode === \"interrupt\" ? { mode: \"interrupt\" } : {},\n );\n return requestJson<MatrxCancelResponse>(\n transport,\n `/ai/cancel/${encodePathSegment(requestId)}${query}`,\n {\n method: \"POST\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n// ─── End-to-end convenience: run to completion ──────────────────────────────\n\n/**\n * A run that terminated unsuccessfully: the server emitted a fatal `error`\n * event, or the `user_request` completion settled `failed`/`cancelled`.\n */\nexport class MatrxRunError extends Error {\n override readonly name = \"MatrxRunError\";\n /** The verbatim `error` event payload, when one fired. */\n readonly errorPayload: Record<string, unknown> | null;\n /** The `user_request` completion status (`\"failed\"` | `\"cancelled\"`), when that was the trigger. */\n readonly completionStatus: string | null;\n /** Text streamed before the failure — partial content never vanishes. */\n readonly partialText: string;\n\n constructor(args: {\n message: string;\n errorPayload?: Record<string, unknown> | null;\n completionStatus?: string | null;\n partialText?: string;\n }) {\n super(args.message);\n this.errorPayload = args.errorPayload ?? null;\n this.completionStatus = args.completionStatus ?? null;\n this.partialText = args.partialText ?? \"\";\n }\n}\n\nexport interface MatrxCompletedRun {\n /** Accumulated `chunk` text (falls back to the completion's `result.output`). */\n text: string;\n requestId: string | null;\n conversationId: string | null;\n /** The `user_request` completion payload, verbatim, when one arrived. */\n completion: Record<string, unknown> | null;\n}\n\nexport interface RunAgentToCompletionOptions extends MatrxStreamCallOptions {\n /** Live progress: the full accumulated text after each chunk. */\n onChunk?: (fullText: string) => void;\n /** Every normalized envelope, before this helper interprets it. */\n onEvent?: (envelope: MatrxStreamEnvelope) => void;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction stringField(value: unknown, key: string): string | null {\n if (!isRecord(value)) return null;\n const field = value[key];\n return typeof field === \"string\" && field ? field : null;\n}\n\n/**\n * Run an agent end-to-end and resolve with its full text output — the\n * package-level equivalent of the simplest existing host path\n * (`useRunAgent`): accumulate `chunk` text, treat a fatal `error` event or a\n * `failed`/`cancelled` `user_request` completion as a thrown `MatrxRunError`,\n * and fall back to the completion's `result.output` when no text streamed.\n *\n * The caller still owns the conversation-start triple on `request` — a\n * one-shot run typically uses `newEphemeralConversationStart()`.\n */\nexport async function runAgentToCompletion(\n transport: MatrxTransport,\n agentId: string,\n request: MatrxAgentStartRequest,\n options: RunAgentToCompletionOptions = {},\n): Promise<MatrxCompletedRun> {\n const handle = await startAgentRun(transport, agentId, request, options);\n\n let text = \"\";\n let completion: Record<string, unknown> | null = null;\n let failure: MatrxRunError | null = null;\n\n for await (const envelope of handle.events) {\n options.onEvent?.(envelope);\n\n if (envelope.event === \"chunk\") {\n const chunk = stringField(envelope.data, \"text\");\n if (chunk !== null) {\n text += chunk;\n options.onChunk?.(text);\n }\n continue;\n }\n\n if (envelope.event === \"error\" && failure === null) {\n const payload = isRecord(envelope.data) ? envelope.data : null;\n failure = new MatrxRunError({\n message: streamErrorText(payload) ?? \"The agent run failed\",\n errorPayload: payload,\n partialText: text,\n });\n continue;\n }\n\n if (envelope.event !== \"completion\" || !isRecord(envelope.data)) continue;\n // `init`/`completion` pairs exist for five operations; the terminal\n // outcome of the run is the `user_request` completion (STREAM-CONTRACT\n // §3.2 — always present, always last).\n if (envelope.data.operation !== \"user_request\") continue;\n\n completion = envelope.data;\n const status = envelope.data.status;\n if ((status === \"failed\" || status === \"cancelled\") && failure === null) {\n const result = isRecord(envelope.data.result) ? envelope.data.result : null;\n failure = new MatrxRunError({\n message:\n stringField(result, \"error\") ??\n stringField(result, \"user_message\") ??\n `The agent run ${status}`,\n completionStatus: status,\n partialText: text,\n });\n }\n }\n\n if (failure) throw failure;\n\n if (!text && completion) {\n const result = completion.result;\n const output = stringField(result, \"output\");\n if (output !== null) text = output;\n }\n\n return {\n text,\n requestId: handle.requestId,\n conversationId: handle.conversationId,\n completion,\n };\n}\n","/**\n * Browser-held provider sessions report their failures through the server.\n *\n * Realtime voice (OpenAI / xAI) and Cartesia TTS run browser → provider\n * directly on an ephemeral token from the token broker, so a provider refusal\n * (e.g. the platform's account is out of credit) never touches the server —\n * the operator would never hear of it, and the person would see raw provider\n * text. Every client calls `reportProviderSessionFailure` from the session's\n * error handler and shows the returned `user_message`.\n *\n * Server truth: `POST /broker/provider-failures`\n * (`aidream/api/routers/token_broker.py`; body `ProviderSessionFailureReport`\n * in `aidream/services/token_broker/models.py` — `extra=\"forbid\"`, allow-listed\n * providers, bounded text; identity and organization come from the session).\n */\n\nimport { requestJson } from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\n\n/** The providers whose sessions a browser holds directly (server allow-list). */\nexport type MatrxClientSessionProvider = \"openai\" | \"xai\" | \"cartesia\";\n\nexport interface ProviderSessionFailure {\n provider: MatrxClientSessionProvider;\n model?: string | null;\n /** HTTP status the provider answered, when the failure was an HTTP answer. */\n status_code?: number | null;\n /** The provider's own error type/code (`insufficient_quota`, …). */\n error_type?: string | null;\n /** The provider's text, verbatim — classified server-side, never shown. */\n message: string;\n}\n\n/** `ProviderSessionFailureVerdict` — what to show, and whether reconnecting can help. */\nexport interface ProviderSessionFailureVerdict {\n error_type: string;\n retryable: boolean;\n /** The sentence to show the person (never the provider's raw text). */\n user_message: string;\n}\n\nconst clip = (value: string, max: number): string =>\n value.length > max ? value.slice(0, max) : value;\n\n/** The body the server accepts — bounded exactly as its model bounds it. */\nexport function providerSessionFailureBody(\n failure: ProviderSessionFailure,\n): Record<string, string | number> {\n const message =\n failure.message?.trim() ||\n failure.error_type?.trim() ||\n (failure.status_code ? `HTTP ${failure.status_code}` : \"provider session failed\");\n const body: Record<string, string | number> = {\n provider: failure.provider,\n message: clip(message, 4000),\n };\n if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);\n if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);\n if (\n typeof failure.status_code === \"number\" &&\n Number.isInteger(failure.status_code) &&\n failure.status_code >= 100 &&\n failure.status_code <= 599\n ) {\n body.status_code = failure.status_code;\n }\n return body;\n}\n\n/**\n * Report a browser-held provider session failure and get the sentence to\n * show. Resolves null (and warns) when the report itself could not be made —\n * the caller then shows its own fallback; it never throws from an error\n * handler.\n */\nexport async function reportProviderSessionFailure(\n transport: MatrxTransport,\n failure: ProviderSessionFailure,\n options: { signal?: AbortSignal } = {},\n): Promise<ProviderSessionFailureVerdict | null> {\n try {\n return await requestJson<ProviderSessionFailureVerdict>(\n transport,\n \"/broker/provider-failures\",\n {\n method: \"POST\",\n body: providerSessionFailureBody(failure),\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n } catch (error) {\n console.warn(\n `[provider-failures] could not report a ${failure.provider} session failure`,\n error,\n );\n return null;\n }\n}\n","/**\n * Delegated client tools — submit results and discover pending calls.\n *\n * Server truth (verified against aidream source,\n * `aidream/api/routers/conversations.py` + `aidream/services/ai_execution/\n * tool_results.py`):\n * - `POST /ai/conversations/{id}/tool_results` — durable, idempotent submit.\n * A delegated tool call HARD-SUSPENDS the loop; when the last outstanding\n * delegated row for the user_request resolves, the response carries\n * `continuation_needed: true` and the owning `user_request_id` — the signal\n * to open `resumeAgentConversation`. `continuation_needed` is best-effort:\n * parallel submits can both see `true`; `/resume` takes an atomic run claim\n * and the loser gets a 409.\n * - `GET /ai/conversations/{id}/pending_calls` — delegated calls awaiting the\n * user in one conversation (rows survive disconnects and reloads).\n * - `GET /ai/user/pending_calls` — every pending call for this user; an\n * optional `instance_id` atomically claims them for a desktop instance.\n *\n * A 404 from the submit means EVERY call_id was unknown (duplicate/expired);\n * partial success returns 200 with `not_found` populated. Batching, retries,\n * and the resume handoff are host policy — this module is the wire.\n */\n\nimport type { MatrxJsonObject, MatrxJsonValue } from \"./conversation\";\nimport { encodePathSegment, buildQuery, requestJson } from \"./internal\";\nimport type { MatrxTransport } from \"./transport\";\n\n/** One client tool answer (`ClientToolResult` server-side). */\nexport interface MatrxClientToolResult {\n call_id: string;\n tool_name: string;\n /** Tool output — inherently polymorphic; recursive JSON by design. */\n output?: MatrxJsonValue | null;\n is_error?: boolean;\n error_message?: string | null;\n /** Client-measured execution time in ms. */\n duration_ms?: number | null;\n}\n\n/** `POST /tool_results` response (`ToolResultsResponse` server-side). */\nexport interface MatrxToolResultsResponse {\n resolved: string[];\n already_resolved: string[];\n not_found: string[];\n /** True when the original stream is gone and no delegated calls remain — open `/resume`. */\n continuation_needed: boolean;\n user_request_id: string | null;\n conversation_id: string;\n}\n\n/** One delegated call awaiting an answer (`PendingCallSummary` server-side). */\nexport interface MatrxPendingCallSummary {\n id: string;\n call_id: string;\n conversation_id: string;\n user_request_id: string | null;\n message_id: string | null;\n tool_name: string;\n /** Tool-call argument bag — schema is per-tool (its input_schema). */\n arguments: MatrxJsonObject;\n iteration: number;\n created_at: string | null;\n expires_at: string | null;\n target_instance_id: string | null;\n claimed_by_instance_id: string | null;\n claim_expires_at: string | null;\n execution_authorization: MatrxJsonObject | null;\n}\n\n/**\n * Submit client tool results: `POST /ai/conversations/{id}/tool_results`.\n * Idempotent — duplicate submits return 200 with the ids in\n * `already_resolved`. Throws `MatrxApiError` (status 404) when every call_id\n * was unknown or expired; the stream stays alive in that case.\n */\nexport function submitAgentToolResults(\n transport: MatrxTransport,\n conversationId: string,\n results: MatrxClientToolResult[],\n options: { instanceId?: string; signal?: AbortSignal } = {},\n): Promise<MatrxToolResultsResponse> {\n return requestJson<MatrxToolResultsResponse>(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/tool_results`,\n {\n method: \"POST\",\n body: {\n results,\n ...(options.instanceId !== undefined\n ? { instance_id: options.instanceId }\n : {}),\n },\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n/**\n * Discover delegated calls awaiting the user in one conversation:\n * `GET /ai/conversations/{id}/pending_calls`. Safe to call on every\n * conversation load; a non-empty list should be surfaced exactly as if the\n * original stream had delivered the `tool_delegated` events live.\n */\nexport function listConversationPendingToolCalls(\n transport: MatrxTransport,\n conversationId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<MatrxPendingCallSummary[]> {\n return requestJson<MatrxPendingCallSummary[]>(\n transport,\n `/ai/conversations/${encodePathSegment(conversationId)}/pending_calls`,\n {\n method: \"GET\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n\n/**\n * Discover every delegated call awaiting this user across all conversations:\n * `GET /ai/user/pending_calls`. Passing `instanceId` atomically CLAIMS the\n * calls for that desktop instance — only pass it from a client that will\n * actually execute them.\n */\nexport function listUserPendingToolCalls(\n transport: MatrxTransport,\n options: { instanceId?: string; signal?: AbortSignal } = {},\n): Promise<MatrxPendingCallSummary[]> {\n const query = buildQuery(\n options.instanceId !== undefined ? { instance_id: options.instanceId } : {},\n );\n return requestJson<MatrxPendingCallSummary[]>(\n transport,\n `/ai/user/pending_calls${query}`,\n {\n method: \"GET\",\n ...(options.signal ? { signal: options.signal } : {}),\n },\n );\n}\n","/**\n * `@ai-matrx/agents/matrx` — every AI Matrx server endpoint path, by feature\n * area (matching the server's router structure). Paths only, rooted at the\n * host (`/ai/...`, `/health`); the HOST owns the base URL.\n *\n * Moved from matrx-frontend `lib/api/endpoints.ts` (chat-package independence\n * P9); the app re-exports it. The production origin and the per-environment\n * base URLs stay in the host (they are environment values).\n */\n\n\nimport type { DynamicMandateKey, MandateKey } from \"../mandates\";\n\n/**\n * All backend API endpoint paths.\n *\n * Organized by feature area matching the backend router structure.\n * Use these constants everywhere instead of hardcoded strings.\n *\n * Auth tiers:\n * - Public: No auth required\n * - Guest OK: Fingerprint or JWT token\n * - Authenticated: Valid JWT token required\n * - Admin: Valid JWT token + admin role\n */\nexport const ENDPOINTS = {\n /** AI endpoints — chat, agents, conversations */\n ai: {\n /**\n * POST — Manual-mode execution (Builder + ephemeral conversations).\n * POST /ai/manual\n *\n * Accepts full message history in `messages` on every call. Used by:\n * • Builder — reads the LIVE agent definition (incl. unsaved edits) and\n * sends it as the system instruction + priming messages.\n * • Ephemeral conversations (turn 2+) — no DB row exists, so the client\n * is the source of truth for history; sends it with each turn.\n *\n * `conversation_id` is optional in the body (for labeling/storage only);\n * pair with `is_new:false, store:false` for fully stateless runs.\n *\n * NOTE: this replaces the legacy `/ai/chat` endpoint. The canonical\n * client-side vocabulary is `manual` (see ConversationInvocation.routing\n * .apiEndpointMode). The legacy `chat` alias below stays for one\n * migration cycle.\n */\n manual: \"/ai/manual\" as const,\n\n /** @deprecated Use `ENDPOINTS.ai.manual`. Kept for one migration cycle. */\n chat: \"/ai/manual\" as const,\n\n /**\n * POST — Start a new agent conversation (Guest OK)\n * POST /ai/agents/{agentId}\n * Never send conversation_id — the server generates it and returns it in the stream.\n */\n agentStart: (agentId: string) => `/ai/agents/${agentId}` as const,\n\n /**\n * POST — THE MANDATE DOOR. Start a new conversation by MANDATE KEY, not by\n * agent id (Guest OK).\n * POST /ai/mandates/{mandateKey}\n *\n * Body is the SAME `AgentStartRequest` as `agentStart`. The server resolves\n * the principal (bearer/fingerprint) → system default → org binding → user\n * binding, applies the binding's `config_overrides`, provision consumption\n * and variable mapping, and then runs the IDENTICAL downstream pipeline\n * (`_run_mandated_agent` → `_run_agent`). A rebind therefore changes which\n * agent answers with NO client deploy — which is the entire point.\n *\n * Never send mandate-derived `config_overrides` on this path: the server\n * treats request config as the EXPLICIT layer that WINS over the binding,\n * so echoing a client-resolved binding back would re-fork resolution.\n *\n * 404 `{code: \"mandate_unfulfilled\"}` when the mandate cannot be resolved —\n * surfaced verbatim, never swallowed into a client-side re-resolve.\n */\n mandateStart: (\n /**\n * 🚨 TYPED, NEVER `string` (V-L6a, 2026-09-17). This is the execute path\n * itself: a stale key here becomes `404 mandate_unfulfilled` on a live\n * surface, so the compiler holds it. `DynamicMandateKey` covers the\n * DB-authored `app.*` / `shortcut.*` jobs that legitimately run here.\n */\n mandateKey: MandateKey | DynamicMandateKey,\n ) => `/ai/mandates/${mandateKey}` as const,\n\n /**\n * POST — Continue any existing conversation (Guest OK)\n * POST /ai/conversations/{conversationId}\n * Conversation ID in URL. Just send user_input in the body.\n */\n conversationContinue: (conversationId: string) =>\n `/ai/conversations/${conversationId}` as const,\n\n /**\n * POST — Pre-warm a conversation's server cache. No body. No auth.\n * POST /ai/conversations/{conversationId}/warm\n * Fire when user navigates to a conversation page.\n */\n conversationWarm: (conversationId: string) =>\n `/ai/conversations/${conversationId}/warm` as const,\n\n /**\n * POST — Pre-warm an agent's server cache. No auth. (public endpoint)\n * POST /ai/agents/{agentId}/warm\n * Optional body: `{ source: \"prompt\" | \"builtin\" | \"prompt_version\" | \"builtin_version\" }`\n */\n agentWarm: (agentId: string) => `/ai/agents/${agentId}/warm` as const,\n\n /**\n * POST — Start a new prompt conversation (Guest OK)\n * POST /ai/prompts/{promptId}\n * Body: PromptStartRequest — user_input, variables, stream, debug, client_tools, etc.\n * Never send conversation_id — the server generates it and returns it in the stream.\n */\n promptStart: (promptId: string) => `/ai/prompts/${promptId}` as const,\n\n /**\n * POST — Pre-warm a prompt's server cache. No auth. (public endpoint)\n * POST /ai/prompts/{promptId}/warm\n * Optional body: `{ source: string | null }`\n */\n promptWarm: (promptId: string) => `/ai/prompts/${promptId}/warm` as const,\n\n /**\n * POST — Start a new block-streaming agent session (Guest OK)\n * POST /ai/agents-blocks/{agentId}\n * Same as agentStart but emits 'content_block' NDJSON events instead of raw 'chunk' events.\n */\n agentBlocksStart: (agentId: string) =>\n `/ai/agents-blocks/${agentId}` as const,\n\n /**\n * POST — Pre-warm a block-streaming agent (Public)\n * POST /ai/agents-blocks/{agentId}/warm\n * Optional body: `{ source: \"prompt\" | \"builtin\" | \"prompt_version\" | \"builtin_version\" }`\n */\n agentBlocksWarm: (agentId: string) =>\n `/ai/agents-blocks/${agentId}/warm` as const,\n\n /**\n * POST — Execute a prompt app using its pinned prompt version (Guest OK)\n * POST /ai/apps/{appId}\n * The backend resolves the pinned prompt version — the client never sees prompt secrets.\n */\n appExecute: (appId: string) => `/ai/apps/${appId}` as const,\n\n /**\n * POST — Pre-warm a prompt app's pinned version into cache (Public, no auth)\n * POST /ai/apps/{appId}/warm\n * Fire when the prompt app page loads so execution is instant.\n */\n appWarm: (appId: string) => `/ai/apps/${appId}/warm` as const,\n\n /** POST — Cancel a running request by request_id (Authenticated) */\n cancel: (requestId: string) => `/ai/cancel/${requestId}` as const,\n },\n\n /** Block processing test endpoints — Guest OK */\n blockProcessing: {\n /** POST — Process raw text/markdown → structured blocks (JSON response) */\n process: \"/utilities/block-processing/process\" as const,\n /** POST — Process raw text/markdown → block events (NDJSON stream, simulates live agent) */\n processStream: \"/utilities/block-processing/process/stream\" as const,\n },\n\n /** CX-data endpoints — conversation/message data (Authenticated) */\n cx: {\n /**\n * GET — Snapshot of \"what the model is currently seeing\" for a conversation.\n * GET /cx/conversations/{conversationId}/context-state\n * Initial hydration for the Model Context tab; live updates come via\n * CONTEXT_STATE / CONTEXT_TRIMMED stream events after each turn.\n */\n contextState: (conversationId: string) =>\n `/cx/conversations/${conversationId}/context-state` as const,\n },\n\n /** CMS server work — authenticated. CMS row CRUD stays direct-to-Supabase. */\n cms: {\n /** POST — Canonical matrx-content-guard validation before CMS writes. */\n validate: \"/cms/validate\" as const,\n /**\n * POST — THE decision door for a queued content exception\n * (`features/approvals/cms-door.ts`). The exception id is the idempotency\n * key; the server finds its queue row and replays the ordinary human write\n * path. Nothing else decides these — the CMS's own review route is gone.\n */\n approveException: (exceptionId: string) =>\n `/cms/exceptions/${encodeURIComponent(exceptionId)}/approve` as const,\n rejectException: (exceptionId: string) =>\n `/cms/exceptions/${encodeURIComponent(exceptionId)}/reject` as const,\n },\n\n /** Tool testing endpoints — Authenticated */\n tools: {\n /** GET — List available tools (?category=) */\n testList: \"/tools/test/list\",\n /** GET — Get tool details by name */\n testDetail: (toolName: string) => `/tools/test/${toolName}` as const,\n /** POST — Create/reuse test session */\n testSession: \"/tools/test/session\",\n /** POST — Execute tool test with streaming */\n testExecute: \"/tools/test/execute\",\n },\n\n /** Scraper endpoints — Authenticated */\n scraper: {\n /** POST — Quick scrape URLs */\n quickScrape: \"/scraper/quick-scrape\",\n /** POST — Search keywords */\n search: \"/scraper/search\",\n /** POST — Search and scrape combined */\n searchAndScrape: \"/scraper/search-and-scrape\",\n /** POST — Search and scrape with limits */\n searchAndScrapeLimited: \"/scraper/search-and-scrape-limited\",\n /** POST — Connectivity check */\n micCheck: \"/scraper/mic-check\",\n },\n\n /** Utility endpoints — Guest OK */\n utilities: {\n /** @deprecated Use ENDPOINTS.pdf.extractText instead */\n pdfExtractText: \"/utilities/pdf/extract-text\",\n },\n\n /**\n * PDF extraction, manipulation, and document management — Authenticated.\n * Most JSON endpoints accept a unified source via `MediaRef` (preferred for\n * cloud files via `cld_id`), `file`, `url`, or `local_path`. See\n * `features/pdf-extractor/types.ts` for the full type re-exports.\n *\n * NOTE: list/detail endpoints below are kept for backwards compatibility\n * but the workspace now reads `processed_documents` directly from Supabase\n * for the sidebar list and the on-click detail (the old `extracted_documents`\n * facade view was retired 2026-06-11). Loading hundreds of full `content`\n * rows from Python was making the window take 2+ minutes to open.\n */\n pdf: {\n // ── Lifecycle ─────────────────────────────────────────────────────────\n /**\n * POST — Compress PDF (multipart file upload). Query params:\n * - `level` (1..5): minimum quality tier. 1=lossless, 5=max compression.\n * - `max_size_mb` (optional float): absolute upper bound on output size;\n * when set, the server escalates `level` one tier at a time until the\n * output fits (or tier 5 is reached). Omit for \"honour level exactly.\"\n * Response headers include `X-Compression-Level-Used` and\n * `X-Compression-Cap-Satisfied` so the caller can see what actually ran.\n */\n compress: \"/utilities/pdf/compress\" as const,\n /** POST — Single-file text extraction (stateless multipart, NDJSON streaming).\n * Emits `pdf_extract_started` / `pdf_page_extracted` / `pdf_extract_complete`\n * data events; the complete event carries the old `{ filename, text_content }`\n * body. Consume via `streamPdfExtractText` (features/pdf-extractor/service/streamPdf.ts). */\n extractText: \"/utilities/pdf/extract-text\" as const,\n /** POST — Batch extraction with NDJSON streaming (saves to DB + storage). */\n batchExtract: \"/utilities/pdf/batch-extract\" as const,\n /**\n * POST — Phone-scanner assembly (NDJSON streaming): ordered photos\n * (optional quad + rotation) + PDFs → ONE user-visible PDF, extracted\n * + handed to the content pipeline. Terminal `data` event carries\n * `{ file_id, doc_id, page_count }`.\n */\n fromImages: \"/utilities/pdf/from-images\" as const,\n\n // ── New `MediaRef`-based JSON endpoints (matrx-utils) ─────────────────\n /** POST — Text extraction from a remote source (MediaRef / url; NDJSON streaming,\n * same events as `extractText`). Consume via `streamPdfExtractTextRemote`. */\n extractTextRemote: \"/utilities/pdf/extract-text-remote\" as const,\n /** POST — Table extraction. Returns `PdfResult`. */\n extractTables: \"/utilities/pdf/extract-tables\" as const,\n /** POST — Extract pages into a new PDF. Returns PDF blob. */\n extractPages: \"/utilities/pdf/extract-pages\" as const,\n /** POST — Crop pages (with `crop_box`). Returns PDF blob. */\n cropPages: \"/utilities/pdf/crop-pages\" as const,\n /** POST — Rotate pages. Returns PDF blob. */\n rotatePages: \"/utilities/pdf/rotate-pages\" as const,\n /** POST — Delete pages. Returns PDF blob. */\n deletePages: \"/utilities/pdf/delete-pages\" as const,\n /** POST — Merge multiple PDFs. Returns PDF blob. */\n merge: \"/utilities/pdf/merge\" as const,\n /** POST — Split PDF into parts (`parts` or `max_pages_per_part`). Returns ZIP blob. */\n split: \"/utilities/pdf/split\" as const,\n\n // ── AI pipelines (streaming JSONL) ────────────────────────────────────\n /** POST — Process a PDF with AI agents (single-pass / chunk / reassembly). Streams JSONL. */\n processWithAi: \"/utilities/pdf/process-with-ai\" as const,\n /** POST — Full pipeline: extract → chunk → AI → reassembly. Streams JSONL with `PdfPipelineOptions`. */\n fullPipeline: \"/utilities/pdf/full-pipeline\" as const,\n /** POST — AI content cleaning on an already-extracted document (NDJSON streaming). */\n cleanContent: (docId: string) =>\n `/utilities/pdf/clean-content/${docId}` as const,\n\n // ── Document management (server-side; prefer direct Supabase reads) ──\n /** @deprecated — Read `processed_documents` directly from Supabase with metadata-only projection. */\n documents: \"/utilities/pdf/documents\" as const,\n /** @deprecated — Read `processed_documents` directly from Supabase. */\n document: (docId: string) => `/utilities/pdf/documents/${docId}` as const,\n\n // ── Phase 2 — render & advanced page ops ──────────────────────────────\n /** POST — Render one page to an image blob (PNG/JPEG/WebP/TIFF). */\n renderPage: \"/utilities/pdf/render-page\" as const,\n /** POST — Render every page; returns a ZIP of per-page images. */\n renderAll: \"/utilities/pdf/render-all\" as const,\n /** POST — Cover thumbnail at `max_side` px. */\n renderThumbnail: \"/utilities/pdf/render-thumbnail\" as const,\n /** POST — Reorder pages by `new_order`. Returns PDF blob. */\n reorderPages: \"/utilities/pdf/reorder-pages\" as const,\n /** POST — Insert pages from `source_*` into target. Returns PDF blob. */\n insertPages: \"/utilities/pdf/insert-pages\" as const,\n /** POST — Duplicate pages inline (`count` copies). Returns PDF blob. */\n duplicatePages: \"/utilities/pdf/duplicate-pages\" as const,\n /** GET — Studio preset catalog. Returns `PdfStudioCatalog`. */\n studioPresets: \"/utilities/pdf/studio/presets\" as const,\n /** POST — Studio dispatcher; image blob or ZIP depending on preset. */\n studioRender: \"/utilities/pdf/studio/render\" as const,\n\n // ── Phase 3 — layout analysis ─────────────────────────────────────────\n /** POST — Detect headers / footers / watermarks / recurring side notes. Returns `RepeatedRegionsReport`. */\n detectRepeatedRegions: \"/utilities/pdf/detect-repeated-regions\" as const,\n /** POST — Detect + strip repeated regions from per-page text. Returns `StripRepeatedRegionsResultSchema`. */\n stripRepeatedRegions: \"/utilities/pdf/strip-repeated-regions\" as const,\n /** POST — Classify every page (cover / TOC / body / exhibit / signature / billing / ...). Returns `LayoutClassificationReport`. */\n classifyPages: \"/utilities/pdf/classify-pages\" as const,\n /** POST — Multi-column → linear reading order. Returns `ReadingOrderReport`. */\n extractReadingOrder: \"/utilities/pdf/extract-reading-order\" as const,\n\n // ── Phase 4 — redaction & privacy ─────────────────────────────────────\n /** GET — Builtin redaction pattern catalog (SSN / email / phone / MRN / ...). */\n redactPatterns: \"/utilities/pdf/redact/patterns\" as const,\n /** POST — Redact one or more page-anchored rectangles. PDF blob or persisted JSON. */\n redactRegions: \"/utilities/pdf/redact-regions\" as const,\n /** POST — Redact every regex match (builtin id or raw pattern). PDF blob or persisted JSON. */\n redactPattern: \"/utilities/pdf/redact-pattern\" as const,\n /** POST — Detect repeated regions then redact selected/all. PDF blob or persisted JSON. */\n redactRepeatedRegions: \"/utilities/pdf/redact-repeated-regions\" as const,\n /** POST — Wipe /Info + XMP metadata + thumbnails. */\n stripMetadata: \"/utilities/pdf/strip-metadata\" as const,\n /** POST — Granular composite scrub (metadata / attachments / JS / flatten). */\n scrub: \"/utilities/pdf/scrub\" as const,\n /** POST — Bake annotations + widgets into page content. */\n flattenAnnotations: \"/utilities/pdf/flatten-annotations\" as const,\n },\n\n /**\n * Per-page AI extraction — fan out an agent across pages of a document and\n * persist structured results anchored to source page numbers. See\n * `features/page-extraction/FEATURE.md` for the data model.\n */\n pageExtraction: {\n /** POST — Run extraction across pages (NDJSON streaming, per-page events). */\n runStream: \"/page-extraction/runs/stream\" as const,\n /** POST — Retry one failed page-run (replaces its results). */\n retryPageRun: (pageRunId: string) =>\n `/page-extraction/page-runs/${pageRunId}/retry` as const,\n /** POST — Cancel an in-flight run. */\n cancelRun: (runId: string) =>\n `/page-extraction/runs/${runId}/cancel` as const,\n },\n\n /** Test/admin endpoints — Admin only */\n tests: {\n /** GET/POST — Example endpoints */\n examples: \"/tests/examples\",\n /** GET — Stream text test */\n streamText: \"/tests/stream/text\",\n },\n\n /** Builtin agent endpoints — Authenticated */\n builtinAgents: {\n /** POST — Categorize a single prompt (streaming) */\n categorize: \"/ai/builtin-agents/categorize\" as const,\n /** POST — Categorize a single prompt (sync, no streaming) */\n categorizeSync: \"/ai/builtin-agents/categorize/sync\" as const,\n },\n\n /** Media processing endpoints — Authenticated */\n media: {\n /**\n * POST — Upload podcast video → extract cover frame, render podcast\n * variants, returns URLs + Asset envelope. Image-only uploads now go\n * through {@link ENDPOINTS.assets.upload} with `preset=\"podcast\"`.\n */\n uploadPodcastVideo: \"/media/podcast/upload-video\" as const,\n /**\n * POST — stream the spoken transcript of a captioned YouTube video as\n * text. Body: `{ youtube_url }`. Reuses the \"YouTube Video Transcription\n * Analysis\" agent server-side (quiet run, no chat clutter). Streams NDJSON:\n * the transcript arrives as chunk text (`accumulatedText`); a captionless\n * video yields a non-fatal warning + empty text so callers stay honest.\n */\n youtubeTranscript: \"/media/youtube/transcript\" as const,\n },\n\n /**\n * Content-processing orchestrator — the interactive counterpart to the\n * automatic post-upload hook. Triggers extract→clean→chunk→embed→NER for an\n * already-uploaded `cld_files` row and streams typed progress (NDJSON). The\n * terminal `data` event carries a `ContentProcessingResult`\n * (`signature: \"ContentProcessingResult\"`) with `status` + `processed_document_id`.\n * Today's content types: `\"pdf\"` (default) and `\"office\"` (docx/pptx/xlsx —\n * pure-python extraction, no LibreOffice/OCR; already-clean markdown so the\n * LLM clean stage is skipped). The extracted text itself is NOT in the\n * stream — read `docproc.processed_documents.content` directly via\n * `docprocDb(supabase)` (canonical direct-Supabase read) once the run\n * completes.\n */\n contentProcessing: {\n process: (cldFileId: string) => `/content-processing/${cldFileId}` as const,\n },\n\n /**\n * Unified asset (image / media) upload + render-variants pipeline.\n *\n * One endpoint family handles every media upload in the platform. The\n * server renders preset variants (cover, OG, thumbnail, avatar sizes,\n * favicons, etc.) and returns the canonical {@link Asset} envelope —\n * see `features/files/types.ts` for the wire shape.\n *\n * Preset → variant key map (high level):\n * - raw → only `original`\n * - podcast → cover_url (3000²), cover_sd_url (1400²) + social baseline\n * - social → og_url, square_url, portrait_url, story_url, yt_thumbnail_url + baseline\n * - web → hero_url, og_url, card_url, touch_icon_url, pwa_icon_url, thumbnail_url + baseline\n * - email → header_url, square_url (no baseline)\n * - logo → logo_lg_url, logo_md_url, logo_sm_url + baseline\n * - avatar → avatar_xl/lg/md/sm/xs_url (no baseline)\n * - favicon → favicon_android/apple_touch/32/16_url (no baseline)\n *\n * Authenticated. See `features/files/api/assets.ts` for the typed\n * client wrapper.\n */\n assets: {\n /** POST — multipart upload + render preset variants. */\n upload: \"/assets\" as const,\n /** GET — read the canonical Asset envelope for an upload's master file. */\n detail: (fileId: string) => `/assets/${fileId}` as const,\n /** PATCH — change sharing / metadata. */\n patch: (fileId: string) => `/assets/${fileId}` as const,\n /** POST — render more variants (idempotent). */\n addVariants: (fileId: string) => `/assets/${fileId}/variants` as const,\n /** GET — list every server-known preset. */\n presets: \"/assets/presets\" as const,\n /**\n * GET — convert any cld_files row to an Asset envelope. The\n * click-to-render primitive: hand any file_id, get back URLs +\n * variants the FE can render directly.\n */\n forFile: (fileId: string) => `/files/${fileId}/asset` as const,\n /**\n * POST — no-persist preview rendering (E.16, matrx-utils v1.1.0).\n * Accepts a `MediaRef` source + variants[]. Returns either base64\n * `data_url` (≤256 KB) or a 5-min `ephemeral_url`. Replaces the\n * deleted Next.js Sharp route at app/api/images/studio/process.\n */\n preview: \"/assets/preview\" as const,\n /**\n * POST — multipart variant of {@link preview}. Render directly without\n * a prior `cld_files` row. Useful for Image Studio drag-and-drop\n * preview before commit-to-save.\n */\n previewMultipart: \"/assets/preview/multipart\" as const,\n /**\n * POST — no-persist PDF compression (E.17). Accepts a `MediaRef` source.\n * Returns `data_url` (≤256 KB) or a 5-min `ephemeral_url`.\n * Replaces the deleted Next.js route at app/api/pdf/compress.\n */\n pdfCompress: \"/assets/pdf-compress\" as const,\n /** POST — multipart variant of {@link pdfCompress}. */\n pdfCompressMultipart: \"/assets/pdf-compress/multipart\" as const,\n },\n\n /** Health endpoints — Public (aligned with types/python-generated OpenAPI) */\n health: {\n /** GET — Basic health check */\n check: \"/health\",\n /** GET — Detailed health with component status */\n detailed: \"/health/detailed\",\n /** GET — Liveness (process up; no I/O) */\n live: \"/health/live\",\n /** GET — Readiness (deps initialized; use for deploy probes) */\n ready: \"/health/ready\",\n },\n\n /** Research endpoints — Authenticated */\n research: {\n /** POST — Initialize research config */\n init: \"/research/init\",\n /** GET — List templates */\n templatesList: \"/research/templates/list\",\n /** POST — Create template */\n templatesCreate: \"/research/templates\",\n /** GET — Template detail */\n templateDetail: (templateId: string) =>\n `/research/templates/${templateId}` as const,\n /** GET — Extension scrape queue */\n extensionScrapeQueue: \"/research/extension/scrape-queue\",\n /** GET — Research state / PATCH — Update config */\n state: (projectId: string) => `/research/${projectId}` as const,\n /** POST — Suggest setup */\n suggest: (projectId: string) => `/research/${projectId}/suggest` as const,\n /** POST — Run full pipeline (streaming) */\n run: (projectId: string) => `/research/${projectId}/run` as const,\n /** POST — Trigger search (streaming) */\n search: (projectId: string) => `/research/${projectId}/search` as const,\n /** POST — Trigger scrape (streaming) */\n scrape: (projectId: string) => `/research/${projectId}/scrape` as const,\n /** POST — Analyze all sources (streaming) */\n analyzeAll: (projectId: string) =>\n `/research/${projectId}/analyze-all` as const,\n /** POST — Synthesize */\n synthesize: (projectId: string) =>\n `/research/${projectId}/synthesize` as const,\n /** GET — Keywords */\n keywords: (projectId: string) => `/research/${projectId}/keywords` as const,\n /** GET — Sources */\n sources: (projectId: string) => `/research/${projectId}/sources` as const,\n /** GET — Tags */\n tags: (projectId: string) => `/research/${projectId}/tags` as const,\n /** GET/POST — Document */\n document: (projectId: string) => `/research/${projectId}/document` as const,\n /** GET — Costs */\n costs: (projectId: string) => `/research/${projectId}/costs` as const,\n },\n\n /**\n * ACTION REQUESTS — `platform.action_request`. An agent asks the person it\n * works for for ONE thing; they answer on `/q/<token>` and the parked turn\n * resumes.\n *\n * All three sit on aidream's PUBLIC router at the BARE prefix (no `/api`,\n * no version), because the person tapping them has no account in the general\n * case. They are POSTs deliberately — the token would otherwise sit in a URL,\n * which means in the access log and in every proxy between here and it.\n *\n * Reached ONLY from `features/action-requests/service.ts` (server lane): the\n * `Authorization` header is what separates a signed-in completion from a\n * bearer one, so the decision to send it belongs where the session cookie is.\n */\n actionRequests: {\n /** POST — what the page draws. MUTATES NOTHING. */\n open: \"/action-requests/open\" as const,\n /** POST — the answer. */\n complete: \"/action-requests/complete\" as const,\n /** POST — \"text me a new link\". Rate-limited in the database. */\n remint: \"/action-requests/remint\" as const,\n },\n} as const;\n","/**\n * `@ai-matrx/agents/matrx` — the single primitive that transforms a server\n * endpoint PATH (never the base URL) before it is sent: an exact per-path\n * override, else a global version prefix. Moved from matrx-frontend\n * `lib/api/resolve-endpoint-path.ts` (chat-package independence P9).\n */\n// Both layers default to off (null / empty), so an untouched app behaves\n// identically to before this primitive existed.\n\nexport interface EndpointOverrideConfig {\n /**\n * Global leading version segment applied to every path that has no exact\n * pathOverride. `null` / empty → no version transform. The value may be\n * given with or without a leading slash (\"v2\" and \"/v2\" both work).\n */\n apiVersion?: string | null;\n\n /**\n * Exact-match canonical-path → replacement-path map. Keys are the path\n * template exactly as written in `ENDPOINTS` / the generated schema\n * (including any `{param}` segments). Wins over `apiVersion`.\n */\n pathOverrides?: Record<string, string>;\n}\n\n/** Normalize a path fragment to a single leading slash, no trailing slash. */\nfunction normalizeLeadingSlash(value: string): string {\n const trimmed = value.trim();\n if (!trimmed) return \"\";\n const withLead = trimmed.startsWith(\"/\") ? trimmed : `/${trimmed}`;\n return withLead.length > 1 && withLead.endsWith(\"/\")\n ? withLead.slice(0, -1)\n : withLead;\n}\n\n/**\n * Resolve the final path for a canonical endpoint path, applying any active\n * override layers. Pure — given the same inputs it always returns the same\n * path. Callers prepend the resolved base URL themselves.\n *\n * @param canonicalPath The path exactly as declared in ENDPOINTS / the schema.\n * @param config The active override layers (read from Redux).\n */\nexport function resolveEndpointPath(\n canonicalPath: string,\n config?: EndpointOverrideConfig | null,\n): string {\n if (!config) return canonicalPath;\n\n // Layer 1 — exact path override wins outright.\n const override = config.pathOverrides?.[canonicalPath];\n if (override && override.trim()) {\n return normalizeLeadingSlash(override);\n }\n\n // Layer 2 — global version prefix.\n const version = config.apiVersion?.trim();\n if (version) {\n const prefix = normalizeLeadingSlash(version);\n const path = canonicalPath.startsWith(\"/\")\n ? canonicalPath\n : `/${canonicalPath}`;\n return `${prefix}${path}`;\n }\n\n return canonicalPath;\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/log-api-target.ts` (chat-package independence P9). */\n/**\n * lib/api/log-api-target.ts\n *\n * ONE place that logs the *final, resolved* destination of every outbound\n * backend call — at the last moment, after every layer of server-address\n * resolution has run and the URL can no longer change before `fetch()`.\n *\n * Why this exists:\n * We have several independent resolution layers — `selectResolvedBaseUrl`\n * (apiConfigSlice), the EC2 / sandbox override channel in\n * `resolve-base-url.ts`, per-call `forceBaseUrl` / `baseUrlOverride`, and\n * the env-var fallback in `python-client.ts`. A bug in any one of them can\n * silently send traffic to the wrong host (or to the sandbox URL, which is\n * reserved for a single rare case). This logger makes the actual target of\n * EVERY call visible in the console so misrouting is impossible to miss.\n *\n * Call this immediately before the `fetch()` / `resilientFetch()` /\n * `XMLHttpRequest.open()` that uses the URL — never earlier.\n */\n\nexport interface ApiTargetLogContext {\n /** Short label of the call site, e.g. \"callApi\", \"python-client.postJson\". */\n source: string;\n /** HTTP method when known. */\n method?: string;\n /**\n * Resolution channel when the call site knows it — \"global\" / \"override\" /\n * \"ec2-dedicated\" / \"force\" / \"env-fallback\". Surfaces sandbox routing.\n */\n channel?: string;\n /** The active server environment key from apiConfigSlice, when available. */\n activeServer?: string;\n /** Anything else worth seeing (conversationId, requestId, etc.). */\n [extra: string]: unknown;\n}\n\n/**\n * Hosts that should almost never appear as an API target. If a resolved URL\n * points at one of these, the log is escalated to a hard `console.error` so it\n * stands out — the sandbox server is reserved for a single, rare case.\n */\nconst SUSPECT_HOST_FRAGMENTS = [\"sandbox\"] as const;\n\nfunction looksSuspect(url: string): boolean {\n const lower = url.toLowerCase();\n return SUSPECT_HOST_FRAGMENTS.some((frag) => lower.includes(frag));\n}\n\n/**\n * Log the final resolved target URL for an outbound backend call.\n *\n * Normal calls log at `console.info` with a green tag. Calls whose host looks\n * like a sandbox/override target log at `console.error` with a red tag so they\n * are impossible to miss while hunting a misrouting bug.\n */\nexport function logApiTarget(url: string, context: ApiTargetLogContext): void {\n const { source, method, channel, activeServer, ...extra } = context;\n\n let origin = url;\n try {\n origin = new URL(url).origin;\n } catch {\n /* relative or malformed — log the raw string */\n }\n\n const suspect = looksSuspect(url);\n const tag = suspect ? \"🚨 API TARGET (SANDBOX?)\" : \"📡 API TARGET\";\n const style = suspect\n ? \"font-weight:bold;color:#fff;background:#c0392b;padding:1px 4px;border-radius:3px;\"\n : \"font-weight:bold;color:#fff;background:#16a085;padding:1px 4px;border-radius:3px;\";\n\n const meta: Record<string, unknown> = {\n origin,\n fullUrl: url,\n source,\n };\n if (method) meta.method = method;\n if (channel) meta.channel = channel;\n if (activeServer) meta.activeServer = activeServer;\n for (const [k, v] of Object.entries(extra)) {\n if (v !== undefined) meta[k] = v;\n }\n\n const log = suspect ? console.error : console.info;\n log(\n `%c${tag}%c ${method ? method + \" \" : \"\"}${url}`,\n style,\n \"color:inherit;\",\n meta,\n );\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/desktop-target-request.ts` (chat-package independence P9). */\nconst DESKTOP_NATIVE_CAPABILITY = \"desktop-native\";\n\ntype MutableRecord = Record<string, unknown>;\n\n/**\n * Stamp the admin desktop-target preference onto a request body — but ONLY\n * when the body already declares a live `desktop-native` capability.\n *\n * The preference (Settings → Admin Server, `adminPreferences.\n * desktopTargetInstanceId`, persisted local-only) may DIRECT delegation to a\n * specific desktop; it must never DECLARE one. Fabricating the capability\n * here used to override the presence gate in `desktop-native.provider.ts`,\n * so a stale preference silently rode every AI turn: the server stamped\n * `target_instance_id` onto delegated tool calls while the smart-input\n * indicator truthfully showed no desktop bound, and browser-executed tools\n * (war_room_*, ui-first) 404'd their own /tool_results (submission-binding\n * check) and wedged the turn.\n */\nexport function applyDesktopTargetToRequestBody(\n body: unknown,\n targetInstanceId: string | null | undefined,\n): void {\n if (!targetInstanceId || !isRecord(body)) return;\n\n const existingClient = isRecord(body.client) ? body.client : null;\n const existingState =\n existingClient && isRecord(existingClient.state)\n ? existingClient.state\n : null;\n const existingDesktopState =\n existingState && isRecord(existingState[DESKTOP_NATIVE_CAPABILITY])\n ? existingState[DESKTOP_NATIVE_CAPABILITY]\n : null;\n\n // No live desktop-native envelope on this request → the presence gate said\n // no desktop is online (or the caller never built a client envelope).\n // Silently skipping is correct: targeting a desktop that isn't declared\n // delegates calls into a void.\n if (!existingClient || !existingState || !existingDesktopState) return;\n\n body.target_instance_id ??= targetInstanceId;\n existingDesktopState.target_instance_id ??= targetInstanceId;\n}\n\nfunction isRecord(value: unknown): value is MutableRecord {\n return value != null && typeof value === \"object\" && !Array.isArray(value);\n}\n","/**\n * `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/run-wait.ts` (chat-package\n * independence P9). The knob read is injected (`resolveRunWaitWith`); the host wraps it.\n */\n/**\n * How long a client waits for the server to START answering a run — per output\n * kind, as an organization knob.\n *\n * 🚨 THE DEFECT (2026-09-22). Pressing Run in the agent builder on an image\n * agent (\"Product Photo Studio\", Gemini 3.1 Flash Image) died on the client with\n * \"Connection timed out after 15000ms\". The builder's manual path was the only\n * agent stream path carrying a fixed 15-second `connectTimeoutMs`, and that\n * timer does not measure a TCP connect: aidream's prepared-streaming routes\n * (`create_prepared_streaming_response`) finish request PREPARATION — auth, the\n * request lane, conversation create, resolving attached files — BEFORE the\n * response headers go out. A busy server or a draining deploy pushed prep past\n * 15 s, the client aborted, and aborting before the headers dropped the server\n * run with it (conversation created, no messages).\n *\n * THE RULE. A generation is a job, not a request with a stopwatch:\n * - Once the stream is open there is NO wall-clock cap — the server heartbeat\n * (every 5 s) keeps the watchdog fed and the run ends on the stream's own\n * `end` event.\n * - The one cap that remains — \"the server never started answering\" — is an\n * organization knob per output kind (`agents.run_wait.<kind>_seconds`),\n * with generous agent-set defaults registered in the knob table, never a\n * constant here.\n * - When that cap is actually hit, the person is told the truth: which model,\n * how long we waited, and that the server may still be working — with a\n * door to the conversation, because the run can finish without us.\n *\n * If the knob snapshot cannot be read the wait falls back to the stream\n * lifetime backstop (announced loudly), never to a number nobody chose.\n */\n\nimport { formatDurationSeconds } from \"@ai-matrx/kit/format\";\n\n\n/** What a run produces. Anything but text is a job (seconds to minutes). */\n/** Every output kind a run can wait on — one `<kind>_seconds` knob each. */\nexport const RUN_OUTPUT_KINDS = [\"text\", \"image\", \"video\", \"audio\"] as const;\nexport type RunOutputKind = (typeof RUN_OUTPUT_KINDS)[number];\n\nexport const RUN_WAIT_KNOB_FEATURE = \"agents.run_wait\";\n\n/**\n * Stream lifetime backstop — the same 24 hours the agent run path\n * (`runAiStream`) has always used. It is the ceiling for a stream that keeps\n * heartbeating forever, not a wait anyone tunes; the heartbeat watchdog is the\n * real liveness check. Also the first-response wait when the knob cannot be\n * read (setTimeout's own ceiling is ~24.8 days, so this stays safe).\n */\nexport const RUN_STREAM_LIFETIME_BACKSTOP_MS = 24 * 60 * 60 * 1000;\n\nexport function isJobOutputKind(kind: RunOutputKind): boolean {\n return kind !== \"text\";\n}\n\n/**\n * The output kind from a model's declared output modalities (the parsed\n * `capabilities.output` list). Video outranks image outranks audio: a model\n * that can emit several is waited on as its slowest.\n */\nexport function runOutputKindFromModalities(\n output: readonly string[] | null | undefined,\n): RunOutputKind {\n const set = new Set((output ?? []).map((m) => m.toLowerCase()));\n if (set.has(\"video\")) return \"video\";\n if (set.has(\"image\")) return \"image\";\n if (set.has(\"audio\")) return \"audio\";\n return \"text\";\n}\n\nexport function runWaitKnobKey(kind: RunOutputKind): string {\n return `${kind}_seconds`;\n}\n\nexport interface RunWait {\n /** Milliseconds the client waits for the stream to open. */\n firstResponseMs: number;\n /** Seconds as configured, or null when the knob could not be read. */\n seconds: number | null;\n kind: RunOutputKind;\n}\n\n/**\n * Resolve the first-response wait for one run from the organization's knob.\n * Never throws — a run is never refused because a setting could not load; the\n * failure is announced and the wait becomes the lifetime backstop.\n */\n/**\n * Reads one settings-register knob for an organization (and person). The HOST\n * supplies it — matrx-frontend: `ensureEffectiveKnob` (lib/scoped-config).\n */\nexport type RunWaitKnobReader = (\n organizationId: string,\n userId: string | null,\n knob: { feature: string; key: string },\n) => Promise<unknown>;\n\nexport async function resolveRunWaitWith(\n readKnob: RunWaitKnobReader,\n organizationId: string | null | undefined,\n userId: string | null | undefined,\n kind: RunOutputKind,\n): Promise<RunWait> {\n const key = runWaitKnobKey(kind);\n if (!organizationId) {\n // The organization-less guest lane has no organization setting to read.\n // It waits on the lifetime backstop — no invented first-response limit.\n return { firstResponseMs: RUN_STREAM_LIFETIME_BACKSTOP_MS, seconds: null, kind };\n }\n try {\n const raw = await readKnob(organizationId, userId ?? null, {\n feature: RUN_WAIT_KNOB_FEATURE,\n key,\n });\n const seconds = typeof raw === \"number\" ? raw : Number(raw);\n if (!Number.isFinite(seconds) || seconds <= 0) {\n throw new Error(`it resolves to ${JSON.stringify(raw)}, not a number of seconds`);\n }\n return { firstResponseMs: Math.round(seconds * 1000), seconds, kind };\n } catch (error) {\n console.error(\n `[run-wait] The \"${RUN_WAIT_KNOB_FEATURE}.${key}\" setting could not be read — ` +\n `${error instanceof Error ? error.message : String(error)}. This run waits ` +\n \"for the server without a first-response limit (the 24-hour stream backstop) \" +\n \"instead of inventing one. Remedy: seed the knob (matrx-frontend \" +\n \"migrations/agents_run_wait_knobs.sql) or fix the knob snapshot read.\",\n );\n return {\n firstResponseMs: RUN_STREAM_LIFETIME_BACKSTOP_MS,\n seconds: null,\n kind,\n };\n }\n}\n\nconst KIND_NOUN: Record<RunOutputKind, string> = {\n text: \"a reply\",\n image: \"an image\",\n video: \"a video\",\n audio: \"audio\",\n};\n\n/** \"Generating an image with Gemini 3.1 Flash Image\" — the job's working line. */\nexport function runJobLabel(kind: RunOutputKind, modelLabel: string | null): string {\n const what =\n kind === \"text\" ? \"Writing a reply\" : `Generating ${KIND_NOUN[kind]}`;\n return modelLabel ? `${what} with ${modelLabel}` : what;\n}\n\n/**\n * The honest sentence for a first-response timeout. The server may still\n * finish the run, so the sentence says so and the caller attaches a door to\n * the conversation.\n */\nexport function runWaitTimeoutMessage(\n kind: RunOutputKind,\n modelLabel: string | null,\n seconds: number | null,\n): string {\n const waited =\n seconds != null\n ? // An exact limit an admin configured, so both tiers: \"1 minute 30 seconds\".\n `within ${formatDurationSeconds(seconds, { style: \"long\", parts: 2, round: \"nearest\" })}`\n : \"in time\";\n const who = modelLabel ? ` (${modelLabel})` : \"\";\n return (\n `The server did not start ${kind === \"text\" ? \"answering\" : `generating ${KIND_NOUN[kind]}`}` +\n `${who} ${waited}, so this page stopped waiting. The run may still finish on ` +\n \"the server — open the conversation to check before running it again. \" +\n \"An organization admin can lengthen this wait in the organization's configuration settings.\"\n );\n}\n","/** `@ai-matrx/agents/matrx` — moved from matrx-frontend `lib/api/warm-helpers.ts` (chat-package independence P9). */\n/**\n * Warm-helper utilities — centralized fire-and-forget pre-warm POSTs to the\n * backend so the next real request finds the resource already cached.\n *\n * Every warm call across the app should go through these helpers. Hand-rolled\n * `fetch(${BACKEND_URLS.production}${ENDPOINTS.ai.agentWarm(id)})` was the old\n * pattern and is being phased out: it ignores the in-header server picker,\n * silently swallows errors, and duplicates the URL-resolution logic at every\n * callsite.\n *\n * Server vs client:\n * - Server callers (page.tsx server components) cannot read the picker —\n * they pass an explicit `baseUrl` (typically `BACKEND_URLS.production`).\n * - Conversation warming is intentionally not exposed here: it requires an\n * authenticated owner and must happen only after client session hydration.\n *\n * Errors are intentionally swallowed — warm is best-effort. Telemetry can be\n * added by listening on the optional `onError` callback.\n */\n\nimport { ENDPOINTS } from \"./endpoints\";\n\ninterface WarmOptions {\n /**\n * Resolved backend URL. Server callers typically pass `BACKEND_URLS.production`,\n * which is `string | undefined` when the env var isn't configured — accepted\n * here (not coerced to `\"\"` at the call site) because the warm functions\n * below already no-op on a falsy `baseUrl`.\n */\n baseUrl: string | undefined;\n /** Optional callback for telemetry; warm failures never throw. */\n onError?: (err: unknown) => void;\n}\n\ninterface WarmAgentOptions extends WarmOptions {\n /** True when the path id is an agx_version id, not an agx_agent id. */\n isVersion?: boolean;\n}\n\n/**\n * POST /ai/agents/{agentId}/warm — preloads the agent's execution payload.\n * Body is `{ \"is_version\": true }` when `isVersion` is true; otherwise omitted.\n * Public route, no auth.\n */\nexport function warmAgent(\n agentId: string,\n { baseUrl, isVersion, onError }: WarmAgentOptions,\n): void {\n if (!baseUrl || !agentId) return;\n const url = `${baseUrl}${ENDPOINTS.ai.agentWarm(agentId)}`;\n const body = isVersion ? JSON.stringify({ is_version: true }) : undefined;\n fetch(\n url,\n body\n ? {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body,\n keepalive: true,\n }\n : { method: \"POST\", keepalive: true },\n ).catch((err) => {\n onError?.(err);\n });\n}\n"],"mappings":"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","names":["isNetError","isRecord","status","isNetError","attempt","isRecord","result","isRecord","isRecord"]}
|