@ai-matrx/agents 0.35.0 → 0.37.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 +15 -0
- package/dist/content-transfer/index.cjs +12 -12
- package/dist/content-transfer/index.cjs.map +1 -1
- package/dist/content-transfer/index.d.cts +1 -1
- package/dist/content-transfer/index.d.ts +1 -1
- package/dist/content-transfer/index.js +12 -12
- package/dist/content-transfer/index.js.map +1 -1
- package/dist/content-transfer/react/index.cjs +12 -12
- package/dist/content-transfer/react/index.cjs.map +1 -1
- package/dist/content-transfer/react/index.d.cts +1 -1
- package/dist/content-transfer/react/index.d.ts +1 -1
- package/dist/content-transfer/react/index.js +12 -12
- package/dist/content-transfer/react/index.js.map +1 -1
- package/dist/index.cjs +1458 -1220
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1461 -1223
- package/dist/index.js.map +1 -1
- package/dist/{keys.generated-BLDTm66e.d.cts → keys.generated-klzs6I1T.d.cts} +4 -4
- package/dist/{keys.generated-BLDTm66e.d.ts → keys.generated-klzs6I1T.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 +1721 -1483
- package/dist/matrx/index.cjs.map +1 -1
- package/dist/matrx/index.d.cts +376 -211
- package/dist/matrx/index.d.ts +376 -211
- package/dist/matrx/index.js +1724 -1486
- package/dist/matrx/index.js.map +1 -1
- package/dist/message-parts/index.cjs +27 -0
- package/dist/message-parts/index.cjs.map +1 -0
- package/dist/message-parts/index.d.cts +105 -0
- package/dist/message-parts/index.d.ts +105 -0
- package/dist/message-parts/index.js +6 -0
- package/dist/message-parts/index.js.map +1 -0
- package/dist/portable/mcp.cjs +99 -11
- package/dist/portable/mcp.cjs.map +1 -1
- package/dist/portable/mcp.js +99 -11
- package/dist/portable/mcp.js.map +1 -1
- package/dist/react/index.cjs +145 -57
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +3 -1
- package/dist/react/index.d.ts +3 -1
- package/dist/react/index.js +145 -57
- package/dist/react/index.js.map +1 -1
- package/mandates/snapshots/keys.0.36.0.json +653 -0
- package/mandates/snapshots/keys.0.37.0.json +653 -0
- package/package.json +13 -3
- package/dist/{operations-BT5kKMHl.d.cts → operations-DqOe2zob.d.cts} +34 -34
- package/dist/{operations-BT5kKMHl.d.ts → operations-DqOe2zob.d.ts} +34 -34
package/dist/matrx/index.js
CHANGED
|
@@ -70,1669 +70,1896 @@ function extractMatrxErrorCode(serverDetail) {
|
|
|
70
70
|
// matrx/client.ts
|
|
71
71
|
import { isNetError as isNetError2 } from "@ai-matrx/data";
|
|
72
72
|
import { credentialToHeaders } from "@ai-matrx/data";
|
|
73
|
+
import { extractErrorMessage } from "@ai-matrx/data/net";
|
|
73
74
|
|
|
74
|
-
// matrx/
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
// matrx/backend-errors.ts
|
|
76
|
+
var BackendApiError = class extends Error {
|
|
77
|
+
/** Machine-readable error code */
|
|
77
78
|
code;
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
/** Developer-facing detail */
|
|
80
|
+
detail;
|
|
81
|
+
/** Safe to display directly in the UI */
|
|
82
|
+
userMessage;
|
|
83
|
+
/** Extra info (validation errors, etc.) */
|
|
84
|
+
details;
|
|
85
|
+
/** Unique request ID for support/debugging */
|
|
86
|
+
requestId;
|
|
87
|
+
/** HTTP status code (if from an HTTP response) */
|
|
88
|
+
status;
|
|
89
|
+
constructor(data) {
|
|
90
|
+
super(data.userMessage);
|
|
91
|
+
this.name = "BackendApiError";
|
|
92
|
+
this.code = data.code;
|
|
93
|
+
this.detail = data.detail;
|
|
94
|
+
this.userMessage = data.userMessage;
|
|
95
|
+
this.details = data.details ?? null;
|
|
96
|
+
this.requestId = data.requestId ?? "";
|
|
97
|
+
this.status = data.status ?? null;
|
|
98
|
+
}
|
|
99
|
+
/** Convert to the wire format for logging */
|
|
100
|
+
toJSON() {
|
|
101
|
+
return {
|
|
102
|
+
error: this.code,
|
|
103
|
+
message: this.detail,
|
|
104
|
+
user_message: this.userMessage,
|
|
105
|
+
details: this.details,
|
|
106
|
+
request_id: this.requestId
|
|
107
|
+
};
|
|
82
108
|
}
|
|
83
109
|
};
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
110
|
+
var StreamTransportError = class extends BackendApiError {
|
|
111
|
+
/** Always true — reattach and let the server settle the outcome. */
|
|
112
|
+
resumable = true;
|
|
113
|
+
constructor(data) {
|
|
114
|
+
super({
|
|
115
|
+
code: "stream_transport_lost",
|
|
116
|
+
detail: data.detail,
|
|
117
|
+
userMessage: "The connection dropped. Your run is still going on the server \u2014 reconnecting to it now.",
|
|
118
|
+
details: data.details ?? null,
|
|
119
|
+
...data.requestId !== void 0 ? { requestId: data.requestId } : {}
|
|
120
|
+
});
|
|
121
|
+
this.name = "StreamTransportError";
|
|
94
122
|
}
|
|
95
|
-
}
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
if (
|
|
99
|
-
|
|
100
|
-
"organization_context_required",
|
|
101
|
-
"Select an organization before sending this request."
|
|
102
|
-
);
|
|
123
|
+
};
|
|
124
|
+
function isStreamTransportLost(error) {
|
|
125
|
+
if (error instanceof StreamTransportError) return true;
|
|
126
|
+
if (error instanceof BackendApiError) {
|
|
127
|
+
return error.code === "stream_transport_lost";
|
|
103
128
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
);
|
|
129
|
+
if (error && typeof error === "object") {
|
|
130
|
+
const code = error.code;
|
|
131
|
+
if (code === "stream_transport_lost") return true;
|
|
132
|
+
const errorType = error.error_type;
|
|
133
|
+
if (errorType === "transport_lost") return true;
|
|
110
134
|
}
|
|
111
|
-
return
|
|
135
|
+
return false;
|
|
112
136
|
}
|
|
113
|
-
function
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
);
|
|
137
|
+
async function parseHttpError(response) {
|
|
138
|
+
const status = response.status;
|
|
139
|
+
let body = null;
|
|
140
|
+
try {
|
|
141
|
+
body = await response.json();
|
|
142
|
+
} catch {
|
|
143
|
+
try {
|
|
144
|
+
const text = await response.text();
|
|
145
|
+
return new BackendApiError({
|
|
146
|
+
code: statusToCode(status),
|
|
147
|
+
detail: text || `HTTP ${status}`,
|
|
148
|
+
userMessage: text || `Request failed (${status})`,
|
|
149
|
+
status
|
|
150
|
+
});
|
|
151
|
+
} catch {
|
|
152
|
+
return new BackendApiError({
|
|
153
|
+
code: statusToCode(status),
|
|
154
|
+
detail: `HTTP ${status}`,
|
|
155
|
+
userMessage: `Request failed (${status})`,
|
|
156
|
+
status
|
|
157
|
+
});
|
|
121
158
|
}
|
|
122
159
|
}
|
|
123
|
-
|
|
124
|
-
Object.entries(headers).filter(
|
|
125
|
-
([name]) => name.toLowerCase() !== "x-organization-id"
|
|
126
|
-
)
|
|
127
|
-
);
|
|
128
|
-
return {
|
|
129
|
-
...withoutOrganizationHeader,
|
|
130
|
-
"X-Organization-Id": normalizedOrganizationId
|
|
131
|
-
};
|
|
132
|
-
}
|
|
133
|
-
function assertQueryOrganizationMatchesContext(queryParams, organizationId) {
|
|
134
|
-
if (!queryParams || queryParams.organization_id === void 0) return;
|
|
135
|
-
const queryOrganizationId = requireOrganizationContext(
|
|
136
|
-
String(queryParams.organization_id)
|
|
137
|
-
);
|
|
138
|
-
if (queryOrganizationId !== requireOrganizationContext(organizationId)) {
|
|
139
|
-
throw new OrganizationContextError(
|
|
140
|
-
"organization_context_mismatch",
|
|
141
|
-
"Query organization_id must match the request context organization."
|
|
142
|
-
);
|
|
143
|
-
}
|
|
160
|
+
return parseHttpErrorBody(body, status);
|
|
144
161
|
}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
"/ai/manual",
|
|
154
|
-
"/ai/chat",
|
|
155
|
-
"/ai/agents/{agent_id}",
|
|
156
|
-
"/ai/agent/{agent_id}",
|
|
157
|
-
// singular alias — behaves identically
|
|
158
|
-
"/ai/conversations/{conversation_id}",
|
|
159
|
-
"/ai/conversation/{conversation_id}",
|
|
160
|
-
// singular alias
|
|
161
|
-
"/ai/prompts/{prompt_id}",
|
|
162
|
-
// saved-prompt execution
|
|
163
|
-
"/ai/mandates/{mandate_key}"
|
|
164
|
-
// THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)
|
|
165
|
-
];
|
|
166
|
-
function toV2Path(path) {
|
|
167
|
-
const withLead = path.startsWith("/") ? path : `/${path}`;
|
|
168
|
-
if (withLead.startsWith("/api/")) {
|
|
169
|
-
const rest = withLead.slice("/api".length);
|
|
170
|
-
return rest.startsWith("/v2/") ? withLead : `/api/v2${rest}`;
|
|
162
|
+
function parseHttpErrorBody(body, status) {
|
|
163
|
+
if (!body) {
|
|
164
|
+
return new BackendApiError({
|
|
165
|
+
code: statusToCode(status),
|
|
166
|
+
detail: `HTTP ${status}`,
|
|
167
|
+
userMessage: `Request failed (${status})`,
|
|
168
|
+
status
|
|
169
|
+
});
|
|
171
170
|
}
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
/^(?:\/api)?\/ai\/prompts\/[^/]+$/,
|
|
182
|
-
// `/warm` etc. deliberately don't match
|
|
183
|
-
/^(?:\/api)?\/ai\/mandates\/[^/]+$/
|
|
184
|
-
// the mandate door
|
|
185
|
-
];
|
|
186
|
-
function isCoveredAiPath(path) {
|
|
187
|
-
return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));
|
|
188
|
-
}
|
|
189
|
-
function isV2Path(pathOrUrl) {
|
|
190
|
-
return /\/v2\/ai\//.test(pathOrUrl);
|
|
191
|
-
}
|
|
192
|
-
function toV1FallbackUrl(url) {
|
|
193
|
-
return url.replace(/\/v2\/ai\//, "/ai/");
|
|
194
|
-
}
|
|
195
|
-
function applyAiApiVersion(path, version) {
|
|
196
|
-
if (version !== "v2") return path;
|
|
197
|
-
return isCoveredAiPath(path) ? toV2Path(path) : path;
|
|
198
|
-
}
|
|
199
|
-
async function fetchWithMatrxProtocolFallback(url, init, opts = {}) {
|
|
200
|
-
const { onDowngrade, ...fetchOpts } = opts;
|
|
201
|
-
const logDowngrade = (reason, status2) => {
|
|
202
|
-
console.warn(
|
|
203
|
-
`[matrx] ai_v2_downgrade \u2192 retrying on v1. v2=${url} reason=${reason}`
|
|
204
|
-
);
|
|
205
|
-
onDowngrade?.({ url, reason, ...status2 !== void 0 ? { status: status2 } : {} });
|
|
206
|
-
};
|
|
207
|
-
if (!isV2Path(url)) return resilientFetch(url, init, fetchOpts);
|
|
208
|
-
let result;
|
|
209
|
-
try {
|
|
210
|
-
result = await resilientFetch(url, init, fetchOpts);
|
|
211
|
-
} catch (err) {
|
|
212
|
-
const isAbort = isNetError(err) && err.code === "aborted" || err instanceof Error && err.name === "AbortError";
|
|
213
|
-
if (isAbort) throw err;
|
|
214
|
-
logDowngrade(String(err));
|
|
215
|
-
return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);
|
|
171
|
+
if (typeof body.error === "string" && typeof body.user_message === "string") {
|
|
172
|
+
return new BackendApiError({
|
|
173
|
+
code: body.error,
|
|
174
|
+
detail: body.message || `HTTP ${status}`,
|
|
175
|
+
userMessage: body.user_message,
|
|
176
|
+
details: body.details ?? null,
|
|
177
|
+
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
178
|
+
status
|
|
179
|
+
});
|
|
216
180
|
}
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
181
|
+
if (typeof body.error === "object" && body.error !== null) {
|
|
182
|
+
const errorObj = body.error;
|
|
183
|
+
return new BackendApiError({
|
|
184
|
+
code: errorObj.type || errorObj.error || statusToCode(status),
|
|
185
|
+
detail: errorObj.message || `HTTP ${status}`,
|
|
186
|
+
userMessage: errorObj.user_message || errorObj.user_visible_message || errorObj.message || `Request failed (${status})`,
|
|
187
|
+
details: errorObj.details ?? null,
|
|
188
|
+
requestId: typeof errorObj.request_id === "string" ? errorObj.request_id : void 0,
|
|
189
|
+
status
|
|
190
|
+
});
|
|
221
191
|
}
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
192
|
+
if (Array.isArray(body.detail)) {
|
|
193
|
+
const first = body.detail[0];
|
|
194
|
+
const firstMsg = first && typeof first.msg === "string" ? first.msg : null;
|
|
195
|
+
return new BackendApiError({
|
|
196
|
+
code: statusToCode(status),
|
|
197
|
+
detail: firstMsg ? `Validation error: ${firstMsg}` : JSON.stringify(body.detail),
|
|
198
|
+
userMessage: firstMsg || `Request failed (${status})`,
|
|
199
|
+
details: body.detail,
|
|
200
|
+
status
|
|
201
|
+
});
|
|
229
202
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
status: err.status,
|
|
243
|
-
serverDetail: err.serverDetail,
|
|
244
|
-
...err.code ? { code: err.code } : {},
|
|
245
|
-
name: err.name
|
|
246
|
-
};
|
|
247
|
-
}
|
|
248
|
-
if (err instanceof OrganizationContextError) {
|
|
249
|
-
return {
|
|
250
|
-
type: "validation_error",
|
|
251
|
-
message: err.message,
|
|
252
|
-
code: err.code,
|
|
253
|
-
name: err.name,
|
|
254
|
-
...err.stack !== void 0 ? { stack: err.stack } : {}
|
|
255
|
-
};
|
|
256
|
-
}
|
|
257
|
-
if (err instanceof DOMException && err.name === "AbortError") {
|
|
258
|
-
return { type: "abort_error", message: "Request was cancelled." };
|
|
259
|
-
}
|
|
260
|
-
if (isNetError2(err)) {
|
|
261
|
-
if (err.code === "aborted") {
|
|
262
|
-
return { type: "abort_error", message: err.message };
|
|
263
|
-
}
|
|
264
|
-
if (err.code === "http") {
|
|
265
|
-
const status = err.status ?? 0;
|
|
266
|
-
return { type: classifyStatus(status), message: err.message, status };
|
|
267
|
-
}
|
|
268
|
-
return { type: "network_error", message: err.message };
|
|
269
|
-
}
|
|
270
|
-
if (err instanceof Error) {
|
|
271
|
-
const httpMatch = err.message.match(/HTTP (\d+):\s*(.*)/);
|
|
272
|
-
if (httpMatch) {
|
|
273
|
-
const status = parseInt(httpMatch[1], 10);
|
|
274
|
-
return {
|
|
275
|
-
type: classifyStatus(status),
|
|
276
|
-
message: httpMatch[2] ?? err.message,
|
|
277
|
-
status
|
|
278
|
-
};
|
|
279
|
-
}
|
|
280
|
-
return { type: "network_error", message: err.message };
|
|
281
|
-
}
|
|
282
|
-
return { type: "unknown", message: String(err ?? "Unknown error") };
|
|
283
|
-
}
|
|
284
|
-
var PRODUCTION_CONNECT_TIMEOUT_MS = 15e3;
|
|
285
|
-
function stripContentType(headers) {
|
|
286
|
-
return Object.fromEntries(
|
|
287
|
-
Object.entries(headers).filter(
|
|
288
|
-
([name]) => name.toLowerCase() !== "content-type"
|
|
289
|
-
)
|
|
290
|
-
);
|
|
291
|
-
}
|
|
292
|
-
function createMatrxTransport(options) {
|
|
293
|
-
const {
|
|
294
|
-
baseUrl,
|
|
295
|
-
resolveTarget,
|
|
296
|
-
credentials,
|
|
297
|
-
organizationId,
|
|
298
|
-
aiApiVersion,
|
|
299
|
-
connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,
|
|
300
|
-
totalTimeoutMs = null,
|
|
301
|
-
expectedErrorStatuses,
|
|
302
|
-
diagnostics,
|
|
303
|
-
source = "matrxTransport"
|
|
304
|
-
} = options;
|
|
305
|
-
if (baseUrl === void 0 === (resolveTarget === void 0)) {
|
|
306
|
-
throw new Error(
|
|
307
|
-
"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`."
|
|
308
|
-
);
|
|
203
|
+
if (typeof body.detail === "object" && body.detail !== null && !Array.isArray(body.detail)) {
|
|
204
|
+
const d = body.detail;
|
|
205
|
+
const code = typeof d.code === "string" && d.code || typeof d.error === "string" && d.error || statusToCode(status);
|
|
206
|
+
const message = typeof d.message === "string" && d.message || typeof d.detail === "string" && d.detail || `HTTP ${status}`;
|
|
207
|
+
return new BackendApiError({
|
|
208
|
+
code,
|
|
209
|
+
detail: message,
|
|
210
|
+
userMessage: typeof d.user_message === "string" && d.user_message || typeof d.user_visible_message === "string" && d.user_visible_message || message,
|
|
211
|
+
details: d.details ?? d,
|
|
212
|
+
requestId: typeof d.request_id === "string" ? d.request_id : void 0,
|
|
213
|
+
status
|
|
214
|
+
});
|
|
309
215
|
}
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
return requireOrganizationContext(candidate);
|
|
319
|
-
};
|
|
320
|
-
return {
|
|
321
|
-
async fetch(path, init) {
|
|
322
|
-
const target = resolve();
|
|
323
|
-
const versionedPath = applyAiApiVersion(path, resolveVersion());
|
|
324
|
-
const url = `${target.baseUrl}${versionedPath}`;
|
|
325
|
-
const credentialHeaders = credentials ? credentialToHeaders(await credentials.get()) : {};
|
|
326
|
-
let headers = {
|
|
327
|
-
...init.headers,
|
|
328
|
-
...stripContentType(credentialHeaders),
|
|
329
|
-
...stripContentType(target.policyHeaders ?? {})
|
|
330
|
-
};
|
|
331
|
-
const orgId = resolveOrganizationId();
|
|
332
|
-
if (orgId !== null) {
|
|
333
|
-
headers = applyOrganizationContextHeader(headers, orgId);
|
|
334
|
-
}
|
|
335
|
-
const info = {
|
|
336
|
-
url,
|
|
337
|
-
method: init.method,
|
|
338
|
-
path,
|
|
339
|
-
channel: target.channel ?? "default",
|
|
340
|
-
source
|
|
341
|
-
};
|
|
342
|
-
diagnostics?.onRequest?.(info);
|
|
343
|
-
let response;
|
|
344
|
-
try {
|
|
345
|
-
({ response } = await fetchWithMatrxProtocolFallback(
|
|
346
|
-
url,
|
|
347
|
-
{
|
|
348
|
-
method: init.method,
|
|
349
|
-
headers,
|
|
350
|
-
...init.body !== void 0 ? { body: init.body } : {}
|
|
351
|
-
},
|
|
352
|
-
{
|
|
353
|
-
...init.signal ? { signal: init.signal } : {},
|
|
354
|
-
connectTimeoutMs,
|
|
355
|
-
totalTimeoutMs,
|
|
356
|
-
throwOnHttpError: false,
|
|
357
|
-
...diagnostics?.onProtocolDowngrade ? { onDowngrade: diagnostics.onProtocolDowngrade } : {}
|
|
358
|
-
}
|
|
359
|
-
));
|
|
360
|
-
} catch (err) {
|
|
361
|
-
diagnostics?.onError?.(normalizeMatrxError(err), info);
|
|
362
|
-
throw err;
|
|
363
|
-
}
|
|
364
|
-
if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {
|
|
365
|
-
const serverDetail = await response.clone().json().catch(() => void 0);
|
|
366
|
-
const code = extractMatrxErrorCode(serverDetail);
|
|
367
|
-
diagnostics?.onError?.(
|
|
368
|
-
{
|
|
369
|
-
type: classifyStatus(response.status),
|
|
370
|
-
message: extractMatrxErrorMessage(serverDetail) ?? `HTTP ${response.status}`,
|
|
371
|
-
status: response.status,
|
|
372
|
-
serverDetail,
|
|
373
|
-
...code ? { code } : {}
|
|
374
|
-
},
|
|
375
|
-
info
|
|
376
|
-
);
|
|
377
|
-
}
|
|
378
|
-
return response;
|
|
379
|
-
}
|
|
380
|
-
};
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// matrx/conversation.ts
|
|
384
|
-
function mintMatrxConversationId() {
|
|
385
|
-
return crypto.randomUUID();
|
|
386
|
-
}
|
|
387
|
-
function newStoredConversationStart(conversationId) {
|
|
388
|
-
return {
|
|
389
|
-
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
390
|
-
is_new: true,
|
|
391
|
-
store: true
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
function continueStoredConversationStart(conversationId) {
|
|
395
|
-
return { conversation_id: conversationId, is_new: false, store: true };
|
|
396
|
-
}
|
|
397
|
-
function newEphemeralConversationStart(conversationId) {
|
|
398
|
-
return {
|
|
399
|
-
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
400
|
-
is_new: true,
|
|
401
|
-
store: false
|
|
402
|
-
};
|
|
403
|
-
}
|
|
404
|
-
function continueEphemeralConversationStart(conversationId, priorMessages) {
|
|
405
|
-
return {
|
|
406
|
-
conversation_id: conversationId,
|
|
407
|
-
is_new: false,
|
|
408
|
-
store: false,
|
|
409
|
-
prior_messages: priorMessages
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
// stream/ndjson.ts
|
|
414
|
-
var DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;
|
|
415
|
-
function isRecord2(value) {
|
|
416
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
216
|
+
return new BackendApiError({
|
|
217
|
+
code: typeof body.error === "string" ? body.error : statusToCode(status),
|
|
218
|
+
detail: body.message || body.detail || body.error || `HTTP ${status}`,
|
|
219
|
+
userMessage: body.user_message || body.user_visible_message || body.message || body.detail || `Request failed (${status})`,
|
|
220
|
+
details: body.details ?? null,
|
|
221
|
+
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
222
|
+
status
|
|
223
|
+
});
|
|
417
224
|
}
|
|
418
|
-
function
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
423
|
-
return {
|
|
424
|
-
event: value.event,
|
|
425
|
-
data: value.data,
|
|
426
|
-
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
427
|
-
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
428
|
-
};
|
|
429
|
-
}
|
|
430
|
-
if (value.e === "c" && typeof value.t === "string") {
|
|
431
|
-
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
432
|
-
const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
|
|
433
|
-
return {
|
|
434
|
-
event: "chunk",
|
|
435
|
-
data: { text: value.t },
|
|
436
|
-
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
437
|
-
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
if (value.e === "r" && typeof value.t === "string") {
|
|
441
|
-
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
442
|
-
const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
|
|
443
|
-
return {
|
|
444
|
-
event: "reasoning_chunk",
|
|
445
|
-
data: { text: value.t },
|
|
446
|
-
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
447
|
-
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
448
|
-
};
|
|
449
|
-
}
|
|
450
|
-
return null;
|
|
225
|
+
function parseCallApiError(error) {
|
|
226
|
+
const status = error.status ?? 500;
|
|
227
|
+
const body = error.serverDetail && typeof error.serverDetail === "object" && !Array.isArray(error.serverDetail) ? error.serverDetail : { message: error.message };
|
|
228
|
+
return parseHttpErrorBody(body, status);
|
|
451
229
|
}
|
|
452
|
-
function
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
if (finished) throw new Error("Matrx NDJSON framer is already finished");
|
|
459
|
-
};
|
|
460
|
-
const parseLine = (line, atCompletion) => {
|
|
461
|
-
const currentLineNumber = ++lineNumber;
|
|
462
|
-
const trimmed = line.trim();
|
|
463
|
-
if (!trimmed) return null;
|
|
464
|
-
let parsed;
|
|
465
|
-
try {
|
|
466
|
-
parsed = JSON.parse(trimmed);
|
|
467
|
-
} catch (error) {
|
|
468
|
-
options.onMalformedLine?.({
|
|
469
|
-
line: trimmed,
|
|
470
|
-
error,
|
|
471
|
-
lineNumber: currentLineNumber,
|
|
472
|
-
atCompletion
|
|
473
|
-
});
|
|
474
|
-
return null;
|
|
475
|
-
}
|
|
476
|
-
const envelope = normalizeMatrxStreamEnvelope(parsed);
|
|
477
|
-
if (!envelope) {
|
|
478
|
-
options.onUnknownEnvelope?.(parsed);
|
|
479
|
-
return null;
|
|
480
|
-
}
|
|
481
|
-
options.onValidEnvelope?.({
|
|
482
|
-
raw: parsed,
|
|
483
|
-
envelope,
|
|
484
|
-
line: trimmed,
|
|
485
|
-
lineNumber: currentLineNumber,
|
|
486
|
-
atCompletion
|
|
230
|
+
function parseStreamError(data) {
|
|
231
|
+
if (!data || typeof data !== "object") {
|
|
232
|
+
return new BackendApiError({
|
|
233
|
+
code: "internal_error",
|
|
234
|
+
detail: typeof data === "string" ? data : "Unknown streaming error",
|
|
235
|
+
userMessage: typeof data === "string" ? data : "Something went wrong"
|
|
487
236
|
});
|
|
488
|
-
return envelope;
|
|
489
|
-
};
|
|
490
|
-
const pushDecodedText = (fragment) => {
|
|
491
|
-
buffer += fragment;
|
|
492
|
-
const lines = buffer.split("\n");
|
|
493
|
-
buffer = lines.pop() ?? "";
|
|
494
|
-
const envelopes = [];
|
|
495
|
-
for (const line of lines) {
|
|
496
|
-
const envelope = parseLine(line, false);
|
|
497
|
-
if (envelope) envelopes.push(envelope);
|
|
498
|
-
}
|
|
499
|
-
return envelopes;
|
|
500
|
-
};
|
|
501
|
-
return {
|
|
502
|
-
pushText(fragment) {
|
|
503
|
-
assertOpen();
|
|
504
|
-
return pushDecodedText(decoder.decode() + fragment);
|
|
505
|
-
},
|
|
506
|
-
pushBytes(fragment) {
|
|
507
|
-
assertOpen();
|
|
508
|
-
return pushDecodedText(decoder.decode(fragment, { stream: true }));
|
|
509
|
-
},
|
|
510
|
-
finish() {
|
|
511
|
-
assertOpen();
|
|
512
|
-
finished = true;
|
|
513
|
-
const envelopes = pushDecodedText(decoder.decode());
|
|
514
|
-
if (buffer.length > 0) {
|
|
515
|
-
const envelope = parseLine(buffer, true);
|
|
516
|
-
buffer = "";
|
|
517
|
-
if (envelope) envelopes.push(envelope);
|
|
518
|
-
}
|
|
519
|
-
return envelopes;
|
|
520
|
-
}
|
|
521
|
-
};
|
|
522
|
-
}
|
|
523
|
-
function readAheadLimit(value) {
|
|
524
|
-
const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;
|
|
525
|
-
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
526
|
-
throw new RangeError("maxReadAhead must be a positive safe integer");
|
|
527
|
-
}
|
|
528
|
-
return limit;
|
|
529
|
-
}
|
|
530
|
-
async function* readMatrxNdjsonStream(body, options = {}) {
|
|
531
|
-
const maxReadAhead = readAheadLimit(options.maxReadAhead);
|
|
532
|
-
const queue = [];
|
|
533
|
-
let queuedEventCount = 0;
|
|
534
|
-
let wakeConsumer = null;
|
|
535
|
-
let wakeProducer = null;
|
|
536
|
-
let readerFinished = false;
|
|
537
|
-
let consumerClosed = false;
|
|
538
|
-
const wakeWaitingConsumer = () => {
|
|
539
|
-
const wake = wakeConsumer;
|
|
540
|
-
wakeConsumer = null;
|
|
541
|
-
wake?.();
|
|
542
|
-
};
|
|
543
|
-
const wakeWaitingProducer = () => {
|
|
544
|
-
const wake = wakeProducer;
|
|
545
|
-
wakeProducer = null;
|
|
546
|
-
wake?.();
|
|
547
|
-
};
|
|
548
|
-
const enqueueTerminal = (item) => {
|
|
549
|
-
if (consumerClosed) return;
|
|
550
|
-
queue.push(item);
|
|
551
|
-
wakeWaitingConsumer();
|
|
552
|
-
};
|
|
553
|
-
const enqueueEvent = async (value) => {
|
|
554
|
-
while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
|
|
555
|
-
await new Promise((resolve) => {
|
|
556
|
-
wakeProducer = resolve;
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
if (consumerClosed || options.signal?.aborted) return false;
|
|
560
|
-
queue.push({ kind: "event", value });
|
|
561
|
-
queuedEventCount += 1;
|
|
562
|
-
wakeWaitingConsumer();
|
|
563
|
-
return true;
|
|
564
|
-
};
|
|
565
|
-
const waitForReadCapacity = async () => {
|
|
566
|
-
while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
|
|
567
|
-
await new Promise((resolve) => {
|
|
568
|
-
wakeProducer = resolve;
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
return !consumerClosed && !options.signal?.aborted;
|
|
572
|
-
};
|
|
573
|
-
const reader = body.getReader();
|
|
574
|
-
const framer = createMatrxNdjsonFramer(options);
|
|
575
|
-
const onAbort = () => {
|
|
576
|
-
wakeWaitingProducer();
|
|
577
|
-
wakeWaitingConsumer();
|
|
578
|
-
void reader.cancel(options.signal?.reason).catch(() => void 0);
|
|
579
|
-
};
|
|
580
|
-
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
581
|
-
if (options.signal?.aborted) onAbort();
|
|
582
|
-
const readerPromise = (async () => {
|
|
583
|
-
try {
|
|
584
|
-
while (!options.signal?.aborted && !consumerClosed) {
|
|
585
|
-
if (!await waitForReadCapacity()) return;
|
|
586
|
-
const { value, done } = await reader.read();
|
|
587
|
-
if (done) break;
|
|
588
|
-
for (const envelope of framer.pushBytes(value)) {
|
|
589
|
-
if (!await enqueueEvent(envelope)) return;
|
|
590
|
-
}
|
|
591
|
-
}
|
|
592
|
-
if (!options.signal?.aborted && !consumerClosed) {
|
|
593
|
-
for (const envelope of framer.finish()) {
|
|
594
|
-
if (!await enqueueEvent(envelope)) return;
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
} catch (error) {
|
|
598
|
-
const aborted = options.signal?.aborted || consumerClosed || error instanceof Error && error.name === "AbortError";
|
|
599
|
-
if (!aborted) enqueueTerminal({ kind: "error", error });
|
|
600
|
-
} finally {
|
|
601
|
-
readerFinished = true;
|
|
602
|
-
reader.releaseLock();
|
|
603
|
-
enqueueTerminal({ kind: "done" });
|
|
604
|
-
}
|
|
605
|
-
})();
|
|
606
|
-
try {
|
|
607
|
-
while (true) {
|
|
608
|
-
if (queue.length === 0) {
|
|
609
|
-
if (options.signal?.aborted || readerFinished) return;
|
|
610
|
-
await new Promise((resolve) => {
|
|
611
|
-
wakeConsumer = resolve;
|
|
612
|
-
});
|
|
613
|
-
}
|
|
614
|
-
const item = queue.shift();
|
|
615
|
-
if (item?.kind === "event") queuedEventCount -= 1;
|
|
616
|
-
wakeWaitingProducer();
|
|
617
|
-
if (!item || item.kind === "done") return;
|
|
618
|
-
if (item.kind === "error") throw item.error;
|
|
619
|
-
yield item.value;
|
|
620
|
-
}
|
|
621
|
-
} finally {
|
|
622
|
-
consumerClosed = true;
|
|
623
|
-
wakeWaitingProducer();
|
|
624
|
-
wakeWaitingConsumer();
|
|
625
|
-
options.signal?.removeEventListener("abort", onAbort);
|
|
626
|
-
if (!readerFinished) {
|
|
627
|
-
await reader.cancel().catch(() => void 0);
|
|
628
|
-
}
|
|
629
|
-
await readerPromise;
|
|
630
237
|
}
|
|
238
|
+
const obj = data;
|
|
239
|
+
const details = typeof obj.details === "object" && obj.details !== null ? obj.details : null;
|
|
240
|
+
return new BackendApiError({
|
|
241
|
+
code: obj.code || obj.error_type || obj.error || "internal_error",
|
|
242
|
+
detail: obj.message || "Streaming error",
|
|
243
|
+
userMessage: obj.user_message || obj.message || "Something went wrong",
|
|
244
|
+
details,
|
|
245
|
+
requestId: typeof obj.request_id === "string" ? obj.request_id : typeof details?.request_id === "string" ? details.request_id : void 0
|
|
246
|
+
});
|
|
631
247
|
}
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
248
|
+
function parsePersistedBackendError(data, requestId = "") {
|
|
249
|
+
if (!data || typeof data !== "object") return null;
|
|
250
|
+
const error = data;
|
|
251
|
+
const failures = Array.isArray(error.failures) ? error.failures : [];
|
|
252
|
+
const firstSpecific = failures.find(
|
|
253
|
+
(failure) => typeof failure === "object" && failure !== null && typeof failure.message === "string"
|
|
254
|
+
);
|
|
255
|
+
const summary = typeof error.message === "string" ? error.message : "Backend operation failed";
|
|
256
|
+
const specific = typeof firstSpecific?.message === "string" ? firstSpecific.message : summary;
|
|
257
|
+
const detail = specific === summary ? summary : `${summary}: ${specific}`;
|
|
258
|
+
const code = typeof error.type === "string" ? error.type : "internal_error";
|
|
259
|
+
const userMessage = typeof error.user_message === "string" && error.user_message ? error.user_message : detail;
|
|
260
|
+
return new BackendApiError({
|
|
261
|
+
code,
|
|
262
|
+
detail,
|
|
263
|
+
userMessage,
|
|
264
|
+
details: error,
|
|
265
|
+
requestId
|
|
266
|
+
});
|
|
636
267
|
}
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
return
|
|
268
|
+
var GENERIC_MESSAGE_PATTERNS = [
|
|
269
|
+
/failed unexpectedly/i,
|
|
270
|
+
/^\s*something went wrong/i,
|
|
271
|
+
/please try again(\s+later)?\.?\s*$/i,
|
|
272
|
+
/^\s*request failed\b/i,
|
|
273
|
+
/^\s*unknown (streaming )?error/i,
|
|
274
|
+
/^\s*internal server error\.?\s*$/i
|
|
275
|
+
];
|
|
276
|
+
function isGenericUserMessage(message) {
|
|
277
|
+
const value = (message ?? "").trim();
|
|
278
|
+
if (!value) return true;
|
|
279
|
+
return GENERIC_MESSAGE_PATTERNS.some((pattern) => pattern.test(value));
|
|
649
280
|
}
|
|
650
|
-
|
|
281
|
+
function unwrapUpstreamError(message) {
|
|
282
|
+
const start = message.indexOf("{");
|
|
283
|
+
const end = message.lastIndexOf("}");
|
|
284
|
+
if (start < 0 || end <= start) return null;
|
|
285
|
+
let parsed;
|
|
651
286
|
try {
|
|
652
|
-
|
|
287
|
+
parsed = JSON.parse(message.slice(start, end + 1));
|
|
653
288
|
} catch {
|
|
654
|
-
return
|
|
289
|
+
return null;
|
|
655
290
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
serverDetail: await readServerDetail(response)
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
async function requestJson(transport, path, options) {
|
|
665
|
-
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
666
|
-
const response = await transport.fetch(path, {
|
|
667
|
-
method: options.method,
|
|
668
|
-
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
669
|
-
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
670
|
-
...options.signal ? { signal: options.signal } : {}
|
|
671
|
-
});
|
|
672
|
-
if (!response.ok) return throwApiError(path, response);
|
|
673
|
-
return await response.json();
|
|
674
|
-
}
|
|
675
|
-
function toRunHandle(response, options) {
|
|
291
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
292
|
+
const body = parsed;
|
|
293
|
+
const inner = typeof body.message === "string" && body.message || typeof body.detail === "string" && body.detail || "";
|
|
294
|
+
if (!inner) return null;
|
|
295
|
+
const statusMatch = /\bHTTP (\d{3})\b/.exec(message.slice(0, start));
|
|
676
296
|
return {
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
...options.onMalformedLine ? { onMalformedLine: options.onMalformedLine } : {},
|
|
683
|
-
...options.onUnknownEnvelope ? { onUnknownEnvelope: options.onUnknownEnvelope } : {},
|
|
684
|
-
...options.onValidEnvelope ? { onValidEnvelope: options.onValidEnvelope } : {}
|
|
685
|
-
}),
|
|
686
|
-
response
|
|
297
|
+
message: inner,
|
|
298
|
+
code: typeof body.error_type === "string" && body.error_type || typeof body.error === "string" && body.error || null,
|
|
299
|
+
userMessage: typeof body.user_message === "string" ? body.user_message : null,
|
|
300
|
+
requestId: typeof body.request_id === "string" ? body.request_id : null,
|
|
301
|
+
status: statusMatch ? Number(statusMatch[1]) : null
|
|
687
302
|
};
|
|
688
303
|
}
|
|
689
|
-
|
|
690
|
-
const
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
304
|
+
function describeBackendFailure(error) {
|
|
305
|
+
const chain = [];
|
|
306
|
+
let code = "internal_error";
|
|
307
|
+
let requestId = "";
|
|
308
|
+
let status = null;
|
|
309
|
+
let userFacing = null;
|
|
310
|
+
if (error instanceof BackendApiError) {
|
|
311
|
+
code = error.code;
|
|
312
|
+
requestId = error.requestId;
|
|
313
|
+
status = error.status;
|
|
314
|
+
userFacing = error.userMessage;
|
|
315
|
+
if (error.detail) chain.push(error.detail);
|
|
316
|
+
if (error.userMessage && error.userMessage !== error.detail) {
|
|
317
|
+
chain.push(error.userMessage);
|
|
318
|
+
}
|
|
319
|
+
} else if (error instanceof Error) {
|
|
320
|
+
chain.push(error.message);
|
|
321
|
+
userFacing = error.message;
|
|
322
|
+
} else if (typeof error === "string") {
|
|
323
|
+
chain.push(error);
|
|
324
|
+
userFacing = error;
|
|
325
|
+
} else {
|
|
326
|
+
chain.push("Unknown error");
|
|
708
327
|
}
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
let event = "message";
|
|
717
|
-
let id = null;
|
|
718
|
-
const dataLines = [];
|
|
719
|
-
let sawData = false;
|
|
720
|
-
for (const line of frame.split(LINE_SEPARATOR)) {
|
|
721
|
-
if (line.startsWith(":")) continue;
|
|
722
|
-
if (line.startsWith("event:")) event = line.slice(6).trim();
|
|
723
|
-
else if (line.startsWith("data:")) {
|
|
724
|
-
sawData = true;
|
|
725
|
-
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
726
|
-
} else if (line.startsWith("id:")) id = line.slice(3).trim();
|
|
328
|
+
for (let cursor = 0; cursor < chain.length && cursor < 12; cursor += 1) {
|
|
329
|
+
const upstream = unwrapUpstreamError(chain[cursor] ?? "");
|
|
330
|
+
if (!upstream || chain.includes(upstream.message)) continue;
|
|
331
|
+
chain.push(upstream.message);
|
|
332
|
+
if (upstream.code) code = upstream.code;
|
|
333
|
+
if (upstream.requestId) requestId = upstream.requestId;
|
|
334
|
+
if (upstream.status !== null) status = upstream.status;
|
|
727
335
|
}
|
|
728
|
-
const
|
|
729
|
-
const
|
|
730
|
-
|
|
731
|
-
}
|
|
732
|
-
function createMatrxSseFramer() {
|
|
733
|
-
let buffer = "";
|
|
336
|
+
const specific = [...chain].reverse().find((message) => !isGenericUserMessage(message));
|
|
337
|
+
const cause = specific ?? chain[0] ?? "Unknown error";
|
|
338
|
+
const headlineWasGeneric = isGenericUserMessage(userFacing);
|
|
734
339
|
return {
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
buffer = buffer.slice(sep.index + sep[0].length);
|
|
743
|
-
frames.push(parseMatrxSseFrame(frame));
|
|
744
|
-
}
|
|
745
|
-
return frames;
|
|
746
|
-
},
|
|
747
|
-
flush() {
|
|
748
|
-
const rest = buffer;
|
|
749
|
-
buffer = "";
|
|
750
|
-
return { incomplete: rest.length > 0 ? rest : null };
|
|
751
|
-
}
|
|
340
|
+
code,
|
|
341
|
+
cause,
|
|
342
|
+
headline: headlineWasGeneric ? cause : userFacing ?? cause,
|
|
343
|
+
headlineWasGeneric,
|
|
344
|
+
chain,
|
|
345
|
+
requestId,
|
|
346
|
+
status
|
|
752
347
|
};
|
|
753
348
|
}
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
for (const frame of tail) yield frame;
|
|
767
|
-
const { incomplete } = framer.flush();
|
|
768
|
-
if (incomplete !== null) options.onIncomplete?.(incomplete);
|
|
769
|
-
} finally {
|
|
770
|
-
reader.releaseLock();
|
|
349
|
+
function getUserMessage(error) {
|
|
350
|
+
if (error instanceof BackendApiError) {
|
|
351
|
+
return error.userMessage;
|
|
352
|
+
}
|
|
353
|
+
if (error instanceof Error) {
|
|
354
|
+
return error.message;
|
|
355
|
+
}
|
|
356
|
+
if (typeof error === "string") {
|
|
357
|
+
return error;
|
|
358
|
+
}
|
|
359
|
+
if (typeof error === "object" && error !== null && typeof error.message === "string" && error.message) {
|
|
360
|
+
return error.message;
|
|
771
361
|
}
|
|
362
|
+
return "Something went wrong";
|
|
772
363
|
}
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
async function getRuntimeOperationStatus(transport, requestId, options = {}) {
|
|
786
|
-
try {
|
|
787
|
-
return await requestJson(
|
|
788
|
-
transport,
|
|
789
|
-
`/runtime/operations/${encodePathSegment(requestId)}`,
|
|
790
|
-
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
791
|
-
);
|
|
792
|
-
} catch (error) {
|
|
793
|
-
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
794
|
-
throw error;
|
|
364
|
+
function statusToCode(status) {
|
|
365
|
+
switch (status) {
|
|
366
|
+
case 401:
|
|
367
|
+
return "auth_required";
|
|
368
|
+
case 403:
|
|
369
|
+
return "admin_required";
|
|
370
|
+
case 404:
|
|
371
|
+
return "not_found";
|
|
372
|
+
case 422:
|
|
373
|
+
return "validation_error";
|
|
374
|
+
default:
|
|
375
|
+
return "internal_error";
|
|
795
376
|
}
|
|
796
377
|
}
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
);
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
378
|
+
|
|
379
|
+
// stream/ndjson.ts
|
|
380
|
+
var DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;
|
|
381
|
+
function isRecord2(value) {
|
|
382
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
383
|
+
}
|
|
384
|
+
function normalizeMatrxStreamEnvelope(value) {
|
|
385
|
+
if (!isRecord2(value)) return null;
|
|
386
|
+
if (typeof value.event === "string") {
|
|
387
|
+
const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
|
|
388
|
+
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
389
|
+
return {
|
|
390
|
+
event: value.event,
|
|
391
|
+
data: value.data,
|
|
392
|
+
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
393
|
+
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
if (value.e === "c" && typeof value.t === "string") {
|
|
397
|
+
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
398
|
+
const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
|
|
399
|
+
return {
|
|
400
|
+
event: "chunk",
|
|
401
|
+
data: { text: value.t },
|
|
402
|
+
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
403
|
+
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
404
|
+
};
|
|
810
405
|
}
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
`/runtime/executions/${encodePathSegment(executionId)}/events${query}`,
|
|
821
|
-
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
822
|
-
);
|
|
823
|
-
}
|
|
824
|
-
function parseEndStatus(data) {
|
|
825
|
-
if (data === null) return null;
|
|
826
|
-
try {
|
|
827
|
-
const parsed = JSON.parse(data);
|
|
828
|
-
if (typeof parsed === "object" && parsed !== null && typeof parsed.status === "string") {
|
|
829
|
-
const status = parsed.status;
|
|
830
|
-
return RUNTIME_STATUSES.has(status) ? status : null;
|
|
831
|
-
}
|
|
832
|
-
} catch {
|
|
406
|
+
if (value.e === "r" && typeof value.t === "string") {
|
|
407
|
+
const streamId = typeof value.stream_id === "string" ? value.stream_id : void 0;
|
|
408
|
+
const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
|
|
409
|
+
return {
|
|
410
|
+
event: "reasoning_chunk",
|
|
411
|
+
data: { text: value.t },
|
|
412
|
+
...streamId === void 0 ? {} : { stream_id: streamId },
|
|
413
|
+
...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
|
|
414
|
+
};
|
|
833
415
|
}
|
|
834
416
|
return null;
|
|
835
417
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
418
|
+
function createMatrxNdjsonFramer(options = {}) {
|
|
419
|
+
const decoder = new TextDecoder();
|
|
420
|
+
let buffer = "";
|
|
421
|
+
let lineNumber = 0;
|
|
422
|
+
let finished = false;
|
|
423
|
+
const assertOpen = () => {
|
|
424
|
+
if (finished) throw new Error("Matrx NDJSON framer is already finished");
|
|
425
|
+
};
|
|
426
|
+
const parseLine = (line, atCompletion) => {
|
|
427
|
+
const currentLineNumber = ++lineNumber;
|
|
428
|
+
const trimmed = line.trim();
|
|
429
|
+
if (!trimmed) return null;
|
|
430
|
+
let parsed;
|
|
431
|
+
try {
|
|
432
|
+
parsed = JSON.parse(trimmed);
|
|
433
|
+
} catch (error) {
|
|
434
|
+
options.onMalformedLine?.({
|
|
435
|
+
line: trimmed,
|
|
436
|
+
error,
|
|
437
|
+
lineNumber: currentLineNumber,
|
|
438
|
+
atCompletion
|
|
439
|
+
});
|
|
440
|
+
return null;
|
|
847
441
|
}
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
);
|
|
853
|
-
for await (const frame of frames) {
|
|
854
|
-
if (frame.event === "end") {
|
|
855
|
-
yield { type: "end", status: parseEndStatus(frame.data), cursor };
|
|
856
|
-
return;
|
|
442
|
+
const envelope = normalizeMatrxStreamEnvelope(parsed);
|
|
443
|
+
if (!envelope) {
|
|
444
|
+
options.onUnknownEnvelope?.(parsed);
|
|
445
|
+
return null;
|
|
857
446
|
}
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
447
|
+
options.onValidEnvelope?.({
|
|
448
|
+
raw: parsed,
|
|
449
|
+
envelope,
|
|
450
|
+
line: trimmed,
|
|
451
|
+
lineNumber: currentLineNumber,
|
|
452
|
+
atCompletion
|
|
453
|
+
});
|
|
454
|
+
return envelope;
|
|
455
|
+
};
|
|
456
|
+
const pushDecodedText = (fragment) => {
|
|
457
|
+
buffer += fragment;
|
|
458
|
+
const lines = buffer.split("\n");
|
|
459
|
+
buffer = lines.pop() ?? "";
|
|
460
|
+
const envelopes = [];
|
|
461
|
+
for (const line of lines) {
|
|
462
|
+
const envelope = parseLine(line, false);
|
|
463
|
+
if (envelope) envelopes.push(envelope);
|
|
464
|
+
}
|
|
465
|
+
return envelopes;
|
|
466
|
+
};
|
|
467
|
+
return {
|
|
468
|
+
pushText(fragment) {
|
|
469
|
+
assertOpen();
|
|
470
|
+
return pushDecodedText(decoder.decode() + fragment);
|
|
471
|
+
},
|
|
472
|
+
pushBytes(fragment) {
|
|
473
|
+
assertOpen();
|
|
474
|
+
return pushDecodedText(decoder.decode(fragment, { stream: true }));
|
|
475
|
+
},
|
|
476
|
+
finish() {
|
|
477
|
+
assertOpen();
|
|
478
|
+
finished = true;
|
|
479
|
+
const envelopes = pushDecodedText(decoder.decode());
|
|
480
|
+
if (buffer.length > 0) {
|
|
481
|
+
const envelope = parseLine(buffer, true);
|
|
482
|
+
buffer = "";
|
|
483
|
+
if (envelope) envelopes.push(envelope);
|
|
866
484
|
}
|
|
867
|
-
|
|
868
|
-
yield { type: "event", event, seq: frame.seq, cursor };
|
|
869
|
-
continue;
|
|
485
|
+
return envelopes;
|
|
870
486
|
}
|
|
871
|
-
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
function readAheadLimit(value) {
|
|
490
|
+
const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;
|
|
491
|
+
if (!Number.isSafeInteger(limit) || limit < 1) {
|
|
492
|
+
throw new RangeError("maxReadAhead must be a positive safe integer");
|
|
872
493
|
}
|
|
494
|
+
return limit;
|
|
873
495
|
}
|
|
874
|
-
async function
|
|
875
|
-
const
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
let
|
|
880
|
-
let
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
496
|
+
async function* readMatrxNdjsonStream(body, options = {}) {
|
|
497
|
+
const maxReadAhead = readAheadLimit(options.maxReadAhead);
|
|
498
|
+
const queue = [];
|
|
499
|
+
let queuedEventCount = 0;
|
|
500
|
+
let wakeConsumer = null;
|
|
501
|
+
let wakeProducer = null;
|
|
502
|
+
let readerFinished = false;
|
|
503
|
+
let consumerClosed = false;
|
|
504
|
+
const wakeWaitingConsumer = () => {
|
|
505
|
+
const wake = wakeConsumer;
|
|
506
|
+
wakeConsumer = null;
|
|
507
|
+
wake?.();
|
|
508
|
+
};
|
|
509
|
+
const wakeWaitingProducer = () => {
|
|
510
|
+
const wake = wakeProducer;
|
|
511
|
+
wakeProducer = null;
|
|
512
|
+
wake?.();
|
|
513
|
+
};
|
|
514
|
+
const enqueueTerminal = (item) => {
|
|
515
|
+
if (consumerClosed) return;
|
|
516
|
+
queue.push(item);
|
|
517
|
+
wakeWaitingConsumer();
|
|
518
|
+
};
|
|
519
|
+
const enqueueEvent = async (value) => {
|
|
520
|
+
while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
|
|
521
|
+
await new Promise((resolve) => {
|
|
522
|
+
wakeProducer = resolve;
|
|
895
523
|
});
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
524
|
+
}
|
|
525
|
+
if (consumerClosed || options.signal?.aborted) return false;
|
|
526
|
+
queue.push({ kind: "event", value });
|
|
527
|
+
queuedEventCount += 1;
|
|
528
|
+
wakeWaitingConsumer();
|
|
529
|
+
return true;
|
|
530
|
+
};
|
|
531
|
+
const waitForReadCapacity = async () => {
|
|
532
|
+
while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
|
|
533
|
+
await new Promise((resolve) => {
|
|
534
|
+
wakeProducer = resolve;
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
return !consumerClosed && !options.signal?.aborted;
|
|
538
|
+
};
|
|
539
|
+
const reader = body.getReader();
|
|
540
|
+
const framer = createMatrxNdjsonFramer(options);
|
|
541
|
+
const onAbort = () => {
|
|
542
|
+
wakeWaitingProducer();
|
|
543
|
+
wakeWaitingConsumer();
|
|
544
|
+
void reader.cancel(options.signal?.reason).catch(() => void 0);
|
|
545
|
+
};
|
|
546
|
+
options.signal?.addEventListener("abort", onAbort, { once: true });
|
|
547
|
+
if (options.signal?.aborted) onAbort();
|
|
548
|
+
const readerPromise = (async () => {
|
|
549
|
+
try {
|
|
550
|
+
while (!options.signal?.aborted && !consumerClosed) {
|
|
551
|
+
if (!await waitForReadCapacity()) return;
|
|
552
|
+
const { value, done } = await reader.read();
|
|
553
|
+
if (done) break;
|
|
554
|
+
for (const envelope of framer.pushBytes(value)) {
|
|
555
|
+
if (!await enqueueEvent(envelope)) return;
|
|
903
556
|
}
|
|
904
|
-
|
|
905
|
-
|
|
557
|
+
}
|
|
558
|
+
if (!options.signal?.aborted && !consumerClosed) {
|
|
559
|
+
for (const envelope of framer.finish()) {
|
|
560
|
+
if (!await enqueueEvent(envelope)) return;
|
|
906
561
|
}
|
|
907
562
|
}
|
|
908
|
-
failures += 1;
|
|
909
563
|
} catch (error) {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
options.onAttemptError?.(error);
|
|
564
|
+
const aborted = options.signal?.aborted || consumerClosed || error instanceof Error && error.name === "AbortError";
|
|
565
|
+
if (!aborted) enqueueTerminal({ kind: "error", error });
|
|
913
566
|
} finally {
|
|
914
|
-
|
|
915
|
-
|
|
567
|
+
readerFinished = true;
|
|
568
|
+
reader.releaseLock();
|
|
569
|
+
enqueueTerminal({ kind: "done" });
|
|
570
|
+
}
|
|
571
|
+
})();
|
|
572
|
+
try {
|
|
573
|
+
while (true) {
|
|
574
|
+
if (queue.length === 0) {
|
|
575
|
+
if (options.signal?.aborted || readerFinished) return;
|
|
576
|
+
await new Promise((resolve) => {
|
|
577
|
+
wakeConsumer = resolve;
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
const item = queue.shift();
|
|
581
|
+
if (item?.kind === "event") queuedEventCount -= 1;
|
|
582
|
+
wakeWaitingProducer();
|
|
583
|
+
if (!item || item.kind === "done") return;
|
|
584
|
+
if (item.kind === "error") throw item.error;
|
|
585
|
+
yield item.value;
|
|
916
586
|
}
|
|
917
|
-
|
|
918
|
-
|
|
587
|
+
} finally {
|
|
588
|
+
consumerClosed = true;
|
|
589
|
+
wakeWaitingProducer();
|
|
590
|
+
wakeWaitingConsumer();
|
|
591
|
+
options.signal?.removeEventListener("abort", onAbort);
|
|
592
|
+
if (!readerFinished) {
|
|
593
|
+
await reader.cancel().catch(() => void 0);
|
|
919
594
|
}
|
|
595
|
+
await readerPromise;
|
|
920
596
|
}
|
|
921
|
-
return { ended: false, status: null };
|
|
922
597
|
}
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
598
|
+
|
|
599
|
+
// matrx/org-context.ts
|
|
600
|
+
import { isUuidShape } from "@ai-matrx/kit/uuid";
|
|
601
|
+
var OrganizationContextError = class extends Error {
|
|
602
|
+
code;
|
|
603
|
+
constructor(code, message) {
|
|
604
|
+
super(message);
|
|
605
|
+
this.name = "OrganizationContextError";
|
|
606
|
+
this.code = code;
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
function createOrganizationOperation(organizationId) {
|
|
610
|
+
const organization_id = requireOrganizationContext(organizationId);
|
|
611
|
+
return Object.freeze({ organization_id });
|
|
612
|
+
}
|
|
613
|
+
function assertOrganizationMatchesOperation(operation, organizationId) {
|
|
614
|
+
if (operation.organization_id !== requireOrganizationContext(organizationId)) {
|
|
615
|
+
throw new OrganizationContextError(
|
|
616
|
+
"organization_context_mismatch",
|
|
617
|
+
"Organization ID must match the request operation."
|
|
618
|
+
);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
function requireOrganizationContext(selectedOrganizationId, overrideOrganizationId) {
|
|
622
|
+
const candidate = overrideOrganizationId ?? selectedOrganizationId;
|
|
623
|
+
if (typeof candidate !== "string" || candidate.trim().length === 0) {
|
|
624
|
+
throw new OrganizationContextError(
|
|
625
|
+
"organization_context_required",
|
|
626
|
+
"Select an organization before sending this request."
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
const normalized = candidate.trim();
|
|
630
|
+
if (!isUuidShape(normalized)) {
|
|
631
|
+
throw new OrganizationContextError(
|
|
632
|
+
"organization_context_invalid",
|
|
633
|
+
"The selected organization ID is invalid."
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
return normalized.toLowerCase();
|
|
637
|
+
}
|
|
638
|
+
function applyOrganizationContextHeader(headers, organizationId) {
|
|
639
|
+
const normalizedOrganizationId = requireOrganizationContext(organizationId);
|
|
640
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
641
|
+
if (name.toLowerCase() === "x-organization-id" && value.trim().toLowerCase() !== normalizedOrganizationId) {
|
|
642
|
+
throw new OrganizationContextError(
|
|
643
|
+
"organization_context_mismatch",
|
|
644
|
+
"X-Organization-Id must match the request context organization."
|
|
645
|
+
);
|
|
933
646
|
}
|
|
647
|
+
}
|
|
648
|
+
const withoutOrganizationHeader = Object.fromEntries(
|
|
649
|
+
Object.entries(headers).filter(
|
|
650
|
+
([name]) => name.toLowerCase() !== "x-organization-id"
|
|
651
|
+
)
|
|
934
652
|
);
|
|
935
|
-
return
|
|
653
|
+
return {
|
|
654
|
+
...withoutOrganizationHeader,
|
|
655
|
+
"X-Organization-Id": normalizedOrganizationId
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
function assertQueryOrganizationMatchesContext(queryParams, organizationId) {
|
|
659
|
+
if (!queryParams || queryParams.organization_id === void 0) return;
|
|
660
|
+
const queryOrganizationId = requireOrganizationContext(
|
|
661
|
+
String(queryParams.organization_id)
|
|
662
|
+
);
|
|
663
|
+
if (queryOrganizationId !== requireOrganizationContext(organizationId)) {
|
|
664
|
+
throw new OrganizationContextError(
|
|
665
|
+
"organization_context_mismatch",
|
|
666
|
+
"Query organization_id must match the request context organization."
|
|
667
|
+
);
|
|
668
|
+
}
|
|
936
669
|
}
|
|
937
670
|
|
|
938
|
-
// matrx/
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
671
|
+
// matrx/protocol.ts
|
|
672
|
+
import {
|
|
673
|
+
isNetError,
|
|
674
|
+
resilientFetch
|
|
675
|
+
} from "@ai-matrx/data/net";
|
|
676
|
+
var MATRX_AI_API_VERSION_DEFAULT = "v2";
|
|
677
|
+
var V2_COVERED_AI_PATH_TEMPLATES = [
|
|
678
|
+
"/ai/manual",
|
|
679
|
+
"/ai/chat",
|
|
680
|
+
"/ai/agents/{agent_id}",
|
|
681
|
+
"/ai/agent/{agent_id}",
|
|
682
|
+
// singular alias — behaves identically
|
|
683
|
+
"/ai/conversations/{conversation_id}",
|
|
684
|
+
"/ai/conversation/{conversation_id}",
|
|
685
|
+
// singular alias
|
|
686
|
+
"/ai/prompts/{prompt_id}",
|
|
687
|
+
// saved-prompt execution
|
|
688
|
+
"/ai/mandates/{mandate_key}"
|
|
689
|
+
// THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)
|
|
690
|
+
];
|
|
691
|
+
function toV2Path(path) {
|
|
692
|
+
const withLead = path.startsWith("/") ? path : `/${path}`;
|
|
693
|
+
if (withLead.startsWith("/api/")) {
|
|
694
|
+
const rest = withLead.slice("/api".length);
|
|
695
|
+
return rest.startsWith("/v2/") ? withLead : `/api/v2${rest}`;
|
|
696
|
+
}
|
|
697
|
+
return withLead.startsWith("/v2/") ? withLead : `/v2${withLead}`;
|
|
944
698
|
}
|
|
945
|
-
|
|
946
|
-
|
|
699
|
+
var COVERED_INTERPOLATED_PATH = [
|
|
700
|
+
/^(?:\/api)?\/ai\/manual$/,
|
|
701
|
+
/^(?:\/api)?\/ai\/chat$/,
|
|
702
|
+
/^(?:\/api)?\/ai\/agents\/[^/]+$/,
|
|
703
|
+
/^(?:\/api)?\/ai\/agent\/[^/]+$/,
|
|
704
|
+
/^(?:\/api)?\/ai\/conversations\/[^/]+$/,
|
|
705
|
+
/^(?:\/api)?\/ai\/conversation\/[^/]+$/,
|
|
706
|
+
/^(?:\/api)?\/ai\/prompts\/[^/]+$/,
|
|
707
|
+
// `/warm` etc. deliberately don't match
|
|
708
|
+
/^(?:\/api)?\/ai\/mandates\/[^/]+$/
|
|
709
|
+
// the mandate door
|
|
710
|
+
];
|
|
711
|
+
function isCoveredAiPath(path) {
|
|
712
|
+
return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));
|
|
947
713
|
}
|
|
948
|
-
function
|
|
949
|
-
|
|
950
|
-
const out = [];
|
|
951
|
-
if (isRecord3(body.detail)) out.push(body.detail);
|
|
952
|
-
if (isRecord3(body.details)) out.push(body.details);
|
|
953
|
-
out.push(body);
|
|
954
|
-
return out;
|
|
714
|
+
function isV2Path(pathOrUrl) {
|
|
715
|
+
return /\/v2\/ai\//.test(pathOrUrl);
|
|
955
716
|
}
|
|
956
|
-
function
|
|
957
|
-
|
|
958
|
-
const status = error.status;
|
|
959
|
-
return typeof status === "number" ? status : null;
|
|
717
|
+
function toV1FallbackUrl(url) {
|
|
718
|
+
return url.replace(/\/v2\/ai\//, "/ai/");
|
|
960
719
|
}
|
|
961
|
-
function
|
|
962
|
-
if (
|
|
963
|
-
return
|
|
720
|
+
function applyAiApiVersion(path, version) {
|
|
721
|
+
if (version !== "v2") return path;
|
|
722
|
+
return isCoveredAiPath(path) ? toV2Path(path) : path;
|
|
964
723
|
}
|
|
965
|
-
function
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
724
|
+
async function fetchWithMatrxProtocolFallback(url, init, opts = {}) {
|
|
725
|
+
const { onDowngrade, ...fetchOpts } = opts;
|
|
726
|
+
const logDowngrade = (reason, status2) => {
|
|
727
|
+
console.warn(
|
|
728
|
+
`[matrx] ai_v2_downgrade \u2192 retrying on v1. v2=${url} reason=${reason}`
|
|
729
|
+
);
|
|
730
|
+
onDowngrade?.({ url, reason, ...status2 !== void 0 ? { status: status2 } : {} });
|
|
731
|
+
};
|
|
732
|
+
if (!isV2Path(url)) return resilientFetch(url, init, fetchOpts);
|
|
733
|
+
let result;
|
|
734
|
+
try {
|
|
735
|
+
result = await resilientFetch(url, init, fetchOpts);
|
|
736
|
+
} catch (err) {
|
|
737
|
+
const isAbort = isNetError(err) && err.code === "aborted" || err instanceof Error && err.name === "AbortError";
|
|
738
|
+
if (isAbort) throw err;
|
|
739
|
+
logDowngrade(String(err));
|
|
740
|
+
return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);
|
|
969
741
|
}
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
742
|
+
const status = result.response.status;
|
|
743
|
+
if (status === 404 || status === 405 || status >= 500) {
|
|
744
|
+
logDowngrade(`HTTP ${status}`, status);
|
|
745
|
+
return resilientFetch(toV1FallbackUrl(url), init, fetchOpts);
|
|
973
746
|
}
|
|
974
|
-
return
|
|
747
|
+
return result;
|
|
975
748
|
}
|
|
976
|
-
|
|
977
|
-
"
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
"run_in_flight"
|
|
982
|
-
];
|
|
983
|
-
function readMatrxErrorCodeFromMessage(message) {
|
|
984
|
-
if (typeof message !== "string") return null;
|
|
985
|
-
for (const code of PREFIXED_ERROR_CODES) {
|
|
986
|
-
if (message.startsWith(`${code}:`)) return code;
|
|
749
|
+
function aiVersionPathOverrides(version) {
|
|
750
|
+
if (version !== "v2") return {};
|
|
751
|
+
const map = {};
|
|
752
|
+
for (const template of V2_COVERED_AI_PATH_TEMPLATES) {
|
|
753
|
+
map[template] = toV2Path(template);
|
|
987
754
|
}
|
|
988
|
-
return
|
|
755
|
+
return map;
|
|
989
756
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
757
|
+
|
|
758
|
+
// matrx/call.ts
|
|
759
|
+
function buildMatrxRequestUrl(baseUrl, pathTemplate, pathParams, queryParams) {
|
|
760
|
+
let resolvedPath = pathTemplate;
|
|
761
|
+
if (pathParams) {
|
|
762
|
+
for (const [key, value] of Object.entries(pathParams)) {
|
|
763
|
+
resolvedPath = resolvedPath.replace(`{${key}}`, encodeURIComponent(value));
|
|
764
|
+
}
|
|
997
765
|
}
|
|
998
|
-
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
766
|
+
const fullPath = resolvedPath.startsWith("/api/") ? resolvedPath.slice(4) : resolvedPath;
|
|
767
|
+
const url = `${baseUrl}${fullPath}`;
|
|
768
|
+
if (queryParams && Object.keys(queryParams).length > 0) {
|
|
769
|
+
const qs = new URLSearchParams(
|
|
770
|
+
Object.fromEntries(
|
|
771
|
+
Object.entries(queryParams).map(([k, v]) => [k, String(v)])
|
|
772
|
+
)
|
|
773
|
+
).toString();
|
|
774
|
+
return `${url}?${qs}`;
|
|
775
|
+
}
|
|
776
|
+
return url;
|
|
777
|
+
}
|
|
778
|
+
var MATRX_UI_ONLY_BODY_FIELDS = /* @__PURE__ */ new Set([
|
|
779
|
+
"youtube_videos",
|
|
780
|
+
"file_urls",
|
|
781
|
+
"image_urls"
|
|
782
|
+
]);
|
|
783
|
+
function buildMatrxRequestBody(body, scope) {
|
|
784
|
+
const raw = body ?? {};
|
|
785
|
+
const base = {};
|
|
786
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
787
|
+
if (!MATRX_UI_ONLY_BODY_FIELDS.has(key)) base[key] = value;
|
|
1004
788
|
}
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
rejoinPath,
|
|
1021
|
-
runId: firstString(candidates, "run_id"),
|
|
1022
|
-
code,
|
|
1023
|
-
body: isRecord3(root) ? root : {}
|
|
789
|
+
if (base.organization_id === null || typeof base.organization_id === "string" && base.organization_id.trim() === "") {
|
|
790
|
+
delete base.organization_id;
|
|
791
|
+
}
|
|
792
|
+
const bodyOrganizationId = base.organization_id;
|
|
793
|
+
if (scope.organization_id !== void 0 && bodyOrganizationId !== void 0 && (typeof bodyOrganizationId !== "string" || bodyOrganizationId.trim() !== scope.organization_id)) {
|
|
794
|
+
throw new OrganizationContextError(
|
|
795
|
+
"organization_context_mismatch",
|
|
796
|
+
"Request body organization_id must match the request context organization."
|
|
797
|
+
);
|
|
798
|
+
}
|
|
799
|
+
if (bodyOrganizationId !== void 0 && scope.organization_id !== void 0) {
|
|
800
|
+
base.organization_id = scope.organization_id;
|
|
801
|
+
}
|
|
802
|
+
const scopeFields = {
|
|
803
|
+
...scope.organization_id !== void 0 ? { organization_id: scope.organization_id } : {}
|
|
1024
804
|
};
|
|
805
|
+
if (scope.project_id !== void 0) scopeFields.project_id = scope.project_id;
|
|
806
|
+
if (scope.task_id !== void 0) scopeFields.task_id = scope.task_id;
|
|
807
|
+
return { ...scopeFields, ...base };
|
|
808
|
+
}
|
|
809
|
+
var BARE_TRANSPORT_CODE = /^\s*(?:HTTP|HTTP\s*Error|Status(?:\s*Code)?)?\s*[:\-]?\s*\d{3}\s*[.:!]?\s*$/i;
|
|
810
|
+
function isBareTransportCode(text) {
|
|
811
|
+
if (!text) return false;
|
|
812
|
+
return BARE_TRANSPORT_CODE.test(text);
|
|
813
|
+
}
|
|
814
|
+
function bareStatusSentence(status) {
|
|
815
|
+
if (status === 401 || status === 403) {
|
|
816
|
+
return "The server would not let this request through \u2014 your session may have expired, or this account may not have access here. Sign in again, and if it repeats, ask an administrator.";
|
|
817
|
+
}
|
|
818
|
+
if (status === 404) {
|
|
819
|
+
return "The server has nothing at that address. Reload the page; if it repeats, report it \u2014 a client asking for something that no longer exists is a defect, not your mistake.";
|
|
820
|
+
}
|
|
821
|
+
if (status === 429) {
|
|
822
|
+
return "The server is rate-limiting this request. Wait a few seconds and try again.";
|
|
823
|
+
}
|
|
824
|
+
if (status >= 500) {
|
|
825
|
+
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.";
|
|
826
|
+
}
|
|
827
|
+
return "The server refused this request and sent no reason with it \u2014 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.";
|
|
1025
828
|
}
|
|
1026
|
-
function
|
|
1027
|
-
|
|
829
|
+
function honestTransportMessage(raw, status) {
|
|
830
|
+
if (raw && !isBareTransportCode(raw)) return raw;
|
|
831
|
+
return bareStatusSentence(status ?? 0);
|
|
1028
832
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
833
|
+
var SENSITIVE_HEADER_NAME = /authorization|cookie|token|api[-_]?key/i;
|
|
834
|
+
function buildSafeRequestLog(headers, body) {
|
|
835
|
+
const safeHeaders = Object.fromEntries(
|
|
836
|
+
Object.entries(headers).map(([name, value]) => [
|
|
837
|
+
name,
|
|
838
|
+
SENSITIVE_HEADER_NAME.test(name) ? "[REDACTED]" : value
|
|
839
|
+
])
|
|
840
|
+
);
|
|
841
|
+
const bodyMetadata = Array.isArray(body) ? { type: "array", itemCount: body.length } : body && typeof body === "object" ? { type: "object", keys: Object.keys(body) } : { type: body === null ? "null" : typeof body };
|
|
842
|
+
return { headers: safeHeaders, body: bodyMetadata };
|
|
1031
843
|
}
|
|
1032
|
-
function
|
|
1033
|
-
|
|
844
|
+
function redactUrlForRequestLog(url) {
|
|
845
|
+
try {
|
|
846
|
+
const parsed = new URL(url);
|
|
847
|
+
for (const key of parsed.searchParams.keys()) {
|
|
848
|
+
parsed.searchParams.set(key, "[REDACTED]");
|
|
849
|
+
}
|
|
850
|
+
return parsed.toString();
|
|
851
|
+
} catch {
|
|
852
|
+
const queryIndex = url.indexOf("?");
|
|
853
|
+
return queryIndex === -1 ? url : `${url.slice(0, queryIndex)}?[REDACTED]`;
|
|
854
|
+
}
|
|
1034
855
|
}
|
|
1035
|
-
function
|
|
1036
|
-
return
|
|
856
|
+
function shouldReportMatrxCallError(status, expectedErrorStatuses) {
|
|
857
|
+
return status == null || !expectedErrorStatuses?.includes(status);
|
|
1037
858
|
}
|
|
1038
|
-
function
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
859
|
+
function parseMatrxNdjsonResponse(response, signal, hooks = {}) {
|
|
860
|
+
const ids = {
|
|
861
|
+
requestId: response.headers.get("X-Request-ID"),
|
|
862
|
+
conversationId: response.headers.get("X-Conversation-ID")
|
|
863
|
+
};
|
|
864
|
+
async function* events() {
|
|
865
|
+
if (!response.body) {
|
|
866
|
+
throw new BackendApiError({
|
|
867
|
+
code: "internal_error",
|
|
868
|
+
detail: "Response has no body",
|
|
869
|
+
userMessage: "No response received from server"
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
try {
|
|
873
|
+
for await (const envelope of readMatrxNdjsonStream(response.body, {
|
|
874
|
+
...signal ? { signal } : {},
|
|
875
|
+
...hooks.onMalformedLine ? { onMalformedLine: hooks.onMalformedLine } : {},
|
|
876
|
+
...hooks.onUnknownEnvelope ? { onUnknownEnvelope: hooks.onUnknownEnvelope } : {}
|
|
877
|
+
})) {
|
|
878
|
+
hooks.onEvent?.(envelope, ids);
|
|
879
|
+
yield envelope;
|
|
880
|
+
}
|
|
881
|
+
} catch (error) {
|
|
882
|
+
if (signal?.aborted || error instanceof Error && error.name === "AbortError") {
|
|
883
|
+
return;
|
|
884
|
+
}
|
|
885
|
+
const transportError = error instanceof BackendApiError ? error : new StreamTransportError({
|
|
886
|
+
detail: error instanceof Error ? error.message : "The response stream ended unexpectedly.",
|
|
887
|
+
details: error,
|
|
888
|
+
...ids.requestId ? { requestId: ids.requestId } : {}
|
|
889
|
+
});
|
|
890
|
+
hooks.onTransportError?.(transportError, ids);
|
|
891
|
+
throw transportError;
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
return { events: events(), ...ids };
|
|
1042
895
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
896
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
|
|
897
|
+
var DEFAULT_JSON_TOTAL_TIMEOUT_MS = 3e4;
|
|
898
|
+
async function httpErrorFrom(response) {
|
|
899
|
+
const serverDetail = await response.json().catch(() => void 0);
|
|
900
|
+
return {
|
|
901
|
+
type: response.status >= 400 && response.status < 500 ? "validation_error" : "http_error",
|
|
902
|
+
message: extractMatrxErrorMessage(serverDetail) ?? bareStatusSentence(response.status),
|
|
903
|
+
status: response.status,
|
|
904
|
+
serverDetail
|
|
905
|
+
};
|
|
1050
906
|
}
|
|
1051
|
-
function
|
|
1052
|
-
const
|
|
907
|
+
async function executeMatrxCall(request, hooks = {}) {
|
|
908
|
+
const upper = request.method.toUpperCase();
|
|
909
|
+
const sendsBody = request.stream || upper !== "GET" && upper !== "HEAD";
|
|
910
|
+
const { response } = await fetchWithMatrxProtocolFallback(
|
|
911
|
+
request.url,
|
|
912
|
+
{
|
|
913
|
+
method: request.method,
|
|
914
|
+
headers: request.headers,
|
|
915
|
+
...sendsBody ? { body: JSON.stringify(request.body) } : {}
|
|
916
|
+
},
|
|
917
|
+
{
|
|
918
|
+
...request.signal ? { signal: request.signal } : {},
|
|
919
|
+
connectTimeoutMs: request.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
|
|
920
|
+
totalTimeoutMs: request.stream ? null : request.totalTimeoutMs === void 0 ? DEFAULT_JSON_TOTAL_TIMEOUT_MS : request.totalTimeoutMs,
|
|
921
|
+
throwOnHttpError: false,
|
|
922
|
+
...hooks.onProtocolDowngrade ? { onDowngrade: hooks.onProtocolDowngrade } : {}
|
|
923
|
+
}
|
|
924
|
+
);
|
|
925
|
+
const requestId = response.headers.get("X-Request-ID");
|
|
926
|
+
const conversationId = response.headers.get("X-Conversation-ID");
|
|
927
|
+
const idFields = {
|
|
928
|
+
...requestId !== null ? { requestId } : {},
|
|
929
|
+
...conversationId !== null ? { conversationId } : {}
|
|
930
|
+
};
|
|
931
|
+
if (!response.ok) {
|
|
932
|
+
const error = await httpErrorFrom(response);
|
|
933
|
+
if (request.stream) request.onStreamError?.(error);
|
|
934
|
+
return { ...idFields, error };
|
|
935
|
+
}
|
|
936
|
+
if (!request.stream) {
|
|
937
|
+
const data = response.status === 204 ? void 0 : await response.json();
|
|
938
|
+
return { data, ...idFields };
|
|
939
|
+
}
|
|
940
|
+
if (request.consumeStream) {
|
|
941
|
+
request.onStreamStart?.(requestId, conversationId);
|
|
942
|
+
await request.consumeStream(response, { requestId, conversationId });
|
|
943
|
+
request.onStreamComplete?.(requestId, conversationId);
|
|
944
|
+
return idFields;
|
|
945
|
+
}
|
|
946
|
+
const parse = hooks.parseStream ?? ((res, signal) => parseMatrxNdjsonResponse(res, signal));
|
|
947
|
+
const parsed = parse(response, request.signal);
|
|
948
|
+
request.onStreamStart?.(parsed.requestId, parsed.conversationId);
|
|
949
|
+
for await (const event of parsed.events) {
|
|
950
|
+
request.onStreamEvent?.(event);
|
|
951
|
+
}
|
|
952
|
+
request.onStreamComplete?.(parsed.requestId, parsed.conversationId);
|
|
1053
953
|
return {
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
headers: { ...init.headers, "X-Organization-Id": orgId }
|
|
1057
|
-
})
|
|
954
|
+
...parsed.requestId !== null ? { requestId: parsed.requestId } : {},
|
|
955
|
+
...parsed.conversationId !== null ? { conversationId: parsed.conversationId } : {}
|
|
1058
956
|
};
|
|
1059
957
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
}
|
|
958
|
+
|
|
959
|
+
// matrx/client.ts
|
|
960
|
+
function classifyStatus(status) {
|
|
961
|
+
return status >= 400 && status < 500 ? "validation_error" : "http_error";
|
|
962
|
+
}
|
|
963
|
+
function normalizeMatrxError(err) {
|
|
964
|
+
if (err instanceof OrganizationContextError) {
|
|
965
|
+
return {
|
|
966
|
+
type: "validation_error",
|
|
967
|
+
message: err.message,
|
|
968
|
+
code: err.code,
|
|
969
|
+
name: err.name,
|
|
970
|
+
...err.stack !== void 0 ? { stack: err.stack } : {}
|
|
971
|
+
};
|
|
972
|
+
}
|
|
973
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
974
|
+
return { type: "abort_error", message: "Request was cancelled." };
|
|
975
|
+
}
|
|
976
|
+
if (err instanceof MatrxApiError) {
|
|
977
|
+
return {
|
|
978
|
+
type: classifyStatus(err.status),
|
|
979
|
+
message: honestTransportMessage(err.message, err.status),
|
|
980
|
+
status: err.status,
|
|
981
|
+
serverDetail: err.serverDetail,
|
|
982
|
+
...err.code ? { code: err.code } : {},
|
|
983
|
+
name: err.name
|
|
984
|
+
};
|
|
985
|
+
}
|
|
986
|
+
if (err instanceof BackendApiError) {
|
|
987
|
+
return {
|
|
988
|
+
type: "network_error",
|
|
989
|
+
message: honestTransportMessage(
|
|
990
|
+
err.detail || err.userMessage,
|
|
991
|
+
err.status ?? void 0
|
|
992
|
+
),
|
|
993
|
+
code: err.code,
|
|
994
|
+
name: err.name,
|
|
995
|
+
...err.status !== null ? { status: err.status } : {},
|
|
996
|
+
...err.details !== null ? { serverDetail: err.details } : {}
|
|
997
|
+
};
|
|
998
|
+
}
|
|
999
|
+
if (isNetError2(err)) {
|
|
1000
|
+
if (err.code === "aborted") {
|
|
1001
|
+
return { type: "abort_error", message: err.message };
|
|
1002
|
+
}
|
|
1003
|
+
if (err.code === "http") {
|
|
1004
|
+
const status = err.status ?? 0;
|
|
1005
|
+
return {
|
|
1006
|
+
type: classifyStatus(status),
|
|
1007
|
+
message: honestTransportMessage(err.message, status),
|
|
1008
|
+
status
|
|
1009
|
+
};
|
|
1010
|
+
}
|
|
1011
|
+
return { type: "network_error", message: err.message };
|
|
1012
|
+
}
|
|
1013
|
+
if (err instanceof Error) {
|
|
1014
|
+
const httpMatch = err.message.match(/HTTP (\d+):\s*(.*)/);
|
|
1015
|
+
if (httpMatch) {
|
|
1016
|
+
const status = parseInt(httpMatch[1], 10);
|
|
1017
|
+
return {
|
|
1018
|
+
type: classifyStatus(status),
|
|
1019
|
+
message: honestTransportMessage(httpMatch[2] ?? err.message, status),
|
|
1020
|
+
status
|
|
1021
|
+
};
|
|
1022
|
+
}
|
|
1023
|
+
if (isBareTransportCode(err.message)) {
|
|
1024
|
+
const status = Number.parseInt(err.message.replace(/\D+/g, ""), 10);
|
|
1025
|
+
return {
|
|
1026
|
+
type: classifyStatus(status),
|
|
1027
|
+
message: bareStatusSentence(status),
|
|
1028
|
+
status
|
|
1029
|
+
};
|
|
1030
|
+
}
|
|
1031
|
+
return { type: "network_error", message: err.message };
|
|
1032
|
+
}
|
|
1033
|
+
return { type: "unknown", message: extractErrorMessage(err) };
|
|
1034
|
+
}
|
|
1035
|
+
var PRODUCTION_CONNECT_TIMEOUT_MS = 15e3;
|
|
1036
|
+
function stripContentType(headers) {
|
|
1037
|
+
return Object.fromEntries(
|
|
1038
|
+
Object.entries(headers).filter(
|
|
1039
|
+
([name]) => name.toLowerCase() !== "content-type"
|
|
1040
|
+
)
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
function createMatrxTransport(options) {
|
|
1044
|
+
const {
|
|
1045
|
+
baseUrl,
|
|
1046
|
+
resolveTarget,
|
|
1047
|
+
credentials,
|
|
1048
|
+
organizationId,
|
|
1049
|
+
aiApiVersion,
|
|
1050
|
+
connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,
|
|
1051
|
+
totalTimeoutMs = null,
|
|
1052
|
+
expectedErrorStatuses,
|
|
1053
|
+
diagnostics,
|
|
1054
|
+
source = "matrxTransport"
|
|
1055
|
+
} = options;
|
|
1056
|
+
if (baseUrl === void 0 === (resolveTarget === void 0)) {
|
|
1057
|
+
throw new Error(
|
|
1058
|
+
"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`."
|
|
1073
1059
|
);
|
|
1074
|
-
} catch (error) {
|
|
1075
|
-
if (options.signal?.aborted) return { ended: false };
|
|
1076
|
-
throw error;
|
|
1077
1060
|
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
)
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1061
|
+
const resolve = resolveTarget ?? (() => ({ baseUrl }));
|
|
1062
|
+
const resolveVersion = () => {
|
|
1063
|
+
if (aiApiVersion === void 0) return MATRX_AI_API_VERSION_DEFAULT;
|
|
1064
|
+
return typeof aiApiVersion === "function" ? aiApiVersion() : aiApiVersion;
|
|
1065
|
+
};
|
|
1066
|
+
const resolveOrganizationId = () => {
|
|
1067
|
+
if (organizationId === void 0) return null;
|
|
1068
|
+
const candidate = typeof organizationId === "function" ? organizationId() : organizationId;
|
|
1069
|
+
return requireOrganizationContext(candidate);
|
|
1070
|
+
};
|
|
1071
|
+
return {
|
|
1072
|
+
async fetch(path, init) {
|
|
1073
|
+
const target = resolve();
|
|
1074
|
+
const versionedPath = applyAiApiVersion(path, resolveVersion());
|
|
1075
|
+
const url = `${target.baseUrl}${versionedPath}`;
|
|
1076
|
+
const credentialHeaders = credentials ? credentialToHeaders(await credentials.get()) : {};
|
|
1077
|
+
let headers = {
|
|
1078
|
+
...init.headers,
|
|
1079
|
+
...stripContentType(credentialHeaders),
|
|
1080
|
+
...stripContentType(target.policyHeaders ?? {})
|
|
1081
|
+
};
|
|
1082
|
+
const orgId = resolveOrganizationId();
|
|
1083
|
+
if (orgId !== null) {
|
|
1084
|
+
headers = applyOrganizationContextHeader(headers, orgId);
|
|
1085
|
+
}
|
|
1086
|
+
const info = {
|
|
1087
|
+
url,
|
|
1088
|
+
method: init.method,
|
|
1089
|
+
path,
|
|
1090
|
+
channel: target.channel ?? "default",
|
|
1091
|
+
source
|
|
1092
|
+
};
|
|
1093
|
+
diagnostics?.onRequest?.(info);
|
|
1094
|
+
let response;
|
|
1085
1095
|
try {
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1096
|
+
({ response } = await fetchWithMatrxProtocolFallback(
|
|
1097
|
+
url,
|
|
1098
|
+
{
|
|
1099
|
+
method: init.method,
|
|
1100
|
+
headers,
|
|
1101
|
+
...init.body !== void 0 ? { body: init.body } : {}
|
|
1102
|
+
},
|
|
1103
|
+
{
|
|
1104
|
+
...init.signal ? { signal: init.signal } : {},
|
|
1105
|
+
connectTimeoutMs,
|
|
1106
|
+
totalTimeoutMs,
|
|
1107
|
+
throwOnHttpError: false,
|
|
1108
|
+
...diagnostics?.onProtocolDowngrade ? { onDowngrade: diagnostics.onProtocolDowngrade } : {}
|
|
1109
|
+
}
|
|
1110
|
+
));
|
|
1111
|
+
} catch (err) {
|
|
1112
|
+
diagnostics?.onError?.(normalizeMatrxError(err), info);
|
|
1113
|
+
throw err;
|
|
1089
1114
|
}
|
|
1090
|
-
if (!
|
|
1091
|
-
|
|
1115
|
+
if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {
|
|
1116
|
+
const serverDetail = await response.clone().json().catch(() => void 0);
|
|
1117
|
+
const code = extractMatrxErrorCode(serverDetail);
|
|
1118
|
+
diagnostics?.onError?.(
|
|
1119
|
+
{
|
|
1120
|
+
type: classifyStatus(response.status),
|
|
1121
|
+
message: extractMatrxErrorMessage(serverDetail) ?? `HTTP ${response.status}`,
|
|
1122
|
+
status: response.status,
|
|
1123
|
+
serverDetail,
|
|
1124
|
+
...code ? { code } : {}
|
|
1125
|
+
},
|
|
1126
|
+
info
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
return response;
|
|
1092
1130
|
}
|
|
1093
|
-
}
|
|
1094
|
-
if (!options.signal?.aborted) throw error;
|
|
1095
|
-
}
|
|
1096
|
-
return { ended: false };
|
|
1131
|
+
};
|
|
1097
1132
|
}
|
|
1098
|
-
|
|
1099
|
-
|
|
1133
|
+
|
|
1134
|
+
// matrx/conversation.ts
|
|
1135
|
+
function mintMatrxConversationId() {
|
|
1136
|
+
return crypto.randomUUID();
|
|
1137
|
+
}
|
|
1138
|
+
function newStoredConversationStart(conversationId) {
|
|
1139
|
+
return {
|
|
1140
|
+
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
1141
|
+
is_new: true,
|
|
1142
|
+
store: true
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
function continueStoredConversationStart(conversationId) {
|
|
1146
|
+
return { conversation_id: conversationId, is_new: false, store: true };
|
|
1100
1147
|
}
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
onOperationEvent,
|
|
1107
|
-
onWorkflowEvent,
|
|
1108
|
-
follow,
|
|
1109
|
-
...rest
|
|
1110
|
-
} = options;
|
|
1111
|
-
const bound = organizationId ? withRunOrganization(transport, organizationId) : transport;
|
|
1112
|
-
const streamOptions = {
|
|
1113
|
-
...rest,
|
|
1114
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1148
|
+
function newEphemeralConversationStart(conversationId) {
|
|
1149
|
+
return {
|
|
1150
|
+
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
1151
|
+
is_new: true,
|
|
1152
|
+
store: false
|
|
1115
1153
|
};
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1127
|
-
|
|
1128
|
-
|
|
1154
|
+
}
|
|
1155
|
+
function continueEphemeralConversationStart(conversationId, priorMessages) {
|
|
1156
|
+
return {
|
|
1157
|
+
conversation_id: conversationId,
|
|
1158
|
+
is_new: false,
|
|
1159
|
+
store: false,
|
|
1160
|
+
prior_messages: priorMessages
|
|
1161
|
+
};
|
|
1162
|
+
}
|
|
1163
|
+
|
|
1164
|
+
// matrx/internal.ts
|
|
1165
|
+
function encodePathSegment(value) {
|
|
1166
|
+
return encodeURIComponent(value);
|
|
1167
|
+
}
|
|
1168
|
+
function buildQuery(params) {
|
|
1169
|
+
const search = new URLSearchParams();
|
|
1170
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1171
|
+
if (value === void 0) continue;
|
|
1172
|
+
if (Array.isArray(value)) {
|
|
1173
|
+
for (const entry of value) search.append(key, entry);
|
|
1174
|
+
} else {
|
|
1175
|
+
search.append(key, String(value));
|
|
1129
1176
|
}
|
|
1130
|
-
rejoin = target;
|
|
1131
1177
|
}
|
|
1132
|
-
|
|
1133
|
-
|
|
1178
|
+
const encoded = search.toString();
|
|
1179
|
+
return encoded ? `?${encoded}` : "";
|
|
1180
|
+
}
|
|
1181
|
+
async function readServerDetail(response) {
|
|
1134
1182
|
try {
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
body: {}
|
|
1139
|
-
});
|
|
1140
|
-
await drain(handle, onEnvelope);
|
|
1141
|
-
return { kind: "rejoined", rejoin };
|
|
1142
|
-
} catch (error) {
|
|
1143
|
-
const read = readLiveStreamUnavailable(error);
|
|
1144
|
-
if (!read) throw error;
|
|
1145
|
-
unavailable = read;
|
|
1183
|
+
return await response.json();
|
|
1184
|
+
} catch {
|
|
1185
|
+
return void 0;
|
|
1146
1186
|
}
|
|
1147
|
-
return followUnavailableRejoin(bound, rejoin, unavailable, {
|
|
1148
|
-
...signalOnly,
|
|
1149
|
-
...onOperationEvent ? { onOperationEvent } : {},
|
|
1150
|
-
...onWorkflowEvent ? { onWorkflowEvent } : {},
|
|
1151
|
-
...follow ? { follow } : {}
|
|
1152
|
-
});
|
|
1153
1187
|
}
|
|
1154
|
-
function
|
|
1155
|
-
|
|
1156
|
-
|
|
1188
|
+
async function throwApiError(path, response) {
|
|
1189
|
+
throw new MatrxApiError({
|
|
1190
|
+
status: response.status,
|
|
1191
|
+
path,
|
|
1192
|
+
serverDetail: await readServerDetail(response)
|
|
1193
|
+
});
|
|
1157
1194
|
}
|
|
1158
|
-
async function
|
|
1159
|
-
const
|
|
1160
|
-
const
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq)
|
|
1166
|
-
});
|
|
1167
|
-
return { kind: "followed_workflow", rejoin, runId, ended: result2.ended };
|
|
1168
|
-
}
|
|
1169
|
-
const liveRequestId = rejoin.liveRequestId;
|
|
1170
|
-
const statusView = liveRequestId ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly) : null;
|
|
1171
|
-
const operation = statusView?.operations.find((op) => !op.is_terminal) ?? statusView?.operations[0] ?? null;
|
|
1172
|
-
if (!operation) {
|
|
1173
|
-
return { kind: "followed", rejoin, executionId: null, ended: false, status: null };
|
|
1174
|
-
}
|
|
1175
|
-
if (operation.is_terminal) {
|
|
1176
|
-
return {
|
|
1177
|
-
kind: "followed",
|
|
1178
|
-
rejoin,
|
|
1179
|
-
executionId: operation.execution_id,
|
|
1180
|
-
ended: true,
|
|
1181
|
-
status: operation.status
|
|
1182
|
-
};
|
|
1183
|
-
}
|
|
1184
|
-
const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {
|
|
1185
|
-
...options.follow,
|
|
1186
|
-
lastEventSeq: operation.last_event_seq,
|
|
1187
|
-
...signalOnly,
|
|
1188
|
-
onEvent: (event) => options.onOperationEvent?.(event)
|
|
1195
|
+
async function requestJson(transport, path, options) {
|
|
1196
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
1197
|
+
const response = await transport.fetch(path, {
|
|
1198
|
+
method: options.method,
|
|
1199
|
+
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
1200
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
1201
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1189
1202
|
});
|
|
1203
|
+
if (!response.ok) return throwApiError(path, response);
|
|
1204
|
+
return await response.json();
|
|
1205
|
+
}
|
|
1206
|
+
function toRunHandle(response, options) {
|
|
1190
1207
|
return {
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1208
|
+
requestId: response.headers.get("X-Request-ID"),
|
|
1209
|
+
conversationId: response.headers.get("X-Conversation-ID"),
|
|
1210
|
+
events: readMatrxNdjsonStream(response.body, {
|
|
1211
|
+
...options.signal ? { signal: options.signal } : {},
|
|
1212
|
+
...options.maxReadAhead !== void 0 ? { maxReadAhead: options.maxReadAhead } : {},
|
|
1213
|
+
...options.onMalformedLine ? { onMalformedLine: options.onMalformedLine } : {},
|
|
1214
|
+
...options.onUnknownEnvelope ? { onUnknownEnvelope: options.onUnknownEnvelope } : {},
|
|
1215
|
+
...options.onValidEnvelope ? { onValidEnvelope: options.onValidEnvelope } : {}
|
|
1216
|
+
}),
|
|
1217
|
+
response
|
|
1196
1218
|
};
|
|
1197
1219
|
}
|
|
1198
|
-
async function
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1220
|
+
async function requestStream(transport, path, options) {
|
|
1221
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
1222
|
+
const response = await transport.fetch(path, {
|
|
1223
|
+
method: options.method,
|
|
1224
|
+
headers: {
|
|
1225
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
1226
|
+
...options.headers
|
|
1227
|
+
},
|
|
1228
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
1229
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1230
|
+
});
|
|
1231
|
+
if (!response.ok) return throwApiError(path, response);
|
|
1232
|
+
if (!response.body) {
|
|
1233
|
+
throw new MatrxApiError({
|
|
1234
|
+
status: response.status,
|
|
1235
|
+
path,
|
|
1236
|
+
serverDetail: { code: "missing_response_body" },
|
|
1237
|
+
message: "The streaming response carried no body."
|
|
1238
|
+
});
|
|
1204
1239
|
}
|
|
1240
|
+
return response;
|
|
1205
1241
|
}
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1242
|
+
|
|
1243
|
+
// stream/sse.ts
|
|
1244
|
+
var FRAME_SEPARATOR = /\r\n\r\n|\n\n|\r\r/;
|
|
1245
|
+
var LINE_SEPARATOR = /\r\n|\n|\r/;
|
|
1246
|
+
function parseMatrxSseFrame(frame) {
|
|
1247
|
+
let event = "message";
|
|
1248
|
+
let id = null;
|
|
1249
|
+
const dataLines = [];
|
|
1250
|
+
let sawData = false;
|
|
1251
|
+
for (const line of frame.split(LINE_SEPARATOR)) {
|
|
1252
|
+
if (line.startsWith(":")) continue;
|
|
1253
|
+
if (line.startsWith("event:")) event = line.slice(6).trim();
|
|
1254
|
+
else if (line.startsWith("data:")) {
|
|
1255
|
+
sawData = true;
|
|
1256
|
+
dataLines.push(line.slice(5).replace(/^ /, ""));
|
|
1257
|
+
} else if (line.startsWith("id:")) id = line.slice(3).trim();
|
|
1258
|
+
}
|
|
1259
|
+
const seqCandidate = id !== null && id !== "" ? Number(id) : NaN;
|
|
1260
|
+
const seq = Number.isSafeInteger(seqCandidate) && seqCandidate >= 0 ? seqCandidate : null;
|
|
1261
|
+
return { event, id, seq, data: sawData ? dataLines.join("\n") : null };
|
|
1262
|
+
}
|
|
1263
|
+
function createMatrxSseFramer() {
|
|
1264
|
+
let buffer = "";
|
|
1265
|
+
return {
|
|
1266
|
+
push(chunk) {
|
|
1267
|
+
buffer += chunk;
|
|
1268
|
+
const frames = [];
|
|
1269
|
+
for (; ; ) {
|
|
1270
|
+
const sep = FRAME_SEPARATOR.exec(buffer);
|
|
1271
|
+
if (sep === null) break;
|
|
1272
|
+
const frame = buffer.slice(0, sep.index);
|
|
1273
|
+
buffer = buffer.slice(sep.index + sep[0].length);
|
|
1274
|
+
frames.push(parseMatrxSseFrame(frame));
|
|
1219
1275
|
}
|
|
1220
|
-
return
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1276
|
+
return frames;
|
|
1277
|
+
},
|
|
1278
|
+
flush() {
|
|
1279
|
+
const rest = buffer;
|
|
1280
|
+
buffer = "";
|
|
1281
|
+
return { incomplete: rest.length > 0 ? rest : null };
|
|
1224
1282
|
}
|
|
1225
|
-
}
|
|
1283
|
+
};
|
|
1226
1284
|
}
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
const
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1285
|
+
async function* readMatrxSseStream(stream, options = {}) {
|
|
1286
|
+
const reader = stream.getReader();
|
|
1287
|
+
const decoder = new TextDecoder();
|
|
1288
|
+
const framer = createMatrxSseFramer();
|
|
1289
|
+
try {
|
|
1290
|
+
for (; ; ) {
|
|
1291
|
+
const { value, done } = await reader.read();
|
|
1292
|
+
if (done) break;
|
|
1293
|
+
const frames = framer.push(decoder.decode(value, { stream: true }));
|
|
1294
|
+
for (const frame of frames) yield frame;
|
|
1295
|
+
}
|
|
1296
|
+
const tail = framer.push(decoder.decode());
|
|
1297
|
+
for (const frame of tail) yield frame;
|
|
1298
|
+
const { incomplete } = framer.flush();
|
|
1299
|
+
if (incomplete !== null) options.onIncomplete?.(incomplete);
|
|
1300
|
+
} finally {
|
|
1301
|
+
reader.releaseLock();
|
|
1302
|
+
}
|
|
1238
1303
|
}
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1304
|
+
|
|
1305
|
+
// matrx/operations.ts
|
|
1306
|
+
var TERMINAL_MATRX_RUNTIME_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
1307
|
+
var RUNTIME_STATUSES = /* @__PURE__ */ new Set([
|
|
1308
|
+
"pending",
|
|
1309
|
+
"running",
|
|
1310
|
+
"paused",
|
|
1311
|
+
"waiting_input",
|
|
1312
|
+
"completed",
|
|
1313
|
+
"failed",
|
|
1314
|
+
"cancelled"
|
|
1315
|
+
]);
|
|
1316
|
+
async function getRuntimeOperationStatus(transport, requestId, options = {}) {
|
|
1317
|
+
try {
|
|
1318
|
+
return await requestJson(
|
|
1319
|
+
transport,
|
|
1320
|
+
`/runtime/operations/${encodePathSegment(requestId)}`,
|
|
1321
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1322
|
+
);
|
|
1323
|
+
} catch (error) {
|
|
1324
|
+
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
1325
|
+
throw error;
|
|
1326
|
+
}
|
|
1246
1327
|
}
|
|
1247
|
-
function
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
`/ai/mandates/${encodePathSegment(mandateKey)}`,
|
|
1251
|
-
request,
|
|
1252
|
-
options
|
|
1328
|
+
async function getRuntimeOperationsByLink(transport, linkKind, linkId, options = {}) {
|
|
1329
|
+
const query = buildQuery(
|
|
1330
|
+
options.limit !== void 0 ? { limit: options.limit } : {}
|
|
1253
1331
|
);
|
|
1332
|
+
try {
|
|
1333
|
+
return await requestJson(
|
|
1334
|
+
transport,
|
|
1335
|
+
`/runtime/operations/by-link/${encodePathSegment(linkKind)}/${encodePathSegment(linkId)}${query}`,
|
|
1336
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1337
|
+
);
|
|
1338
|
+
} catch (error) {
|
|
1339
|
+
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
1340
|
+
throw error;
|
|
1341
|
+
}
|
|
1254
1342
|
}
|
|
1255
|
-
function
|
|
1256
|
-
|
|
1343
|
+
function listRuntimeOperationEvents(transport, executionId, options = {}) {
|
|
1344
|
+
const query = buildQuery({
|
|
1345
|
+
...options.afterSeq !== void 0 ? { after_seq: options.afterSeq } : {},
|
|
1346
|
+
...options.limit !== void 0 ? { limit: options.limit } : {},
|
|
1347
|
+
...options.kinds !== void 0 ? { kind: options.kinds } : {}
|
|
1348
|
+
});
|
|
1349
|
+
return requestJson(
|
|
1257
1350
|
transport,
|
|
1258
|
-
`/
|
|
1259
|
-
|
|
1260
|
-
options
|
|
1351
|
+
`/runtime/executions/${encodePathSegment(executionId)}/events${query}`,
|
|
1352
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1261
1353
|
);
|
|
1262
1354
|
}
|
|
1263
|
-
function
|
|
1264
|
-
return
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1355
|
+
function parseEndStatus(data) {
|
|
1356
|
+
if (data === null) return null;
|
|
1357
|
+
try {
|
|
1358
|
+
const parsed = JSON.parse(data);
|
|
1359
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.status === "string") {
|
|
1360
|
+
const status = parsed.status;
|
|
1361
|
+
return RUNTIME_STATUSES.has(status) ? status : null;
|
|
1362
|
+
}
|
|
1363
|
+
} catch {
|
|
1364
|
+
}
|
|
1365
|
+
return null;
|
|
1270
1366
|
}
|
|
1271
|
-
function
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
);
|
|
1275
|
-
|
|
1367
|
+
async function* followRuntimeOperationEvents(transport, executionId, options = {}) {
|
|
1368
|
+
let cursor = options.lastEventSeq ?? 0;
|
|
1369
|
+
const headers = { Accept: "text/event-stream" };
|
|
1370
|
+
if (cursor > 0) headers["Last-Event-ID"] = String(cursor);
|
|
1371
|
+
const response = await requestStream(
|
|
1276
1372
|
transport,
|
|
1277
|
-
`/
|
|
1373
|
+
`/runtime/executions/${encodePathSegment(executionId)}/events/stream`,
|
|
1278
1374
|
{
|
|
1279
|
-
method: "
|
|
1375
|
+
method: "GET",
|
|
1376
|
+
headers,
|
|
1280
1377
|
...options.signal ? { signal: options.signal } : {}
|
|
1281
1378
|
}
|
|
1282
1379
|
);
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
partialText;
|
|
1292
|
-
constructor(args) {
|
|
1293
|
-
super(args.message);
|
|
1294
|
-
this.errorPayload = args.errorPayload ?? null;
|
|
1295
|
-
this.completionStatus = args.completionStatus ?? null;
|
|
1296
|
-
this.partialText = args.partialText ?? "";
|
|
1297
|
-
}
|
|
1298
|
-
};
|
|
1299
|
-
function isRecord4(value) {
|
|
1300
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1301
|
-
}
|
|
1302
|
-
function stringField(value, key) {
|
|
1303
|
-
if (!isRecord4(value)) return null;
|
|
1304
|
-
const field = value[key];
|
|
1305
|
-
return typeof field === "string" && field ? field : null;
|
|
1306
|
-
}
|
|
1307
|
-
async function runAgentToCompletion(transport, agentId, request, options = {}) {
|
|
1308
|
-
const handle = await startAgentRun(transport, agentId, request, options);
|
|
1309
|
-
let text = "";
|
|
1310
|
-
let completion = null;
|
|
1311
|
-
let failure = null;
|
|
1312
|
-
for await (const envelope of handle.events) {
|
|
1313
|
-
options.onEvent?.(envelope);
|
|
1314
|
-
if (envelope.event === "chunk") {
|
|
1315
|
-
const chunk = stringField(envelope.data, "text");
|
|
1316
|
-
if (chunk !== null) {
|
|
1317
|
-
text += chunk;
|
|
1318
|
-
options.onChunk?.(text);
|
|
1319
|
-
}
|
|
1320
|
-
continue;
|
|
1380
|
+
const frames = readMatrxSseStream(
|
|
1381
|
+
response.body,
|
|
1382
|
+
options.onIncomplete ? { onIncomplete: options.onIncomplete } : {}
|
|
1383
|
+
);
|
|
1384
|
+
for await (const frame of frames) {
|
|
1385
|
+
if (frame.event === "end") {
|
|
1386
|
+
yield { type: "end", status: parseEndStatus(frame.data), cursor };
|
|
1387
|
+
return;
|
|
1321
1388
|
}
|
|
1322
|
-
if (
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1389
|
+
if (frame.event === "execution_event" && frame.data !== null) {
|
|
1390
|
+
let event;
|
|
1391
|
+
try {
|
|
1392
|
+
event = JSON.parse(frame.data);
|
|
1393
|
+
} catch (error) {
|
|
1394
|
+
options.onMalformedFrame?.(frame, error);
|
|
1395
|
+
yield { type: "liveness", cursor };
|
|
1396
|
+
continue;
|
|
1397
|
+
}
|
|
1398
|
+
if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;
|
|
1399
|
+
yield { type: "event", event, seq: frame.seq, cursor };
|
|
1329
1400
|
continue;
|
|
1330
1401
|
}
|
|
1331
|
-
|
|
1332
|
-
if (envelope.data.operation !== "user_request") continue;
|
|
1333
|
-
completion = envelope.data;
|
|
1334
|
-
const status = envelope.data.status;
|
|
1335
|
-
if ((status === "failed" || status === "cancelled") && failure === null) {
|
|
1336
|
-
const result = isRecord4(envelope.data.result) ? envelope.data.result : null;
|
|
1337
|
-
failure = new MatrxRunError({
|
|
1338
|
-
message: stringField(result, "error") ?? stringField(result, "user_message") ?? `The agent run ${status}`,
|
|
1339
|
-
completionStatus: status,
|
|
1340
|
-
partialText: text
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
if (failure) throw failure;
|
|
1345
|
-
if (!text && completion) {
|
|
1346
|
-
const result = completion.result;
|
|
1347
|
-
const output = stringField(result, "output");
|
|
1348
|
-
if (output !== null) text = output;
|
|
1349
|
-
}
|
|
1350
|
-
return {
|
|
1351
|
-
text,
|
|
1352
|
-
requestId: handle.requestId,
|
|
1353
|
-
conversationId: handle.conversationId,
|
|
1354
|
-
completion
|
|
1355
|
-
};
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
// matrx/provider-failures.ts
|
|
1359
|
-
var clip = (value, max) => value.length > max ? value.slice(0, max) : value;
|
|
1360
|
-
function providerSessionFailureBody(failure) {
|
|
1361
|
-
const message = failure.message?.trim() || failure.error_type?.trim() || (failure.status_code ? `HTTP ${failure.status_code}` : "provider session failed");
|
|
1362
|
-
const body = {
|
|
1363
|
-
provider: failure.provider,
|
|
1364
|
-
message: clip(message, 4e3)
|
|
1365
|
-
};
|
|
1366
|
-
if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);
|
|
1367
|
-
if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);
|
|
1368
|
-
if (typeof failure.status_code === "number" && Number.isInteger(failure.status_code) && failure.status_code >= 100 && failure.status_code <= 599) {
|
|
1369
|
-
body.status_code = failure.status_code;
|
|
1402
|
+
yield { type: "liveness", cursor };
|
|
1370
1403
|
}
|
|
1371
|
-
return body;
|
|
1372
1404
|
}
|
|
1373
|
-
async function
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1405
|
+
async function followRuntimeOperationToEnd(transport, executionId, options) {
|
|
1406
|
+
const stallTimeoutMs = options.stallTimeoutMs ?? 45e3;
|
|
1407
|
+
const reconnectLimit = options.reconnectLimit ?? 60;
|
|
1408
|
+
const reconnectDelayMs = options.reconnectDelayMs ?? 2e3;
|
|
1409
|
+
const outer = options.signal;
|
|
1410
|
+
let cursor = options.lastEventSeq ?? 0;
|
|
1411
|
+
let failures = 0;
|
|
1412
|
+
while (!outer?.aborted && failures < reconnectLimit) {
|
|
1413
|
+
const attempt2 = new AbortController();
|
|
1414
|
+
const onOuterAbort = () => attempt2.abort();
|
|
1415
|
+
outer?.addEventListener("abort", onOuterAbort, { once: true });
|
|
1416
|
+
let stallTimer = null;
|
|
1417
|
+
const armStall = () => {
|
|
1418
|
+
if (stallTimer !== null) clearTimeout(stallTimer);
|
|
1419
|
+
stallTimer = setTimeout(() => attempt2.abort(), stallTimeoutMs);
|
|
1420
|
+
};
|
|
1421
|
+
try {
|
|
1422
|
+
const items = followRuntimeOperationEvents(transport, executionId, {
|
|
1423
|
+
lastEventSeq: cursor,
|
|
1424
|
+
signal: attempt2.signal,
|
|
1425
|
+
...options.onMalformedFrame ? { onMalformedFrame: options.onMalformedFrame } : {}
|
|
1426
|
+
});
|
|
1427
|
+
armStall();
|
|
1428
|
+
for await (const item of items) {
|
|
1429
|
+
armStall();
|
|
1430
|
+
failures = 0;
|
|
1431
|
+
cursor = item.cursor;
|
|
1432
|
+
if (item.type === "end") {
|
|
1433
|
+
return { ended: true, status: item.status };
|
|
1434
|
+
}
|
|
1435
|
+
if (item.type === "event") {
|
|
1436
|
+
options.onEvent(item.event, item.seq);
|
|
1437
|
+
}
|
|
1382
1438
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
error
|
|
1388
|
-
|
|
1389
|
-
|
|
1439
|
+
failures += 1;
|
|
1440
|
+
} catch (error) {
|
|
1441
|
+
if (outer?.aborted) break;
|
|
1442
|
+
failures += 1;
|
|
1443
|
+
options.onAttemptError?.(error);
|
|
1444
|
+
} finally {
|
|
1445
|
+
if (stallTimer !== null) clearTimeout(stallTimer);
|
|
1446
|
+
outer?.removeEventListener("abort", onOuterAbort);
|
|
1447
|
+
}
|
|
1448
|
+
if (!outer?.aborted && failures < reconnectLimit) {
|
|
1449
|
+
await new Promise((r) => setTimeout(r, reconnectDelayMs));
|
|
1450
|
+
}
|
|
1390
1451
|
}
|
|
1452
|
+
return { ended: false, status: null };
|
|
1391
1453
|
}
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
function submitAgentToolResults(transport, conversationId, results, options = {}) {
|
|
1395
|
-
return requestJson(
|
|
1454
|
+
async function rejoinRuntimeOperation(transport, requestId, options = {}) {
|
|
1455
|
+
const response = await requestStream(
|
|
1396
1456
|
transport,
|
|
1397
|
-
`/
|
|
1457
|
+
`/runtime/operations/${encodePathSegment(requestId)}/rejoin`,
|
|
1398
1458
|
{
|
|
1399
1459
|
method: "POST",
|
|
1400
|
-
body
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
},
|
|
1460
|
+
// The route takes no body model; the reference client posts an empty
|
|
1461
|
+
// JSON object. Match it so proxies see an ordinary JSON POST.
|
|
1462
|
+
body: {},
|
|
1404
1463
|
...options.signal ? { signal: options.signal } : {}
|
|
1405
1464
|
}
|
|
1406
1465
|
);
|
|
1466
|
+
return toRunHandle(response, options);
|
|
1407
1467
|
}
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
}
|
|
1416
|
-
);
|
|
1468
|
+
|
|
1469
|
+
// matrx/rejoin.ts
|
|
1470
|
+
var MATRX_RUN_IN_PROGRESS = "run_in_progress";
|
|
1471
|
+
var MATRX_RESUME_CONFLICT = "resume_conflict";
|
|
1472
|
+
var MATRX_LIVE_STREAM_UNAVAILABLE = "live_stream_unavailable";
|
|
1473
|
+
function isRecord3(value) {
|
|
1474
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1417
1475
|
}
|
|
1418
|
-
function
|
|
1419
|
-
|
|
1420
|
-
options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
1421
|
-
);
|
|
1422
|
-
return requestJson(
|
|
1423
|
-
transport,
|
|
1424
|
-
`/ai/user/pending_calls${query}`,
|
|
1425
|
-
{
|
|
1426
|
-
method: "GET",
|
|
1427
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1428
|
-
}
|
|
1429
|
-
);
|
|
1476
|
+
function nonBlank(value) {
|
|
1477
|
+
return typeof value === "string" && value.trim() ? value : null;
|
|
1430
1478
|
}
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
this.details = data.details ?? null;
|
|
1453
|
-
this.requestId = data.requestId ?? "";
|
|
1454
|
-
this.status = data.status ?? null;
|
|
1479
|
+
function detailCandidates(body) {
|
|
1480
|
+
if (!isRecord3(body)) return [];
|
|
1481
|
+
const out = [];
|
|
1482
|
+
if (isRecord3(body.detail)) out.push(body.detail);
|
|
1483
|
+
if (isRecord3(body.details)) out.push(body.details);
|
|
1484
|
+
out.push(body);
|
|
1485
|
+
return out;
|
|
1486
|
+
}
|
|
1487
|
+
function statusOf(error) {
|
|
1488
|
+
if (!isRecord3(error) && !(error instanceof Error)) return null;
|
|
1489
|
+
const status = error.status;
|
|
1490
|
+
return typeof status === "number" ? status : null;
|
|
1491
|
+
}
|
|
1492
|
+
function bodyOf(error) {
|
|
1493
|
+
if (!isRecord3(error) && !(error instanceof Error)) return void 0;
|
|
1494
|
+
return error.serverDetail;
|
|
1495
|
+
}
|
|
1496
|
+
function readMatrxErrorCode(error) {
|
|
1497
|
+
for (const candidate of detailCandidates(bodyOf(error))) {
|
|
1498
|
+
const code = nonBlank(candidate.code);
|
|
1499
|
+
if (code) return code;
|
|
1455
1500
|
}
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
return
|
|
1459
|
-
error: this.code,
|
|
1460
|
-
message: this.detail,
|
|
1461
|
-
user_message: this.userMessage,
|
|
1462
|
-
details: this.details,
|
|
1463
|
-
request_id: this.requestId
|
|
1464
|
-
};
|
|
1501
|
+
for (const candidate of detailCandidates(bodyOf(error))) {
|
|
1502
|
+
const code = nonBlank(candidate.error);
|
|
1503
|
+
if (code) return code;
|
|
1465
1504
|
}
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1505
|
+
return null;
|
|
1506
|
+
}
|
|
1507
|
+
var PREFIXED_ERROR_CODES = [
|
|
1508
|
+
"resume_conflict",
|
|
1509
|
+
"not_resumable",
|
|
1510
|
+
"outstanding_delegated_calls",
|
|
1511
|
+
"user_request_not_found",
|
|
1512
|
+
"run_in_flight"
|
|
1513
|
+
];
|
|
1514
|
+
function readMatrxErrorCodeFromMessage(message) {
|
|
1515
|
+
if (typeof message !== "string") return null;
|
|
1516
|
+
for (const code of PREFIXED_ERROR_CODES) {
|
|
1517
|
+
if (message.startsWith(`${code}:`)) return code;
|
|
1479
1518
|
}
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1519
|
+
return null;
|
|
1520
|
+
}
|
|
1521
|
+
async function readConversationOrganizationId(conversationId, read, onUnreadable) {
|
|
1522
|
+
try {
|
|
1523
|
+
const value = await read(conversationId);
|
|
1524
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
1525
|
+
onUnreadable?.(null);
|
|
1526
|
+
} catch (error) {
|
|
1527
|
+
onUnreadable?.(error instanceof Error ? error.message : String(error));
|
|
1485
1528
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1529
|
+
return null;
|
|
1530
|
+
}
|
|
1531
|
+
function firstString(candidates, key) {
|
|
1532
|
+
for (const candidate of candidates) {
|
|
1533
|
+
const value = nonBlank(candidate[key]);
|
|
1534
|
+
if (value) return value.trim();
|
|
1491
1535
|
}
|
|
1492
|
-
return
|
|
1536
|
+
return null;
|
|
1493
1537
|
}
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1538
|
+
function readLiveRunRejoin(error) {
|
|
1539
|
+
if (statusOf(error) !== 409) return null;
|
|
1540
|
+
const candidates = detailCandidates(bodyOf(error));
|
|
1541
|
+
if (candidates.length === 0) return null;
|
|
1542
|
+
const code = readMatrxErrorCode(error);
|
|
1543
|
+
if (code !== MATRX_RUN_IN_PROGRESS) return null;
|
|
1544
|
+
const liveRequestId = firstString(candidates, "live_request_id");
|
|
1545
|
+
const pathFromBody = firstString(candidates, "rejoin_path");
|
|
1546
|
+
const rejoinPath = pathFromBody && pathFromBody.startsWith("/") ? pathFromBody : liveRequestId ? runtimeOperationRejoinPath(liveRequestId) : null;
|
|
1547
|
+
if (!rejoinPath) return null;
|
|
1548
|
+
const root = bodyOf(error);
|
|
1549
|
+
return {
|
|
1550
|
+
liveRequestId,
|
|
1551
|
+
rejoinPath,
|
|
1552
|
+
runId: firstString(candidates, "run_id"),
|
|
1553
|
+
code,
|
|
1554
|
+
body: isRecord3(root) ? root : {}
|
|
1555
|
+
};
|
|
1556
|
+
}
|
|
1557
|
+
function readLiveRunRequestId(error) {
|
|
1558
|
+
return readLiveRunRejoin(error)?.liveRequestId ?? null;
|
|
1559
|
+
}
|
|
1560
|
+
function isResumeConflict(error) {
|
|
1561
|
+
return statusOf(error) === 409 && readMatrxErrorCode(error) === MATRX_RESUME_CONFLICT;
|
|
1562
|
+
}
|
|
1563
|
+
function isLiveStreamUnavailable(error) {
|
|
1564
|
+
return statusOf(error) === 409 && readMatrxErrorCode(error) === MATRX_LIVE_STREAM_UNAVAILABLE;
|
|
1565
|
+
}
|
|
1566
|
+
function runtimeOperationRejoinPath(requestId) {
|
|
1567
|
+
return `/runtime/operations/${encodePathSegment(requestId)}/rejoin`;
|
|
1568
|
+
}
|
|
1569
|
+
function streamErrorText(eventOrPayload) {
|
|
1570
|
+
if (!isRecord3(eventOrPayload)) return null;
|
|
1571
|
+
const payload = typeof eventOrPayload.event === "string" && isRecord3(eventOrPayload.data) ? eventOrPayload.data : eventOrPayload;
|
|
1572
|
+
return nonBlank(payload.user_message) ?? nonBlank(payload.message);
|
|
1573
|
+
}
|
|
1574
|
+
async function openMatrxStream(transport, path, options = {}) {
|
|
1575
|
+
const response = await requestStream(transport, path, {
|
|
1576
|
+
method: "POST",
|
|
1577
|
+
...options.body !== void 0 ? { body: options.body } : {},
|
|
1578
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1579
|
+
});
|
|
1580
|
+
return toRunHandle(response, options);
|
|
1581
|
+
}
|
|
1582
|
+
function withRunOrganization(transport, organizationId) {
|
|
1583
|
+
const orgId = requireOrganizationContext(organizationId);
|
|
1584
|
+
return {
|
|
1585
|
+
fetch: (path, init) => transport.fetch(path, {
|
|
1586
|
+
...init,
|
|
1587
|
+
headers: { ...init.headers, "X-Organization-Id": orgId }
|
|
1588
|
+
})
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
async function followWorkflowRunEvents(transport, runId, options) {
|
|
1592
|
+
const headers = { Accept: "text/event-stream" };
|
|
1593
|
+
if (options.lastEventId) headers["Last-Event-ID"] = String(options.lastEventId);
|
|
1594
|
+
let response;
|
|
1497
1595
|
try {
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1596
|
+
response = await requestStream(
|
|
1597
|
+
transport,
|
|
1598
|
+
`/runs/${encodePathSegment(runId)}/events/stream`,
|
|
1599
|
+
{
|
|
1600
|
+
method: "GET",
|
|
1601
|
+
headers,
|
|
1602
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1603
|
+
}
|
|
1604
|
+
);
|
|
1605
|
+
} catch (error) {
|
|
1606
|
+
if (options.signal?.aborted) return { ended: false };
|
|
1607
|
+
throw error;
|
|
1608
|
+
}
|
|
1609
|
+
try {
|
|
1610
|
+
for await (const frame of readMatrxSseStream(
|
|
1611
|
+
response.body
|
|
1612
|
+
)) {
|
|
1613
|
+
if (frame.event === "end") return { ended: true };
|
|
1614
|
+
if (frame.data === null) continue;
|
|
1615
|
+
let parsed;
|
|
1616
|
+
try {
|
|
1617
|
+
parsed = JSON.parse(frame.data);
|
|
1618
|
+
} catch {
|
|
1619
|
+
continue;
|
|
1620
|
+
}
|
|
1621
|
+
if (!isRecord3(parsed)) continue;
|
|
1622
|
+
options.onEvent(parsed, parsed.event === "node_stream" ? null : frame.seq);
|
|
1515
1623
|
}
|
|
1624
|
+
} catch (error) {
|
|
1625
|
+
if (!options.signal?.aborted) throw error;
|
|
1516
1626
|
}
|
|
1517
|
-
return
|
|
1627
|
+
return { ended: false };
|
|
1518
1628
|
}
|
|
1519
|
-
function
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1629
|
+
async function drain(handle, onEnvelope) {
|
|
1630
|
+
for await (const envelope of handle.events) onEnvelope(envelope);
|
|
1631
|
+
}
|
|
1632
|
+
async function resumeOrRejoin(transport, resumeCall, options) {
|
|
1633
|
+
const {
|
|
1634
|
+
onEnvelope,
|
|
1635
|
+
organizationId,
|
|
1636
|
+
onRejoin,
|
|
1637
|
+
onOperationEvent,
|
|
1638
|
+
onWorkflowEvent,
|
|
1639
|
+
follow,
|
|
1640
|
+
...rest
|
|
1641
|
+
} = options;
|
|
1642
|
+
const bound = organizationId ? withRunOrganization(transport, organizationId) : transport;
|
|
1643
|
+
const streamOptions = {
|
|
1644
|
+
...rest,
|
|
1645
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1646
|
+
};
|
|
1647
|
+
const signalOnly = options.signal ? { signal: options.signal } : {};
|
|
1648
|
+
let rejoin;
|
|
1649
|
+
try {
|
|
1650
|
+
const handle = await resumeCall(bound, streamOptions);
|
|
1651
|
+
await drain(handle, onEnvelope);
|
|
1652
|
+
return { kind: "resumed", requestId: handle.requestId };
|
|
1653
|
+
} catch (error) {
|
|
1654
|
+
const target = readLiveRunRejoin(error);
|
|
1655
|
+
if (!target) {
|
|
1656
|
+
if (error instanceof MatrxApiError && isResumeConflict(error)) {
|
|
1657
|
+
return { kind: "resume_conflict", error };
|
|
1658
|
+
}
|
|
1659
|
+
throw error;
|
|
1660
|
+
}
|
|
1661
|
+
rejoin = target;
|
|
1527
1662
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
status
|
|
1663
|
+
onRejoin?.(rejoin);
|
|
1664
|
+
let unavailable;
|
|
1665
|
+
try {
|
|
1666
|
+
const handle = await openMatrxStream(bound, rejoin.rejoinPath, {
|
|
1667
|
+
...streamOptions,
|
|
1668
|
+
// The rejoin routes take no body model; the reference client posts {}.
|
|
1669
|
+
body: {}
|
|
1536
1670
|
});
|
|
1671
|
+
await drain(handle, onEnvelope);
|
|
1672
|
+
return { kind: "rejoined", rejoin };
|
|
1673
|
+
} catch (error) {
|
|
1674
|
+
const read = readLiveStreamUnavailable(error);
|
|
1675
|
+
if (!read) throw error;
|
|
1676
|
+
unavailable = read;
|
|
1537
1677
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1678
|
+
return followUnavailableRejoin(bound, rejoin, unavailable, {
|
|
1679
|
+
...signalOnly,
|
|
1680
|
+
...onOperationEvent ? { onOperationEvent } : {},
|
|
1681
|
+
...onWorkflowEvent ? { onWorkflowEvent } : {},
|
|
1682
|
+
...follow ? { follow } : {}
|
|
1683
|
+
});
|
|
1684
|
+
}
|
|
1685
|
+
function readLiveStreamUnavailable(error) {
|
|
1686
|
+
if (!isLiveStreamUnavailable(error)) return null;
|
|
1687
|
+
return { runId: firstString(detailCandidates(bodyOf(error)), "run_id") };
|
|
1688
|
+
}
|
|
1689
|
+
async function followUnavailableRejoin(transport, rejoin, unavailable, options = {}) {
|
|
1690
|
+
const bound = options.organizationId ? withRunOrganization(transport, options.organizationId) : transport;
|
|
1691
|
+
const signalOnly = options.signal ? { signal: options.signal } : {};
|
|
1692
|
+
const runId = unavailable.runId ?? rejoin.runId;
|
|
1693
|
+
if (runId && rejoin.rejoinPath.startsWith("/runtime/operations/")) {
|
|
1694
|
+
const result2 = await followWorkflowRunEvents(bound, runId, {
|
|
1695
|
+
...signalOnly,
|
|
1696
|
+
onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq)
|
|
1547
1697
|
});
|
|
1698
|
+
return { kind: "followed_workflow", rejoin, runId, ended: result2.ended };
|
|
1548
1699
|
}
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
detail: firstMsg ? `Validation error: ${firstMsg}` : JSON.stringify(body.detail),
|
|
1555
|
-
userMessage: firstMsg || `Request failed (${status})`,
|
|
1556
|
-
details: body.detail,
|
|
1557
|
-
status
|
|
1558
|
-
});
|
|
1700
|
+
const liveRequestId = rejoin.liveRequestId;
|
|
1701
|
+
const statusView = liveRequestId ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly) : null;
|
|
1702
|
+
const operation = statusView?.operations.find((op) => !op.is_terminal) ?? statusView?.operations[0] ?? null;
|
|
1703
|
+
if (!operation) {
|
|
1704
|
+
return { kind: "followed", rejoin, executionId: null, ended: false, status: null };
|
|
1559
1705
|
}
|
|
1560
|
-
if (
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
details: d.details ?? d,
|
|
1569
|
-
requestId: typeof d.request_id === "string" ? d.request_id : void 0,
|
|
1570
|
-
status
|
|
1571
|
-
});
|
|
1706
|
+
if (operation.is_terminal) {
|
|
1707
|
+
return {
|
|
1708
|
+
kind: "followed",
|
|
1709
|
+
rejoin,
|
|
1710
|
+
executionId: operation.execution_id,
|
|
1711
|
+
ended: true,
|
|
1712
|
+
status: operation.status
|
|
1713
|
+
};
|
|
1572
1714
|
}
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
1579
|
-
status
|
|
1715
|
+
const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {
|
|
1716
|
+
...options.follow,
|
|
1717
|
+
lastEventSeq: operation.last_event_seq,
|
|
1718
|
+
...signalOnly,
|
|
1719
|
+
onEvent: (event) => options.onOperationEvent?.(event)
|
|
1580
1720
|
});
|
|
1721
|
+
return {
|
|
1722
|
+
kind: "followed",
|
|
1723
|
+
rejoin,
|
|
1724
|
+
executionId: operation.execution_id,
|
|
1725
|
+
ended: result.ended,
|
|
1726
|
+
status: result.status
|
|
1727
|
+
};
|
|
1581
1728
|
}
|
|
1582
|
-
function
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1729
|
+
async function attempt(run) {
|
|
1730
|
+
try {
|
|
1731
|
+
await run();
|
|
1732
|
+
return { reloaded: true };
|
|
1733
|
+
} catch (error) {
|
|
1734
|
+
return { reloaded: false, error };
|
|
1735
|
+
}
|
|
1586
1736
|
}
|
|
1587
|
-
function
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1737
|
+
async function settleRunPickup(pickup, options) {
|
|
1738
|
+
switch (pickup.kind) {
|
|
1739
|
+
case "resumed":
|
|
1740
|
+
case "rejoined":
|
|
1741
|
+
return { state: "streamed" };
|
|
1742
|
+
case "resume_conflict":
|
|
1743
|
+
return { state: "retry" };
|
|
1744
|
+
case "followed_workflow":
|
|
1745
|
+
case "followed": {
|
|
1746
|
+
const status = pickup.kind === "followed" ? pickup.status : null;
|
|
1747
|
+
const nothingLive = pickup.kind === "followed" && pickup.executionId === null;
|
|
1748
|
+
if (pickup.ended || nothingLive) {
|
|
1749
|
+
return { state: "settled", status, ...await attempt(options.reloadSavedTurn) };
|
|
1750
|
+
}
|
|
1751
|
+
return {
|
|
1752
|
+
state: "still_running",
|
|
1753
|
+
...await attempt(options.onStillRunning ?? options.reloadSavedTurn)
|
|
1754
|
+
};
|
|
1755
|
+
}
|
|
1594
1756
|
}
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1757
|
+
}
|
|
1758
|
+
|
|
1759
|
+
// matrx/run.ts
|
|
1760
|
+
async function streamCall(transport, path, body, options) {
|
|
1761
|
+
const response = await requestStream(transport, path, {
|
|
1762
|
+
method: "POST",
|
|
1763
|
+
// This client IS the streaming path — `stream: true` always, last so a
|
|
1764
|
+
// caller-supplied value can never flip the response off NDJSON.
|
|
1765
|
+
body: { ...body, stream: true },
|
|
1766
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1603
1767
|
});
|
|
1768
|
+
return toRunHandle(response, options);
|
|
1604
1769
|
}
|
|
1605
|
-
function
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1770
|
+
function startAgentRun(transport, agentId, request, options = {}) {
|
|
1771
|
+
return streamCall(
|
|
1772
|
+
transport,
|
|
1773
|
+
`/ai/agents/${encodePathSegment(agentId)}`,
|
|
1774
|
+
request,
|
|
1775
|
+
options
|
|
1776
|
+
);
|
|
1777
|
+
}
|
|
1778
|
+
function startMandateRun(transport, mandateKey, request, options = {}) {
|
|
1779
|
+
return streamCall(
|
|
1780
|
+
transport,
|
|
1781
|
+
`/ai/mandates/${encodePathSegment(mandateKey)}`,
|
|
1782
|
+
request,
|
|
1783
|
+
options
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
function continueAgentConversation(transport, conversationId, request, options = {}) {
|
|
1787
|
+
return streamCall(
|
|
1788
|
+
transport,
|
|
1789
|
+
`/ai/conversations/${encodePathSegment(conversationId)}`,
|
|
1790
|
+
request,
|
|
1791
|
+
options
|
|
1792
|
+
);
|
|
1793
|
+
}
|
|
1794
|
+
function resumeAgentConversation(transport, conversationId, request = {}, options = {}) {
|
|
1795
|
+
return streamCall(
|
|
1796
|
+
transport,
|
|
1797
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/resume`,
|
|
1798
|
+
request,
|
|
1799
|
+
options
|
|
1611
1800
|
);
|
|
1612
|
-
const summary = typeof error.message === "string" ? error.message : "Backend operation failed";
|
|
1613
|
-
const specific = typeof firstSpecific?.message === "string" ? firstSpecific.message : summary;
|
|
1614
|
-
const detail = specific === summary ? summary : `${summary}: ${specific}`;
|
|
1615
|
-
const code = typeof error.type === "string" ? error.type : "internal_error";
|
|
1616
|
-
const userMessage = typeof error.user_message === "string" && error.user_message ? error.user_message : detail;
|
|
1617
|
-
return new BackendApiError({
|
|
1618
|
-
code,
|
|
1619
|
-
detail,
|
|
1620
|
-
userMessage,
|
|
1621
|
-
details: error,
|
|
1622
|
-
requestId
|
|
1623
|
-
});
|
|
1624
1801
|
}
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1802
|
+
function cancelAgentRun(transport, requestId, options = {}) {
|
|
1803
|
+
const query = buildQuery(
|
|
1804
|
+
options.mode === "interrupt" ? { mode: "interrupt" } : {}
|
|
1805
|
+
);
|
|
1806
|
+
return requestJson(
|
|
1807
|
+
transport,
|
|
1808
|
+
`/ai/cancel/${encodePathSegment(requestId)}${query}`,
|
|
1809
|
+
{
|
|
1810
|
+
method: "POST",
|
|
1811
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1812
|
+
}
|
|
1813
|
+
);
|
|
1637
1814
|
}
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1815
|
+
var MatrxRunError = class extends Error {
|
|
1816
|
+
name = "MatrxRunError";
|
|
1817
|
+
/** The verbatim `error` event payload, when one fired. */
|
|
1818
|
+
errorPayload;
|
|
1819
|
+
/** The `user_request` completion status (`"failed"` | `"cancelled"`), when that was the trigger. */
|
|
1820
|
+
completionStatus;
|
|
1821
|
+
/** Text streamed before the failure — partial content never vanishes. */
|
|
1822
|
+
partialText;
|
|
1823
|
+
constructor(args) {
|
|
1824
|
+
super(args.message);
|
|
1825
|
+
this.errorPayload = args.errorPayload ?? null;
|
|
1826
|
+
this.completionStatus = args.completionStatus ?? null;
|
|
1827
|
+
this.partialText = args.partialText ?? "";
|
|
1647
1828
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
if (!inner) return null;
|
|
1652
|
-
const statusMatch = /\bHTTP (\d{3})\b/.exec(message.slice(0, start));
|
|
1653
|
-
return {
|
|
1654
|
-
message: inner,
|
|
1655
|
-
code: typeof body.error_type === "string" && body.error_type || typeof body.error === "string" && body.error || null,
|
|
1656
|
-
userMessage: typeof body.user_message === "string" ? body.user_message : null,
|
|
1657
|
-
requestId: typeof body.request_id === "string" ? body.request_id : null,
|
|
1658
|
-
status: statusMatch ? Number(statusMatch[1]) : null
|
|
1659
|
-
};
|
|
1829
|
+
};
|
|
1830
|
+
function isRecord4(value) {
|
|
1831
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1660
1832
|
}
|
|
1661
|
-
function
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
if (
|
|
1674
|
-
|
|
1833
|
+
function stringField(value, key) {
|
|
1834
|
+
if (!isRecord4(value)) return null;
|
|
1835
|
+
const field = value[key];
|
|
1836
|
+
return typeof field === "string" && field ? field : null;
|
|
1837
|
+
}
|
|
1838
|
+
async function runAgentToCompletion(transport, agentId, request, options = {}) {
|
|
1839
|
+
const handle = await startAgentRun(transport, agentId, request, options);
|
|
1840
|
+
let text = "";
|
|
1841
|
+
let completion = null;
|
|
1842
|
+
let failure = null;
|
|
1843
|
+
for await (const envelope of handle.events) {
|
|
1844
|
+
options.onEvent?.(envelope);
|
|
1845
|
+
if (envelope.event === "chunk") {
|
|
1846
|
+
const chunk = stringField(envelope.data, "text");
|
|
1847
|
+
if (chunk !== null) {
|
|
1848
|
+
text += chunk;
|
|
1849
|
+
options.onChunk?.(text);
|
|
1850
|
+
}
|
|
1851
|
+
continue;
|
|
1852
|
+
}
|
|
1853
|
+
if (envelope.event === "error" && failure === null) {
|
|
1854
|
+
const payload = isRecord4(envelope.data) ? envelope.data : null;
|
|
1855
|
+
failure = new MatrxRunError({
|
|
1856
|
+
message: streamErrorText(payload) ?? "The agent run failed",
|
|
1857
|
+
errorPayload: payload,
|
|
1858
|
+
partialText: text
|
|
1859
|
+
});
|
|
1860
|
+
continue;
|
|
1861
|
+
}
|
|
1862
|
+
if (envelope.event !== "completion" || !isRecord4(envelope.data)) continue;
|
|
1863
|
+
if (envelope.data.operation !== "user_request") continue;
|
|
1864
|
+
completion = envelope.data;
|
|
1865
|
+
const status = envelope.data.status;
|
|
1866
|
+
if ((status === "failed" || status === "cancelled") && failure === null) {
|
|
1867
|
+
const result = isRecord4(envelope.data.result) ? envelope.data.result : null;
|
|
1868
|
+
failure = new MatrxRunError({
|
|
1869
|
+
message: stringField(result, "error") ?? stringField(result, "user_message") ?? `The agent run ${status}`,
|
|
1870
|
+
completionStatus: status,
|
|
1871
|
+
partialText: text
|
|
1872
|
+
});
|
|
1675
1873
|
}
|
|
1676
|
-
} else if (error instanceof Error) {
|
|
1677
|
-
chain.push(error.message);
|
|
1678
|
-
userFacing = error.message;
|
|
1679
|
-
} else if (typeof error === "string") {
|
|
1680
|
-
chain.push(error);
|
|
1681
|
-
userFacing = error;
|
|
1682
|
-
} else {
|
|
1683
|
-
chain.push("Unknown error");
|
|
1684
1874
|
}
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
if (
|
|
1690
|
-
if (upstream.requestId) requestId = upstream.requestId;
|
|
1691
|
-
if (upstream.status !== null) status = upstream.status;
|
|
1875
|
+
if (failure) throw failure;
|
|
1876
|
+
if (!text && completion) {
|
|
1877
|
+
const result = completion.result;
|
|
1878
|
+
const output = stringField(result, "output");
|
|
1879
|
+
if (output !== null) text = output;
|
|
1692
1880
|
}
|
|
1693
|
-
const specific = [...chain].reverse().find((message) => !isGenericUserMessage(message));
|
|
1694
|
-
const cause = specific ?? chain[0] ?? "Unknown error";
|
|
1695
|
-
const headlineWasGeneric = isGenericUserMessage(userFacing);
|
|
1696
1881
|
return {
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
chain,
|
|
1702
|
-
requestId,
|
|
1703
|
-
status
|
|
1882
|
+
text,
|
|
1883
|
+
requestId: handle.requestId,
|
|
1884
|
+
conversationId: handle.conversationId,
|
|
1885
|
+
completion
|
|
1704
1886
|
};
|
|
1705
1887
|
}
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
if (
|
|
1717
|
-
|
|
1888
|
+
|
|
1889
|
+
// matrx/provider-failures.ts
|
|
1890
|
+
var clip = (value, max) => value.length > max ? value.slice(0, max) : value;
|
|
1891
|
+
function providerSessionFailureBody(failure) {
|
|
1892
|
+
const message = failure.message?.trim() || failure.error_type?.trim() || (failure.status_code ? `HTTP ${failure.status_code}` : "provider session failed");
|
|
1893
|
+
const body = {
|
|
1894
|
+
provider: failure.provider,
|
|
1895
|
+
message: clip(message, 4e3)
|
|
1896
|
+
};
|
|
1897
|
+
if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);
|
|
1898
|
+
if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);
|
|
1899
|
+
if (typeof failure.status_code === "number" && Number.isInteger(failure.status_code) && failure.status_code >= 100 && failure.status_code <= 599) {
|
|
1900
|
+
body.status_code = failure.status_code;
|
|
1718
1901
|
}
|
|
1719
|
-
return
|
|
1902
|
+
return body;
|
|
1720
1903
|
}
|
|
1721
|
-
function
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1904
|
+
async function reportProviderSessionFailure(transport, failure, options = {}) {
|
|
1905
|
+
try {
|
|
1906
|
+
return await requestJson(
|
|
1907
|
+
transport,
|
|
1908
|
+
"/broker/provider-failures",
|
|
1909
|
+
{
|
|
1910
|
+
method: "POST",
|
|
1911
|
+
body: providerSessionFailureBody(failure),
|
|
1912
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1913
|
+
}
|
|
1914
|
+
);
|
|
1915
|
+
} catch (error) {
|
|
1916
|
+
console.warn(
|
|
1917
|
+
`[provider-failures] could not report a ${failure.provider} session failure`,
|
|
1918
|
+
error
|
|
1919
|
+
);
|
|
1920
|
+
return null;
|
|
1733
1921
|
}
|
|
1734
1922
|
}
|
|
1735
1923
|
|
|
1924
|
+
// matrx/tools.ts
|
|
1925
|
+
function submitAgentToolResults(transport, conversationId, results, options = {}) {
|
|
1926
|
+
return requestJson(
|
|
1927
|
+
transport,
|
|
1928
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/tool_results`,
|
|
1929
|
+
{
|
|
1930
|
+
method: "POST",
|
|
1931
|
+
body: {
|
|
1932
|
+
results,
|
|
1933
|
+
...options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
1934
|
+
},
|
|
1935
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1936
|
+
}
|
|
1937
|
+
);
|
|
1938
|
+
}
|
|
1939
|
+
function listConversationPendingToolCalls(transport, conversationId, options = {}) {
|
|
1940
|
+
return requestJson(
|
|
1941
|
+
transport,
|
|
1942
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/pending_calls`,
|
|
1943
|
+
{
|
|
1944
|
+
method: "GET",
|
|
1945
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1946
|
+
}
|
|
1947
|
+
);
|
|
1948
|
+
}
|
|
1949
|
+
function listUserPendingToolCalls(transport, options = {}) {
|
|
1950
|
+
const query = buildQuery(
|
|
1951
|
+
options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
1952
|
+
);
|
|
1953
|
+
return requestJson(
|
|
1954
|
+
transport,
|
|
1955
|
+
`/ai/user/pending_calls${query}`,
|
|
1956
|
+
{
|
|
1957
|
+
method: "GET",
|
|
1958
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1959
|
+
}
|
|
1960
|
+
);
|
|
1961
|
+
}
|
|
1962
|
+
|
|
1736
1963
|
// matrx/endpoints.ts
|
|
1737
1964
|
var ENDPOINTS = {
|
|
1738
1965
|
/** AI endpoints — chat, agents, conversations */
|
|
@@ -2363,6 +2590,7 @@ export {
|
|
|
2363
2590
|
MATRX_LIVE_STREAM_UNAVAILABLE,
|
|
2364
2591
|
MATRX_RESUME_CONFLICT,
|
|
2365
2592
|
MATRX_RUN_IN_PROGRESS,
|
|
2593
|
+
MATRX_UI_ONLY_BODY_FIELDS,
|
|
2366
2594
|
MatrxApiError,
|
|
2367
2595
|
MatrxRunError,
|
|
2368
2596
|
OrganizationContextError,
|
|
@@ -2378,6 +2606,10 @@ export {
|
|
|
2378
2606
|
applyOrganizationContextHeader,
|
|
2379
2607
|
assertOrganizationMatchesOperation,
|
|
2380
2608
|
assertQueryOrganizationMatchesContext,
|
|
2609
|
+
bareStatusSentence,
|
|
2610
|
+
buildMatrxRequestBody,
|
|
2611
|
+
buildMatrxRequestUrl,
|
|
2612
|
+
buildSafeRequestLog,
|
|
2381
2613
|
cancelAgentRun,
|
|
2382
2614
|
continueAgentConversation,
|
|
2383
2615
|
continueEphemeralConversationStart,
|
|
@@ -2385,6 +2617,7 @@ export {
|
|
|
2385
2617
|
createMatrxTransport,
|
|
2386
2618
|
createOrganizationOperation,
|
|
2387
2619
|
describeBackendFailure,
|
|
2620
|
+
executeMatrxCall,
|
|
2388
2621
|
extractMatrxErrorCode,
|
|
2389
2622
|
extractMatrxErrorMessage,
|
|
2390
2623
|
fetchWithMatrxProtocolFallback,
|
|
@@ -2395,6 +2628,8 @@ export {
|
|
|
2395
2628
|
getRuntimeOperationStatus,
|
|
2396
2629
|
getRuntimeOperationsByLink,
|
|
2397
2630
|
getUserMessage,
|
|
2631
|
+
honestTransportMessage,
|
|
2632
|
+
isBareTransportCode,
|
|
2398
2633
|
isCoveredAiPath,
|
|
2399
2634
|
isGenericUserMessage,
|
|
2400
2635
|
isJobOutputKind,
|
|
@@ -2414,6 +2649,7 @@ export {
|
|
|
2414
2649
|
parseCallApiError,
|
|
2415
2650
|
parseHttpError,
|
|
2416
2651
|
parseHttpErrorBody,
|
|
2652
|
+
parseMatrxNdjsonResponse,
|
|
2417
2653
|
parsePersistedBackendError,
|
|
2418
2654
|
parseStreamError,
|
|
2419
2655
|
providerSessionFailureBody,
|
|
@@ -2423,6 +2659,7 @@ export {
|
|
|
2423
2659
|
readLiveStreamUnavailable,
|
|
2424
2660
|
readMatrxErrorCode,
|
|
2425
2661
|
readMatrxErrorCodeFromMessage,
|
|
2662
|
+
redactUrlForRequestLog,
|
|
2426
2663
|
rejoinRuntimeOperation,
|
|
2427
2664
|
reportProviderSessionFailure,
|
|
2428
2665
|
requireOrganizationContext,
|
|
@@ -2437,6 +2674,7 @@ export {
|
|
|
2437
2674
|
runWaitTimeoutMessage,
|
|
2438
2675
|
runtimeOperationRejoinPath,
|
|
2439
2676
|
settleRunPickup,
|
|
2677
|
+
shouldReportMatrxCallError,
|
|
2440
2678
|
startAgentRun,
|
|
2441
2679
|
startMandateRun,
|
|
2442
2680
|
streamErrorText,
|