@ai-matrx/agents 0.2.0 → 0.3.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.
@@ -1,11 +1,17 @@
1
1
  // stream/ndjson.ts
2
+ var DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;
2
3
  function isRecord(value) {
3
4
  return typeof value === "object" && value !== null && !Array.isArray(value);
4
5
  }
5
6
  function normalizeMatrxStreamEnvelope(value) {
6
7
  if (!isRecord(value)) return null;
7
8
  if (typeof value.event === "string") {
8
- return { event: value.event, data: value.data };
9
+ const streamSeq = typeof value.stream_seq === "number" && Number.isFinite(value.stream_seq) ? value.stream_seq : void 0;
10
+ return {
11
+ event: value.event,
12
+ data: value.data,
13
+ ...streamSeq === void 0 ? {} : { stream_seq: streamSeq }
14
+ };
9
15
  }
10
16
  if (value.e === "c" && typeof value.t === "string") {
11
17
  return { event: "chunk", data: { text: value.t } };
@@ -15,74 +21,179 @@ function normalizeMatrxStreamEnvelope(value) {
15
21
  }
16
22
  return null;
17
23
  }
18
- async function* readMatrxNdjsonStream(body, options = {}) {
19
- const queue = [];
20
- let wakeConsumer = null;
21
- let readerFinished = false;
22
- const enqueue = (item) => {
23
- queue.push(item);
24
- const wake = wakeConsumer;
25
- wakeConsumer = null;
26
- wake?.();
27
- };
28
- const reader = body.getReader();
24
+ function createMatrxNdjsonFramer(options = {}) {
29
25
  const decoder = new TextDecoder();
30
- const parseLine = (line) => {
26
+ let buffer = "";
27
+ let lineNumber = 0;
28
+ let finished = false;
29
+ const assertOpen = () => {
30
+ if (finished) throw new Error("Matrx NDJSON framer is already finished");
31
+ };
32
+ const parseLine = (line, atCompletion) => {
33
+ const currentLineNumber = ++lineNumber;
31
34
  const trimmed = line.trim();
32
- if (!trimmed) return;
35
+ if (!trimmed) return null;
33
36
  let parsed;
34
37
  try {
35
38
  parsed = JSON.parse(trimmed);
36
39
  } catch (error) {
37
- options.onMalformedLine?.({ line: trimmed, error });
38
- return;
40
+ options.onMalformedLine?.({
41
+ line: trimmed,
42
+ error,
43
+ lineNumber: currentLineNumber,
44
+ atCompletion
45
+ });
46
+ return null;
39
47
  }
40
48
  const envelope = normalizeMatrxStreamEnvelope(parsed);
41
- if (envelope) {
42
- enqueue({ kind: "event", value: envelope });
43
- } else {
49
+ if (!envelope) {
44
50
  options.onUnknownEnvelope?.(parsed);
51
+ return null;
52
+ }
53
+ options.onValidEnvelope?.({
54
+ raw: parsed,
55
+ envelope,
56
+ line: trimmed,
57
+ lineNumber: currentLineNumber,
58
+ atCompletion
59
+ });
60
+ return envelope;
61
+ };
62
+ const pushDecodedText = (fragment) => {
63
+ buffer += fragment;
64
+ const lines = buffer.split("\n");
65
+ buffer = lines.pop() ?? "";
66
+ const envelopes = [];
67
+ for (const line of lines) {
68
+ const envelope = parseLine(line, false);
69
+ if (envelope) envelopes.push(envelope);
45
70
  }
71
+ return envelopes;
46
72
  };
73
+ return {
74
+ pushText(fragment) {
75
+ assertOpen();
76
+ return pushDecodedText(decoder.decode() + fragment);
77
+ },
78
+ pushBytes(fragment) {
79
+ assertOpen();
80
+ return pushDecodedText(decoder.decode(fragment, { stream: true }));
81
+ },
82
+ finish() {
83
+ assertOpen();
84
+ finished = true;
85
+ const envelopes = pushDecodedText(decoder.decode());
86
+ if (buffer.length > 0) {
87
+ const envelope = parseLine(buffer, true);
88
+ buffer = "";
89
+ if (envelope) envelopes.push(envelope);
90
+ }
91
+ return envelopes;
92
+ }
93
+ };
94
+ }
95
+ function readAheadLimit(value) {
96
+ const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;
97
+ if (!Number.isSafeInteger(limit) || limit < 1) {
98
+ throw new RangeError("maxReadAhead must be a positive safe integer");
99
+ }
100
+ return limit;
101
+ }
102
+ async function* readMatrxNdjsonStream(body, options = {}) {
103
+ const maxReadAhead = readAheadLimit(options.maxReadAhead);
104
+ const queue = [];
105
+ let queuedEventCount = 0;
106
+ let wakeConsumer = null;
107
+ let wakeProducer = null;
108
+ let readerFinished = false;
109
+ let consumerClosed = false;
110
+ const wakeWaitingConsumer = () => {
111
+ const wake = wakeConsumer;
112
+ wakeConsumer = null;
113
+ wake?.();
114
+ };
115
+ const wakeWaitingProducer = () => {
116
+ const wake = wakeProducer;
117
+ wakeProducer = null;
118
+ wake?.();
119
+ };
120
+ const enqueueTerminal = (item) => {
121
+ if (consumerClosed) return;
122
+ queue.push(item);
123
+ wakeWaitingConsumer();
124
+ };
125
+ const enqueueEvent = async (value) => {
126
+ while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
127
+ await new Promise((resolve) => {
128
+ wakeProducer = resolve;
129
+ });
130
+ }
131
+ if (consumerClosed || options.signal?.aborted) return false;
132
+ queue.push({ kind: "event", value });
133
+ queuedEventCount += 1;
134
+ wakeWaitingConsumer();
135
+ return true;
136
+ };
137
+ const waitForReadCapacity = async () => {
138
+ while (queuedEventCount >= maxReadAhead && !consumerClosed && !options.signal?.aborted) {
139
+ await new Promise((resolve) => {
140
+ wakeProducer = resolve;
141
+ });
142
+ }
143
+ return !consumerClosed && !options.signal?.aborted;
144
+ };
145
+ const reader = body.getReader();
146
+ const framer = createMatrxNdjsonFramer(options);
47
147
  const onAbort = () => {
148
+ wakeWaitingProducer();
149
+ wakeWaitingConsumer();
48
150
  void reader.cancel(options.signal?.reason).catch(() => void 0);
49
151
  };
50
152
  options.signal?.addEventListener("abort", onAbort, { once: true });
153
+ if (options.signal?.aborted) onAbort();
51
154
  const readerPromise = (async () => {
52
- let buffer = "";
53
155
  try {
54
- while (!options.signal?.aborted) {
156
+ while (!options.signal?.aborted && !consumerClosed) {
157
+ if (!await waitForReadCapacity()) return;
55
158
  const { value, done } = await reader.read();
56
159
  if (done) break;
57
- buffer += decoder.decode(value, { stream: true });
58
- const lines = buffer.split("\n");
59
- buffer = lines.pop() ?? "";
60
- for (const line of lines) parseLine(line);
160
+ for (const envelope of framer.pushBytes(value)) {
161
+ if (!await enqueueEvent(envelope)) return;
162
+ }
163
+ }
164
+ if (!options.signal?.aborted && !consumerClosed) {
165
+ for (const envelope of framer.finish()) {
166
+ if (!await enqueueEvent(envelope)) return;
167
+ }
61
168
  }
62
- buffer += decoder.decode();
63
- if (!options.signal?.aborted && buffer.trim()) parseLine(buffer);
64
169
  } catch (error) {
65
- const aborted = options.signal?.aborted || error instanceof Error && error.name === "AbortError";
66
- if (!aborted) enqueue({ kind: "error", error });
170
+ const aborted = options.signal?.aborted || consumerClosed || error instanceof Error && error.name === "AbortError";
171
+ if (!aborted) enqueueTerminal({ kind: "error", error });
67
172
  } finally {
68
173
  readerFinished = true;
69
174
  reader.releaseLock();
70
- enqueue({ kind: "done" });
175
+ enqueueTerminal({ kind: "done" });
71
176
  }
72
177
  })();
73
178
  try {
74
179
  while (true) {
75
180
  if (queue.length === 0) {
181
+ if (options.signal?.aborted || readerFinished) return;
76
182
  await new Promise((resolve) => {
77
183
  wakeConsumer = resolve;
78
184
  });
79
185
  }
80
186
  const item = queue.shift();
187
+ if (item?.kind === "event") queuedEventCount -= 1;
188
+ wakeWaitingProducer();
81
189
  if (!item || item.kind === "done") return;
82
190
  if (item.kind === "error") throw item.error;
83
191
  yield item.value;
84
192
  }
85
193
  } finally {
194
+ consumerClosed = true;
195
+ wakeWaitingProducer();
196
+ wakeWaitingConsumer();
86
197
  options.signal?.removeEventListener("abort", onAbort);
87
198
  if (!readerFinished) {
88
199
  await reader.cancel().catch(() => void 0);
@@ -91,6 +202,6 @@ async function* readMatrxNdjsonStream(body, options = {}) {
91
202
  }
92
203
  }
93
204
 
94
- export { normalizeMatrxStreamEnvelope, readMatrxNdjsonStream };
205
+ export { DEFAULT_MATRX_NDJSON_READ_AHEAD, createMatrxNdjsonFramer, normalizeMatrxStreamEnvelope, readMatrxNdjsonStream };
95
206
  //# sourceMappingURL=ndjson.js.map
96
207
  //# sourceMappingURL=ndjson.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../stream/ndjson.ts"],"names":[],"mappings":"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","file":"ndjson.js","sourcesContent":["/**\n * Canonical AI Matrx NDJSON wire kernel.\n *\n * This module is deliberately independent of React, Redux, Next.js, Supabase,\n * and generated application types. Every Matrx client uses it to turn the\n * backend's byte stream into the same normalized `{ event, data }` envelopes.\n * Host runtimes remain responsible for HTTP/auth errors and for deciding what\n * each event means in their state model.\n */\n\nexport interface MatrxStreamEnvelope<TData = unknown> {\n event: string;\n data: TData;\n}\n\nexport interface MatrxNdjsonIssue {\n line: string;\n error: unknown;\n}\n\nexport interface ReadMatrxNdjsonOptions {\n signal?: AbortSignal;\n /** Malformed JSON is non-fatal, but it must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx event envelope is also non-fatal. */\n onUnknownEnvelope?: (value: unknown) => void;\n}\n\ntype QueueItem =\n | { kind: \"event\"; value: MatrxStreamEnvelope }\n | { kind: \"error\"; error: unknown }\n | { kind: \"done\" };\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize both supported Matrx wire shapes:\n *\n * - full: `{ \"event\": \"chunk\", \"data\": { \"text\": \"...\" } }`\n * - compact chunk: `{ \"e\": \"c\", \"t\": \"...\" }`\n * - compact reasoning: `{ \"e\": \"r\", \"t\": \"...\" }`\n */\nexport function normalizeMatrxStreamEnvelope(\n value: unknown,\n): MatrxStreamEnvelope | null {\n if (!isRecord(value)) return null;\n\n if (typeof value.event === \"string\") {\n return { event: value.event, data: value.data };\n }\n if (value.e === \"c\" && typeof value.t === \"string\") {\n return { event: \"chunk\", data: { text: value.t } };\n }\n if (value.e === \"r\" && typeof value.t === \"string\") {\n return { event: \"reasoning_chunk\", data: { text: value.t } };\n }\n return null;\n}\n\n/**\n * Read and normalize a Matrx NDJSON response body without applying consumer\n * backpressure to the network reader. The background read-ahead is important:\n * large tool payloads must keep draining even while React or another host is\n * processing the previous event.\n */\nexport async function* readMatrxNdjsonStream(\n body: ReadableStream<Uint8Array>,\n options: ReadMatrxNdjsonOptions = {},\n): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n const queue: QueueItem[] = [];\n let wakeConsumer: (() => void) | null = null;\n let readerFinished = false;\n\n const enqueue = (item: QueueItem): void => {\n queue.push(item);\n const wake = wakeConsumer;\n wakeConsumer = null;\n wake?.();\n };\n\n const reader = body.getReader();\n const decoder = new TextDecoder();\n\n const parseLine = (line: string): void => {\n const trimmed = line.trim();\n if (!trimmed) return;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed) as unknown;\n } catch (error) {\n options.onMalformedLine?.({ line: trimmed, error });\n return;\n }\n\n const envelope = normalizeMatrxStreamEnvelope(parsed);\n if (envelope) {\n enqueue({ kind: \"event\", value: envelope });\n } else {\n options.onUnknownEnvelope?.(parsed);\n }\n };\n\n const onAbort = (): void => {\n void reader.cancel(options.signal?.reason).catch(() => undefined);\n };\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n\n const readerPromise = (async (): Promise<void> => {\n let buffer = \"\";\n try {\n while (!options.signal?.aborted) {\n const { value, done } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n for (const line of lines) parseLine(line);\n }\n\n buffer += decoder.decode();\n if (!options.signal?.aborted && buffer.trim()) parseLine(buffer);\n } catch (error) {\n const aborted =\n options.signal?.aborted ||\n (error instanceof Error && error.name === \"AbortError\");\n if (!aborted) enqueue({ kind: \"error\", error });\n } finally {\n readerFinished = true;\n reader.releaseLock();\n enqueue({ kind: \"done\" });\n }\n })();\n\n try {\n while (true) {\n if (queue.length === 0) {\n await new Promise<void>((resolve) => {\n wakeConsumer = resolve;\n });\n }\n\n const item = queue.shift();\n if (!item || item.kind === \"done\") return;\n if (item.kind === \"error\") throw item.error;\n yield item.value;\n }\n } finally {\n options.signal?.removeEventListener(\"abort\", onAbort);\n if (!readerFinished) {\n await reader.cancel().catch(() => undefined);\n }\n await readerPromise;\n }\n}\n"]}
1
+ {"version":3,"sources":["../../stream/ndjson.ts"],"names":[],"mappings":"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","file":"ndjson.js","sourcesContent":["/**\n * Canonical AI Matrx NDJSON wire kernel.\n *\n * This module is deliberately independent of React, Redux, Next.js, Supabase,\n * and generated application types. Every Matrx client uses it to turn the\n * backend's byte stream into the same normalized `{ event, data }` envelopes.\n * Host runtimes remain responsible for HTTP/auth errors and for deciding what\n * each event means in their state model.\n */\n\nexport interface MatrxStreamEnvelope<TData = unknown> {\n event: string;\n data: TData;\n /** Monotonic transport sequence from full envelopes, when supplied. */\n stream_seq?: number;\n}\n\nexport interface MatrxNdjsonIssue {\n line: string;\n error: unknown;\n /** One-based physical NDJSON line number. */\n lineNumber: number;\n /** True when an unterminated trailing fragment was parsed by `finish()`. */\n atCompletion: boolean;\n}\n\nexport interface MatrxStreamEnvelopeObservation {\n /** Exact parsed JSON value before compact/full normalization. */\n raw: unknown;\n envelope: MatrxStreamEnvelope;\n line: string;\n lineNumber: number;\n atCompletion: boolean;\n}\n\nexport interface MatrxNdjsonFramerOptions {\n /** Malformed JSON is non-fatal, but it must never disappear silently. */\n onMalformedLine?: (issue: MatrxNdjsonIssue) => void;\n /** Valid JSON with no recognized Matrx event envelope is also non-fatal. */\n onUnknownEnvelope?: (value: unknown) => void;\n /** Observe every valid envelope without changing or consuming it. */\n onValidEnvelope?: (observation: MatrxStreamEnvelopeObservation) => void;\n}\n\nexport interface ReadMatrxNdjsonOptions extends MatrxNdjsonFramerOptions {\n signal?: AbortSignal;\n /** Maximum normalized events read ahead of the iterator consumer. */\n maxReadAhead?: number;\n}\n\nexport interface MatrxNdjsonFramer {\n /** Push a text fragment. Fragments may split JSON tokens or line endings. */\n pushText(fragment: string): MatrxStreamEnvelope[];\n /** Push a byte fragment. UTF-8 code points may span calls. */\n pushBytes(fragment: Uint8Array): MatrxStreamEnvelope[];\n /** Parse the final unterminated line and flush any pending UTF-8 bytes. */\n finish(): MatrxStreamEnvelope[];\n}\n\ntype QueueItem =\n | { kind: \"event\"; value: MatrxStreamEnvelope }\n | { kind: \"error\"; error: unknown }\n | { kind: \"done\" };\n\nexport const DEFAULT_MATRX_NDJSON_READ_AHEAD = 64;\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * Normalize both supported Matrx wire shapes:\n *\n * - full: `{ \"event\": \"chunk\", \"data\": { \"text\": \"...\" } }`\n * - compact chunk: `{ \"e\": \"c\", \"t\": \"...\" }`\n * - compact reasoning: `{ \"e\": \"r\", \"t\": \"...\" }`\n */\nexport function normalizeMatrxStreamEnvelope(\n value: unknown,\n): MatrxStreamEnvelope | null {\n if (!isRecord(value)) return null;\n\n if (typeof value.event === \"string\") {\n const streamSeq =\n typeof value.stream_seq === \"number\" && Number.isFinite(value.stream_seq)\n ? value.stream_seq\n : undefined;\n return {\n event: value.event,\n data: value.data,\n ...(streamSeq === undefined ? {} : { stream_seq: streamSeq }),\n };\n }\n if (value.e === \"c\" && typeof value.t === \"string\") {\n return { event: \"chunk\", data: { text: value.t } };\n }\n if (value.e === \"r\" && typeof value.t === \"string\") {\n return { event: \"reasoning_chunk\", data: { text: value.t } };\n }\n return null;\n}\n\n/**\n * Create the transport-independent NDJSON framer used by the stream reader.\n * Browser extensions, desktop bridges, WebSockets, and tests can feed it\n * fragmented strings or bytes without constructing a `ReadableStream`.\n */\nexport function createMatrxNdjsonFramer(\n options: MatrxNdjsonFramerOptions = {},\n): MatrxNdjsonFramer {\n const decoder = new TextDecoder();\n let buffer = \"\";\n let lineNumber = 0;\n let finished = false;\n\n const assertOpen = (): void => {\n if (finished) throw new Error(\"Matrx NDJSON framer is already finished\");\n };\n\n const parseLine = (\n line: string,\n atCompletion: boolean,\n ): MatrxStreamEnvelope | null => {\n const currentLineNumber = ++lineNumber;\n const trimmed = line.trim();\n if (!trimmed) return null;\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed) as unknown;\n } catch (error) {\n options.onMalformedLine?.({\n line: trimmed,\n error,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return null;\n }\n\n const envelope = normalizeMatrxStreamEnvelope(parsed);\n if (!envelope) {\n options.onUnknownEnvelope?.(parsed);\n return null;\n }\n options.onValidEnvelope?.({\n raw: parsed,\n envelope,\n line: trimmed,\n lineNumber: currentLineNumber,\n atCompletion,\n });\n return envelope;\n };\n\n const pushDecodedText = (fragment: string): MatrxStreamEnvelope[] => {\n buffer += fragment;\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() ?? \"\";\n const envelopes: MatrxStreamEnvelope[] = [];\n for (const line of lines) {\n const envelope = parseLine(line, false);\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n };\n\n return {\n pushText(fragment) {\n assertOpen();\n // Flush any pending byte fragment before switching to explicit text.\n return pushDecodedText(decoder.decode() + fragment);\n },\n pushBytes(fragment) {\n assertOpen();\n return pushDecodedText(decoder.decode(fragment, { stream: true }));\n },\n finish() {\n assertOpen();\n finished = true;\n const envelopes = pushDecodedText(decoder.decode());\n if (buffer.length > 0) {\n const envelope = parseLine(buffer, true);\n buffer = \"\";\n if (envelope) envelopes.push(envelope);\n }\n return envelopes;\n },\n };\n}\n\nfunction readAheadLimit(value: number | undefined): number {\n const limit = value ?? DEFAULT_MATRX_NDJSON_READ_AHEAD;\n if (!Number.isSafeInteger(limit) || limit < 1) {\n throw new RangeError(\"maxReadAhead must be a positive safe integer\");\n }\n return limit;\n}\n\n/**\n * Read and normalize a Matrx NDJSON response body with bounded background\n * read-ahead. Consumer work does not stall the network until `maxReadAhead`\n * complete events are waiting; the bound prevents an abandoned or blocked\n * consumer from growing memory without limit.\n */\nexport async function* readMatrxNdjsonStream(\n body: ReadableStream<Uint8Array>,\n options: ReadMatrxNdjsonOptions = {},\n): AsyncGenerator<MatrxStreamEnvelope, void, undefined> {\n const maxReadAhead = readAheadLimit(options.maxReadAhead);\n const queue: QueueItem[] = [];\n let queuedEventCount = 0;\n let wakeConsumer: (() => void) | null = null;\n let wakeProducer: (() => void) | null = null;\n let readerFinished = false;\n let consumerClosed = false;\n\n const wakeWaitingConsumer = (): void => {\n const wake = wakeConsumer;\n wakeConsumer = null;\n wake?.();\n };\n const wakeWaitingProducer = (): void => {\n const wake = wakeProducer;\n wakeProducer = null;\n wake?.();\n };\n const enqueueTerminal = (item: QueueItem): void => {\n if (consumerClosed) return;\n queue.push(item);\n wakeWaitingConsumer();\n };\n const enqueueEvent = async (value: MatrxStreamEnvelope): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n if (consumerClosed || options.signal?.aborted) return false;\n queue.push({ kind: \"event\", value });\n queuedEventCount += 1;\n wakeWaitingConsumer();\n return true;\n };\n const waitForReadCapacity = async (): Promise<boolean> => {\n while (\n queuedEventCount >= maxReadAhead &&\n !consumerClosed &&\n !options.signal?.aborted\n ) {\n await new Promise<void>((resolve) => {\n wakeProducer = resolve;\n });\n }\n return !consumerClosed && !options.signal?.aborted;\n };\n\n const reader = body.getReader();\n const framer = createMatrxNdjsonFramer(options);\n\n const onAbort = (): void => {\n wakeWaitingProducer();\n wakeWaitingConsumer();\n void reader.cancel(options.signal?.reason).catch(() => undefined);\n };\n options.signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (options.signal?.aborted) onAbort();\n\n const readerPromise = (async (): Promise<void> => {\n try {\n while (!options.signal?.aborted && !consumerClosed) {\n if (!(await waitForReadCapacity())) return;\n const { value, done } = await reader.read();\n if (done) break;\n for (const envelope of framer.pushBytes(value)) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n\n if (!options.signal?.aborted && !consumerClosed) {\n for (const envelope of framer.finish()) {\n if (!(await enqueueEvent(envelope))) return;\n }\n }\n } catch (error) {\n const aborted =\n options.signal?.aborted ||\n consumerClosed ||\n (error instanceof Error && error.name === \"AbortError\");\n if (!aborted) enqueueTerminal({ kind: \"error\", error });\n } finally {\n readerFinished = true;\n reader.releaseLock();\n enqueueTerminal({ kind: \"done\" });\n }\n })();\n\n try {\n while (true) {\n if (queue.length === 0) {\n if (options.signal?.aborted || readerFinished) return;\n await new Promise<void>((resolve) => {\n wakeConsumer = resolve;\n });\n }\n\n const item = queue.shift();\n if (item?.kind === \"event\") queuedEventCount -= 1;\n wakeWaitingProducer();\n if (!item || item.kind === \"done\") return;\n if (item.kind === \"error\") throw item.error;\n yield item.value;\n }\n } finally {\n consumerClosed = true;\n wakeWaitingProducer();\n wakeWaitingConsumer();\n options.signal?.removeEventListener(\"abort\", onAbort);\n if (!readerFinished) {\n await reader.cancel().catch(() => undefined);\n }\n await readerPromise;\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-matrx/agents",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Portable AI Matrx agent stream protocol, event projection, and safe result-presentation primitives.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -69,6 +69,16 @@
69
69
  "default": "./dist/projection/request.cjs"
70
70
  }
71
71
  },
72
+ "./projection/workflow": {
73
+ "import": {
74
+ "types": "./dist/projection/workflow.d.ts",
75
+ "default": "./dist/projection/workflow.js"
76
+ },
77
+ "require": {
78
+ "types": "./dist/projection/workflow.d.cts",
79
+ "default": "./dist/projection/workflow.cjs"
80
+ }
81
+ },
72
82
  "./package.json": "./package.json"
73
83
  },
74
84
  "devDependencies": {