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