@ai-matrx/agents 0.3.0 → 0.5.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/dist/index.js CHANGED
@@ -202,6 +202,68 @@ async function* readMatrxNdjsonStream(body, options = {}) {
202
202
  }
203
203
  }
204
204
 
205
+ // stream/sse.ts
206
+ var FRAME_SEPARATOR = /\r\n\r\n|\n\n|\r\r/;
207
+ var LINE_SEPARATOR = /\r\n|\n|\r/;
208
+ function parseMatrxSseFrame(frame) {
209
+ let event = "message";
210
+ let id = null;
211
+ const dataLines = [];
212
+ let sawData = false;
213
+ for (const line of frame.split(LINE_SEPARATOR)) {
214
+ if (line.startsWith(":")) continue;
215
+ if (line.startsWith("event:")) event = line.slice(6).trim();
216
+ else if (line.startsWith("data:")) {
217
+ sawData = true;
218
+ dataLines.push(line.slice(5).replace(/^ /, ""));
219
+ } else if (line.startsWith("id:")) id = line.slice(3).trim();
220
+ }
221
+ const seqCandidate = id !== null && id !== "" ? Number(id) : NaN;
222
+ const seq = Number.isSafeInteger(seqCandidate) && seqCandidate >= 0 ? seqCandidate : null;
223
+ return { event, id, seq, data: sawData ? dataLines.join("\n") : null };
224
+ }
225
+ function createMatrxSseFramer() {
226
+ let buffer = "";
227
+ return {
228
+ push(chunk) {
229
+ buffer += chunk;
230
+ const frames = [];
231
+ for (; ; ) {
232
+ const sep = FRAME_SEPARATOR.exec(buffer);
233
+ if (sep === null) break;
234
+ const frame = buffer.slice(0, sep.index);
235
+ buffer = buffer.slice(sep.index + sep[0].length);
236
+ frames.push(parseMatrxSseFrame(frame));
237
+ }
238
+ return frames;
239
+ },
240
+ flush() {
241
+ const rest = buffer;
242
+ buffer = "";
243
+ return { incomplete: rest.length > 0 ? rest : null };
244
+ }
245
+ };
246
+ }
247
+ async function* readMatrxSseStream(stream, options = {}) {
248
+ const reader = stream.getReader();
249
+ const decoder = new TextDecoder();
250
+ const framer = createMatrxSseFramer();
251
+ try {
252
+ for (; ; ) {
253
+ const { value, done } = await reader.read();
254
+ if (done) break;
255
+ const frames = framer.push(decoder.decode(value, { stream: true }));
256
+ for (const frame of frames) yield frame;
257
+ }
258
+ const tail = framer.push(decoder.decode());
259
+ for (const frame of tail) yield frame;
260
+ const { incomplete } = framer.flush();
261
+ if (incomplete !== null) options.onIncomplete?.(incomplete);
262
+ } finally {
263
+ reader.releaseLock();
264
+ }
265
+ }
266
+
205
267
  // presentation/result.ts
206
268
  var PRIVATE_REASONING_TYPES = /* @__PURE__ */ new Set([
207
269
  "thinking",
@@ -703,6 +765,460 @@ function projectWorkflowNodeEvent(current, event) {
703
765
  }
704
766
  }
705
767
 
706
- export { DEFAULT_MATRX_NDJSON_READ_AHEAD, DEFAULT_WORKFLOW_PROJECTION_LIMITS, createAgentRequestProjection, createMatrxNdjsonFramer, createWorkflowNodeProjection, normalizeMatrxStreamEnvelope, projectAgentEvent, projectAgentEvents, projectAgentResultForDisplay, projectWorkflowNodeEvent, readMatrxNdjsonStream };
768
+ // matrx/transport.ts
769
+ var MatrxApiError = class extends Error {
770
+ name = "MatrxApiError";
771
+ /** HTTP status of the failed response. */
772
+ status;
773
+ /** Machine code from the server body (`code`, or `detail.code`), when present. */
774
+ code;
775
+ /** The parsed server error body, verbatim (undefined when unparsable). */
776
+ serverDetail;
777
+ /** The request path the failure came from (server-relative). */
778
+ path;
779
+ constructor(args) {
780
+ super(
781
+ args.message ?? extractMatrxErrorMessage(args.serverDetail) ?? `HTTP ${args.status}`
782
+ );
783
+ this.status = args.status;
784
+ this.path = args.path;
785
+ this.serverDetail = args.serverDetail;
786
+ this.code = extractMatrxErrorCode(args.serverDetail);
787
+ }
788
+ };
789
+ function isRecord3(value) {
790
+ return typeof value === "object" && value !== null && !Array.isArray(value);
791
+ }
792
+ function nonBlankString(value) {
793
+ return typeof value === "string" && value.trim() ? value : void 0;
794
+ }
795
+ function extractMatrxErrorMessage(serverDetail) {
796
+ if (!isRecord3(serverDetail)) return void 0;
797
+ const userMessage = nonBlankString(serverDetail.user_message);
798
+ if (userMessage) return userMessage;
799
+ const message = nonBlankString(serverDetail.message);
800
+ if (message) return message;
801
+ if (Array.isArray(serverDetail.details)) {
802
+ const messages = serverDetail.details.map((entry) => {
803
+ if (!isRecord3(entry)) return void 0;
804
+ const detailMessage = nonBlankString(entry.message);
805
+ if (!detailMessage) return void 0;
806
+ const field = nonBlankString(entry.field);
807
+ return field ? `${field}: ${detailMessage}` : detailMessage;
808
+ }).filter((m) => typeof m === "string");
809
+ if (messages.length > 0) return messages.join("; ");
810
+ }
811
+ const detail = serverDetail.detail;
812
+ if (isRecord3(detail)) {
813
+ const detailMessage = nonBlankString(detail.message) ?? nonBlankString(detail.user_message);
814
+ if (detailMessage) return detailMessage;
815
+ }
816
+ if (typeof detail === "string" && detail.trim()) return detail;
817
+ if (Array.isArray(detail)) {
818
+ const messages = detail.map(
819
+ (entry) => isRecord3(entry) ? nonBlankString(entry.msg) : void 0
820
+ ).filter((m) => typeof m === "string");
821
+ if (messages.length > 0) return messages.join("; ");
822
+ }
823
+ return void 0;
824
+ }
825
+ function extractMatrxErrorCode(serverDetail) {
826
+ if (!isRecord3(serverDetail)) return null;
827
+ const topLevel = nonBlankString(serverDetail.code);
828
+ if (topLevel) return topLevel;
829
+ const detail = serverDetail.detail;
830
+ if (isRecord3(detail)) {
831
+ const nested = nonBlankString(detail.code);
832
+ if (nested) return nested;
833
+ }
834
+ return null;
835
+ }
836
+
837
+ // matrx/conversation.ts
838
+ function mintMatrxConversationId() {
839
+ return crypto.randomUUID();
840
+ }
841
+ function newStoredConversationStart(conversationId) {
842
+ return {
843
+ conversation_id: conversationId ?? mintMatrxConversationId(),
844
+ is_new: true,
845
+ store: true
846
+ };
847
+ }
848
+ function continueStoredConversationStart(conversationId) {
849
+ return { conversation_id: conversationId, is_new: false, store: true };
850
+ }
851
+ function newEphemeralConversationStart(conversationId) {
852
+ return {
853
+ conversation_id: conversationId ?? mintMatrxConversationId(),
854
+ is_new: true,
855
+ store: false
856
+ };
857
+ }
858
+ function continueEphemeralConversationStart(conversationId, priorMessages) {
859
+ return {
860
+ conversation_id: conversationId,
861
+ is_new: false,
862
+ store: false,
863
+ prior_messages: priorMessages
864
+ };
865
+ }
866
+
867
+ // matrx/internal.ts
868
+ function encodePathSegment(value) {
869
+ return encodeURIComponent(value);
870
+ }
871
+ function buildQuery(params) {
872
+ const search = new URLSearchParams();
873
+ for (const [key, value] of Object.entries(params)) {
874
+ if (value === void 0) continue;
875
+ if (Array.isArray(value)) {
876
+ for (const entry of value) search.append(key, entry);
877
+ } else {
878
+ search.append(key, String(value));
879
+ }
880
+ }
881
+ const encoded = search.toString();
882
+ return encoded ? `?${encoded}` : "";
883
+ }
884
+ async function readServerDetail(response) {
885
+ try {
886
+ return await response.json();
887
+ } catch {
888
+ return void 0;
889
+ }
890
+ }
891
+ async function throwApiError(path, response) {
892
+ throw new MatrxApiError({
893
+ status: response.status,
894
+ path,
895
+ serverDetail: await readServerDetail(response)
896
+ });
897
+ }
898
+ async function requestJson(transport, path, options) {
899
+ const hasBody = options.method !== "GET" && options.body !== void 0;
900
+ const response = await transport.fetch(path, {
901
+ method: options.method,
902
+ headers: hasBody ? { "Content-Type": "application/json" } : {},
903
+ ...hasBody ? { body: JSON.stringify(options.body) } : {},
904
+ ...options.signal ? { signal: options.signal } : {}
905
+ });
906
+ if (!response.ok) return throwApiError(path, response);
907
+ return await response.json();
908
+ }
909
+ function toRunHandle(response, options) {
910
+ return {
911
+ requestId: response.headers.get("X-Request-ID"),
912
+ conversationId: response.headers.get("X-Conversation-ID"),
913
+ events: readMatrxNdjsonStream(response.body, {
914
+ ...options.signal ? { signal: options.signal } : {},
915
+ ...options.maxReadAhead !== void 0 ? { maxReadAhead: options.maxReadAhead } : {},
916
+ ...options.onMalformedLine ? { onMalformedLine: options.onMalformedLine } : {},
917
+ ...options.onUnknownEnvelope ? { onUnknownEnvelope: options.onUnknownEnvelope } : {},
918
+ ...options.onValidEnvelope ? { onValidEnvelope: options.onValidEnvelope } : {}
919
+ }),
920
+ response
921
+ };
922
+ }
923
+ async function requestStream(transport, path, options) {
924
+ const hasBody = options.method !== "GET" && options.body !== void 0;
925
+ const response = await transport.fetch(path, {
926
+ method: options.method,
927
+ headers: {
928
+ ...hasBody ? { "Content-Type": "application/json" } : {},
929
+ ...options.headers
930
+ },
931
+ ...hasBody ? { body: JSON.stringify(options.body) } : {},
932
+ ...options.signal ? { signal: options.signal } : {}
933
+ });
934
+ if (!response.ok) return throwApiError(path, response);
935
+ if (!response.body) {
936
+ throw new MatrxApiError({
937
+ status: response.status,
938
+ path,
939
+ serverDetail: { code: "missing_response_body" },
940
+ message: "The streaming response carried no body."
941
+ });
942
+ }
943
+ return response;
944
+ }
945
+
946
+ // matrx/run.ts
947
+ async function streamCall(transport, path, body, options) {
948
+ const response = await requestStream(transport, path, {
949
+ method: "POST",
950
+ // This client IS the streaming path — `stream: true` always, last so a
951
+ // caller-supplied value can never flip the response off NDJSON.
952
+ body: { ...body, stream: true },
953
+ ...options.signal ? { signal: options.signal } : {}
954
+ });
955
+ return toRunHandle(response, options);
956
+ }
957
+ function startAgentRun(transport, agentId, request, options = {}) {
958
+ return streamCall(
959
+ transport,
960
+ `/ai/agents/${encodePathSegment(agentId)}`,
961
+ request,
962
+ options
963
+ );
964
+ }
965
+ function continueAgentConversation(transport, conversationId, request, options = {}) {
966
+ return streamCall(
967
+ transport,
968
+ `/ai/conversations/${encodePathSegment(conversationId)}`,
969
+ request,
970
+ options
971
+ );
972
+ }
973
+ function resumeAgentConversation(transport, conversationId, request = {}, options = {}) {
974
+ return streamCall(
975
+ transport,
976
+ `/ai/conversations/${encodePathSegment(conversationId)}/resume`,
977
+ request,
978
+ options
979
+ );
980
+ }
981
+ function cancelAgentRun(transport, requestId, options = {}) {
982
+ const query = buildQuery(
983
+ options.mode === "interrupt" ? { mode: "interrupt" } : {}
984
+ );
985
+ return requestJson(
986
+ transport,
987
+ `/ai/cancel/${encodePathSegment(requestId)}${query}`,
988
+ {
989
+ method: "POST",
990
+ ...options.signal ? { signal: options.signal } : {}
991
+ }
992
+ );
993
+ }
994
+ var MatrxRunError = class extends Error {
995
+ name = "MatrxRunError";
996
+ /** The verbatim `error` event payload, when one fired. */
997
+ errorPayload;
998
+ /** The `user_request` completion status (`"failed"` | `"cancelled"`), when that was the trigger. */
999
+ completionStatus;
1000
+ /** Text streamed before the failure — partial content never vanishes. */
1001
+ partialText;
1002
+ constructor(args) {
1003
+ super(args.message);
1004
+ this.errorPayload = args.errorPayload ?? null;
1005
+ this.completionStatus = args.completionStatus ?? null;
1006
+ this.partialText = args.partialText ?? "";
1007
+ }
1008
+ };
1009
+ function isRecord4(value) {
1010
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1011
+ }
1012
+ function stringField(value, key) {
1013
+ if (!isRecord4(value)) return null;
1014
+ const field = value[key];
1015
+ return typeof field === "string" && field ? field : null;
1016
+ }
1017
+ async function runAgentToCompletion(transport, agentId, request, options = {}) {
1018
+ const handle = await startAgentRun(transport, agentId, request, options);
1019
+ let text = "";
1020
+ let completion = null;
1021
+ let failure = null;
1022
+ for await (const envelope of handle.events) {
1023
+ options.onEvent?.(envelope);
1024
+ if (envelope.event === "chunk") {
1025
+ const chunk = stringField(envelope.data, "text");
1026
+ if (chunk !== null) {
1027
+ text += chunk;
1028
+ options.onChunk?.(text);
1029
+ }
1030
+ continue;
1031
+ }
1032
+ if (envelope.event === "error" && failure === null) {
1033
+ const payload = isRecord4(envelope.data) ? envelope.data : null;
1034
+ failure = new MatrxRunError({
1035
+ message: stringField(payload, "user_message") ?? stringField(payload, "message") ?? "The agent run failed",
1036
+ errorPayload: payload,
1037
+ partialText: text
1038
+ });
1039
+ continue;
1040
+ }
1041
+ if (envelope.event !== "completion" || !isRecord4(envelope.data)) continue;
1042
+ if (envelope.data.operation !== "user_request") continue;
1043
+ completion = envelope.data;
1044
+ const status = envelope.data.status;
1045
+ if ((status === "failed" || status === "cancelled") && failure === null) {
1046
+ const result = isRecord4(envelope.data.result) ? envelope.data.result : null;
1047
+ failure = new MatrxRunError({
1048
+ message: stringField(result, "error") ?? stringField(result, "user_message") ?? `The agent run ${status}`,
1049
+ completionStatus: status,
1050
+ partialText: text
1051
+ });
1052
+ }
1053
+ }
1054
+ if (failure) throw failure;
1055
+ if (!text && completion) {
1056
+ const result = completion.result;
1057
+ const output = stringField(result, "output");
1058
+ if (output !== null) text = output;
1059
+ }
1060
+ return {
1061
+ text,
1062
+ requestId: handle.requestId,
1063
+ conversationId: handle.conversationId,
1064
+ completion
1065
+ };
1066
+ }
1067
+
1068
+ // matrx/operations.ts
1069
+ var TERMINAL_MATRX_RUNTIME_STATUSES = /* @__PURE__ */ new Set(["completed", "failed", "cancelled"]);
1070
+ var RUNTIME_STATUSES = /* @__PURE__ */ new Set([
1071
+ "pending",
1072
+ "running",
1073
+ "paused",
1074
+ "waiting_input",
1075
+ "completed",
1076
+ "failed",
1077
+ "cancelled"
1078
+ ]);
1079
+ async function getRuntimeOperationStatus(transport, requestId, options = {}) {
1080
+ try {
1081
+ return await requestJson(
1082
+ transport,
1083
+ `/runtime/operations/${encodePathSegment(requestId)}`,
1084
+ { method: "GET", ...options.signal ? { signal: options.signal } : {} }
1085
+ );
1086
+ } catch (error) {
1087
+ if (error instanceof MatrxApiError && error.status === 404) return null;
1088
+ throw error;
1089
+ }
1090
+ }
1091
+ async function getRuntimeOperationsByLink(transport, linkKind, linkId, options = {}) {
1092
+ const query = buildQuery(
1093
+ options.limit !== void 0 ? { limit: options.limit } : {}
1094
+ );
1095
+ try {
1096
+ return await requestJson(
1097
+ transport,
1098
+ `/runtime/operations/by-link/${encodePathSegment(linkKind)}/${encodePathSegment(linkId)}${query}`,
1099
+ { method: "GET", ...options.signal ? { signal: options.signal } : {} }
1100
+ );
1101
+ } catch (error) {
1102
+ if (error instanceof MatrxApiError && error.status === 404) return null;
1103
+ throw error;
1104
+ }
1105
+ }
1106
+ function listRuntimeOperationEvents(transport, executionId, options = {}) {
1107
+ const query = buildQuery({
1108
+ ...options.afterSeq !== void 0 ? { after_seq: options.afterSeq } : {},
1109
+ ...options.limit !== void 0 ? { limit: options.limit } : {},
1110
+ ...options.kinds !== void 0 ? { kind: options.kinds } : {}
1111
+ });
1112
+ return requestJson(
1113
+ transport,
1114
+ `/runtime/executions/${encodePathSegment(executionId)}/events${query}`,
1115
+ { method: "GET", ...options.signal ? { signal: options.signal } : {} }
1116
+ );
1117
+ }
1118
+ function parseEndStatus(data) {
1119
+ if (data === null) return null;
1120
+ try {
1121
+ const parsed = JSON.parse(data);
1122
+ if (typeof parsed === "object" && parsed !== null && typeof parsed.status === "string") {
1123
+ const status = parsed.status;
1124
+ return RUNTIME_STATUSES.has(status) ? status : null;
1125
+ }
1126
+ } catch {
1127
+ }
1128
+ return null;
1129
+ }
1130
+ async function* followRuntimeOperationEvents(transport, executionId, options = {}) {
1131
+ let cursor = options.lastEventSeq ?? 0;
1132
+ const headers = { Accept: "text/event-stream" };
1133
+ if (cursor > 0) headers["Last-Event-ID"] = String(cursor);
1134
+ const response = await requestStream(
1135
+ transport,
1136
+ `/runtime/executions/${encodePathSegment(executionId)}/events/stream`,
1137
+ {
1138
+ method: "GET",
1139
+ headers,
1140
+ ...options.signal ? { signal: options.signal } : {}
1141
+ }
1142
+ );
1143
+ const frames = readMatrxSseStream(
1144
+ response.body,
1145
+ options.onIncomplete ? { onIncomplete: options.onIncomplete } : {}
1146
+ );
1147
+ for await (const frame of frames) {
1148
+ if (frame.event === "end") {
1149
+ yield { type: "end", status: parseEndStatus(frame.data), cursor };
1150
+ return;
1151
+ }
1152
+ if (frame.event === "execution_event" && frame.data !== null) {
1153
+ let event;
1154
+ try {
1155
+ event = JSON.parse(frame.data);
1156
+ } catch (error) {
1157
+ options.onMalformedFrame?.(frame, error);
1158
+ yield { type: "liveness", cursor };
1159
+ continue;
1160
+ }
1161
+ if (frame.seq !== null && frame.seq > cursor) cursor = frame.seq;
1162
+ yield { type: "event", event, seq: frame.seq, cursor };
1163
+ continue;
1164
+ }
1165
+ yield { type: "liveness", cursor };
1166
+ }
1167
+ }
1168
+ async function rejoinRuntimeOperation(transport, requestId, options = {}) {
1169
+ const response = await requestStream(
1170
+ transport,
1171
+ `/runtime/operations/${encodePathSegment(requestId)}/rejoin`,
1172
+ {
1173
+ method: "POST",
1174
+ // The route takes no body model; the reference client posts an empty
1175
+ // JSON object. Match it so proxies see an ordinary JSON POST.
1176
+ body: {},
1177
+ ...options.signal ? { signal: options.signal } : {}
1178
+ }
1179
+ );
1180
+ return toRunHandle(response, options);
1181
+ }
1182
+
1183
+ // matrx/tools.ts
1184
+ function submitAgentToolResults(transport, conversationId, results, options = {}) {
1185
+ return requestJson(
1186
+ transport,
1187
+ `/ai/conversations/${encodePathSegment(conversationId)}/tool_results`,
1188
+ {
1189
+ method: "POST",
1190
+ body: {
1191
+ results,
1192
+ ...options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
1193
+ },
1194
+ ...options.signal ? { signal: options.signal } : {}
1195
+ }
1196
+ );
1197
+ }
1198
+ function listConversationPendingToolCalls(transport, conversationId, options = {}) {
1199
+ return requestJson(
1200
+ transport,
1201
+ `/ai/conversations/${encodePathSegment(conversationId)}/pending_calls`,
1202
+ {
1203
+ method: "GET",
1204
+ ...options.signal ? { signal: options.signal } : {}
1205
+ }
1206
+ );
1207
+ }
1208
+ function listUserPendingToolCalls(transport, options = {}) {
1209
+ const query = buildQuery(
1210
+ options.instanceId !== void 0 ? { instance_id: options.instanceId } : {}
1211
+ );
1212
+ return requestJson(
1213
+ transport,
1214
+ `/ai/user/pending_calls${query}`,
1215
+ {
1216
+ method: "GET",
1217
+ ...options.signal ? { signal: options.signal } : {}
1218
+ }
1219
+ );
1220
+ }
1221
+
1222
+ export { DEFAULT_MATRX_NDJSON_READ_AHEAD, DEFAULT_WORKFLOW_PROJECTION_LIMITS, MatrxApiError, MatrxRunError, TERMINAL_MATRX_RUNTIME_STATUSES, cancelAgentRun, continueAgentConversation, continueEphemeralConversationStart, continueStoredConversationStart, createAgentRequestProjection, createMatrxNdjsonFramer, createMatrxSseFramer, createWorkflowNodeProjection, extractMatrxErrorCode, extractMatrxErrorMessage, followRuntimeOperationEvents, getRuntimeOperationStatus, getRuntimeOperationsByLink, listConversationPendingToolCalls, listRuntimeOperationEvents, listUserPendingToolCalls, mintMatrxConversationId, newEphemeralConversationStart, newStoredConversationStart, normalizeMatrxStreamEnvelope, parseMatrxSseFrame, projectAgentEvent, projectAgentEvents, projectAgentResultForDisplay, projectWorkflowNodeEvent, readMatrxNdjsonStream, readMatrxSseStream, rejoinRuntimeOperation, resumeAgentConversation, runAgentToCompletion, startAgentRun, submitAgentToolResults };
707
1223
  //# sourceMappingURL=index.js.map
708
1224
  //# sourceMappingURL=index.js.map