@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/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ __export(index_exports, {
|
|
|
31
31
|
MATRX_LIVE_STREAM_UNAVAILABLE: () => MATRX_LIVE_STREAM_UNAVAILABLE,
|
|
32
32
|
MATRX_RESUME_CONFLICT: () => MATRX_RESUME_CONFLICT,
|
|
33
33
|
MATRX_RUN_IN_PROGRESS: () => MATRX_RUN_IN_PROGRESS,
|
|
34
|
+
MATRX_UI_ONLY_BODY_FIELDS: () => MATRX_UI_ONLY_BODY_FIELDS,
|
|
34
35
|
MatrxApiError: () => MatrxApiError,
|
|
35
36
|
MatrxRunError: () => MatrxRunError,
|
|
36
37
|
OrganizationContextError: () => OrganizationContextError,
|
|
@@ -48,6 +49,10 @@ __export(index_exports, {
|
|
|
48
49
|
applyOrganizationContextHeader: () => applyOrganizationContextHeader,
|
|
49
50
|
assertOrganizationMatchesOperation: () => assertOrganizationMatchesOperation,
|
|
50
51
|
assertQueryOrganizationMatchesContext: () => assertQueryOrganizationMatchesContext,
|
|
52
|
+
bareStatusSentence: () => bareStatusSentence,
|
|
53
|
+
buildMatrxRequestBody: () => buildMatrxRequestBody,
|
|
54
|
+
buildMatrxRequestUrl: () => buildMatrxRequestUrl,
|
|
55
|
+
buildSafeRequestLog: () => buildSafeRequestLog,
|
|
51
56
|
cancelAgentRun: () => cancelAgentRun,
|
|
52
57
|
continueAgentConversation: () => continueAgentConversation,
|
|
53
58
|
continueEphemeralConversationStart: () => continueEphemeralConversationStart,
|
|
@@ -60,6 +65,7 @@ __export(index_exports, {
|
|
|
60
65
|
createWorkflowNodeProjection: () => createWorkflowNodeProjection,
|
|
61
66
|
deriveRunInputs: () => deriveRunInputs,
|
|
62
67
|
describeBackendFailure: () => describeBackendFailure,
|
|
68
|
+
executeMatrxCall: () => executeMatrxCall,
|
|
63
69
|
extractMatrxErrorCode: () => extractMatrxErrorCode,
|
|
64
70
|
extractMatrxErrorMessage: () => extractMatrxErrorMessage,
|
|
65
71
|
fetchWithMatrxProtocolFallback: () => fetchWithMatrxProtocolFallback,
|
|
@@ -70,7 +76,9 @@ __export(index_exports, {
|
|
|
70
76
|
getRuntimeOperationStatus: () => getRuntimeOperationStatus,
|
|
71
77
|
getRuntimeOperationsByLink: () => getRuntimeOperationsByLink,
|
|
72
78
|
getUserMessage: () => getUserMessage,
|
|
79
|
+
honestTransportMessage: () => honestTransportMessage,
|
|
73
80
|
imageRoleVerdict: () => imageRoleVerdict,
|
|
81
|
+
isBareTransportCode: () => isBareTransportCode,
|
|
74
82
|
isControlVariable: () => isControlVariable,
|
|
75
83
|
isCoveredAiPath: () => isCoveredAiPath,
|
|
76
84
|
isGenericUserMessage: () => isGenericUserMessage,
|
|
@@ -97,6 +105,7 @@ __export(index_exports, {
|
|
|
97
105
|
parseCallApiError: () => parseCallApiError,
|
|
98
106
|
parseHttpError: () => parseHttpError,
|
|
99
107
|
parseHttpErrorBody: () => parseHttpErrorBody,
|
|
108
|
+
parseMatrxNdjsonResponse: () => parseMatrxNdjsonResponse,
|
|
100
109
|
parseMatrxSseFrame: () => parseMatrxSseFrame,
|
|
101
110
|
parsePersistedBackendError: () => parsePersistedBackendError,
|
|
102
111
|
parseStreamError: () => parseStreamError,
|
|
@@ -115,6 +124,7 @@ __export(index_exports, {
|
|
|
115
124
|
readMatrxErrorCodeFromMessage: () => readMatrxErrorCodeFromMessage,
|
|
116
125
|
readMatrxNdjsonStream: () => readMatrxNdjsonStream,
|
|
117
126
|
readMatrxSseStream: () => readMatrxSseStream,
|
|
127
|
+
redactUrlForRequestLog: () => redactUrlForRequestLog,
|
|
118
128
|
referenceRoleCaption: () => referenceRoleCaption,
|
|
119
129
|
rejoinRuntimeOperation: () => rejoinRuntimeOperation,
|
|
120
130
|
reportProviderSessionFailure: () => reportProviderSessionFailure,
|
|
@@ -132,6 +142,7 @@ __export(index_exports, {
|
|
|
132
142
|
runWaitTimeoutMessage: () => runWaitTimeoutMessage,
|
|
133
143
|
runtimeOperationRejoinPath: () => runtimeOperationRejoinPath,
|
|
134
144
|
settleRunPickup: () => settleRunPickup,
|
|
145
|
+
shouldReportMatrxCallError: () => shouldReportMatrxCallError,
|
|
135
146
|
startAgentRun: () => startAgentRun,
|
|
136
147
|
startMandateRun: () => startMandateRun,
|
|
137
148
|
streamErrorText: () => streamErrorText,
|
|
@@ -1009,1384 +1020,1611 @@ function extractMatrxErrorCode(serverDetail) {
|
|
|
1009
1020
|
// matrx/client.ts
|
|
1010
1021
|
var import_data = require("@ai-matrx/data");
|
|
1011
1022
|
var import_data2 = require("@ai-matrx/data");
|
|
1023
|
+
var import_net2 = require("@ai-matrx/data/net");
|
|
1012
1024
|
|
|
1013
|
-
// matrx/
|
|
1014
|
-
var
|
|
1015
|
-
|
|
1025
|
+
// matrx/backend-errors.ts
|
|
1026
|
+
var BackendApiError = class extends Error {
|
|
1027
|
+
/** Machine-readable error code */
|
|
1016
1028
|
code;
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
const candidate = overrideOrganizationId ?? selectedOrganizationId;
|
|
1037
|
-
if (typeof candidate !== "string" || candidate.trim().length === 0) {
|
|
1038
|
-
throw new OrganizationContextError(
|
|
1039
|
-
"organization_context_required",
|
|
1040
|
-
"Select an organization before sending this request."
|
|
1041
|
-
);
|
|
1029
|
+
/** Developer-facing detail */
|
|
1030
|
+
detail;
|
|
1031
|
+
/** Safe to display directly in the UI */
|
|
1032
|
+
userMessage;
|
|
1033
|
+
/** Extra info (validation errors, etc.) */
|
|
1034
|
+
details;
|
|
1035
|
+
/** Unique request ID for support/debugging */
|
|
1036
|
+
requestId;
|
|
1037
|
+
/** HTTP status code (if from an HTTP response) */
|
|
1038
|
+
status;
|
|
1039
|
+
constructor(data) {
|
|
1040
|
+
super(data.userMessage);
|
|
1041
|
+
this.name = "BackendApiError";
|
|
1042
|
+
this.code = data.code;
|
|
1043
|
+
this.detail = data.detail;
|
|
1044
|
+
this.userMessage = data.userMessage;
|
|
1045
|
+
this.details = data.details ?? null;
|
|
1046
|
+
this.requestId = data.requestId ?? "";
|
|
1047
|
+
this.status = data.status ?? null;
|
|
1042
1048
|
}
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
+
/** Convert to the wire format for logging */
|
|
1050
|
+
toJSON() {
|
|
1051
|
+
return {
|
|
1052
|
+
error: this.code,
|
|
1053
|
+
message: this.detail,
|
|
1054
|
+
user_message: this.userMessage,
|
|
1055
|
+
details: this.details,
|
|
1056
|
+
request_id: this.requestId
|
|
1057
|
+
};
|
|
1049
1058
|
}
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1059
|
+
};
|
|
1060
|
+
var StreamTransportError = class extends BackendApiError {
|
|
1061
|
+
/** Always true — reattach and let the server settle the outcome. */
|
|
1062
|
+
resumable = true;
|
|
1063
|
+
constructor(data) {
|
|
1064
|
+
super({
|
|
1065
|
+
code: "stream_transport_lost",
|
|
1066
|
+
detail: data.detail,
|
|
1067
|
+
userMessage: "The connection dropped. Your run is still going on the server \u2014 reconnecting to it now.",
|
|
1068
|
+
details: data.details ?? null,
|
|
1069
|
+
...data.requestId !== void 0 ? { requestId: data.requestId } : {}
|
|
1070
|
+
});
|
|
1071
|
+
this.name = "StreamTransportError";
|
|
1061
1072
|
}
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
return {
|
|
1068
|
-
...withoutOrganizationHeader,
|
|
1069
|
-
"X-Organization-Id": normalizedOrganizationId
|
|
1070
|
-
};
|
|
1071
|
-
}
|
|
1072
|
-
function assertQueryOrganizationMatchesContext(queryParams, organizationId) {
|
|
1073
|
-
if (!queryParams || queryParams.organization_id === void 0) return;
|
|
1074
|
-
const queryOrganizationId = requireOrganizationContext(
|
|
1075
|
-
String(queryParams.organization_id)
|
|
1076
|
-
);
|
|
1077
|
-
if (queryOrganizationId !== requireOrganizationContext(organizationId)) {
|
|
1078
|
-
throw new OrganizationContextError(
|
|
1079
|
-
"organization_context_mismatch",
|
|
1080
|
-
"Query organization_id must match the request context organization."
|
|
1081
|
-
);
|
|
1073
|
+
};
|
|
1074
|
+
function isStreamTransportLost(error) {
|
|
1075
|
+
if (error instanceof StreamTransportError) return true;
|
|
1076
|
+
if (error instanceof BackendApiError) {
|
|
1077
|
+
return error.code === "stream_transport_lost";
|
|
1082
1078
|
}
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
var V2_COVERED_AI_PATH_TEMPLATES = [
|
|
1089
|
-
"/ai/manual",
|
|
1090
|
-
"/ai/chat",
|
|
1091
|
-
"/ai/agents/{agent_id}",
|
|
1092
|
-
"/ai/agent/{agent_id}",
|
|
1093
|
-
// singular alias — behaves identically
|
|
1094
|
-
"/ai/conversations/{conversation_id}",
|
|
1095
|
-
"/ai/conversation/{conversation_id}",
|
|
1096
|
-
// singular alias
|
|
1097
|
-
"/ai/prompts/{prompt_id}",
|
|
1098
|
-
// saved-prompt execution
|
|
1099
|
-
"/ai/mandates/{mandate_key}"
|
|
1100
|
-
// THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)
|
|
1101
|
-
];
|
|
1102
|
-
function toV2Path(path) {
|
|
1103
|
-
const withLead = path.startsWith("/") ? path : `/${path}`;
|
|
1104
|
-
if (withLead.startsWith("/api/")) {
|
|
1105
|
-
const rest = withLead.slice("/api".length);
|
|
1106
|
-
return rest.startsWith("/v2/") ? withLead : `/api/v2${rest}`;
|
|
1079
|
+
if (error && typeof error === "object") {
|
|
1080
|
+
const code = error.code;
|
|
1081
|
+
if (code === "stream_transport_lost") return true;
|
|
1082
|
+
const errorType = error.error_type;
|
|
1083
|
+
if (errorType === "transport_lost") return true;
|
|
1107
1084
|
}
|
|
1108
|
-
return
|
|
1109
|
-
}
|
|
1110
|
-
var COVERED_INTERPOLATED_PATH = [
|
|
1111
|
-
/^(?:\/api)?\/ai\/manual$/,
|
|
1112
|
-
/^(?:\/api)?\/ai\/chat$/,
|
|
1113
|
-
/^(?:\/api)?\/ai\/agents\/[^/]+$/,
|
|
1114
|
-
/^(?:\/api)?\/ai\/agent\/[^/]+$/,
|
|
1115
|
-
/^(?:\/api)?\/ai\/conversations\/[^/]+$/,
|
|
1116
|
-
/^(?:\/api)?\/ai\/conversation\/[^/]+$/,
|
|
1117
|
-
/^(?:\/api)?\/ai\/prompts\/[^/]+$/,
|
|
1118
|
-
// `/warm` etc. deliberately don't match
|
|
1119
|
-
/^(?:\/api)?\/ai\/mandates\/[^/]+$/
|
|
1120
|
-
// the mandate door
|
|
1121
|
-
];
|
|
1122
|
-
function isCoveredAiPath(path) {
|
|
1123
|
-
return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));
|
|
1124
|
-
}
|
|
1125
|
-
function isV2Path(pathOrUrl) {
|
|
1126
|
-
return /\/v2\/ai\//.test(pathOrUrl);
|
|
1127
|
-
}
|
|
1128
|
-
function toV1FallbackUrl(url) {
|
|
1129
|
-
return url.replace(/\/v2\/ai\//, "/ai/");
|
|
1130
|
-
}
|
|
1131
|
-
function applyAiApiVersion(path, version) {
|
|
1132
|
-
if (version !== "v2") return path;
|
|
1133
|
-
return isCoveredAiPath(path) ? toV2Path(path) : path;
|
|
1085
|
+
return false;
|
|
1134
1086
|
}
|
|
1135
|
-
async function
|
|
1136
|
-
const
|
|
1137
|
-
|
|
1138
|
-
console.warn(
|
|
1139
|
-
`[matrx] ai_v2_downgrade \u2192 retrying on v1. v2=${url} reason=${reason}`
|
|
1140
|
-
);
|
|
1141
|
-
onDowngrade?.({ url, reason, ...status2 !== void 0 ? { status: status2 } : {} });
|
|
1142
|
-
};
|
|
1143
|
-
if (!isV2Path(url)) return (0, import_net.resilientFetch)(url, init, fetchOpts);
|
|
1144
|
-
let result;
|
|
1087
|
+
async function parseHttpError(response) {
|
|
1088
|
+
const status = response.status;
|
|
1089
|
+
let body = null;
|
|
1145
1090
|
try {
|
|
1146
|
-
|
|
1147
|
-
} catch
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
map[template] = toV2Path(template);
|
|
1091
|
+
body = await response.json();
|
|
1092
|
+
} catch {
|
|
1093
|
+
try {
|
|
1094
|
+
const text = await response.text();
|
|
1095
|
+
return new BackendApiError({
|
|
1096
|
+
code: statusToCode(status),
|
|
1097
|
+
detail: text || `HTTP ${status}`,
|
|
1098
|
+
userMessage: text || `Request failed (${status})`,
|
|
1099
|
+
status
|
|
1100
|
+
});
|
|
1101
|
+
} catch {
|
|
1102
|
+
return new BackendApiError({
|
|
1103
|
+
code: statusToCode(status),
|
|
1104
|
+
detail: `HTTP ${status}`,
|
|
1105
|
+
userMessage: `Request failed (${status})`,
|
|
1106
|
+
status
|
|
1107
|
+
});
|
|
1108
|
+
}
|
|
1165
1109
|
}
|
|
1166
|
-
return
|
|
1167
|
-
}
|
|
1168
|
-
|
|
1169
|
-
// matrx/client.ts
|
|
1170
|
-
function classifyStatus(status) {
|
|
1171
|
-
return status >= 400 && status < 500 ? "validation_error" : "http_error";
|
|
1110
|
+
return parseHttpErrorBody(body, status);
|
|
1172
1111
|
}
|
|
1173
|
-
function
|
|
1174
|
-
if (
|
|
1175
|
-
return {
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
name: err.name
|
|
1182
|
-
};
|
|
1112
|
+
function parseHttpErrorBody(body, status) {
|
|
1113
|
+
if (!body) {
|
|
1114
|
+
return new BackendApiError({
|
|
1115
|
+
code: statusToCode(status),
|
|
1116
|
+
detail: `HTTP ${status}`,
|
|
1117
|
+
userMessage: `Request failed (${status})`,
|
|
1118
|
+
status
|
|
1119
|
+
});
|
|
1183
1120
|
}
|
|
1184
|
-
if (
|
|
1185
|
-
return {
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1121
|
+
if (typeof body.error === "string" && typeof body.user_message === "string") {
|
|
1122
|
+
return new BackendApiError({
|
|
1123
|
+
code: body.error,
|
|
1124
|
+
detail: body.message || `HTTP ${status}`,
|
|
1125
|
+
userMessage: body.user_message,
|
|
1126
|
+
details: body.details ?? null,
|
|
1127
|
+
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
1128
|
+
status
|
|
1129
|
+
});
|
|
1192
1130
|
}
|
|
1193
|
-
if (
|
|
1194
|
-
|
|
1131
|
+
if (typeof body.error === "object" && body.error !== null) {
|
|
1132
|
+
const errorObj = body.error;
|
|
1133
|
+
return new BackendApiError({
|
|
1134
|
+
code: errorObj.type || errorObj.error || statusToCode(status),
|
|
1135
|
+
detail: errorObj.message || `HTTP ${status}`,
|
|
1136
|
+
userMessage: errorObj.user_message || errorObj.user_visible_message || errorObj.message || `Request failed (${status})`,
|
|
1137
|
+
details: errorObj.details ?? null,
|
|
1138
|
+
requestId: typeof errorObj.request_id === "string" ? errorObj.request_id : void 0,
|
|
1139
|
+
status
|
|
1140
|
+
});
|
|
1195
1141
|
}
|
|
1196
|
-
if ((
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1142
|
+
if (Array.isArray(body.detail)) {
|
|
1143
|
+
const first = body.detail[0];
|
|
1144
|
+
const firstMsg = first && typeof first.msg === "string" ? first.msg : null;
|
|
1145
|
+
return new BackendApiError({
|
|
1146
|
+
code: statusToCode(status),
|
|
1147
|
+
detail: firstMsg ? `Validation error: ${firstMsg}` : JSON.stringify(body.detail),
|
|
1148
|
+
userMessage: firstMsg || `Request failed (${status})`,
|
|
1149
|
+
details: body.detail,
|
|
1150
|
+
status
|
|
1151
|
+
});
|
|
1205
1152
|
}
|
|
1206
|
-
if (
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1153
|
+
if (typeof body.detail === "object" && body.detail !== null && !Array.isArray(body.detail)) {
|
|
1154
|
+
const d = body.detail;
|
|
1155
|
+
const code = typeof d.code === "string" && d.code || typeof d.error === "string" && d.error || statusToCode(status);
|
|
1156
|
+
const message = typeof d.message === "string" && d.message || typeof d.detail === "string" && d.detail || `HTTP ${status}`;
|
|
1157
|
+
return new BackendApiError({
|
|
1158
|
+
code,
|
|
1159
|
+
detail: message,
|
|
1160
|
+
userMessage: typeof d.user_message === "string" && d.user_message || typeof d.user_visible_message === "string" && d.user_visible_message || message,
|
|
1161
|
+
details: d.details ?? d,
|
|
1162
|
+
requestId: typeof d.request_id === "string" ? d.request_id : void 0,
|
|
1163
|
+
status
|
|
1164
|
+
});
|
|
1217
1165
|
}
|
|
1218
|
-
return
|
|
1166
|
+
return new BackendApiError({
|
|
1167
|
+
code: typeof body.error === "string" ? body.error : statusToCode(status),
|
|
1168
|
+
detail: body.message || body.detail || body.error || `HTTP ${status}`,
|
|
1169
|
+
userMessage: body.user_message || body.user_visible_message || body.message || body.detail || `Request failed (${status})`,
|
|
1170
|
+
details: body.details ?? null,
|
|
1171
|
+
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
1172
|
+
status
|
|
1173
|
+
});
|
|
1219
1174
|
}
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
([name]) => name.toLowerCase() !== "content-type"
|
|
1225
|
-
)
|
|
1226
|
-
);
|
|
1175
|
+
function parseCallApiError(error) {
|
|
1176
|
+
const status = error.status ?? 500;
|
|
1177
|
+
const body = error.serverDetail && typeof error.serverDetail === "object" && !Array.isArray(error.serverDetail) ? error.serverDetail : { message: error.message };
|
|
1178
|
+
return parseHttpErrorBody(body, status);
|
|
1227
1179
|
}
|
|
1228
|
-
function
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,
|
|
1236
|
-
totalTimeoutMs = null,
|
|
1237
|
-
expectedErrorStatuses,
|
|
1238
|
-
diagnostics,
|
|
1239
|
-
source = "matrxTransport"
|
|
1240
|
-
} = options;
|
|
1241
|
-
if (baseUrl === void 0 === (resolveTarget === void 0)) {
|
|
1242
|
-
throw new Error(
|
|
1243
|
-
"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`."
|
|
1244
|
-
);
|
|
1180
|
+
function parseStreamError(data) {
|
|
1181
|
+
if (!data || typeof data !== "object") {
|
|
1182
|
+
return new BackendApiError({
|
|
1183
|
+
code: "internal_error",
|
|
1184
|
+
detail: typeof data === "string" ? data : "Unknown streaming error",
|
|
1185
|
+
userMessage: typeof data === "string" ? data : "Something went wrong"
|
|
1186
|
+
});
|
|
1245
1187
|
}
|
|
1246
|
-
const
|
|
1247
|
-
const
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
};
|
|
1256
|
-
return {
|
|
1257
|
-
async fetch(path, init) {
|
|
1258
|
-
const target = resolve();
|
|
1259
|
-
const versionedPath = applyAiApiVersion(path, resolveVersion());
|
|
1260
|
-
const url = `${target.baseUrl}${versionedPath}`;
|
|
1261
|
-
const credentialHeaders = credentials ? (0, import_data2.credentialToHeaders)(await credentials.get()) : {};
|
|
1262
|
-
let headers = {
|
|
1263
|
-
...init.headers,
|
|
1264
|
-
...stripContentType(credentialHeaders),
|
|
1265
|
-
...stripContentType(target.policyHeaders ?? {})
|
|
1266
|
-
};
|
|
1267
|
-
const orgId = resolveOrganizationId();
|
|
1268
|
-
if (orgId !== null) {
|
|
1269
|
-
headers = applyOrganizationContextHeader(headers, orgId);
|
|
1270
|
-
}
|
|
1271
|
-
const info = {
|
|
1272
|
-
url,
|
|
1273
|
-
method: init.method,
|
|
1274
|
-
path,
|
|
1275
|
-
channel: target.channel ?? "default",
|
|
1276
|
-
source
|
|
1277
|
-
};
|
|
1278
|
-
diagnostics?.onRequest?.(info);
|
|
1279
|
-
let response;
|
|
1280
|
-
try {
|
|
1281
|
-
({ response } = await fetchWithMatrxProtocolFallback(
|
|
1282
|
-
url,
|
|
1283
|
-
{
|
|
1284
|
-
method: init.method,
|
|
1285
|
-
headers,
|
|
1286
|
-
...init.body !== void 0 ? { body: init.body } : {}
|
|
1287
|
-
},
|
|
1288
|
-
{
|
|
1289
|
-
...init.signal ? { signal: init.signal } : {},
|
|
1290
|
-
connectTimeoutMs,
|
|
1291
|
-
totalTimeoutMs,
|
|
1292
|
-
throwOnHttpError: false,
|
|
1293
|
-
...diagnostics?.onProtocolDowngrade ? { onDowngrade: diagnostics.onProtocolDowngrade } : {}
|
|
1294
|
-
}
|
|
1295
|
-
));
|
|
1296
|
-
} catch (err) {
|
|
1297
|
-
diagnostics?.onError?.(normalizeMatrxError(err), info);
|
|
1298
|
-
throw err;
|
|
1299
|
-
}
|
|
1300
|
-
if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {
|
|
1301
|
-
const serverDetail = await response.clone().json().catch(() => void 0);
|
|
1302
|
-
const code = extractMatrxErrorCode(serverDetail);
|
|
1303
|
-
diagnostics?.onError?.(
|
|
1304
|
-
{
|
|
1305
|
-
type: classifyStatus(response.status),
|
|
1306
|
-
message: extractMatrxErrorMessage(serverDetail) ?? `HTTP ${response.status}`,
|
|
1307
|
-
status: response.status,
|
|
1308
|
-
serverDetail,
|
|
1309
|
-
...code ? { code } : {}
|
|
1310
|
-
},
|
|
1311
|
-
info
|
|
1312
|
-
);
|
|
1313
|
-
}
|
|
1314
|
-
return response;
|
|
1315
|
-
}
|
|
1316
|
-
};
|
|
1317
|
-
}
|
|
1318
|
-
|
|
1319
|
-
// matrx/conversation.ts
|
|
1320
|
-
function mintMatrxConversationId() {
|
|
1321
|
-
return crypto.randomUUID();
|
|
1322
|
-
}
|
|
1323
|
-
function newStoredConversationStart(conversationId) {
|
|
1324
|
-
return {
|
|
1325
|
-
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
1326
|
-
is_new: true,
|
|
1327
|
-
store: true
|
|
1328
|
-
};
|
|
1188
|
+
const obj = data;
|
|
1189
|
+
const details = typeof obj.details === "object" && obj.details !== null ? obj.details : null;
|
|
1190
|
+
return new BackendApiError({
|
|
1191
|
+
code: obj.code || obj.error_type || obj.error || "internal_error",
|
|
1192
|
+
detail: obj.message || "Streaming error",
|
|
1193
|
+
userMessage: obj.user_message || obj.message || "Something went wrong",
|
|
1194
|
+
details,
|
|
1195
|
+
requestId: typeof obj.request_id === "string" ? obj.request_id : typeof details?.request_id === "string" ? details.request_id : void 0
|
|
1196
|
+
});
|
|
1329
1197
|
}
|
|
1330
|
-
function
|
|
1331
|
-
|
|
1198
|
+
function parsePersistedBackendError(data, requestId = "") {
|
|
1199
|
+
if (!data || typeof data !== "object") return null;
|
|
1200
|
+
const error = data;
|
|
1201
|
+
const failures = Array.isArray(error.failures) ? error.failures : [];
|
|
1202
|
+
const firstSpecific = failures.find(
|
|
1203
|
+
(failure) => typeof failure === "object" && failure !== null && typeof failure.message === "string"
|
|
1204
|
+
);
|
|
1205
|
+
const summary = typeof error.message === "string" ? error.message : "Backend operation failed";
|
|
1206
|
+
const specific = typeof firstSpecific?.message === "string" ? firstSpecific.message : summary;
|
|
1207
|
+
const detail = specific === summary ? summary : `${summary}: ${specific}`;
|
|
1208
|
+
const code = typeof error.type === "string" ? error.type : "internal_error";
|
|
1209
|
+
const userMessage = typeof error.user_message === "string" && error.user_message ? error.user_message : detail;
|
|
1210
|
+
return new BackendApiError({
|
|
1211
|
+
code,
|
|
1212
|
+
detail,
|
|
1213
|
+
userMessage,
|
|
1214
|
+
details: error,
|
|
1215
|
+
requestId
|
|
1216
|
+
});
|
|
1332
1217
|
}
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1218
|
+
var GENERIC_MESSAGE_PATTERNS = [
|
|
1219
|
+
/failed unexpectedly/i,
|
|
1220
|
+
/^\s*something went wrong/i,
|
|
1221
|
+
/please try again(\s+later)?\.?\s*$/i,
|
|
1222
|
+
/^\s*request failed\b/i,
|
|
1223
|
+
/^\s*unknown (streaming )?error/i,
|
|
1224
|
+
/^\s*internal server error\.?\s*$/i
|
|
1225
|
+
];
|
|
1226
|
+
function isGenericUserMessage(message) {
|
|
1227
|
+
const value = (message ?? "").trim();
|
|
1228
|
+
if (!value) return true;
|
|
1229
|
+
return GENERIC_MESSAGE_PATTERNS.some((pattern) => pattern.test(value));
|
|
1339
1230
|
}
|
|
1340
|
-
function
|
|
1231
|
+
function unwrapUpstreamError(message) {
|
|
1232
|
+
const start = message.indexOf("{");
|
|
1233
|
+
const end = message.lastIndexOf("}");
|
|
1234
|
+
if (start < 0 || end <= start) return null;
|
|
1235
|
+
let parsed;
|
|
1236
|
+
try {
|
|
1237
|
+
parsed = JSON.parse(message.slice(start, end + 1));
|
|
1238
|
+
} catch {
|
|
1239
|
+
return null;
|
|
1240
|
+
}
|
|
1241
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
1242
|
+
const body = parsed;
|
|
1243
|
+
const inner = typeof body.message === "string" && body.message || typeof body.detail === "string" && body.detail || "";
|
|
1244
|
+
if (!inner) return null;
|
|
1245
|
+
const statusMatch = /\bHTTP (\d{3})\b/.exec(message.slice(0, start));
|
|
1341
1246
|
return {
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1247
|
+
message: inner,
|
|
1248
|
+
code: typeof body.error_type === "string" && body.error_type || typeof body.error === "string" && body.error || null,
|
|
1249
|
+
userMessage: typeof body.user_message === "string" ? body.user_message : null,
|
|
1250
|
+
requestId: typeof body.request_id === "string" ? body.request_id : null,
|
|
1251
|
+
status: statusMatch ? Number(statusMatch[1]) : null
|
|
1346
1252
|
};
|
|
1347
1253
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1254
|
+
function describeBackendFailure(error) {
|
|
1255
|
+
const chain = [];
|
|
1256
|
+
let code = "internal_error";
|
|
1257
|
+
let requestId = "";
|
|
1258
|
+
let status = null;
|
|
1259
|
+
let userFacing = null;
|
|
1260
|
+
if (error instanceof BackendApiError) {
|
|
1261
|
+
code = error.code;
|
|
1262
|
+
requestId = error.requestId;
|
|
1263
|
+
status = error.status;
|
|
1264
|
+
userFacing = error.userMessage;
|
|
1265
|
+
if (error.detail) chain.push(error.detail);
|
|
1266
|
+
if (error.userMessage && error.userMessage !== error.detail) {
|
|
1267
|
+
chain.push(error.userMessage);
|
|
1361
1268
|
}
|
|
1269
|
+
} else if (error instanceof Error) {
|
|
1270
|
+
chain.push(error.message);
|
|
1271
|
+
userFacing = error.message;
|
|
1272
|
+
} else if (typeof error === "string") {
|
|
1273
|
+
chain.push(error);
|
|
1274
|
+
userFacing = error;
|
|
1275
|
+
} else {
|
|
1276
|
+
chain.push("Unknown error");
|
|
1362
1277
|
}
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
return void 0;
|
|
1278
|
+
for (let cursor = 0; cursor < chain.length && cursor < 12; cursor += 1) {
|
|
1279
|
+
const upstream = unwrapUpstreamError(chain[cursor] ?? "");
|
|
1280
|
+
if (!upstream || chain.includes(upstream.message)) continue;
|
|
1281
|
+
chain.push(upstream.message);
|
|
1282
|
+
if (upstream.code) code = upstream.code;
|
|
1283
|
+
if (upstream.requestId) requestId = upstream.requestId;
|
|
1284
|
+
if (upstream.status !== null) status = upstream.status;
|
|
1371
1285
|
}
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1375
|
-
status: response.status,
|
|
1376
|
-
path,
|
|
1377
|
-
serverDetail: await readServerDetail(response)
|
|
1378
|
-
});
|
|
1379
|
-
}
|
|
1380
|
-
async function requestJson(transport, path, options) {
|
|
1381
|
-
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
1382
|
-
const response = await transport.fetch(path, {
|
|
1383
|
-
method: options.method,
|
|
1384
|
-
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
1385
|
-
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
1386
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1387
|
-
});
|
|
1388
|
-
if (!response.ok) return throwApiError(path, response);
|
|
1389
|
-
return await response.json();
|
|
1390
|
-
}
|
|
1391
|
-
function toRunHandle(response, options) {
|
|
1286
|
+
const specific = [...chain].reverse().find((message) => !isGenericUserMessage(message));
|
|
1287
|
+
const cause = specific ?? chain[0] ?? "Unknown error";
|
|
1288
|
+
const headlineWasGeneric = isGenericUserMessage(userFacing);
|
|
1392
1289
|
return {
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
...options.onValidEnvelope ? { onValidEnvelope: options.onValidEnvelope } : {}
|
|
1401
|
-
}),
|
|
1402
|
-
response
|
|
1290
|
+
code,
|
|
1291
|
+
cause,
|
|
1292
|
+
headline: headlineWasGeneric ? cause : userFacing ?? cause,
|
|
1293
|
+
headlineWasGeneric,
|
|
1294
|
+
chain,
|
|
1295
|
+
requestId,
|
|
1296
|
+
status
|
|
1403
1297
|
};
|
|
1404
1298
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1299
|
+
function getUserMessage(error) {
|
|
1300
|
+
if (error instanceof BackendApiError) {
|
|
1301
|
+
return error.userMessage;
|
|
1302
|
+
}
|
|
1303
|
+
if (error instanceof Error) {
|
|
1304
|
+
return error.message;
|
|
1305
|
+
}
|
|
1306
|
+
if (typeof error === "string") {
|
|
1307
|
+
return error;
|
|
1308
|
+
}
|
|
1309
|
+
if (typeof error === "object" && error !== null && typeof error.message === "string" && error.message) {
|
|
1310
|
+
return error.message;
|
|
1311
|
+
}
|
|
1312
|
+
return "Something went wrong";
|
|
1313
|
+
}
|
|
1314
|
+
function statusToCode(status) {
|
|
1315
|
+
switch (status) {
|
|
1316
|
+
case 401:
|
|
1317
|
+
return "auth_required";
|
|
1318
|
+
case 403:
|
|
1319
|
+
return "admin_required";
|
|
1320
|
+
case 404:
|
|
1321
|
+
return "not_found";
|
|
1322
|
+
case 422:
|
|
1323
|
+
return "validation_error";
|
|
1324
|
+
default:
|
|
1325
|
+
return "internal_error";
|
|
1424
1326
|
}
|
|
1425
|
-
return response;
|
|
1426
1327
|
}
|
|
1427
1328
|
|
|
1428
|
-
// matrx/
|
|
1429
|
-
var
|
|
1430
|
-
var
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1329
|
+
// matrx/org-context.ts
|
|
1330
|
+
var import_uuid = require("@ai-matrx/kit/uuid");
|
|
1331
|
+
var OrganizationContextError = class extends Error {
|
|
1332
|
+
code;
|
|
1333
|
+
constructor(code, message) {
|
|
1334
|
+
super(message);
|
|
1335
|
+
this.name = "OrganizationContextError";
|
|
1336
|
+
this.code = code;
|
|
1337
|
+
}
|
|
1338
|
+
};
|
|
1339
|
+
function createOrganizationOperation(organizationId) {
|
|
1340
|
+
const organization_id = requireOrganizationContext(organizationId);
|
|
1341
|
+
return Object.freeze({ organization_id });
|
|
1342
|
+
}
|
|
1343
|
+
function assertOrganizationMatchesOperation(operation, organizationId) {
|
|
1344
|
+
if (operation.organization_id !== requireOrganizationContext(organizationId)) {
|
|
1345
|
+
throw new OrganizationContextError(
|
|
1346
|
+
"organization_context_mismatch",
|
|
1347
|
+
"Organization ID must match the request operation."
|
|
1445
1348
|
);
|
|
1446
|
-
} catch (error) {
|
|
1447
|
-
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
1448
|
-
throw error;
|
|
1449
1349
|
}
|
|
1450
1350
|
}
|
|
1451
|
-
|
|
1452
|
-
const
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1351
|
+
function requireOrganizationContext(selectedOrganizationId, overrideOrganizationId) {
|
|
1352
|
+
const candidate = overrideOrganizationId ?? selectedOrganizationId;
|
|
1353
|
+
if (typeof candidate !== "string" || candidate.trim().length === 0) {
|
|
1354
|
+
throw new OrganizationContextError(
|
|
1355
|
+
"organization_context_required",
|
|
1356
|
+
"Select an organization before sending this request."
|
|
1357
|
+
);
|
|
1358
|
+
}
|
|
1359
|
+
const normalized = candidate.trim();
|
|
1360
|
+
if (!(0, import_uuid.isUuidShape)(normalized)) {
|
|
1361
|
+
throw new OrganizationContextError(
|
|
1362
|
+
"organization_context_invalid",
|
|
1363
|
+
"The selected organization ID is invalid."
|
|
1460
1364
|
);
|
|
1461
|
-
} catch (error) {
|
|
1462
|
-
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
1463
|
-
throw error;
|
|
1464
1365
|
}
|
|
1366
|
+
return normalized.toLowerCase();
|
|
1465
1367
|
}
|
|
1466
|
-
function
|
|
1467
|
-
const
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
`/runtime/executions/${encodePathSegment(executionId)}/events${query}`,
|
|
1475
|
-
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1476
|
-
);
|
|
1477
|
-
}
|
|
1478
|
-
function parseEndStatus(data) {
|
|
1479
|
-
if (data === null) return null;
|
|
1480
|
-
try {
|
|
1481
|
-
const parsed = JSON.parse(data);
|
|
1482
|
-
if (typeof parsed === "object" && parsed !== null && typeof parsed.status === "string") {
|
|
1483
|
-
const status = parsed.status;
|
|
1484
|
-
return RUNTIME_STATUSES.has(status) ? status : null;
|
|
1368
|
+
function applyOrganizationContextHeader(headers, organizationId) {
|
|
1369
|
+
const normalizedOrganizationId = requireOrganizationContext(organizationId);
|
|
1370
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
1371
|
+
if (name.toLowerCase() === "x-organization-id" && value.trim().toLowerCase() !== normalizedOrganizationId) {
|
|
1372
|
+
throw new OrganizationContextError(
|
|
1373
|
+
"organization_context_mismatch",
|
|
1374
|
+
"X-Organization-Id must match the request context organization."
|
|
1375
|
+
);
|
|
1485
1376
|
}
|
|
1486
|
-
} catch {
|
|
1487
1377
|
}
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
const headers = { Accept: "text/event-stream" };
|
|
1493
|
-
if (cursor > 0) headers["Last-Event-ID"] = String(cursor);
|
|
1494
|
-
const response = await requestStream(
|
|
1495
|
-
transport,
|
|
1496
|
-
`/runtime/executions/${encodePathSegment(executionId)}/events/stream`,
|
|
1497
|
-
{
|
|
1498
|
-
method: "GET",
|
|
1499
|
-
headers,
|
|
1500
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1501
|
-
}
|
|
1378
|
+
const withoutOrganizationHeader = Object.fromEntries(
|
|
1379
|
+
Object.entries(headers).filter(
|
|
1380
|
+
([name]) => name.toLowerCase() !== "x-organization-id"
|
|
1381
|
+
)
|
|
1502
1382
|
);
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1383
|
+
return {
|
|
1384
|
+
...withoutOrganizationHeader,
|
|
1385
|
+
"X-Organization-Id": normalizedOrganizationId
|
|
1386
|
+
};
|
|
1387
|
+
}
|
|
1388
|
+
function assertQueryOrganizationMatchesContext(queryParams, organizationId) {
|
|
1389
|
+
if (!queryParams || queryParams.organization_id === void 0) return;
|
|
1390
|
+
const queryOrganizationId = requireOrganizationContext(
|
|
1391
|
+
String(queryParams.organization_id)
|
|
1506
1392
|
);
|
|
1507
|
-
|
|
1508
|
-
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
if (frame.event === "execution_event" && frame.data !== null) {
|
|
1513
|
-
let event;
|
|
1514
|
-
try {
|
|
1515
|
-
event = JSON.parse(frame.data);
|
|
1516
|
-
} catch (error) {
|
|
1517
|
-
options.onMalformedFrame?.(frame, error);
|
|
1518
|
-
yield { type: "liveness", cursor };
|
|
1519
|
-
continue;
|
|
1520
|
-
}
|
|
1521
|
-
if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;
|
|
1522
|
-
yield { type: "event", event, seq: frame.seq, cursor };
|
|
1523
|
-
continue;
|
|
1524
|
-
}
|
|
1525
|
-
yield { type: "liveness", cursor };
|
|
1393
|
+
if (queryOrganizationId !== requireOrganizationContext(organizationId)) {
|
|
1394
|
+
throw new OrganizationContextError(
|
|
1395
|
+
"organization_context_mismatch",
|
|
1396
|
+
"Query organization_id must match the request context organization."
|
|
1397
|
+
);
|
|
1526
1398
|
}
|
|
1527
1399
|
}
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
for await (const item of items) {
|
|
1552
|
-
armStall();
|
|
1553
|
-
failures = 0;
|
|
1554
|
-
cursor = item.cursor;
|
|
1555
|
-
if (item.type === "end") {
|
|
1556
|
-
return { ended: true, status: item.status };
|
|
1557
|
-
}
|
|
1558
|
-
if (item.type === "event") {
|
|
1559
|
-
options.onEvent(item.event, item.seq);
|
|
1560
|
-
}
|
|
1561
|
-
}
|
|
1562
|
-
failures += 1;
|
|
1563
|
-
} catch (error) {
|
|
1564
|
-
if (outer?.aborted) break;
|
|
1565
|
-
failures += 1;
|
|
1566
|
-
options.onAttemptError?.(error);
|
|
1567
|
-
} finally {
|
|
1568
|
-
if (stallTimer !== null) clearTimeout(stallTimer);
|
|
1569
|
-
outer?.removeEventListener("abort", onOuterAbort);
|
|
1570
|
-
}
|
|
1571
|
-
if (!outer?.aborted && failures < reconnectLimit) {
|
|
1572
|
-
await new Promise((r) => setTimeout(r, reconnectDelayMs));
|
|
1573
|
-
}
|
|
1400
|
+
|
|
1401
|
+
// matrx/protocol.ts
|
|
1402
|
+
var import_net = require("@ai-matrx/data/net");
|
|
1403
|
+
var MATRX_AI_API_VERSION_DEFAULT = "v2";
|
|
1404
|
+
var V2_COVERED_AI_PATH_TEMPLATES = [
|
|
1405
|
+
"/ai/manual",
|
|
1406
|
+
"/ai/chat",
|
|
1407
|
+
"/ai/agents/{agent_id}",
|
|
1408
|
+
"/ai/agent/{agent_id}",
|
|
1409
|
+
// singular alias — behaves identically
|
|
1410
|
+
"/ai/conversations/{conversation_id}",
|
|
1411
|
+
"/ai/conversation/{conversation_id}",
|
|
1412
|
+
// singular alias
|
|
1413
|
+
"/ai/prompts/{prompt_id}",
|
|
1414
|
+
// saved-prompt execution
|
|
1415
|
+
"/ai/mandates/{mandate_key}"
|
|
1416
|
+
// THE MANDATE DOOR — `/v2` sibling exists (routers/v2.py)
|
|
1417
|
+
];
|
|
1418
|
+
function toV2Path(path) {
|
|
1419
|
+
const withLead = path.startsWith("/") ? path : `/${path}`;
|
|
1420
|
+
if (withLead.startsWith("/api/")) {
|
|
1421
|
+
const rest = withLead.slice("/api".length);
|
|
1422
|
+
return rest.startsWith("/v2/") ? withLead : `/api/v2${rest}`;
|
|
1574
1423
|
}
|
|
1575
|
-
return
|
|
1424
|
+
return withLead.startsWith("/v2/") ? withLead : `/v2${withLead}`;
|
|
1576
1425
|
}
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1426
|
+
var COVERED_INTERPOLATED_PATH = [
|
|
1427
|
+
/^(?:\/api)?\/ai\/manual$/,
|
|
1428
|
+
/^(?:\/api)?\/ai\/chat$/,
|
|
1429
|
+
/^(?:\/api)?\/ai\/agents\/[^/]+$/,
|
|
1430
|
+
/^(?:\/api)?\/ai\/agent\/[^/]+$/,
|
|
1431
|
+
/^(?:\/api)?\/ai\/conversations\/[^/]+$/,
|
|
1432
|
+
/^(?:\/api)?\/ai\/conversation\/[^/]+$/,
|
|
1433
|
+
/^(?:\/api)?\/ai\/prompts\/[^/]+$/,
|
|
1434
|
+
// `/warm` etc. deliberately don't match
|
|
1435
|
+
/^(?:\/api)?\/ai\/mandates\/[^/]+$/
|
|
1436
|
+
// the mandate door
|
|
1437
|
+
];
|
|
1438
|
+
function isCoveredAiPath(path) {
|
|
1439
|
+
return COVERED_INTERPOLATED_PATH.some((re) => re.test(path));
|
|
1590
1440
|
}
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
var MATRX_RUN_IN_PROGRESS = "run_in_progress";
|
|
1594
|
-
var MATRX_RESUME_CONFLICT = "resume_conflict";
|
|
1595
|
-
var MATRX_LIVE_STREAM_UNAVAILABLE = "live_stream_unavailable";
|
|
1596
|
-
function isRecord4(value) {
|
|
1597
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1441
|
+
function isV2Path(pathOrUrl) {
|
|
1442
|
+
return /\/v2\/ai\//.test(pathOrUrl);
|
|
1598
1443
|
}
|
|
1599
|
-
function
|
|
1600
|
-
return
|
|
1444
|
+
function toV1FallbackUrl(url) {
|
|
1445
|
+
return url.replace(/\/v2\/ai\//, "/ai/");
|
|
1601
1446
|
}
|
|
1602
|
-
function
|
|
1603
|
-
if (
|
|
1604
|
-
|
|
1605
|
-
if (isRecord4(body.detail)) out.push(body.detail);
|
|
1606
|
-
if (isRecord4(body.details)) out.push(body.details);
|
|
1607
|
-
out.push(body);
|
|
1608
|
-
return out;
|
|
1447
|
+
function applyAiApiVersion(path, version) {
|
|
1448
|
+
if (version !== "v2") return path;
|
|
1449
|
+
return isCoveredAiPath(path) ? toV2Path(path) : path;
|
|
1609
1450
|
}
|
|
1610
|
-
function
|
|
1611
|
-
|
|
1612
|
-
const
|
|
1613
|
-
|
|
1451
|
+
async function fetchWithMatrxProtocolFallback(url, init, opts = {}) {
|
|
1452
|
+
const { onDowngrade, ...fetchOpts } = opts;
|
|
1453
|
+
const logDowngrade = (reason, status2) => {
|
|
1454
|
+
console.warn(
|
|
1455
|
+
`[matrx] ai_v2_downgrade \u2192 retrying on v1. v2=${url} reason=${reason}`
|
|
1456
|
+
);
|
|
1457
|
+
onDowngrade?.({ url, reason, ...status2 !== void 0 ? { status: status2 } : {} });
|
|
1458
|
+
};
|
|
1459
|
+
if (!isV2Path(url)) return (0, import_net.resilientFetch)(url, init, fetchOpts);
|
|
1460
|
+
let result;
|
|
1461
|
+
try {
|
|
1462
|
+
result = await (0, import_net.resilientFetch)(url, init, fetchOpts);
|
|
1463
|
+
} catch (err) {
|
|
1464
|
+
const isAbort = (0, import_net.isNetError)(err) && err.code === "aborted" || err instanceof Error && err.name === "AbortError";
|
|
1465
|
+
if (isAbort) throw err;
|
|
1466
|
+
logDowngrade(String(err));
|
|
1467
|
+
return (0, import_net.resilientFetch)(toV1FallbackUrl(url), init, fetchOpts);
|
|
1468
|
+
}
|
|
1469
|
+
const status = result.response.status;
|
|
1470
|
+
if (status === 404 || status === 405 || status >= 500) {
|
|
1471
|
+
logDowngrade(`HTTP ${status}`, status);
|
|
1472
|
+
return (0, import_net.resilientFetch)(toV1FallbackUrl(url), init, fetchOpts);
|
|
1473
|
+
}
|
|
1474
|
+
return result;
|
|
1475
|
+
}
|
|
1476
|
+
function aiVersionPathOverrides(version) {
|
|
1477
|
+
if (version !== "v2") return {};
|
|
1478
|
+
const map = {};
|
|
1479
|
+
for (const template of V2_COVERED_AI_PATH_TEMPLATES) {
|
|
1480
|
+
map[template] = toV2Path(template);
|
|
1481
|
+
}
|
|
1482
|
+
return map;
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1485
|
+
// matrx/call.ts
|
|
1486
|
+
function buildMatrxRequestUrl(baseUrl, pathTemplate, pathParams, queryParams) {
|
|
1487
|
+
let resolvedPath = pathTemplate;
|
|
1488
|
+
if (pathParams) {
|
|
1489
|
+
for (const [key, value] of Object.entries(pathParams)) {
|
|
1490
|
+
resolvedPath = resolvedPath.replace(`{${key}}`, encodeURIComponent(value));
|
|
1491
|
+
}
|
|
1492
|
+
}
|
|
1493
|
+
const fullPath = resolvedPath.startsWith("/api/") ? resolvedPath.slice(4) : resolvedPath;
|
|
1494
|
+
const url = `${baseUrl}${fullPath}`;
|
|
1495
|
+
if (queryParams && Object.keys(queryParams).length > 0) {
|
|
1496
|
+
const qs = new URLSearchParams(
|
|
1497
|
+
Object.fromEntries(
|
|
1498
|
+
Object.entries(queryParams).map(([k, v]) => [k, String(v)])
|
|
1499
|
+
)
|
|
1500
|
+
).toString();
|
|
1501
|
+
return `${url}?${qs}`;
|
|
1502
|
+
}
|
|
1503
|
+
return url;
|
|
1504
|
+
}
|
|
1505
|
+
var MATRX_UI_ONLY_BODY_FIELDS = /* @__PURE__ */ new Set([
|
|
1506
|
+
"youtube_videos",
|
|
1507
|
+
"file_urls",
|
|
1508
|
+
"image_urls"
|
|
1509
|
+
]);
|
|
1510
|
+
function buildMatrxRequestBody(body, scope) {
|
|
1511
|
+
const raw = body ?? {};
|
|
1512
|
+
const base = {};
|
|
1513
|
+
for (const [key, value] of Object.entries(raw)) {
|
|
1514
|
+
if (!MATRX_UI_ONLY_BODY_FIELDS.has(key)) base[key] = value;
|
|
1515
|
+
}
|
|
1516
|
+
if (base.organization_id === null || typeof base.organization_id === "string" && base.organization_id.trim() === "") {
|
|
1517
|
+
delete base.organization_id;
|
|
1518
|
+
}
|
|
1519
|
+
const bodyOrganizationId = base.organization_id;
|
|
1520
|
+
if (scope.organization_id !== void 0 && bodyOrganizationId !== void 0 && (typeof bodyOrganizationId !== "string" || bodyOrganizationId.trim() !== scope.organization_id)) {
|
|
1521
|
+
throw new OrganizationContextError(
|
|
1522
|
+
"organization_context_mismatch",
|
|
1523
|
+
"Request body organization_id must match the request context organization."
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
if (bodyOrganizationId !== void 0 && scope.organization_id !== void 0) {
|
|
1527
|
+
base.organization_id = scope.organization_id;
|
|
1528
|
+
}
|
|
1529
|
+
const scopeFields = {
|
|
1530
|
+
...scope.organization_id !== void 0 ? { organization_id: scope.organization_id } : {}
|
|
1531
|
+
};
|
|
1532
|
+
if (scope.project_id !== void 0) scopeFields.project_id = scope.project_id;
|
|
1533
|
+
if (scope.task_id !== void 0) scopeFields.task_id = scope.task_id;
|
|
1534
|
+
return { ...scopeFields, ...base };
|
|
1614
1535
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
return
|
|
1536
|
+
var BARE_TRANSPORT_CODE = /^\s*(?:HTTP|HTTP\s*Error|Status(?:\s*Code)?)?\s*[:\-]?\s*\d{3}\s*[.:!]?\s*$/i;
|
|
1537
|
+
function isBareTransportCode(text) {
|
|
1538
|
+
if (!text) return false;
|
|
1539
|
+
return BARE_TRANSPORT_CODE.test(text);
|
|
1618
1540
|
}
|
|
1619
|
-
function
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
if (code) return code;
|
|
1541
|
+
function bareStatusSentence(status) {
|
|
1542
|
+
if (status === 401 || status === 403) {
|
|
1543
|
+
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.";
|
|
1623
1544
|
}
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
if (code) return code;
|
|
1545
|
+
if (status === 404) {
|
|
1546
|
+
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.";
|
|
1627
1547
|
}
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
var PREFIXED_ERROR_CODES = [
|
|
1631
|
-
"resume_conflict",
|
|
1632
|
-
"not_resumable",
|
|
1633
|
-
"outstanding_delegated_calls",
|
|
1634
|
-
"user_request_not_found",
|
|
1635
|
-
"run_in_flight"
|
|
1636
|
-
];
|
|
1637
|
-
function readMatrxErrorCodeFromMessage(message) {
|
|
1638
|
-
if (typeof message !== "string") return null;
|
|
1639
|
-
for (const code of PREFIXED_ERROR_CODES) {
|
|
1640
|
-
if (message.startsWith(`${code}:`)) return code;
|
|
1548
|
+
if (status === 429) {
|
|
1549
|
+
return "The server is rate-limiting this request. Wait a few seconds and try again.";
|
|
1641
1550
|
}
|
|
1642
|
-
|
|
1551
|
+
if (status >= 500) {
|
|
1552
|
+
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.";
|
|
1553
|
+
}
|
|
1554
|
+
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.";
|
|
1643
1555
|
}
|
|
1644
|
-
|
|
1556
|
+
function honestTransportMessage(raw, status) {
|
|
1557
|
+
if (raw && !isBareTransportCode(raw)) return raw;
|
|
1558
|
+
return bareStatusSentence(status ?? 0);
|
|
1559
|
+
}
|
|
1560
|
+
var SENSITIVE_HEADER_NAME = /authorization|cookie|token|api[-_]?key/i;
|
|
1561
|
+
function buildSafeRequestLog(headers, body) {
|
|
1562
|
+
const safeHeaders = Object.fromEntries(
|
|
1563
|
+
Object.entries(headers).map(([name, value]) => [
|
|
1564
|
+
name,
|
|
1565
|
+
SENSITIVE_HEADER_NAME.test(name) ? "[REDACTED]" : value
|
|
1566
|
+
])
|
|
1567
|
+
);
|
|
1568
|
+
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 };
|
|
1569
|
+
return { headers: safeHeaders, body: bodyMetadata };
|
|
1570
|
+
}
|
|
1571
|
+
function redactUrlForRequestLog(url) {
|
|
1645
1572
|
try {
|
|
1646
|
-
const
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1573
|
+
const parsed = new URL(url);
|
|
1574
|
+
for (const key of parsed.searchParams.keys()) {
|
|
1575
|
+
parsed.searchParams.set(key, "[REDACTED]");
|
|
1576
|
+
}
|
|
1577
|
+
return parsed.toString();
|
|
1578
|
+
} catch {
|
|
1579
|
+
const queryIndex = url.indexOf("?");
|
|
1580
|
+
return queryIndex === -1 ? url : `${url.slice(0, queryIndex)}?[REDACTED]`;
|
|
1651
1581
|
}
|
|
1652
|
-
return null;
|
|
1653
1582
|
}
|
|
1654
|
-
function
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1583
|
+
function shouldReportMatrxCallError(status, expectedErrorStatuses) {
|
|
1584
|
+
return status == null || !expectedErrorStatuses?.includes(status);
|
|
1585
|
+
}
|
|
1586
|
+
function parseMatrxNdjsonResponse(response, signal, hooks = {}) {
|
|
1587
|
+
const ids = {
|
|
1588
|
+
requestId: response.headers.get("X-Request-ID"),
|
|
1589
|
+
conversationId: response.headers.get("X-Conversation-ID")
|
|
1590
|
+
};
|
|
1591
|
+
async function* events() {
|
|
1592
|
+
if (!response.body) {
|
|
1593
|
+
throw new BackendApiError({
|
|
1594
|
+
code: "internal_error",
|
|
1595
|
+
detail: "Response has no body",
|
|
1596
|
+
userMessage: "No response received from server"
|
|
1597
|
+
});
|
|
1598
|
+
}
|
|
1599
|
+
try {
|
|
1600
|
+
for await (const envelope of readMatrxNdjsonStream(response.body, {
|
|
1601
|
+
...signal ? { signal } : {},
|
|
1602
|
+
...hooks.onMalformedLine ? { onMalformedLine: hooks.onMalformedLine } : {},
|
|
1603
|
+
...hooks.onUnknownEnvelope ? { onUnknownEnvelope: hooks.onUnknownEnvelope } : {}
|
|
1604
|
+
})) {
|
|
1605
|
+
hooks.onEvent?.(envelope, ids);
|
|
1606
|
+
yield envelope;
|
|
1607
|
+
}
|
|
1608
|
+
} catch (error) {
|
|
1609
|
+
if (signal?.aborted || error instanceof Error && error.name === "AbortError") {
|
|
1610
|
+
return;
|
|
1611
|
+
}
|
|
1612
|
+
const transportError = error instanceof BackendApiError ? error : new StreamTransportError({
|
|
1613
|
+
detail: error instanceof Error ? error.message : "The response stream ended unexpectedly.",
|
|
1614
|
+
details: error,
|
|
1615
|
+
...ids.requestId ? { requestId: ids.requestId } : {}
|
|
1616
|
+
});
|
|
1617
|
+
hooks.onTransportError?.(transportError, ids);
|
|
1618
|
+
throw transportError;
|
|
1619
|
+
}
|
|
1658
1620
|
}
|
|
1659
|
-
return
|
|
1621
|
+
return { events: events(), ...ids };
|
|
1660
1622
|
}
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
const code = readMatrxErrorCode(error);
|
|
1666
|
-
if (code !== MATRX_RUN_IN_PROGRESS) return null;
|
|
1667
|
-
const liveRequestId = firstString(candidates, "live_request_id");
|
|
1668
|
-
const pathFromBody = firstString(candidates, "rejoin_path");
|
|
1669
|
-
const rejoinPath = pathFromBody && pathFromBody.startsWith("/") ? pathFromBody : liveRequestId ? runtimeOperationRejoinPath(liveRequestId) : null;
|
|
1670
|
-
if (!rejoinPath) return null;
|
|
1671
|
-
const root = bodyOf(error);
|
|
1623
|
+
var DEFAULT_CONNECT_TIMEOUT_MS = 15e3;
|
|
1624
|
+
var DEFAULT_JSON_TOTAL_TIMEOUT_MS = 3e4;
|
|
1625
|
+
async function httpErrorFrom(response) {
|
|
1626
|
+
const serverDetail = await response.json().catch(() => void 0);
|
|
1672
1627
|
return {
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
body: isRecord4(root) ? root : {}
|
|
1628
|
+
type: response.status >= 400 && response.status < 500 ? "validation_error" : "http_error",
|
|
1629
|
+
message: extractMatrxErrorMessage(serverDetail) ?? bareStatusSentence(response.status),
|
|
1630
|
+
status: response.status,
|
|
1631
|
+
serverDetail
|
|
1678
1632
|
};
|
|
1679
1633
|
}
|
|
1680
|
-
function
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1634
|
+
async function executeMatrxCall(request, hooks = {}) {
|
|
1635
|
+
const upper = request.method.toUpperCase();
|
|
1636
|
+
const sendsBody = request.stream || upper !== "GET" && upper !== "HEAD";
|
|
1637
|
+
const { response } = await fetchWithMatrxProtocolFallback(
|
|
1638
|
+
request.url,
|
|
1639
|
+
{
|
|
1640
|
+
method: request.method,
|
|
1641
|
+
headers: request.headers,
|
|
1642
|
+
...sendsBody ? { body: JSON.stringify(request.body) } : {}
|
|
1643
|
+
},
|
|
1644
|
+
{
|
|
1645
|
+
...request.signal ? { signal: request.signal } : {},
|
|
1646
|
+
connectTimeoutMs: request.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
|
|
1647
|
+
totalTimeoutMs: request.stream ? null : request.totalTimeoutMs === void 0 ? DEFAULT_JSON_TOTAL_TIMEOUT_MS : request.totalTimeoutMs,
|
|
1648
|
+
throwOnHttpError: false,
|
|
1649
|
+
...hooks.onProtocolDowngrade ? { onDowngrade: hooks.onProtocolDowngrade } : {}
|
|
1650
|
+
}
|
|
1651
|
+
);
|
|
1652
|
+
const requestId = response.headers.get("X-Request-ID");
|
|
1653
|
+
const conversationId = response.headers.get("X-Conversation-ID");
|
|
1654
|
+
const idFields = {
|
|
1655
|
+
...requestId !== null ? { requestId } : {},
|
|
1656
|
+
...conversationId !== null ? { conversationId } : {}
|
|
1657
|
+
};
|
|
1658
|
+
if (!response.ok) {
|
|
1659
|
+
const error = await httpErrorFrom(response);
|
|
1660
|
+
if (request.stream) request.onStreamError?.(error);
|
|
1661
|
+
return { ...idFields, error };
|
|
1662
|
+
}
|
|
1663
|
+
if (!request.stream) {
|
|
1664
|
+
const data = response.status === 204 ? void 0 : await response.json();
|
|
1665
|
+
return { data, ...idFields };
|
|
1666
|
+
}
|
|
1667
|
+
if (request.consumeStream) {
|
|
1668
|
+
request.onStreamStart?.(requestId, conversationId);
|
|
1669
|
+
await request.consumeStream(response, { requestId, conversationId });
|
|
1670
|
+
request.onStreamComplete?.(requestId, conversationId);
|
|
1671
|
+
return idFields;
|
|
1672
|
+
}
|
|
1673
|
+
const parse = hooks.parseStream ?? ((res, signal) => parseMatrxNdjsonResponse(res, signal));
|
|
1674
|
+
const parsed = parse(response, request.signal);
|
|
1675
|
+
request.onStreamStart?.(parsed.requestId, parsed.conversationId);
|
|
1676
|
+
for await (const event of parsed.events) {
|
|
1677
|
+
request.onStreamEvent?.(event);
|
|
1678
|
+
}
|
|
1679
|
+
request.onStreamComplete?.(parsed.requestId, parsed.conversationId);
|
|
1680
|
+
return {
|
|
1681
|
+
...parsed.requestId !== null ? { requestId: parsed.requestId } : {},
|
|
1682
|
+
...parsed.conversationId !== null ? { conversationId: parsed.conversationId } : {}
|
|
1683
|
+
};
|
|
1685
1684
|
}
|
|
1686
|
-
|
|
1687
|
-
|
|
1685
|
+
|
|
1686
|
+
// matrx/client.ts
|
|
1687
|
+
function classifyStatus(status) {
|
|
1688
|
+
return status >= 400 && status < 500 ? "validation_error" : "http_error";
|
|
1688
1689
|
}
|
|
1689
|
-
function
|
|
1690
|
-
|
|
1690
|
+
function normalizeMatrxError(err) {
|
|
1691
|
+
if (err instanceof OrganizationContextError) {
|
|
1692
|
+
return {
|
|
1693
|
+
type: "validation_error",
|
|
1694
|
+
message: err.message,
|
|
1695
|
+
code: err.code,
|
|
1696
|
+
name: err.name,
|
|
1697
|
+
...err.stack !== void 0 ? { stack: err.stack } : {}
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
1701
|
+
return { type: "abort_error", message: "Request was cancelled." };
|
|
1702
|
+
}
|
|
1703
|
+
if (err instanceof MatrxApiError) {
|
|
1704
|
+
return {
|
|
1705
|
+
type: classifyStatus(err.status),
|
|
1706
|
+
message: honestTransportMessage(err.message, err.status),
|
|
1707
|
+
status: err.status,
|
|
1708
|
+
serverDetail: err.serverDetail,
|
|
1709
|
+
...err.code ? { code: err.code } : {},
|
|
1710
|
+
name: err.name
|
|
1711
|
+
};
|
|
1712
|
+
}
|
|
1713
|
+
if (err instanceof BackendApiError) {
|
|
1714
|
+
return {
|
|
1715
|
+
type: "network_error",
|
|
1716
|
+
message: honestTransportMessage(
|
|
1717
|
+
err.detail || err.userMessage,
|
|
1718
|
+
err.status ?? void 0
|
|
1719
|
+
),
|
|
1720
|
+
code: err.code,
|
|
1721
|
+
name: err.name,
|
|
1722
|
+
...err.status !== null ? { status: err.status } : {},
|
|
1723
|
+
...err.details !== null ? { serverDetail: err.details } : {}
|
|
1724
|
+
};
|
|
1725
|
+
}
|
|
1726
|
+
if ((0, import_data.isNetError)(err)) {
|
|
1727
|
+
if (err.code === "aborted") {
|
|
1728
|
+
return { type: "abort_error", message: err.message };
|
|
1729
|
+
}
|
|
1730
|
+
if (err.code === "http") {
|
|
1731
|
+
const status = err.status ?? 0;
|
|
1732
|
+
return {
|
|
1733
|
+
type: classifyStatus(status),
|
|
1734
|
+
message: honestTransportMessage(err.message, status),
|
|
1735
|
+
status
|
|
1736
|
+
};
|
|
1737
|
+
}
|
|
1738
|
+
return { type: "network_error", message: err.message };
|
|
1739
|
+
}
|
|
1740
|
+
if (err instanceof Error) {
|
|
1741
|
+
const httpMatch = err.message.match(/HTTP (\d+):\s*(.*)/);
|
|
1742
|
+
if (httpMatch) {
|
|
1743
|
+
const status = parseInt(httpMatch[1], 10);
|
|
1744
|
+
return {
|
|
1745
|
+
type: classifyStatus(status),
|
|
1746
|
+
message: honestTransportMessage(httpMatch[2] ?? err.message, status),
|
|
1747
|
+
status
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
if (isBareTransportCode(err.message)) {
|
|
1751
|
+
const status = Number.parseInt(err.message.replace(/\D+/g, ""), 10);
|
|
1752
|
+
return {
|
|
1753
|
+
type: classifyStatus(status),
|
|
1754
|
+
message: bareStatusSentence(status),
|
|
1755
|
+
status
|
|
1756
|
+
};
|
|
1757
|
+
}
|
|
1758
|
+
return { type: "network_error", message: err.message };
|
|
1759
|
+
}
|
|
1760
|
+
return { type: "unknown", message: (0, import_net2.extractErrorMessage)(err) };
|
|
1691
1761
|
}
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1762
|
+
var PRODUCTION_CONNECT_TIMEOUT_MS = 15e3;
|
|
1763
|
+
function stripContentType(headers) {
|
|
1764
|
+
return Object.fromEntries(
|
|
1765
|
+
Object.entries(headers).filter(
|
|
1766
|
+
([name]) => name.toLowerCase() !== "content-type"
|
|
1767
|
+
)
|
|
1768
|
+
);
|
|
1696
1769
|
}
|
|
1697
|
-
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1770
|
+
function createMatrxTransport(options) {
|
|
1771
|
+
const {
|
|
1772
|
+
baseUrl,
|
|
1773
|
+
resolveTarget,
|
|
1774
|
+
credentials,
|
|
1775
|
+
organizationId,
|
|
1776
|
+
aiApiVersion,
|
|
1777
|
+
connectTimeoutMs = PRODUCTION_CONNECT_TIMEOUT_MS,
|
|
1778
|
+
totalTimeoutMs = null,
|
|
1779
|
+
expectedErrorStatuses,
|
|
1780
|
+
diagnostics,
|
|
1781
|
+
source = "matrxTransport"
|
|
1782
|
+
} = options;
|
|
1783
|
+
if (baseUrl === void 0 === (resolveTarget === void 0)) {
|
|
1784
|
+
throw new Error(
|
|
1785
|
+
"createMatrxTransport: provide exactly one of `baseUrl` or `resolveTarget`."
|
|
1786
|
+
);
|
|
1787
|
+
}
|
|
1788
|
+
const resolve = resolveTarget ?? (() => ({ baseUrl }));
|
|
1789
|
+
const resolveVersion = () => {
|
|
1790
|
+
if (aiApiVersion === void 0) return MATRX_AI_API_VERSION_DEFAULT;
|
|
1791
|
+
return typeof aiApiVersion === "function" ? aiApiVersion() : aiApiVersion;
|
|
1792
|
+
};
|
|
1793
|
+
const resolveOrganizationId = () => {
|
|
1794
|
+
if (organizationId === void 0) return null;
|
|
1795
|
+
const candidate = typeof organizationId === "function" ? organizationId() : organizationId;
|
|
1796
|
+
return requireOrganizationContext(candidate);
|
|
1797
|
+
};
|
|
1798
|
+
return {
|
|
1799
|
+
async fetch(path, init) {
|
|
1800
|
+
const target = resolve();
|
|
1801
|
+
const versionedPath = applyAiApiVersion(path, resolveVersion());
|
|
1802
|
+
const url = `${target.baseUrl}${versionedPath}`;
|
|
1803
|
+
const credentialHeaders = credentials ? (0, import_data2.credentialToHeaders)(await credentials.get()) : {};
|
|
1804
|
+
let headers = {
|
|
1805
|
+
...init.headers,
|
|
1806
|
+
...stripContentType(credentialHeaders),
|
|
1807
|
+
...stripContentType(target.policyHeaders ?? {})
|
|
1808
|
+
};
|
|
1809
|
+
const orgId = resolveOrganizationId();
|
|
1810
|
+
if (orgId !== null) {
|
|
1811
|
+
headers = applyOrganizationContextHeader(headers, orgId);
|
|
1812
|
+
}
|
|
1813
|
+
const info = {
|
|
1814
|
+
url,
|
|
1815
|
+
method: init.method,
|
|
1816
|
+
path,
|
|
1817
|
+
channel: target.channel ?? "default",
|
|
1818
|
+
source
|
|
1819
|
+
};
|
|
1820
|
+
diagnostics?.onRequest?.(info);
|
|
1821
|
+
let response;
|
|
1822
|
+
try {
|
|
1823
|
+
({ response } = await fetchWithMatrxProtocolFallback(
|
|
1824
|
+
url,
|
|
1825
|
+
{
|
|
1826
|
+
method: init.method,
|
|
1827
|
+
headers,
|
|
1828
|
+
...init.body !== void 0 ? { body: init.body } : {}
|
|
1829
|
+
},
|
|
1830
|
+
{
|
|
1831
|
+
...init.signal ? { signal: init.signal } : {},
|
|
1832
|
+
connectTimeoutMs,
|
|
1833
|
+
totalTimeoutMs,
|
|
1834
|
+
throwOnHttpError: false,
|
|
1835
|
+
...diagnostics?.onProtocolDowngrade ? { onDowngrade: diagnostics.onProtocolDowngrade } : {}
|
|
1836
|
+
}
|
|
1837
|
+
));
|
|
1838
|
+
} catch (err) {
|
|
1839
|
+
diagnostics?.onError?.(normalizeMatrxError(err), info);
|
|
1840
|
+
throw err;
|
|
1841
|
+
}
|
|
1842
|
+
if (!response.ok && !expectedErrorStatuses?.includes(response.status)) {
|
|
1843
|
+
const serverDetail = await response.clone().json().catch(() => void 0);
|
|
1844
|
+
const code = extractMatrxErrorCode(serverDetail);
|
|
1845
|
+
diagnostics?.onError?.(
|
|
1846
|
+
{
|
|
1847
|
+
type: classifyStatus(response.status),
|
|
1848
|
+
message: extractMatrxErrorMessage(serverDetail) ?? `HTTP ${response.status}`,
|
|
1849
|
+
status: response.status,
|
|
1850
|
+
serverDetail,
|
|
1851
|
+
...code ? { code } : {}
|
|
1852
|
+
},
|
|
1853
|
+
info
|
|
1854
|
+
);
|
|
1855
|
+
}
|
|
1856
|
+
return response;
|
|
1857
|
+
}
|
|
1858
|
+
};
|
|
1704
1859
|
}
|
|
1705
|
-
|
|
1706
|
-
|
|
1860
|
+
|
|
1861
|
+
// matrx/conversation.ts
|
|
1862
|
+
function mintMatrxConversationId() {
|
|
1863
|
+
return crypto.randomUUID();
|
|
1864
|
+
}
|
|
1865
|
+
function newStoredConversationStart(conversationId) {
|
|
1707
1866
|
return {
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
})
|
|
1867
|
+
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
1868
|
+
is_new: true,
|
|
1869
|
+
store: true
|
|
1712
1870
|
};
|
|
1713
1871
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
if (options.lastEventId) headers["Last-Event-ID"] = String(options.lastEventId);
|
|
1717
|
-
let response;
|
|
1718
|
-
try {
|
|
1719
|
-
response = await requestStream(
|
|
1720
|
-
transport,
|
|
1721
|
-
`/runs/${encodePathSegment(runId)}/events/stream`,
|
|
1722
|
-
{
|
|
1723
|
-
method: "GET",
|
|
1724
|
-
headers,
|
|
1725
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1726
|
-
}
|
|
1727
|
-
);
|
|
1728
|
-
} catch (error) {
|
|
1729
|
-
if (options.signal?.aborted) return { ended: false };
|
|
1730
|
-
throw error;
|
|
1731
|
-
}
|
|
1732
|
-
try {
|
|
1733
|
-
for await (const frame of readMatrxSseStream(
|
|
1734
|
-
response.body
|
|
1735
|
-
)) {
|
|
1736
|
-
if (frame.event === "end") return { ended: true };
|
|
1737
|
-
if (frame.data === null) continue;
|
|
1738
|
-
let parsed;
|
|
1739
|
-
try {
|
|
1740
|
-
parsed = JSON.parse(frame.data);
|
|
1741
|
-
} catch {
|
|
1742
|
-
continue;
|
|
1743
|
-
}
|
|
1744
|
-
if (!isRecord4(parsed)) continue;
|
|
1745
|
-
options.onEvent(parsed, parsed.event === "node_stream" ? null : frame.seq);
|
|
1746
|
-
}
|
|
1747
|
-
} catch (error) {
|
|
1748
|
-
if (!options.signal?.aborted) throw error;
|
|
1749
|
-
}
|
|
1750
|
-
return { ended: false };
|
|
1872
|
+
function continueStoredConversationStart(conversationId) {
|
|
1873
|
+
return { conversation_id: conversationId, is_new: false, store: true };
|
|
1751
1874
|
}
|
|
1752
|
-
|
|
1753
|
-
|
|
1875
|
+
function newEphemeralConversationStart(conversationId) {
|
|
1876
|
+
return {
|
|
1877
|
+
conversation_id: conversationId ?? mintMatrxConversationId(),
|
|
1878
|
+
is_new: true,
|
|
1879
|
+
store: false
|
|
1880
|
+
};
|
|
1754
1881
|
}
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
onWorkflowEvent,
|
|
1762
|
-
follow,
|
|
1763
|
-
...rest
|
|
1764
|
-
} = options;
|
|
1765
|
-
const bound = organizationId ? withRunOrganization(transport, organizationId) : transport;
|
|
1766
|
-
const streamOptions = {
|
|
1767
|
-
...rest,
|
|
1768
|
-
...options.signal ? { signal: options.signal } : {}
|
|
1882
|
+
function continueEphemeralConversationStart(conversationId, priorMessages) {
|
|
1883
|
+
return {
|
|
1884
|
+
conversation_id: conversationId,
|
|
1885
|
+
is_new: false,
|
|
1886
|
+
store: false,
|
|
1887
|
+
prior_messages: priorMessages
|
|
1769
1888
|
};
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1889
|
+
}
|
|
1890
|
+
|
|
1891
|
+
// matrx/internal.ts
|
|
1892
|
+
function encodePathSegment(value) {
|
|
1893
|
+
return encodeURIComponent(value);
|
|
1894
|
+
}
|
|
1895
|
+
function buildQuery(params) {
|
|
1896
|
+
const search = new URLSearchParams();
|
|
1897
|
+
for (const [key, value] of Object.entries(params)) {
|
|
1898
|
+
if (value === void 0) continue;
|
|
1899
|
+
if (Array.isArray(value)) {
|
|
1900
|
+
for (const entry of value) search.append(key, entry);
|
|
1901
|
+
} else {
|
|
1902
|
+
search.append(key, String(value));
|
|
1783
1903
|
}
|
|
1784
|
-
rejoin = target;
|
|
1785
1904
|
}
|
|
1786
|
-
|
|
1787
|
-
|
|
1905
|
+
const encoded = search.toString();
|
|
1906
|
+
return encoded ? `?${encoded}` : "";
|
|
1907
|
+
}
|
|
1908
|
+
async function readServerDetail(response) {
|
|
1788
1909
|
try {
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
body: {}
|
|
1793
|
-
});
|
|
1794
|
-
await drain(handle, onEnvelope);
|
|
1795
|
-
return { kind: "rejoined", rejoin };
|
|
1796
|
-
} catch (error) {
|
|
1797
|
-
const read = readLiveStreamUnavailable(error);
|
|
1798
|
-
if (!read) throw error;
|
|
1799
|
-
unavailable = read;
|
|
1910
|
+
return await response.json();
|
|
1911
|
+
} catch {
|
|
1912
|
+
return void 0;
|
|
1800
1913
|
}
|
|
1801
|
-
return followUnavailableRejoin(bound, rejoin, unavailable, {
|
|
1802
|
-
...signalOnly,
|
|
1803
|
-
...onOperationEvent ? { onOperationEvent } : {},
|
|
1804
|
-
...onWorkflowEvent ? { onWorkflowEvent } : {},
|
|
1805
|
-
...follow ? { follow } : {}
|
|
1806
|
-
});
|
|
1807
1914
|
}
|
|
1808
|
-
function
|
|
1809
|
-
|
|
1810
|
-
|
|
1915
|
+
async function throwApiError(path, response) {
|
|
1916
|
+
throw new MatrxApiError({
|
|
1917
|
+
status: response.status,
|
|
1918
|
+
path,
|
|
1919
|
+
serverDetail: await readServerDetail(response)
|
|
1920
|
+
});
|
|
1811
1921
|
}
|
|
1812
|
-
async function
|
|
1813
|
-
const
|
|
1814
|
-
const
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq)
|
|
1820
|
-
});
|
|
1821
|
-
return { kind: "followed_workflow", rejoin, runId, ended: result2.ended };
|
|
1822
|
-
}
|
|
1823
|
-
const liveRequestId = rejoin.liveRequestId;
|
|
1824
|
-
const statusView = liveRequestId ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly) : null;
|
|
1825
|
-
const operation = statusView?.operations.find((op) => !op.is_terminal) ?? statusView?.operations[0] ?? null;
|
|
1826
|
-
if (!operation) {
|
|
1827
|
-
return { kind: "followed", rejoin, executionId: null, ended: false, status: null };
|
|
1828
|
-
}
|
|
1829
|
-
if (operation.is_terminal) {
|
|
1830
|
-
return {
|
|
1831
|
-
kind: "followed",
|
|
1832
|
-
rejoin,
|
|
1833
|
-
executionId: operation.execution_id,
|
|
1834
|
-
ended: true,
|
|
1835
|
-
status: operation.status
|
|
1836
|
-
};
|
|
1837
|
-
}
|
|
1838
|
-
const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {
|
|
1839
|
-
...options.follow,
|
|
1840
|
-
lastEventSeq: operation.last_event_seq,
|
|
1841
|
-
...signalOnly,
|
|
1842
|
-
onEvent: (event) => options.onOperationEvent?.(event)
|
|
1922
|
+
async function requestJson(transport, path, options) {
|
|
1923
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
1924
|
+
const response = await transport.fetch(path, {
|
|
1925
|
+
method: options.method,
|
|
1926
|
+
headers: hasBody ? { "Content-Type": "application/json" } : {},
|
|
1927
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
1928
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1843
1929
|
});
|
|
1930
|
+
if (!response.ok) return throwApiError(path, response);
|
|
1931
|
+
return await response.json();
|
|
1932
|
+
}
|
|
1933
|
+
function toRunHandle(response, options) {
|
|
1844
1934
|
return {
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1935
|
+
requestId: response.headers.get("X-Request-ID"),
|
|
1936
|
+
conversationId: response.headers.get("X-Conversation-ID"),
|
|
1937
|
+
events: readMatrxNdjsonStream(response.body, {
|
|
1938
|
+
...options.signal ? { signal: options.signal } : {},
|
|
1939
|
+
...options.maxReadAhead !== void 0 ? { maxReadAhead: options.maxReadAhead } : {},
|
|
1940
|
+
...options.onMalformedLine ? { onMalformedLine: options.onMalformedLine } : {},
|
|
1941
|
+
...options.onUnknownEnvelope ? { onUnknownEnvelope: options.onUnknownEnvelope } : {},
|
|
1942
|
+
...options.onValidEnvelope ? { onValidEnvelope: options.onValidEnvelope } : {}
|
|
1943
|
+
}),
|
|
1944
|
+
response
|
|
1850
1945
|
};
|
|
1851
1946
|
}
|
|
1852
|
-
async function
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
}
|
|
1860
|
-
|
|
1861
|
-
switch (pickup.kind) {
|
|
1862
|
-
case "resumed":
|
|
1863
|
-
case "rejoined":
|
|
1864
|
-
return { state: "streamed" };
|
|
1865
|
-
case "resume_conflict":
|
|
1866
|
-
return { state: "retry" };
|
|
1867
|
-
case "followed_workflow":
|
|
1868
|
-
case "followed": {
|
|
1869
|
-
const status = pickup.kind === "followed" ? pickup.status : null;
|
|
1870
|
-
const nothingLive = pickup.kind === "followed" && pickup.executionId === null;
|
|
1871
|
-
if (pickup.ended || nothingLive) {
|
|
1872
|
-
return { state: "settled", status, ...await attempt(options.reloadSavedTurn) };
|
|
1873
|
-
}
|
|
1874
|
-
return {
|
|
1875
|
-
state: "still_running",
|
|
1876
|
-
...await attempt(options.onStillRunning ?? options.reloadSavedTurn)
|
|
1877
|
-
};
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
}
|
|
1881
|
-
|
|
1882
|
-
// matrx/run.ts
|
|
1883
|
-
async function streamCall(transport, path, body, options) {
|
|
1884
|
-
const response = await requestStream(transport, path, {
|
|
1885
|
-
method: "POST",
|
|
1886
|
-
// This client IS the streaming path — `stream: true` always, last so a
|
|
1887
|
-
// caller-supplied value can never flip the response off NDJSON.
|
|
1888
|
-
body: { ...body, stream: true },
|
|
1947
|
+
async function requestStream(transport, path, options) {
|
|
1948
|
+
const hasBody = options.method !== "GET" && options.body !== void 0;
|
|
1949
|
+
const response = await transport.fetch(path, {
|
|
1950
|
+
method: options.method,
|
|
1951
|
+
headers: {
|
|
1952
|
+
...hasBody ? { "Content-Type": "application/json" } : {},
|
|
1953
|
+
...options.headers
|
|
1954
|
+
},
|
|
1955
|
+
...hasBody ? { body: JSON.stringify(options.body) } : {},
|
|
1889
1956
|
...options.signal ? { signal: options.signal } : {}
|
|
1890
1957
|
});
|
|
1891
|
-
return
|
|
1958
|
+
if (!response.ok) return throwApiError(path, response);
|
|
1959
|
+
if (!response.body) {
|
|
1960
|
+
throw new MatrxApiError({
|
|
1961
|
+
status: response.status,
|
|
1962
|
+
path,
|
|
1963
|
+
serverDetail: { code: "missing_response_body" },
|
|
1964
|
+
message: "The streaming response carried no body."
|
|
1965
|
+
});
|
|
1966
|
+
}
|
|
1967
|
+
return response;
|
|
1892
1968
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1969
|
+
|
|
1970
|
+
// matrx/operations.ts
|
|
1971
|
+
var TERMINAL_MATRX_RUNTIME_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
|
|
1972
|
+
var RUNTIME_STATUSES = /* @__PURE__ */ new Set([
|
|
1973
|
+
"pending",
|
|
1974
|
+
"running",
|
|
1975
|
+
"paused",
|
|
1976
|
+
"waiting_input",
|
|
1977
|
+
"completed",
|
|
1978
|
+
"failed",
|
|
1979
|
+
"cancelled"
|
|
1980
|
+
]);
|
|
1981
|
+
async function getRuntimeOperationStatus(transport, requestId, options = {}) {
|
|
1982
|
+
try {
|
|
1983
|
+
return await requestJson(
|
|
1984
|
+
transport,
|
|
1985
|
+
`/runtime/operations/${encodePathSegment(requestId)}`,
|
|
1986
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1987
|
+
);
|
|
1988
|
+
} catch (error) {
|
|
1989
|
+
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
1990
|
+
throw error;
|
|
1991
|
+
}
|
|
1900
1992
|
}
|
|
1901
|
-
function
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
`/ai/mandates/${encodePathSegment(mandateKey)}`,
|
|
1905
|
-
request,
|
|
1906
|
-
options
|
|
1993
|
+
async function getRuntimeOperationsByLink(transport, linkKind, linkId, options = {}) {
|
|
1994
|
+
const query = buildQuery(
|
|
1995
|
+
options.limit !== void 0 ? { limit: options.limit } : {}
|
|
1907
1996
|
);
|
|
1997
|
+
try {
|
|
1998
|
+
return await requestJson(
|
|
1999
|
+
transport,
|
|
2000
|
+
`/runtime/operations/by-link/${encodePathSegment(linkKind)}/${encodePathSegment(linkId)}${query}`,
|
|
2001
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
2002
|
+
);
|
|
2003
|
+
} catch (error) {
|
|
2004
|
+
if (error instanceof MatrxApiError && error.status === 404) return null;
|
|
2005
|
+
throw error;
|
|
2006
|
+
}
|
|
1908
2007
|
}
|
|
1909
|
-
function
|
|
1910
|
-
|
|
2008
|
+
function listRuntimeOperationEvents(transport, executionId, options = {}) {
|
|
2009
|
+
const query = buildQuery({
|
|
2010
|
+
...options.afterSeq !== void 0 ? { after_seq: options.afterSeq } : {},
|
|
2011
|
+
...options.limit !== void 0 ? { limit: options.limit } : {},
|
|
2012
|
+
...options.kinds !== void 0 ? { kind: options.kinds } : {}
|
|
2013
|
+
});
|
|
2014
|
+
return requestJson(
|
|
1911
2015
|
transport,
|
|
1912
|
-
`/
|
|
1913
|
-
|
|
1914
|
-
options
|
|
2016
|
+
`/runtime/executions/${encodePathSegment(executionId)}/events${query}`,
|
|
2017
|
+
{ method: "GET", ...options.signal ? { signal: options.signal } : {} }
|
|
1915
2018
|
);
|
|
1916
2019
|
}
|
|
1917
|
-
function
|
|
1918
|
-
return
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
2020
|
+
function parseEndStatus(data) {
|
|
2021
|
+
if (data === null) return null;
|
|
2022
|
+
try {
|
|
2023
|
+
const parsed = JSON.parse(data);
|
|
2024
|
+
if (typeof parsed === "object" && parsed !== null && typeof parsed.status === "string") {
|
|
2025
|
+
const status = parsed.status;
|
|
2026
|
+
return RUNTIME_STATUSES.has(status) ? status : null;
|
|
2027
|
+
}
|
|
2028
|
+
} catch {
|
|
2029
|
+
}
|
|
2030
|
+
return null;
|
|
1924
2031
|
}
|
|
1925
|
-
function
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
);
|
|
1929
|
-
|
|
2032
|
+
async function* followRuntimeOperationEvents(transport, executionId, options = {}) {
|
|
2033
|
+
let cursor = options.lastEventSeq ?? 0;
|
|
2034
|
+
const headers = { Accept: "text/event-stream" };
|
|
2035
|
+
if (cursor > 0) headers["Last-Event-ID"] = String(cursor);
|
|
2036
|
+
const response = await requestStream(
|
|
1930
2037
|
transport,
|
|
1931
|
-
`/
|
|
2038
|
+
`/runtime/executions/${encodePathSegment(executionId)}/events/stream`,
|
|
1932
2039
|
{
|
|
1933
|
-
method: "
|
|
2040
|
+
method: "GET",
|
|
2041
|
+
headers,
|
|
1934
2042
|
...options.signal ? { signal: options.signal } : {}
|
|
1935
2043
|
}
|
|
1936
2044
|
);
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
partialText;
|
|
1946
|
-
constructor(args) {
|
|
1947
|
-
super(args.message);
|
|
1948
|
-
this.errorPayload = args.errorPayload ?? null;
|
|
1949
|
-
this.completionStatus = args.completionStatus ?? null;
|
|
1950
|
-
this.partialText = args.partialText ?? "";
|
|
1951
|
-
}
|
|
1952
|
-
};
|
|
1953
|
-
function isRecord5(value) {
|
|
1954
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1955
|
-
}
|
|
1956
|
-
function stringField(value, key) {
|
|
1957
|
-
if (!isRecord5(value)) return null;
|
|
1958
|
-
const field = value[key];
|
|
1959
|
-
return typeof field === "string" && field ? field : null;
|
|
1960
|
-
}
|
|
1961
|
-
async function runAgentToCompletion(transport, agentId, request, options = {}) {
|
|
1962
|
-
const handle = await startAgentRun(transport, agentId, request, options);
|
|
1963
|
-
let text = "";
|
|
1964
|
-
let completion = null;
|
|
1965
|
-
let failure = null;
|
|
1966
|
-
for await (const envelope of handle.events) {
|
|
1967
|
-
options.onEvent?.(envelope);
|
|
1968
|
-
if (envelope.event === "chunk") {
|
|
1969
|
-
const chunk = stringField(envelope.data, "text");
|
|
1970
|
-
if (chunk !== null) {
|
|
1971
|
-
text += chunk;
|
|
1972
|
-
options.onChunk?.(text);
|
|
1973
|
-
}
|
|
1974
|
-
continue;
|
|
2045
|
+
const frames = readMatrxSseStream(
|
|
2046
|
+
response.body,
|
|
2047
|
+
options.onIncomplete ? { onIncomplete: options.onIncomplete } : {}
|
|
2048
|
+
);
|
|
2049
|
+
for await (const frame of frames) {
|
|
2050
|
+
if (frame.event === "end") {
|
|
2051
|
+
yield { type: "end", status: parseEndStatus(frame.data), cursor };
|
|
2052
|
+
return;
|
|
1975
2053
|
}
|
|
1976
|
-
if (
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
2054
|
+
if (frame.event === "execution_event" && frame.data !== null) {
|
|
2055
|
+
let event;
|
|
2056
|
+
try {
|
|
2057
|
+
event = JSON.parse(frame.data);
|
|
2058
|
+
} catch (error) {
|
|
2059
|
+
options.onMalformedFrame?.(frame, error);
|
|
2060
|
+
yield { type: "liveness", cursor };
|
|
2061
|
+
continue;
|
|
2062
|
+
}
|
|
2063
|
+
if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;
|
|
2064
|
+
yield { type: "event", event, seq: frame.seq, cursor };
|
|
1983
2065
|
continue;
|
|
1984
2066
|
}
|
|
1985
|
-
|
|
1986
|
-
if (envelope.data.operation !== "user_request") continue;
|
|
1987
|
-
completion = envelope.data;
|
|
1988
|
-
const status = envelope.data.status;
|
|
1989
|
-
if ((status === "failed" || status === "cancelled") && failure === null) {
|
|
1990
|
-
const result = isRecord5(envelope.data.result) ? envelope.data.result : null;
|
|
1991
|
-
failure = new MatrxRunError({
|
|
1992
|
-
message: stringField(result, "error") ?? stringField(result, "user_message") ?? `The agent run ${status}`,
|
|
1993
|
-
completionStatus: status,
|
|
1994
|
-
partialText: text
|
|
1995
|
-
});
|
|
1996
|
-
}
|
|
1997
|
-
}
|
|
1998
|
-
if (failure) throw failure;
|
|
1999
|
-
if (!text && completion) {
|
|
2000
|
-
const result = completion.result;
|
|
2001
|
-
const output = stringField(result, "output");
|
|
2002
|
-
if (output !== null) text = output;
|
|
2003
|
-
}
|
|
2004
|
-
return {
|
|
2005
|
-
text,
|
|
2006
|
-
requestId: handle.requestId,
|
|
2007
|
-
conversationId: handle.conversationId,
|
|
2008
|
-
completion
|
|
2009
|
-
};
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
// matrx/provider-failures.ts
|
|
2013
|
-
var clip = (value, max) => value.length > max ? value.slice(0, max) : value;
|
|
2014
|
-
function providerSessionFailureBody(failure) {
|
|
2015
|
-
const message = failure.message?.trim() || failure.error_type?.trim() || (failure.status_code ? `HTTP ${failure.status_code}` : "provider session failed");
|
|
2016
|
-
const body = {
|
|
2017
|
-
provider: failure.provider,
|
|
2018
|
-
message: clip(message, 4e3)
|
|
2019
|
-
};
|
|
2020
|
-
if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);
|
|
2021
|
-
if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);
|
|
2022
|
-
if (typeof failure.status_code === "number" && Number.isInteger(failure.status_code) && failure.status_code >= 100 && failure.status_code <= 599) {
|
|
2023
|
-
body.status_code = failure.status_code;
|
|
2067
|
+
yield { type: "liveness", cursor };
|
|
2024
2068
|
}
|
|
2025
|
-
return body;
|
|
2026
2069
|
}
|
|
2027
|
-
async function
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2070
|
+
async function followRuntimeOperationToEnd(transport, executionId, options) {
|
|
2071
|
+
const stallTimeoutMs = options.stallTimeoutMs ?? 45e3;
|
|
2072
|
+
const reconnectLimit = options.reconnectLimit ?? 60;
|
|
2073
|
+
const reconnectDelayMs = options.reconnectDelayMs ?? 2e3;
|
|
2074
|
+
const outer = options.signal;
|
|
2075
|
+
let cursor = options.lastEventSeq ?? 0;
|
|
2076
|
+
let failures = 0;
|
|
2077
|
+
while (!outer?.aborted && failures < reconnectLimit) {
|
|
2078
|
+
const attempt2 = new AbortController();
|
|
2079
|
+
const onOuterAbort = () => attempt2.abort();
|
|
2080
|
+
outer?.addEventListener("abort", onOuterAbort, { once: true });
|
|
2081
|
+
let stallTimer = null;
|
|
2082
|
+
const armStall = () => {
|
|
2083
|
+
if (stallTimer !== null) clearTimeout(stallTimer);
|
|
2084
|
+
stallTimer = setTimeout(() => attempt2.abort(), stallTimeoutMs);
|
|
2085
|
+
};
|
|
2086
|
+
try {
|
|
2087
|
+
const items = followRuntimeOperationEvents(transport, executionId, {
|
|
2088
|
+
lastEventSeq: cursor,
|
|
2089
|
+
signal: attempt2.signal,
|
|
2090
|
+
...options.onMalformedFrame ? { onMalformedFrame: options.onMalformedFrame } : {}
|
|
2091
|
+
});
|
|
2092
|
+
armStall();
|
|
2093
|
+
for await (const item of items) {
|
|
2094
|
+
armStall();
|
|
2095
|
+
failures = 0;
|
|
2096
|
+
cursor = item.cursor;
|
|
2097
|
+
if (item.type === "end") {
|
|
2098
|
+
return { ended: true, status: item.status };
|
|
2099
|
+
}
|
|
2100
|
+
if (item.type === "event") {
|
|
2101
|
+
options.onEvent(item.event, item.seq);
|
|
2102
|
+
}
|
|
2036
2103
|
}
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
error
|
|
2042
|
-
|
|
2043
|
-
|
|
2104
|
+
failures += 1;
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
if (outer?.aborted) break;
|
|
2107
|
+
failures += 1;
|
|
2108
|
+
options.onAttemptError?.(error);
|
|
2109
|
+
} finally {
|
|
2110
|
+
if (stallTimer !== null) clearTimeout(stallTimer);
|
|
2111
|
+
outer?.removeEventListener("abort", onOuterAbort);
|
|
2112
|
+
}
|
|
2113
|
+
if (!outer?.aborted && failures < reconnectLimit) {
|
|
2114
|
+
await new Promise((r) => setTimeout(r, reconnectDelayMs));
|
|
2115
|
+
}
|
|
2044
2116
|
}
|
|
2117
|
+
return { ended: false, status: null };
|
|
2045
2118
|
}
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
function submitAgentToolResults(transport, conversationId, results, options = {}) {
|
|
2049
|
-
return requestJson(
|
|
2119
|
+
async function rejoinRuntimeOperation(transport, requestId, options = {}) {
|
|
2120
|
+
const response = await requestStream(
|
|
2050
2121
|
transport,
|
|
2051
|
-
`/
|
|
2122
|
+
`/runtime/operations/${encodePathSegment(requestId)}/rejoin`,
|
|
2052
2123
|
{
|
|
2053
2124
|
method: "POST",
|
|
2054
|
-
body
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
},
|
|
2125
|
+
// The route takes no body model; the reference client posts an empty
|
|
2126
|
+
// JSON object. Match it so proxies see an ordinary JSON POST.
|
|
2127
|
+
body: {},
|
|
2058
2128
|
...options.signal ? { signal: options.signal } : {}
|
|
2059
2129
|
}
|
|
2060
2130
|
);
|
|
2131
|
+
return toRunHandle(response, options);
|
|
2061
2132
|
}
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
}
|
|
2070
|
-
);
|
|
2133
|
+
|
|
2134
|
+
// matrx/rejoin.ts
|
|
2135
|
+
var MATRX_RUN_IN_PROGRESS = "run_in_progress";
|
|
2136
|
+
var MATRX_RESUME_CONFLICT = "resume_conflict";
|
|
2137
|
+
var MATRX_LIVE_STREAM_UNAVAILABLE = "live_stream_unavailable";
|
|
2138
|
+
function isRecord4(value) {
|
|
2139
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2071
2140
|
}
|
|
2072
|
-
function
|
|
2073
|
-
|
|
2074
|
-
options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
2075
|
-
);
|
|
2076
|
-
return requestJson(
|
|
2077
|
-
transport,
|
|
2078
|
-
`/ai/user/pending_calls${query}`,
|
|
2079
|
-
{
|
|
2080
|
-
method: "GET",
|
|
2081
|
-
...options.signal ? { signal: options.signal } : {}
|
|
2082
|
-
}
|
|
2083
|
-
);
|
|
2141
|
+
function nonBlank(value) {
|
|
2142
|
+
return typeof value === "string" && value.trim() ? value : null;
|
|
2084
2143
|
}
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
this.details = data.details ?? null;
|
|
2107
|
-
this.requestId = data.requestId ?? "";
|
|
2108
|
-
this.status = data.status ?? null;
|
|
2144
|
+
function detailCandidates(body) {
|
|
2145
|
+
if (!isRecord4(body)) return [];
|
|
2146
|
+
const out = [];
|
|
2147
|
+
if (isRecord4(body.detail)) out.push(body.detail);
|
|
2148
|
+
if (isRecord4(body.details)) out.push(body.details);
|
|
2149
|
+
out.push(body);
|
|
2150
|
+
return out;
|
|
2151
|
+
}
|
|
2152
|
+
function statusOf(error) {
|
|
2153
|
+
if (!isRecord4(error) && !(error instanceof Error)) return null;
|
|
2154
|
+
const status = error.status;
|
|
2155
|
+
return typeof status === "number" ? status : null;
|
|
2156
|
+
}
|
|
2157
|
+
function bodyOf(error) {
|
|
2158
|
+
if (!isRecord4(error) && !(error instanceof Error)) return void 0;
|
|
2159
|
+
return error.serverDetail;
|
|
2160
|
+
}
|
|
2161
|
+
function readMatrxErrorCode(error) {
|
|
2162
|
+
for (const candidate of detailCandidates(bodyOf(error))) {
|
|
2163
|
+
const code = nonBlank(candidate.code);
|
|
2164
|
+
if (code) return code;
|
|
2109
2165
|
}
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
return
|
|
2113
|
-
error: this.code,
|
|
2114
|
-
message: this.detail,
|
|
2115
|
-
user_message: this.userMessage,
|
|
2116
|
-
details: this.details,
|
|
2117
|
-
request_id: this.requestId
|
|
2118
|
-
};
|
|
2166
|
+
for (const candidate of detailCandidates(bodyOf(error))) {
|
|
2167
|
+
const code = nonBlank(candidate.error);
|
|
2168
|
+
if (code) return code;
|
|
2119
2169
|
}
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2170
|
+
return null;
|
|
2171
|
+
}
|
|
2172
|
+
var PREFIXED_ERROR_CODES = [
|
|
2173
|
+
"resume_conflict",
|
|
2174
|
+
"not_resumable",
|
|
2175
|
+
"outstanding_delegated_calls",
|
|
2176
|
+
"user_request_not_found",
|
|
2177
|
+
"run_in_flight"
|
|
2178
|
+
];
|
|
2179
|
+
function readMatrxErrorCodeFromMessage(message) {
|
|
2180
|
+
if (typeof message !== "string") return null;
|
|
2181
|
+
for (const code of PREFIXED_ERROR_CODES) {
|
|
2182
|
+
if (message.startsWith(`${code}:`)) return code;
|
|
2133
2183
|
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2184
|
+
return null;
|
|
2185
|
+
}
|
|
2186
|
+
async function readConversationOrganizationId(conversationId, read, onUnreadable) {
|
|
2187
|
+
try {
|
|
2188
|
+
const value = await read(conversationId);
|
|
2189
|
+
if (typeof value === "string" && value.trim()) return value;
|
|
2190
|
+
onUnreadable?.(null);
|
|
2191
|
+
} catch (error) {
|
|
2192
|
+
onUnreadable?.(error instanceof Error ? error.message : String(error));
|
|
2139
2193
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2194
|
+
return null;
|
|
2195
|
+
}
|
|
2196
|
+
function firstString(candidates, key) {
|
|
2197
|
+
for (const candidate of candidates) {
|
|
2198
|
+
const value = nonBlank(candidate[key]);
|
|
2199
|
+
if (value) return value.trim();
|
|
2145
2200
|
}
|
|
2146
|
-
return
|
|
2201
|
+
return null;
|
|
2147
2202
|
}
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2203
|
+
function readLiveRunRejoin(error) {
|
|
2204
|
+
if (statusOf(error) !== 409) return null;
|
|
2205
|
+
const candidates = detailCandidates(bodyOf(error));
|
|
2206
|
+
if (candidates.length === 0) return null;
|
|
2207
|
+
const code = readMatrxErrorCode(error);
|
|
2208
|
+
if (code !== MATRX_RUN_IN_PROGRESS) return null;
|
|
2209
|
+
const liveRequestId = firstString(candidates, "live_request_id");
|
|
2210
|
+
const pathFromBody = firstString(candidates, "rejoin_path");
|
|
2211
|
+
const rejoinPath = pathFromBody && pathFromBody.startsWith("/") ? pathFromBody : liveRequestId ? runtimeOperationRejoinPath(liveRequestId) : null;
|
|
2212
|
+
if (!rejoinPath) return null;
|
|
2213
|
+
const root = bodyOf(error);
|
|
2214
|
+
return {
|
|
2215
|
+
liveRequestId,
|
|
2216
|
+
rejoinPath,
|
|
2217
|
+
runId: firstString(candidates, "run_id"),
|
|
2218
|
+
code,
|
|
2219
|
+
body: isRecord4(root) ? root : {}
|
|
2220
|
+
};
|
|
2221
|
+
}
|
|
2222
|
+
function readLiveRunRequestId(error) {
|
|
2223
|
+
return readLiveRunRejoin(error)?.liveRequestId ?? null;
|
|
2224
|
+
}
|
|
2225
|
+
function isResumeConflict(error) {
|
|
2226
|
+
return statusOf(error) === 409 && readMatrxErrorCode(error) === MATRX_RESUME_CONFLICT;
|
|
2227
|
+
}
|
|
2228
|
+
function isLiveStreamUnavailable(error) {
|
|
2229
|
+
return statusOf(error) === 409 && readMatrxErrorCode(error) === MATRX_LIVE_STREAM_UNAVAILABLE;
|
|
2230
|
+
}
|
|
2231
|
+
function runtimeOperationRejoinPath(requestId) {
|
|
2232
|
+
return `/runtime/operations/${encodePathSegment(requestId)}/rejoin`;
|
|
2233
|
+
}
|
|
2234
|
+
function streamErrorText(eventOrPayload) {
|
|
2235
|
+
if (!isRecord4(eventOrPayload)) return null;
|
|
2236
|
+
const payload = typeof eventOrPayload.event === "string" && isRecord4(eventOrPayload.data) ? eventOrPayload.data : eventOrPayload;
|
|
2237
|
+
return nonBlank(payload.user_message) ?? nonBlank(payload.message);
|
|
2238
|
+
}
|
|
2239
|
+
async function openMatrxStream(transport, path, options = {}) {
|
|
2240
|
+
const response = await requestStream(transport, path, {
|
|
2241
|
+
method: "POST",
|
|
2242
|
+
...options.body !== void 0 ? { body: options.body } : {},
|
|
2243
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2244
|
+
});
|
|
2245
|
+
return toRunHandle(response, options);
|
|
2246
|
+
}
|
|
2247
|
+
function withRunOrganization(transport, organizationId) {
|
|
2248
|
+
const orgId = requireOrganizationContext(organizationId);
|
|
2249
|
+
return {
|
|
2250
|
+
fetch: (path, init) => transport.fetch(path, {
|
|
2251
|
+
...init,
|
|
2252
|
+
headers: { ...init.headers, "X-Organization-Id": orgId }
|
|
2253
|
+
})
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
async function followWorkflowRunEvents(transport, runId, options) {
|
|
2257
|
+
const headers = { Accept: "text/event-stream" };
|
|
2258
|
+
if (options.lastEventId) headers["Last-Event-ID"] = String(options.lastEventId);
|
|
2259
|
+
let response;
|
|
2151
2260
|
try {
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2261
|
+
response = await requestStream(
|
|
2262
|
+
transport,
|
|
2263
|
+
`/runs/${encodePathSegment(runId)}/events/stream`,
|
|
2264
|
+
{
|
|
2265
|
+
method: "GET",
|
|
2266
|
+
headers,
|
|
2267
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2268
|
+
}
|
|
2269
|
+
);
|
|
2270
|
+
} catch (error) {
|
|
2271
|
+
if (options.signal?.aborted) return { ended: false };
|
|
2272
|
+
throw error;
|
|
2273
|
+
}
|
|
2274
|
+
try {
|
|
2275
|
+
for await (const frame of readMatrxSseStream(
|
|
2276
|
+
response.body
|
|
2277
|
+
)) {
|
|
2278
|
+
if (frame.event === "end") return { ended: true };
|
|
2279
|
+
if (frame.data === null) continue;
|
|
2280
|
+
let parsed;
|
|
2281
|
+
try {
|
|
2282
|
+
parsed = JSON.parse(frame.data);
|
|
2283
|
+
} catch {
|
|
2284
|
+
continue;
|
|
2285
|
+
}
|
|
2286
|
+
if (!isRecord4(parsed)) continue;
|
|
2287
|
+
options.onEvent(parsed, parsed.event === "node_stream" ? null : frame.seq);
|
|
2169
2288
|
}
|
|
2289
|
+
} catch (error) {
|
|
2290
|
+
if (!options.signal?.aborted) throw error;
|
|
2170
2291
|
}
|
|
2171
|
-
return
|
|
2292
|
+
return { ended: false };
|
|
2172
2293
|
}
|
|
2173
|
-
function
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2294
|
+
async function drain(handle, onEnvelope) {
|
|
2295
|
+
for await (const envelope of handle.events) onEnvelope(envelope);
|
|
2296
|
+
}
|
|
2297
|
+
async function resumeOrRejoin(transport, resumeCall, options) {
|
|
2298
|
+
const {
|
|
2299
|
+
onEnvelope,
|
|
2300
|
+
organizationId,
|
|
2301
|
+
onRejoin,
|
|
2302
|
+
onOperationEvent,
|
|
2303
|
+
onWorkflowEvent,
|
|
2304
|
+
follow,
|
|
2305
|
+
...rest
|
|
2306
|
+
} = options;
|
|
2307
|
+
const bound = organizationId ? withRunOrganization(transport, organizationId) : transport;
|
|
2308
|
+
const streamOptions = {
|
|
2309
|
+
...rest,
|
|
2310
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2311
|
+
};
|
|
2312
|
+
const signalOnly = options.signal ? { signal: options.signal } : {};
|
|
2313
|
+
let rejoin;
|
|
2314
|
+
try {
|
|
2315
|
+
const handle = await resumeCall(bound, streamOptions);
|
|
2316
|
+
await drain(handle, onEnvelope);
|
|
2317
|
+
return { kind: "resumed", requestId: handle.requestId };
|
|
2318
|
+
} catch (error) {
|
|
2319
|
+
const target = readLiveRunRejoin(error);
|
|
2320
|
+
if (!target) {
|
|
2321
|
+
if (error instanceof MatrxApiError && isResumeConflict(error)) {
|
|
2322
|
+
return { kind: "resume_conflict", error };
|
|
2323
|
+
}
|
|
2324
|
+
throw error;
|
|
2325
|
+
}
|
|
2326
|
+
rejoin = target;
|
|
2181
2327
|
}
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
status
|
|
2328
|
+
onRejoin?.(rejoin);
|
|
2329
|
+
let unavailable;
|
|
2330
|
+
try {
|
|
2331
|
+
const handle = await openMatrxStream(bound, rejoin.rejoinPath, {
|
|
2332
|
+
...streamOptions,
|
|
2333
|
+
// The rejoin routes take no body model; the reference client posts {}.
|
|
2334
|
+
body: {}
|
|
2190
2335
|
});
|
|
2336
|
+
await drain(handle, onEnvelope);
|
|
2337
|
+
return { kind: "rejoined", rejoin };
|
|
2338
|
+
} catch (error) {
|
|
2339
|
+
const read = readLiveStreamUnavailable(error);
|
|
2340
|
+
if (!read) throw error;
|
|
2341
|
+
unavailable = read;
|
|
2191
2342
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
|
|
2343
|
+
return followUnavailableRejoin(bound, rejoin, unavailable, {
|
|
2344
|
+
...signalOnly,
|
|
2345
|
+
...onOperationEvent ? { onOperationEvent } : {},
|
|
2346
|
+
...onWorkflowEvent ? { onWorkflowEvent } : {},
|
|
2347
|
+
...follow ? { follow } : {}
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
function readLiveStreamUnavailable(error) {
|
|
2351
|
+
if (!isLiveStreamUnavailable(error)) return null;
|
|
2352
|
+
return { runId: firstString(detailCandidates(bodyOf(error)), "run_id") };
|
|
2353
|
+
}
|
|
2354
|
+
async function followUnavailableRejoin(transport, rejoin, unavailable, options = {}) {
|
|
2355
|
+
const bound = options.organizationId ? withRunOrganization(transport, options.organizationId) : transport;
|
|
2356
|
+
const signalOnly = options.signal ? { signal: options.signal } : {};
|
|
2357
|
+
const runId = unavailable.runId ?? rejoin.runId;
|
|
2358
|
+
if (runId && rejoin.rejoinPath.startsWith("/runtime/operations/")) {
|
|
2359
|
+
const result2 = await followWorkflowRunEvents(bound, runId, {
|
|
2360
|
+
...signalOnly,
|
|
2361
|
+
onEvent: (event, seq) => options.onWorkflowEvent?.(event, seq)
|
|
2201
2362
|
});
|
|
2363
|
+
return { kind: "followed_workflow", rejoin, runId, ended: result2.ended };
|
|
2202
2364
|
}
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
detail: firstMsg ? `Validation error: ${firstMsg}` : JSON.stringify(body.detail),
|
|
2209
|
-
userMessage: firstMsg || `Request failed (${status})`,
|
|
2210
|
-
details: body.detail,
|
|
2211
|
-
status
|
|
2212
|
-
});
|
|
2365
|
+
const liveRequestId = rejoin.liveRequestId;
|
|
2366
|
+
const statusView = liveRequestId ? await getRuntimeOperationStatus(bound, liveRequestId, signalOnly) : null;
|
|
2367
|
+
const operation = statusView?.operations.find((op) => !op.is_terminal) ?? statusView?.operations[0] ?? null;
|
|
2368
|
+
if (!operation) {
|
|
2369
|
+
return { kind: "followed", rejoin, executionId: null, ended: false, status: null };
|
|
2213
2370
|
}
|
|
2214
|
-
if (
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
details: d.details ?? d,
|
|
2223
|
-
requestId: typeof d.request_id === "string" ? d.request_id : void 0,
|
|
2224
|
-
status
|
|
2225
|
-
});
|
|
2371
|
+
if (operation.is_terminal) {
|
|
2372
|
+
return {
|
|
2373
|
+
kind: "followed",
|
|
2374
|
+
rejoin,
|
|
2375
|
+
executionId: operation.execution_id,
|
|
2376
|
+
ended: true,
|
|
2377
|
+
status: operation.status
|
|
2378
|
+
};
|
|
2226
2379
|
}
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
requestId: typeof body.request_id === "string" ? body.request_id : void 0,
|
|
2233
|
-
status
|
|
2380
|
+
const result = await followRuntimeOperationToEnd(bound, operation.execution_id, {
|
|
2381
|
+
...options.follow,
|
|
2382
|
+
lastEventSeq: operation.last_event_seq,
|
|
2383
|
+
...signalOnly,
|
|
2384
|
+
onEvent: (event) => options.onOperationEvent?.(event)
|
|
2234
2385
|
});
|
|
2386
|
+
return {
|
|
2387
|
+
kind: "followed",
|
|
2388
|
+
rejoin,
|
|
2389
|
+
executionId: operation.execution_id,
|
|
2390
|
+
ended: result.ended,
|
|
2391
|
+
status: result.status
|
|
2392
|
+
};
|
|
2235
2393
|
}
|
|
2236
|
-
function
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2394
|
+
async function attempt(run) {
|
|
2395
|
+
try {
|
|
2396
|
+
await run();
|
|
2397
|
+
return { reloaded: true };
|
|
2398
|
+
} catch (error) {
|
|
2399
|
+
return { reloaded: false, error };
|
|
2400
|
+
}
|
|
2240
2401
|
}
|
|
2241
|
-
function
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2402
|
+
async function settleRunPickup(pickup, options) {
|
|
2403
|
+
switch (pickup.kind) {
|
|
2404
|
+
case "resumed":
|
|
2405
|
+
case "rejoined":
|
|
2406
|
+
return { state: "streamed" };
|
|
2407
|
+
case "resume_conflict":
|
|
2408
|
+
return { state: "retry" };
|
|
2409
|
+
case "followed_workflow":
|
|
2410
|
+
case "followed": {
|
|
2411
|
+
const status = pickup.kind === "followed" ? pickup.status : null;
|
|
2412
|
+
const nothingLive = pickup.kind === "followed" && pickup.executionId === null;
|
|
2413
|
+
if (pickup.ended || nothingLive) {
|
|
2414
|
+
return { state: "settled", status, ...await attempt(options.reloadSavedTurn) };
|
|
2415
|
+
}
|
|
2416
|
+
return {
|
|
2417
|
+
state: "still_running",
|
|
2418
|
+
...await attempt(options.onStillRunning ?? options.reloadSavedTurn)
|
|
2419
|
+
};
|
|
2420
|
+
}
|
|
2248
2421
|
}
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2422
|
+
}
|
|
2423
|
+
|
|
2424
|
+
// matrx/run.ts
|
|
2425
|
+
async function streamCall(transport, path, body, options) {
|
|
2426
|
+
const response = await requestStream(transport, path, {
|
|
2427
|
+
method: "POST",
|
|
2428
|
+
// This client IS the streaming path — `stream: true` always, last so a
|
|
2429
|
+
// caller-supplied value can never flip the response off NDJSON.
|
|
2430
|
+
body: { ...body, stream: true },
|
|
2431
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2257
2432
|
});
|
|
2433
|
+
return toRunHandle(response, options);
|
|
2258
2434
|
}
|
|
2259
|
-
function
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2435
|
+
function startAgentRun(transport, agentId, request, options = {}) {
|
|
2436
|
+
return streamCall(
|
|
2437
|
+
transport,
|
|
2438
|
+
`/ai/agents/${encodePathSegment(agentId)}`,
|
|
2439
|
+
request,
|
|
2440
|
+
options
|
|
2441
|
+
);
|
|
2442
|
+
}
|
|
2443
|
+
function startMandateRun(transport, mandateKey, request, options = {}) {
|
|
2444
|
+
return streamCall(
|
|
2445
|
+
transport,
|
|
2446
|
+
`/ai/mandates/${encodePathSegment(mandateKey)}`,
|
|
2447
|
+
request,
|
|
2448
|
+
options
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
2451
|
+
function continueAgentConversation(transport, conversationId, request, options = {}) {
|
|
2452
|
+
return streamCall(
|
|
2453
|
+
transport,
|
|
2454
|
+
`/ai/conversations/${encodePathSegment(conversationId)}`,
|
|
2455
|
+
request,
|
|
2456
|
+
options
|
|
2457
|
+
);
|
|
2458
|
+
}
|
|
2459
|
+
function resumeAgentConversation(transport, conversationId, request = {}, options = {}) {
|
|
2460
|
+
return streamCall(
|
|
2461
|
+
transport,
|
|
2462
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/resume`,
|
|
2463
|
+
request,
|
|
2464
|
+
options
|
|
2265
2465
|
);
|
|
2266
|
-
const summary = typeof error.message === "string" ? error.message : "Backend operation failed";
|
|
2267
|
-
const specific = typeof firstSpecific?.message === "string" ? firstSpecific.message : summary;
|
|
2268
|
-
const detail = specific === summary ? summary : `${summary}: ${specific}`;
|
|
2269
|
-
const code = typeof error.type === "string" ? error.type : "internal_error";
|
|
2270
|
-
const userMessage = typeof error.user_message === "string" && error.user_message ? error.user_message : detail;
|
|
2271
|
-
return new BackendApiError({
|
|
2272
|
-
code,
|
|
2273
|
-
detail,
|
|
2274
|
-
userMessage,
|
|
2275
|
-
details: error,
|
|
2276
|
-
requestId
|
|
2277
|
-
});
|
|
2278
2466
|
}
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2467
|
+
function cancelAgentRun(transport, requestId, options = {}) {
|
|
2468
|
+
const query = buildQuery(
|
|
2469
|
+
options.mode === "interrupt" ? { mode: "interrupt" } : {}
|
|
2470
|
+
);
|
|
2471
|
+
return requestJson(
|
|
2472
|
+
transport,
|
|
2473
|
+
`/ai/cancel/${encodePathSegment(requestId)}${query}`,
|
|
2474
|
+
{
|
|
2475
|
+
method: "POST",
|
|
2476
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2477
|
+
}
|
|
2478
|
+
);
|
|
2291
2479
|
}
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2480
|
+
var MatrxRunError = class extends Error {
|
|
2481
|
+
name = "MatrxRunError";
|
|
2482
|
+
/** The verbatim `error` event payload, when one fired. */
|
|
2483
|
+
errorPayload;
|
|
2484
|
+
/** The `user_request` completion status (`"failed"` | `"cancelled"`), when that was the trigger. */
|
|
2485
|
+
completionStatus;
|
|
2486
|
+
/** Text streamed before the failure — partial content never vanishes. */
|
|
2487
|
+
partialText;
|
|
2488
|
+
constructor(args) {
|
|
2489
|
+
super(args.message);
|
|
2490
|
+
this.errorPayload = args.errorPayload ?? null;
|
|
2491
|
+
this.completionStatus = args.completionStatus ?? null;
|
|
2492
|
+
this.partialText = args.partialText ?? "";
|
|
2301
2493
|
}
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
if (!inner) return null;
|
|
2306
|
-
const statusMatch = /\bHTTP (\d{3})\b/.exec(message.slice(0, start));
|
|
2307
|
-
return {
|
|
2308
|
-
message: inner,
|
|
2309
|
-
code: typeof body.error_type === "string" && body.error_type || typeof body.error === "string" && body.error || null,
|
|
2310
|
-
userMessage: typeof body.user_message === "string" ? body.user_message : null,
|
|
2311
|
-
requestId: typeof body.request_id === "string" ? body.request_id : null,
|
|
2312
|
-
status: statusMatch ? Number(statusMatch[1]) : null
|
|
2313
|
-
};
|
|
2494
|
+
};
|
|
2495
|
+
function isRecord5(value) {
|
|
2496
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
2314
2497
|
}
|
|
2315
|
-
function
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
if (
|
|
2328
|
-
|
|
2498
|
+
function stringField(value, key) {
|
|
2499
|
+
if (!isRecord5(value)) return null;
|
|
2500
|
+
const field = value[key];
|
|
2501
|
+
return typeof field === "string" && field ? field : null;
|
|
2502
|
+
}
|
|
2503
|
+
async function runAgentToCompletion(transport, agentId, request, options = {}) {
|
|
2504
|
+
const handle = await startAgentRun(transport, agentId, request, options);
|
|
2505
|
+
let text = "";
|
|
2506
|
+
let completion = null;
|
|
2507
|
+
let failure = null;
|
|
2508
|
+
for await (const envelope of handle.events) {
|
|
2509
|
+
options.onEvent?.(envelope);
|
|
2510
|
+
if (envelope.event === "chunk") {
|
|
2511
|
+
const chunk = stringField(envelope.data, "text");
|
|
2512
|
+
if (chunk !== null) {
|
|
2513
|
+
text += chunk;
|
|
2514
|
+
options.onChunk?.(text);
|
|
2515
|
+
}
|
|
2516
|
+
continue;
|
|
2517
|
+
}
|
|
2518
|
+
if (envelope.event === "error" && failure === null) {
|
|
2519
|
+
const payload = isRecord5(envelope.data) ? envelope.data : null;
|
|
2520
|
+
failure = new MatrxRunError({
|
|
2521
|
+
message: streamErrorText(payload) ?? "The agent run failed",
|
|
2522
|
+
errorPayload: payload,
|
|
2523
|
+
partialText: text
|
|
2524
|
+
});
|
|
2525
|
+
continue;
|
|
2526
|
+
}
|
|
2527
|
+
if (envelope.event !== "completion" || !isRecord5(envelope.data)) continue;
|
|
2528
|
+
if (envelope.data.operation !== "user_request") continue;
|
|
2529
|
+
completion = envelope.data;
|
|
2530
|
+
const status = envelope.data.status;
|
|
2531
|
+
if ((status === "failed" || status === "cancelled") && failure === null) {
|
|
2532
|
+
const result = isRecord5(envelope.data.result) ? envelope.data.result : null;
|
|
2533
|
+
failure = new MatrxRunError({
|
|
2534
|
+
message: stringField(result, "error") ?? stringField(result, "user_message") ?? `The agent run ${status}`,
|
|
2535
|
+
completionStatus: status,
|
|
2536
|
+
partialText: text
|
|
2537
|
+
});
|
|
2329
2538
|
}
|
|
2330
|
-
} else if (error instanceof Error) {
|
|
2331
|
-
chain.push(error.message);
|
|
2332
|
-
userFacing = error.message;
|
|
2333
|
-
} else if (typeof error === "string") {
|
|
2334
|
-
chain.push(error);
|
|
2335
|
-
userFacing = error;
|
|
2336
|
-
} else {
|
|
2337
|
-
chain.push("Unknown error");
|
|
2338
2539
|
}
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
if (
|
|
2344
|
-
if (upstream.requestId) requestId = upstream.requestId;
|
|
2345
|
-
if (upstream.status !== null) status = upstream.status;
|
|
2540
|
+
if (failure) throw failure;
|
|
2541
|
+
if (!text && completion) {
|
|
2542
|
+
const result = completion.result;
|
|
2543
|
+
const output = stringField(result, "output");
|
|
2544
|
+
if (output !== null) text = output;
|
|
2346
2545
|
}
|
|
2347
|
-
const specific = [...chain].reverse().find((message) => !isGenericUserMessage(message));
|
|
2348
|
-
const cause = specific ?? chain[0] ?? "Unknown error";
|
|
2349
|
-
const headlineWasGeneric = isGenericUserMessage(userFacing);
|
|
2350
2546
|
return {
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
chain,
|
|
2356
|
-
requestId,
|
|
2357
|
-
status
|
|
2547
|
+
text,
|
|
2548
|
+
requestId: handle.requestId,
|
|
2549
|
+
conversationId: handle.conversationId,
|
|
2550
|
+
completion
|
|
2358
2551
|
};
|
|
2359
2552
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
if (
|
|
2371
|
-
|
|
2553
|
+
|
|
2554
|
+
// matrx/provider-failures.ts
|
|
2555
|
+
var clip = (value, max) => value.length > max ? value.slice(0, max) : value;
|
|
2556
|
+
function providerSessionFailureBody(failure) {
|
|
2557
|
+
const message = failure.message?.trim() || failure.error_type?.trim() || (failure.status_code ? `HTTP ${failure.status_code}` : "provider session failed");
|
|
2558
|
+
const body = {
|
|
2559
|
+
provider: failure.provider,
|
|
2560
|
+
message: clip(message, 4e3)
|
|
2561
|
+
};
|
|
2562
|
+
if (failure.model?.trim()) body.model = clip(failure.model.trim(), 200);
|
|
2563
|
+
if (failure.error_type?.trim()) body.error_type = clip(failure.error_type.trim(), 200);
|
|
2564
|
+
if (typeof failure.status_code === "number" && Number.isInteger(failure.status_code) && failure.status_code >= 100 && failure.status_code <= 599) {
|
|
2565
|
+
body.status_code = failure.status_code;
|
|
2372
2566
|
}
|
|
2373
|
-
return
|
|
2567
|
+
return body;
|
|
2374
2568
|
}
|
|
2375
|
-
function
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2569
|
+
async function reportProviderSessionFailure(transport, failure, options = {}) {
|
|
2570
|
+
try {
|
|
2571
|
+
return await requestJson(
|
|
2572
|
+
transport,
|
|
2573
|
+
"/broker/provider-failures",
|
|
2574
|
+
{
|
|
2575
|
+
method: "POST",
|
|
2576
|
+
body: providerSessionFailureBody(failure),
|
|
2577
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2578
|
+
}
|
|
2579
|
+
);
|
|
2580
|
+
} catch (error) {
|
|
2581
|
+
console.warn(
|
|
2582
|
+
`[provider-failures] could not report a ${failure.provider} session failure`,
|
|
2583
|
+
error
|
|
2584
|
+
);
|
|
2585
|
+
return null;
|
|
2387
2586
|
}
|
|
2388
2587
|
}
|
|
2389
2588
|
|
|
2589
|
+
// matrx/tools.ts
|
|
2590
|
+
function submitAgentToolResults(transport, conversationId, results, options = {}) {
|
|
2591
|
+
return requestJson(
|
|
2592
|
+
transport,
|
|
2593
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/tool_results`,
|
|
2594
|
+
{
|
|
2595
|
+
method: "POST",
|
|
2596
|
+
body: {
|
|
2597
|
+
results,
|
|
2598
|
+
...options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
2599
|
+
},
|
|
2600
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2601
|
+
}
|
|
2602
|
+
);
|
|
2603
|
+
}
|
|
2604
|
+
function listConversationPendingToolCalls(transport, conversationId, options = {}) {
|
|
2605
|
+
return requestJson(
|
|
2606
|
+
transport,
|
|
2607
|
+
`/ai/conversations/${encodePathSegment(conversationId)}/pending_calls`,
|
|
2608
|
+
{
|
|
2609
|
+
method: "GET",
|
|
2610
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2611
|
+
}
|
|
2612
|
+
);
|
|
2613
|
+
}
|
|
2614
|
+
function listUserPendingToolCalls(transport, options = {}) {
|
|
2615
|
+
const query = buildQuery(
|
|
2616
|
+
options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
|
|
2617
|
+
);
|
|
2618
|
+
return requestJson(
|
|
2619
|
+
transport,
|
|
2620
|
+
`/ai/user/pending_calls${query}`,
|
|
2621
|
+
{
|
|
2622
|
+
method: "GET",
|
|
2623
|
+
...options.signal ? { signal: options.signal } : {}
|
|
2624
|
+
}
|
|
2625
|
+
);
|
|
2626
|
+
}
|
|
2627
|
+
|
|
2390
2628
|
// matrx/endpoints.ts
|
|
2391
2629
|
var ENDPOINTS = {
|
|
2392
2630
|
/** AI endpoints — chat, agents, conversations */
|