@ai-matrx/agents 0.28.0 → 0.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.d.cts +2 -1
- package/dist/content-transfer/index.d.ts +2 -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/context/index.cjs +29 -5
- package/dist/context/index.cjs.map +1 -1
- package/dist/context/index.d.cts +65 -13
- package/dist/context/index.d.ts +65 -13
- package/dist/context/index.js +29 -5
- package/dist/context/index.js.map +1 -1
- package/dist/context/react/index.cjs +262 -78
- package/dist/context/react/index.cjs.map +1 -1
- package/dist/context/react/index.d.cts +100 -21
- package/dist/context/react/index.d.ts +100 -21
- package/dist/context/react/index.js +261 -77
- package/dist/context/react/index.js.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/mandates/index.cjs +2 -2
- package/dist/mandates/index.cjs.map +1 -1
- package/dist/mandates/index.d.cts +4 -4
- package/dist/mandates/index.d.ts +4 -4
- package/dist/mandates/index.js +2 -2
- package/dist/mandates/index.js.map +1 -1
- package/dist/matrx/index.d.cts +4 -2
- package/dist/matrx/index.d.ts +4 -2
- package/dist/{operations-Dp4ut-ac.d.ts → operations-C3iHFcnt.d.ts} +2 -94
- package/dist/{operations--f5ko9Su.d.cts → operations-C9QvBH_2.d.cts} +2 -94
- package/dist/portable/index.cjs +164 -0
- package/dist/portable/index.cjs.map +1 -0
- package/dist/portable/index.d.cts +74 -0
- package/dist/portable/index.d.ts +74 -0
- package/dist/portable/index.js +141 -0
- package/dist/portable/index.js.map +1 -0
- package/dist/portable/mcp.cjs +512 -0
- package/dist/portable/mcp.cjs.map +1 -0
- package/dist/portable/mcp.d.cts +81 -0
- package/dist/portable/mcp.d.ts +81 -0
- package/dist/portable/mcp.js +492 -0
- package/dist/portable/mcp.js.map +1 -0
- package/dist/transport-CxD0fL8p.d.cts +94 -0
- package/dist/transport-CxD0fL8p.d.ts +94 -0
- package/dist/types.generated-BydVlqDC.d.cts +49 -0
- package/dist/types.generated-BydVlqDC.d.ts +49 -0
- package/mandates/snapshots/keys.0.28.1.json +652 -0
- package/mandates/snapshots/keys.0.29.0.json +652 -0
- package/package.json +24 -4
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// portable/index.ts
|
|
21
|
+
var portable_exports = {};
|
|
22
|
+
__export(portable_exports, {
|
|
23
|
+
PORTABLE_AGENT_CONTRACT: () => PORTABLE_AGENT_CONTRACT,
|
|
24
|
+
fetchPortableAgent: () => fetchPortableAgent,
|
|
25
|
+
fetchPortableAgentVersions: () => fetchPortableAgentVersions,
|
|
26
|
+
portableAgentPath: () => portableAgentPath,
|
|
27
|
+
summarizePortableAgent: () => summarizePortableAgent
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(portable_exports);
|
|
30
|
+
|
|
31
|
+
// matrx/transport.ts
|
|
32
|
+
var MatrxApiError = class extends Error {
|
|
33
|
+
name = "MatrxApiError";
|
|
34
|
+
/** HTTP status of the failed response. */
|
|
35
|
+
status;
|
|
36
|
+
/** Machine code from the server body (`code`, or `detail.code`), when present. */
|
|
37
|
+
code;
|
|
38
|
+
/** The parsed server error body, verbatim (undefined when unparsable). */
|
|
39
|
+
serverDetail;
|
|
40
|
+
/** The request path the failure came from (server-relative). */
|
|
41
|
+
path;
|
|
42
|
+
constructor(args) {
|
|
43
|
+
super(
|
|
44
|
+
args.message ?? extractMatrxErrorMessage(args.serverDetail) ?? `HTTP ${args.status}`
|
|
45
|
+
);
|
|
46
|
+
this.status = args.status;
|
|
47
|
+
this.path = args.path;
|
|
48
|
+
this.serverDetail = args.serverDetail;
|
|
49
|
+
this.code = extractMatrxErrorCode(args.serverDetail);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function isRecord(value) {
|
|
53
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
54
|
+
}
|
|
55
|
+
function nonBlankString(value) {
|
|
56
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
57
|
+
}
|
|
58
|
+
function extractMatrxErrorMessage(serverDetail) {
|
|
59
|
+
if (!isRecord(serverDetail)) return void 0;
|
|
60
|
+
const userMessage = nonBlankString(serverDetail.user_message);
|
|
61
|
+
if (userMessage) return userMessage;
|
|
62
|
+
const message = nonBlankString(serverDetail.message);
|
|
63
|
+
if (message) return message;
|
|
64
|
+
if (Array.isArray(serverDetail.details)) {
|
|
65
|
+
const messages = serverDetail.details.map((entry) => {
|
|
66
|
+
if (!isRecord(entry)) return void 0;
|
|
67
|
+
const detailMessage = nonBlankString(entry.message);
|
|
68
|
+
if (!detailMessage) return void 0;
|
|
69
|
+
const field = nonBlankString(entry.field);
|
|
70
|
+
return field ? `${field}: ${detailMessage}` : detailMessage;
|
|
71
|
+
}).filter((m) => typeof m === "string");
|
|
72
|
+
if (messages.length > 0) return messages.join("; ");
|
|
73
|
+
}
|
|
74
|
+
const detail = serverDetail.detail;
|
|
75
|
+
if (isRecord(detail)) {
|
|
76
|
+
const detailMessage = nonBlankString(detail.message) ?? nonBlankString(detail.user_message);
|
|
77
|
+
if (detailMessage) return detailMessage;
|
|
78
|
+
}
|
|
79
|
+
if (typeof detail === "string" && detail.trim()) return detail;
|
|
80
|
+
if (Array.isArray(detail)) {
|
|
81
|
+
const messages = detail.map(
|
|
82
|
+
(entry) => isRecord(entry) ? nonBlankString(entry.msg) : void 0
|
|
83
|
+
).filter((m) => typeof m === "string");
|
|
84
|
+
if (messages.length > 0) return messages.join("; ");
|
|
85
|
+
}
|
|
86
|
+
return void 0;
|
|
87
|
+
}
|
|
88
|
+
function extractMatrxErrorCode(serverDetail) {
|
|
89
|
+
if (!isRecord(serverDetail)) return null;
|
|
90
|
+
const topLevel = nonBlankString(serverDetail.code);
|
|
91
|
+
if (topLevel) return topLevel;
|
|
92
|
+
const detail = serverDetail.detail;
|
|
93
|
+
if (isRecord(detail)) {
|
|
94
|
+
const nested = nonBlankString(detail.code);
|
|
95
|
+
if (nested) return nested;
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// matrx/internal.ts
|
|
101
|
+
function encodePathSegment(value) {
|
|
102
|
+
return encodeURIComponent(value);
|
|
103
|
+
}
|
|
104
|
+
async function readServerDetail(response) {
|
|
105
|
+
try {
|
|
106
|
+
return await response.json();
|
|
107
|
+
} catch {
|
|
108
|
+
return void 0;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async function throwApiError(path, response) {
|
|
112
|
+
throw new MatrxApiError({
|
|
113
|
+
status: response.status,
|
|
114
|
+
path,
|
|
115
|
+
serverDetail: await readServerDetail(response)
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
async function requestJson(transport, path, options) {
|
|
119
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
120
|
+
const response = await transport.fetch(path, {
|
|
121
|
+
method: options.method,
|
|
122
|
+
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
123
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
124
|
+
...options.signal ? { signal: options.signal } : {}
|
|
125
|
+
});
|
|
126
|
+
if (!response.ok) return throwApiError(path, response);
|
|
127
|
+
return await response.json();
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// portable/types.generated.ts
|
|
131
|
+
var PORTABLE_AGENT_CONTRACT = "portable-agent.v1";
|
|
132
|
+
|
|
133
|
+
// portable/index.ts
|
|
134
|
+
function portableAgentPath(target) {
|
|
135
|
+
return target.versionId ? `/ai/agents/versions/${encodePathSegment(target.versionId)}/portable` : `/ai/agents/${encodePathSegment(target.agentId ?? "")}/portable`;
|
|
136
|
+
}
|
|
137
|
+
function fetchPortableAgent(transport, target, options = {}) {
|
|
138
|
+
const body = {
|
|
139
|
+
variables: options.variables ?? {},
|
|
140
|
+
...options.surface ? { surface: options.surface } : {}
|
|
141
|
+
};
|
|
142
|
+
return requestJson(transport, portableAgentPath(target), {
|
|
143
|
+
method: "POST",
|
|
144
|
+
body,
|
|
145
|
+
...options.signal ? { signal: options.signal } : {}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function fetchPortableAgentVersions(transport, agentId, options = {}) {
|
|
149
|
+
return requestJson(
|
|
150
|
+
transport,
|
|
151
|
+
`/agent-service/agents/${encodePathSegment(agentId)}/versions`,
|
|
152
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
153
|
+
);
|
|
154
|
+
}
|
|
155
|
+
function summarizePortableAgent(bundle) {
|
|
156
|
+
const missingSkills = bundle.unavailable.filter((u) => u.kind === "skill").length;
|
|
157
|
+
const missingTools = bundle.unavailable.filter((u) => u.kind === "tool").length;
|
|
158
|
+
return {
|
|
159
|
+
instructions: bundle.instructions.trim().length > 0,
|
|
160
|
+
skills: { loaded: bundle.skills.length, total: bundle.skills.length + missingSkills },
|
|
161
|
+
tools: { loaded: bundle.tools.length, total: bundle.tools.length + missingTools }
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../portable/index.ts","../../matrx/transport.ts","../../matrx/internal.ts","../../portable/types.generated.ts"],"sourcesContent":["/**\n * `@ai-matrx/agents/portable` — an AI Matrx agent as pieces a coding CLI loads.\n *\n * `fetchPortableAgent` reads `POST /ai/agents/{id}/portable` (or the version\n * door) and returns the server's `PortableAgentBundle`: the instructions with\n * the person's variable values filled, the skills as Claude `SKILL.md` files,\n * the server tools in MCP shape, and `unavailable[]` — what could not be\n * carried and why. The types are GENERATED from the server's Pydantic models\n * (`types.generated.ts`, `uv run python scripts/generate_types.py portable-agent`\n * in aidream), so the two cannot drift.\n *\n * Pure entry: no React, no Node, no I/O at import. Credentials and the\n * organization travel through the host's `MatrxTransport`\n * (`createMatrxTransport({ credentials, organizationId })`).\n */\n\nimport { encodePathSegment, requestJson } from \"../matrx/internal\";\nimport type { MatrxTransport } from \"../matrx/transport\";\nimport type {\n JsonValue,\n PortableAgentBundle,\n PortableAgentRequest,\n} from \"./types.generated\";\n\nexport * from \"./types.generated\";\n\n/** Which definition to load: the agent's current one, or one immutable version. */\nexport type PortableAgentTarget =\n | { agentId: string; versionId?: undefined }\n | { versionId: string; agentId?: string | undefined };\n\nexport interface FetchPortableAgentOptions {\n /** The person's values, by variable name. Unfilled variables use the agent's defaults. */\n variables?: Record<string, JsonValue>;\n /** The `ui.ui_surface` tools resolve on. Default: the server's coding-session surface. */\n surface?: string;\n signal?: AbortSignal;\n}\n\n/** The server path for a target — exported so a host's tests can assert it. */\nexport function portableAgentPath(target: PortableAgentTarget): string {\n return target.versionId\n ? `/ai/agents/versions/${encodePathSegment(target.versionId)}/portable`\n : `/ai/agents/${encodePathSegment(target.agentId ?? \"\")}/portable`;\n}\n\n/**\n * Load one agent as a portable bundle. Throws `MatrxApiError` on refusal —\n * 401 signed out, 404 not found or not shared with this person.\n */\nexport function fetchPortableAgent(\n transport: MatrxTransport,\n target: PortableAgentTarget,\n options: FetchPortableAgentOptions = {},\n): Promise<PortableAgentBundle> {\n const body: PortableAgentRequest = {\n variables: options.variables ?? {},\n ...(options.surface ? { surface: options.surface } : {}),\n };\n return requestJson<PortableAgentBundle>(transport, portableAgentPath(target), {\n method: \"POST\",\n body,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n}\n\n/** One saved version of an agent (`AgentVersionInfo` server-side). */\nexport interface PortableAgentVersion {\n id: string;\n agent_id: string;\n version_number: number;\n name: string;\n change_note: string | null;\n changed_at: string | null;\n}\n\n/**\n * The agent's saved versions, oldest first (`GET /agent-service/agents/{id}/versions`,\n * authorized through the same viewer rule as the agent). Feeds a version menu.\n */\nexport function fetchPortableAgentVersions(\n transport: MatrxTransport,\n agentId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<PortableAgentVersion[]> {\n return requestJson<PortableAgentVersion[]>(\n transport,\n `/agent-service/agents/${encodePathSegment(agentId)}/versions`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n}\n\n/** What a bundle loaded, counted — what a header chip shows. */\nexport interface PortableAgentLoadSummary {\n instructions: boolean;\n skills: { loaded: number; total: number };\n tools: { loaded: number; total: number };\n}\n\n/** Count what a bundle carries against what the agent declares. */\nexport function summarizePortableAgent(bundle: PortableAgentBundle): PortableAgentLoadSummary {\n const missingSkills = bundle.unavailable.filter((u) => u.kind === \"skill\").length;\n const missingTools = bundle.unavailable.filter((u) => u.kind === \"tool\").length;\n return {\n instructions: bundle.instructions.trim().length > 0,\n skills: { loaded: bundle.skills.length, total: bundle.skills.length + missingSkills },\n tools: { loaded: bundle.tools.length, total: bundle.tools.length + missingTools },\n };\n}\n","/**\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 * 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","// AUTO-GENERATED — do not edit by hand.\n// Source: aidream/services/agent_service/portable.py\n// Run: uv run python scripts/generate_types.py portable-agent\n\nexport const PORTABLE_AGENT_CONTRACT = \"portable-agent.v1\";\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nexport interface PortableAgentRequest {\n variables?: Record<string, JsonValue>;\n surface?: string;\n}\n\nexport interface PortableSkill {\n id: string;\n tier: \"included\" | \"listed\";\n slug: string;\n label: string;\n description: string;\n path: string;\n content: string;\n body: string;\n content_hash: string;\n}\n\nexport interface PortableTool {\n name: string;\n canonical_name: string;\n description: string;\n parameters: Record<string, JsonValue>;\n}\n\nexport interface PortableUnavailable {\n kind: \"tool\" | \"skill\" | \"variable\" | \"message\" | \"mcp_server\" | \"tools\";\n name: string;\n reason: string;\n}\n\nexport interface PortableAgentBundle {\n contract: \"portable-agent.v1\";\n agent_id: string;\n version_id: string | null;\n version_number: number | null;\n is_version: boolean;\n name: string;\n definition_hash: string;\n model_id: string;\n instructions: string;\n variables: Record<string, JsonValue>[];\n filled_variables: string[];\n skills: PortableSkill[];\n tools: PortableTool[];\n surface: string;\n unavailable: PortableUnavailable[];\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { M as MatrxTransport } from '../transport-CxD0fL8p.cjs';
|
|
2
|
+
import { J as JsonValue, P as PortableAgentBundle } from '../types.generated-BydVlqDC.cjs';
|
|
3
|
+
export { a as PORTABLE_AGENT_CONTRACT, b as PortableAgentRequest, c as PortableSkill, d as PortableTool, e as PortableUnavailable } from '../types.generated-BydVlqDC.cjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `@ai-matrx/agents/portable` — an AI Matrx agent as pieces a coding CLI loads.
|
|
7
|
+
*
|
|
8
|
+
* `fetchPortableAgent` reads `POST /ai/agents/{id}/portable` (or the version
|
|
9
|
+
* door) and returns the server's `PortableAgentBundle`: the instructions with
|
|
10
|
+
* the person's variable values filled, the skills as Claude `SKILL.md` files,
|
|
11
|
+
* the server tools in MCP shape, and `unavailable[]` — what could not be
|
|
12
|
+
* carried and why. The types are GENERATED from the server's Pydantic models
|
|
13
|
+
* (`types.generated.ts`, `uv run python scripts/generate_types.py portable-agent`
|
|
14
|
+
* in aidream), so the two cannot drift.
|
|
15
|
+
*
|
|
16
|
+
* Pure entry: no React, no Node, no I/O at import. Credentials and the
|
|
17
|
+
* organization travel through the host's `MatrxTransport`
|
|
18
|
+
* (`createMatrxTransport({ credentials, organizationId })`).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Which definition to load: the agent's current one, or one immutable version. */
|
|
22
|
+
type PortableAgentTarget = {
|
|
23
|
+
agentId: string;
|
|
24
|
+
versionId?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
versionId: string;
|
|
27
|
+
agentId?: string | undefined;
|
|
28
|
+
};
|
|
29
|
+
interface FetchPortableAgentOptions {
|
|
30
|
+
/** The person's values, by variable name. Unfilled variables use the agent's defaults. */
|
|
31
|
+
variables?: Record<string, JsonValue>;
|
|
32
|
+
/** The `ui.ui_surface` tools resolve on. Default: the server's coding-session surface. */
|
|
33
|
+
surface?: string;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/** The server path for a target — exported so a host's tests can assert it. */
|
|
37
|
+
declare function portableAgentPath(target: PortableAgentTarget): string;
|
|
38
|
+
/**
|
|
39
|
+
* Load one agent as a portable bundle. Throws `MatrxApiError` on refusal —
|
|
40
|
+
* 401 signed out, 404 not found or not shared with this person.
|
|
41
|
+
*/
|
|
42
|
+
declare function fetchPortableAgent(transport: MatrxTransport, target: PortableAgentTarget, options?: FetchPortableAgentOptions): Promise<PortableAgentBundle>;
|
|
43
|
+
/** One saved version of an agent (`AgentVersionInfo` server-side). */
|
|
44
|
+
interface PortableAgentVersion {
|
|
45
|
+
id: string;
|
|
46
|
+
agent_id: string;
|
|
47
|
+
version_number: number;
|
|
48
|
+
name: string;
|
|
49
|
+
change_note: string | null;
|
|
50
|
+
changed_at: string | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The agent's saved versions, oldest first (`GET /agent-service/agents/{id}/versions`,
|
|
54
|
+
* authorized through the same viewer rule as the agent). Feeds a version menu.
|
|
55
|
+
*/
|
|
56
|
+
declare function fetchPortableAgentVersions(transport: MatrxTransport, agentId: string, options?: {
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}): Promise<PortableAgentVersion[]>;
|
|
59
|
+
/** What a bundle loaded, counted — what a header chip shows. */
|
|
60
|
+
interface PortableAgentLoadSummary {
|
|
61
|
+
instructions: boolean;
|
|
62
|
+
skills: {
|
|
63
|
+
loaded: number;
|
|
64
|
+
total: number;
|
|
65
|
+
};
|
|
66
|
+
tools: {
|
|
67
|
+
loaded: number;
|
|
68
|
+
total: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Count what a bundle carries against what the agent declares. */
|
|
72
|
+
declare function summarizePortableAgent(bundle: PortableAgentBundle): PortableAgentLoadSummary;
|
|
73
|
+
|
|
74
|
+
export { type FetchPortableAgentOptions, JsonValue, PortableAgentBundle, type PortableAgentLoadSummary, type PortableAgentTarget, type PortableAgentVersion, fetchPortableAgent, fetchPortableAgentVersions, portableAgentPath, summarizePortableAgent };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { M as MatrxTransport } from '../transport-CxD0fL8p.js';
|
|
2
|
+
import { J as JsonValue, P as PortableAgentBundle } from '../types.generated-BydVlqDC.js';
|
|
3
|
+
export { a as PORTABLE_AGENT_CONTRACT, b as PortableAgentRequest, c as PortableSkill, d as PortableTool, e as PortableUnavailable } from '../types.generated-BydVlqDC.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* `@ai-matrx/agents/portable` — an AI Matrx agent as pieces a coding CLI loads.
|
|
7
|
+
*
|
|
8
|
+
* `fetchPortableAgent` reads `POST /ai/agents/{id}/portable` (or the version
|
|
9
|
+
* door) and returns the server's `PortableAgentBundle`: the instructions with
|
|
10
|
+
* the person's variable values filled, the skills as Claude `SKILL.md` files,
|
|
11
|
+
* the server tools in MCP shape, and `unavailable[]` — what could not be
|
|
12
|
+
* carried and why. The types are GENERATED from the server's Pydantic models
|
|
13
|
+
* (`types.generated.ts`, `uv run python scripts/generate_types.py portable-agent`
|
|
14
|
+
* in aidream), so the two cannot drift.
|
|
15
|
+
*
|
|
16
|
+
* Pure entry: no React, no Node, no I/O at import. Credentials and the
|
|
17
|
+
* organization travel through the host's `MatrxTransport`
|
|
18
|
+
* (`createMatrxTransport({ credentials, organizationId })`).
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/** Which definition to load: the agent's current one, or one immutable version. */
|
|
22
|
+
type PortableAgentTarget = {
|
|
23
|
+
agentId: string;
|
|
24
|
+
versionId?: undefined;
|
|
25
|
+
} | {
|
|
26
|
+
versionId: string;
|
|
27
|
+
agentId?: string | undefined;
|
|
28
|
+
};
|
|
29
|
+
interface FetchPortableAgentOptions {
|
|
30
|
+
/** The person's values, by variable name. Unfilled variables use the agent's defaults. */
|
|
31
|
+
variables?: Record<string, JsonValue>;
|
|
32
|
+
/** The `ui.ui_surface` tools resolve on. Default: the server's coding-session surface. */
|
|
33
|
+
surface?: string;
|
|
34
|
+
signal?: AbortSignal;
|
|
35
|
+
}
|
|
36
|
+
/** The server path for a target — exported so a host's tests can assert it. */
|
|
37
|
+
declare function portableAgentPath(target: PortableAgentTarget): string;
|
|
38
|
+
/**
|
|
39
|
+
* Load one agent as a portable bundle. Throws `MatrxApiError` on refusal —
|
|
40
|
+
* 401 signed out, 404 not found or not shared with this person.
|
|
41
|
+
*/
|
|
42
|
+
declare function fetchPortableAgent(transport: MatrxTransport, target: PortableAgentTarget, options?: FetchPortableAgentOptions): Promise<PortableAgentBundle>;
|
|
43
|
+
/** One saved version of an agent (`AgentVersionInfo` server-side). */
|
|
44
|
+
interface PortableAgentVersion {
|
|
45
|
+
id: string;
|
|
46
|
+
agent_id: string;
|
|
47
|
+
version_number: number;
|
|
48
|
+
name: string;
|
|
49
|
+
change_note: string | null;
|
|
50
|
+
changed_at: string | null;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The agent's saved versions, oldest first (`GET /agent-service/agents/{id}/versions`,
|
|
54
|
+
* authorized through the same viewer rule as the agent). Feeds a version menu.
|
|
55
|
+
*/
|
|
56
|
+
declare function fetchPortableAgentVersions(transport: MatrxTransport, agentId: string, options?: {
|
|
57
|
+
signal?: AbortSignal;
|
|
58
|
+
}): Promise<PortableAgentVersion[]>;
|
|
59
|
+
/** What a bundle loaded, counted — what a header chip shows. */
|
|
60
|
+
interface PortableAgentLoadSummary {
|
|
61
|
+
instructions: boolean;
|
|
62
|
+
skills: {
|
|
63
|
+
loaded: number;
|
|
64
|
+
total: number;
|
|
65
|
+
};
|
|
66
|
+
tools: {
|
|
67
|
+
loaded: number;
|
|
68
|
+
total: number;
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
/** Count what a bundle carries against what the agent declares. */
|
|
72
|
+
declare function summarizePortableAgent(bundle: PortableAgentBundle): PortableAgentLoadSummary;
|
|
73
|
+
|
|
74
|
+
export { type FetchPortableAgentOptions, JsonValue, PortableAgentBundle, type PortableAgentLoadSummary, type PortableAgentTarget, type PortableAgentVersion, fetchPortableAgent, fetchPortableAgentVersions, portableAgentPath, summarizePortableAgent };
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
// matrx/transport.ts
|
|
2
|
+
var MatrxApiError = class extends Error {
|
|
3
|
+
name = "MatrxApiError";
|
|
4
|
+
/** HTTP status of the failed response. */
|
|
5
|
+
status;
|
|
6
|
+
/** Machine code from the server body (`code`, or `detail.code`), when present. */
|
|
7
|
+
code;
|
|
8
|
+
/** The parsed server error body, verbatim (undefined when unparsable). */
|
|
9
|
+
serverDetail;
|
|
10
|
+
/** The request path the failure came from (server-relative). */
|
|
11
|
+
path;
|
|
12
|
+
constructor(args) {
|
|
13
|
+
super(
|
|
14
|
+
args.message ?? extractMatrxErrorMessage(args.serverDetail) ?? `HTTP ${args.status}`
|
|
15
|
+
);
|
|
16
|
+
this.status = args.status;
|
|
17
|
+
this.path = args.path;
|
|
18
|
+
this.serverDetail = args.serverDetail;
|
|
19
|
+
this.code = extractMatrxErrorCode(args.serverDetail);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
function isRecord(value) {
|
|
23
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
|
+
}
|
|
25
|
+
function nonBlankString(value) {
|
|
26
|
+
return typeof value === "string" && value.trim() ? value : void 0;
|
|
27
|
+
}
|
|
28
|
+
function extractMatrxErrorMessage(serverDetail) {
|
|
29
|
+
if (!isRecord(serverDetail)) return void 0;
|
|
30
|
+
const userMessage = nonBlankString(serverDetail.user_message);
|
|
31
|
+
if (userMessage) return userMessage;
|
|
32
|
+
const message = nonBlankString(serverDetail.message);
|
|
33
|
+
if (message) return message;
|
|
34
|
+
if (Array.isArray(serverDetail.details)) {
|
|
35
|
+
const messages = serverDetail.details.map((entry) => {
|
|
36
|
+
if (!isRecord(entry)) return void 0;
|
|
37
|
+
const detailMessage = nonBlankString(entry.message);
|
|
38
|
+
if (!detailMessage) return void 0;
|
|
39
|
+
const field = nonBlankString(entry.field);
|
|
40
|
+
return field ? `${field}: ${detailMessage}` : detailMessage;
|
|
41
|
+
}).filter((m) => typeof m === "string");
|
|
42
|
+
if (messages.length > 0) return messages.join("; ");
|
|
43
|
+
}
|
|
44
|
+
const detail = serverDetail.detail;
|
|
45
|
+
if (isRecord(detail)) {
|
|
46
|
+
const detailMessage = nonBlankString(detail.message) ?? nonBlankString(detail.user_message);
|
|
47
|
+
if (detailMessage) return detailMessage;
|
|
48
|
+
}
|
|
49
|
+
if (typeof detail === "string" && detail.trim()) return detail;
|
|
50
|
+
if (Array.isArray(detail)) {
|
|
51
|
+
const messages = detail.map(
|
|
52
|
+
(entry) => isRecord(entry) ? nonBlankString(entry.msg) : void 0
|
|
53
|
+
).filter((m) => typeof m === "string");
|
|
54
|
+
if (messages.length > 0) return messages.join("; ");
|
|
55
|
+
}
|
|
56
|
+
return void 0;
|
|
57
|
+
}
|
|
58
|
+
function extractMatrxErrorCode(serverDetail) {
|
|
59
|
+
if (!isRecord(serverDetail)) return null;
|
|
60
|
+
const topLevel = nonBlankString(serverDetail.code);
|
|
61
|
+
if (topLevel) return topLevel;
|
|
62
|
+
const detail = serverDetail.detail;
|
|
63
|
+
if (isRecord(detail)) {
|
|
64
|
+
const nested = nonBlankString(detail.code);
|
|
65
|
+
if (nested) return nested;
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// matrx/internal.ts
|
|
71
|
+
function encodePathSegment(value) {
|
|
72
|
+
return encodeURIComponent(value);
|
|
73
|
+
}
|
|
74
|
+
async function readServerDetail(response) {
|
|
75
|
+
try {
|
|
76
|
+
return await response.json();
|
|
77
|
+
} catch {
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
async function throwApiError(path, response) {
|
|
82
|
+
throw new MatrxApiError({
|
|
83
|
+
status: response.status,
|
|
84
|
+
path,
|
|
85
|
+
serverDetail: await readServerDetail(response)
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
async function requestJson(transport, path, options) {
|
|
89
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
90
|
+
const response = await transport.fetch(path, {
|
|
91
|
+
method: options.method,
|
|
92
|
+
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
93
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
94
|
+
...options.signal ? { signal: options.signal } : {}
|
|
95
|
+
});
|
|
96
|
+
if (!response.ok) return throwApiError(path, response);
|
|
97
|
+
return await response.json();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// portable/types.generated.ts
|
|
101
|
+
var PORTABLE_AGENT_CONTRACT = "portable-agent.v1";
|
|
102
|
+
|
|
103
|
+
// portable/index.ts
|
|
104
|
+
function portableAgentPath(target) {
|
|
105
|
+
return target.versionId ? `/ai/agents/versions/${encodePathSegment(target.versionId)}/portable` : `/ai/agents/${encodePathSegment(target.agentId ?? "")}/portable`;
|
|
106
|
+
}
|
|
107
|
+
function fetchPortableAgent(transport, target, options = {}) {
|
|
108
|
+
const body = {
|
|
109
|
+
variables: options.variables ?? {},
|
|
110
|
+
...options.surface ? { surface: options.surface } : {}
|
|
111
|
+
};
|
|
112
|
+
return requestJson(transport, portableAgentPath(target), {
|
|
113
|
+
method: "POST",
|
|
114
|
+
body,
|
|
115
|
+
...options.signal ? { signal: options.signal } : {}
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function fetchPortableAgentVersions(transport, agentId, options = {}) {
|
|
119
|
+
return requestJson(
|
|
120
|
+
transport,
|
|
121
|
+
`/agent-service/agents/${encodePathSegment(agentId)}/versions`,
|
|
122
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
function summarizePortableAgent(bundle) {
|
|
126
|
+
const missingSkills = bundle.unavailable.filter((u) => u.kind === "skill").length;
|
|
127
|
+
const missingTools = bundle.unavailable.filter((u) => u.kind === "tool").length;
|
|
128
|
+
return {
|
|
129
|
+
instructions: bundle.instructions.trim().length > 0,
|
|
130
|
+
skills: { loaded: bundle.skills.length, total: bundle.skills.length + missingSkills },
|
|
131
|
+
tools: { loaded: bundle.tools.length, total: bundle.tools.length + missingTools }
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
export {
|
|
135
|
+
PORTABLE_AGENT_CONTRACT,
|
|
136
|
+
fetchPortableAgent,
|
|
137
|
+
fetchPortableAgentVersions,
|
|
138
|
+
portableAgentPath,
|
|
139
|
+
summarizePortableAgent
|
|
140
|
+
};
|
|
141
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../matrx/transport.ts","../../matrx/internal.ts","../../portable/types.generated.ts","../../portable/index.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 * 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","// AUTO-GENERATED — do not edit by hand.\n// Source: aidream/services/agent_service/portable.py\n// Run: uv run python scripts/generate_types.py portable-agent\n\nexport const PORTABLE_AGENT_CONTRACT = \"portable-agent.v1\";\n\nexport type JsonValue =\n | string\n | number\n | boolean\n | null\n | JsonValue[]\n | { [key: string]: JsonValue };\n\nexport interface PortableAgentRequest {\n variables?: Record<string, JsonValue>;\n surface?: string;\n}\n\nexport interface PortableSkill {\n id: string;\n tier: \"included\" | \"listed\";\n slug: string;\n label: string;\n description: string;\n path: string;\n content: string;\n body: string;\n content_hash: string;\n}\n\nexport interface PortableTool {\n name: string;\n canonical_name: string;\n description: string;\n parameters: Record<string, JsonValue>;\n}\n\nexport interface PortableUnavailable {\n kind: \"tool\" | \"skill\" | \"variable\" | \"message\" | \"mcp_server\" | \"tools\";\n name: string;\n reason: string;\n}\n\nexport interface PortableAgentBundle {\n contract: \"portable-agent.v1\";\n agent_id: string;\n version_id: string | null;\n version_number: number | null;\n is_version: boolean;\n name: string;\n definition_hash: string;\n model_id: string;\n instructions: string;\n variables: Record<string, JsonValue>[];\n filled_variables: string[];\n skills: PortableSkill[];\n tools: PortableTool[];\n surface: string;\n unavailable: PortableUnavailable[];\n}\n","/**\n * `@ai-matrx/agents/portable` — an AI Matrx agent as pieces a coding CLI loads.\n *\n * `fetchPortableAgent` reads `POST /ai/agents/{id}/portable` (or the version\n * door) and returns the server's `PortableAgentBundle`: the instructions with\n * the person's variable values filled, the skills as Claude `SKILL.md` files,\n * the server tools in MCP shape, and `unavailable[]` — what could not be\n * carried and why. The types are GENERATED from the server's Pydantic models\n * (`types.generated.ts`, `uv run python scripts/generate_types.py portable-agent`\n * in aidream), so the two cannot drift.\n *\n * Pure entry: no React, no Node, no I/O at import. Credentials and the\n * organization travel through the host's `MatrxTransport`\n * (`createMatrxTransport({ credentials, organizationId })`).\n */\n\nimport { encodePathSegment, requestJson } from \"../matrx/internal\";\nimport type { MatrxTransport } from \"../matrx/transport\";\nimport type {\n JsonValue,\n PortableAgentBundle,\n PortableAgentRequest,\n} from \"./types.generated\";\n\nexport * from \"./types.generated\";\n\n/** Which definition to load: the agent's current one, or one immutable version. */\nexport type PortableAgentTarget =\n | { agentId: string; versionId?: undefined }\n | { versionId: string; agentId?: string | undefined };\n\nexport interface FetchPortableAgentOptions {\n /** The person's values, by variable name. Unfilled variables use the agent's defaults. */\n variables?: Record<string, JsonValue>;\n /** The `ui.ui_surface` tools resolve on. Default: the server's coding-session surface. */\n surface?: string;\n signal?: AbortSignal;\n}\n\n/** The server path for a target — exported so a host's tests can assert it. */\nexport function portableAgentPath(target: PortableAgentTarget): string {\n return target.versionId\n ? `/ai/agents/versions/${encodePathSegment(target.versionId)}/portable`\n : `/ai/agents/${encodePathSegment(target.agentId ?? \"\")}/portable`;\n}\n\n/**\n * Load one agent as a portable bundle. Throws `MatrxApiError` on refusal —\n * 401 signed out, 404 not found or not shared with this person.\n */\nexport function fetchPortableAgent(\n transport: MatrxTransport,\n target: PortableAgentTarget,\n options: FetchPortableAgentOptions = {},\n): Promise<PortableAgentBundle> {\n const body: PortableAgentRequest = {\n variables: options.variables ?? {},\n ...(options.surface ? { surface: options.surface } : {}),\n };\n return requestJson<PortableAgentBundle>(transport, portableAgentPath(target), {\n method: \"POST\",\n body,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n}\n\n/** One saved version of an agent (`AgentVersionInfo` server-side). */\nexport interface PortableAgentVersion {\n id: string;\n agent_id: string;\n version_number: number;\n name: string;\n change_note: string | null;\n changed_at: string | null;\n}\n\n/**\n * The agent's saved versions, oldest first (`GET /agent-service/agents/{id}/versions`,\n * authorized through the same viewer rule as the agent). Feeds a version menu.\n */\nexport function fetchPortableAgentVersions(\n transport: MatrxTransport,\n agentId: string,\n options: { signal?: AbortSignal } = {},\n): Promise<PortableAgentVersion[]> {\n return requestJson<PortableAgentVersion[]>(\n transport,\n `/agent-service/agents/${encodePathSegment(agentId)}/versions`,\n { method: \"GET\", ...(options.signal ? { signal: options.signal } : {}) },\n );\n}\n\n/** What a bundle loaded, counted — what a header chip shows. */\nexport interface PortableAgentLoadSummary {\n instructions: boolean;\n skills: { loaded: number; total: number };\n tools: { loaded: number; total: number };\n}\n\n/** Count what a bundle carries against what the agent declares. */\nexport function summarizePortableAgent(bundle: PortableAgentBundle): PortableAgentLoadSummary {\n const missingSkills = bundle.unavailable.filter((u) => u.kind === \"skill\").length;\n const missingTools = bundle.unavailable.filter((u) => u.kind === \"tool\").length;\n return {\n instructions: bundle.instructions.trim().length > 0,\n skills: { loaded: bundle.skills.length, total: bundle.skills.length + missingSkills },\n tools: { loaded: bundle.tools.length, total: bundle.tools.length + missingTools },\n };\n}\n"],"mappings":"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","names":[]}
|