@ai-matrx/agents 0.1.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 ADDED
@@ -0,0 +1,9 @@
1
+ # Changelog
2
+
3
+ ## 0.1.0 — 2026-08-22
4
+
5
+ - Published the canonical NDJSON stream reader and envelope normalizer.
6
+ - Published the copy-on-write result projection that removes provider-private
7
+ reasoning and signature material from Creator-facing output.
8
+ - Added strict tests, ESM declarations, packed-artifact validation, and an
9
+ isolated consumer import canary.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 AI Matrix Engine
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # @ai-matrx/agents
2
+
3
+ Portable client-side primitives for AI Matrx agent applications. Version 1 is
4
+ intentionally narrow: it standardizes the stream wire boundary and the safe
5
+ Creator-facing result boundary without importing React, Redux, Next.js, or any
6
+ application code.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ pnpm add @ai-matrx/agents
12
+ ```
13
+
14
+ ## Read an agent stream
15
+
16
+ ```ts
17
+ import { readMatrxNdjsonStream } from "@ai-matrx/agents/stream/ndjson";
18
+
19
+ for await (const envelope of readMatrxNdjsonStream(response.body!, {
20
+ onMalformedLine: reportProtocolDamage,
21
+ onUnknownEnvelope: reportUnknownEnvelope,
22
+ })) {
23
+ handleEvent(envelope);
24
+ }
25
+ ```
26
+
27
+ The reader preserves split UTF-8, drains the network independently of consumer
28
+ work, supports cancellation, normalizes full and compact Matrx envelopes, and
29
+ reports malformed or unknown input through explicit callbacks.
30
+
31
+ ## Present a settled result safely
32
+
33
+ ```ts
34
+ import { projectAgentResultForDisplay } from "@ai-matrx/agents/presentation/result";
35
+
36
+ const displayValue = projectAgentResultForDisplay(persistedExecutionValue);
37
+ ```
38
+
39
+ The projection removes provider-private reasoning blocks and signature material
40
+ without mutating the execution value. It is only for display, JSON views, and
41
+ exports. Never persist the projected result or use it to continue an agent run.
42
+
43
+ ## Runtime support
44
+
45
+ The package is framework-free ESM targeting modern browsers, browser-based
46
+ desktop shells, extensions, Next.js client or server modules, and Node 20+.
47
+ It has no runtime dependencies and performs no work at import time.
48
+
49
+ ## Development
50
+
51
+ ```bash
52
+ pnpm typecheck
53
+ pnpm test
54
+ pnpm check:package
55
+ ```
56
+
57
+ `check:package` builds JavaScript and declarations, validates the manifest,
58
+ packs the release artifact, checks its public types, installs it into an empty
59
+ project, and imports every entry point.
60
+
61
+ Never publish directly from this working directory. Release the verified
62
+ tarball produced by `pnpm pack`; `prepublishOnly` blocks the unsafe path.
@@ -0,0 +1,2 @@
1
+ export { MatrxNdjsonIssue, MatrxStreamEnvelope, ReadMatrxNdjsonOptions, normalizeMatrxStreamEnvelope, readMatrxNdjsonStream } from './stream/ndjson.js';
2
+ export { projectAgentResultForDisplay } from './presentation/result.js';
package/dist/index.js ADDED
@@ -0,0 +1,168 @@
1
+ // stream/ndjson.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function normalizeMatrxStreamEnvelope(value) {
6
+ if (!isRecord(value)) return null;
7
+ if (typeof value.event === "string") {
8
+ return { event: value.event, data: value.data };
9
+ }
10
+ if (value.e === "c" && typeof value.t === "string") {
11
+ return { event: "chunk", data: { text: value.t } };
12
+ }
13
+ if (value.e === "r" && typeof value.t === "string") {
14
+ return { event: "reasoning_chunk", data: { text: value.t } };
15
+ }
16
+ return null;
17
+ }
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();
29
+ const decoder = new TextDecoder();
30
+ const parseLine = (line) => {
31
+ const trimmed = line.trim();
32
+ if (!trimmed) return;
33
+ let parsed;
34
+ try {
35
+ parsed = JSON.parse(trimmed);
36
+ } catch (error) {
37
+ options.onMalformedLine?.({ line: trimmed, error });
38
+ return;
39
+ }
40
+ const envelope = normalizeMatrxStreamEnvelope(parsed);
41
+ if (envelope) {
42
+ enqueue({ kind: "event", value: envelope });
43
+ } else {
44
+ options.onUnknownEnvelope?.(parsed);
45
+ }
46
+ };
47
+ const onAbort = () => {
48
+ void reader.cancel(options.signal?.reason).catch(() => void 0);
49
+ };
50
+ options.signal?.addEventListener("abort", onAbort, { once: true });
51
+ const readerPromise = (async () => {
52
+ let buffer = "";
53
+ try {
54
+ while (!options.signal?.aborted) {
55
+ const { value, done } = await reader.read();
56
+ 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);
61
+ }
62
+ buffer += decoder.decode();
63
+ if (!options.signal?.aborted && buffer.trim()) parseLine(buffer);
64
+ } catch (error) {
65
+ const aborted = options.signal?.aborted || error instanceof Error && error.name === "AbortError";
66
+ if (!aborted) enqueue({ kind: "error", error });
67
+ } finally {
68
+ readerFinished = true;
69
+ reader.releaseLock();
70
+ enqueue({ kind: "done" });
71
+ }
72
+ })();
73
+ try {
74
+ while (true) {
75
+ if (queue.length === 0) {
76
+ await new Promise((resolve) => {
77
+ wakeConsumer = resolve;
78
+ });
79
+ }
80
+ const item = queue.shift();
81
+ if (!item || item.kind === "done") return;
82
+ if (item.kind === "error") throw item.error;
83
+ yield item.value;
84
+ }
85
+ } finally {
86
+ options.signal?.removeEventListener("abort", onAbort);
87
+ if (!readerFinished) {
88
+ await reader.cancel().catch(() => void 0);
89
+ }
90
+ await readerPromise;
91
+ }
92
+ }
93
+
94
+ // presentation/result.ts
95
+ var PRIVATE_REASONING_TYPES = /* @__PURE__ */ new Set([
96
+ "thinking",
97
+ "redacted_thinking",
98
+ "reasoning"
99
+ ]);
100
+ var PRIVATE_PROVIDER_KEYS = /* @__PURE__ */ new Set([
101
+ "thought_signature",
102
+ "thoughtSignature",
103
+ "google_thought_signature",
104
+ "anthropic_signature",
105
+ "encrypted_content",
106
+ "signature_encoding"
107
+ ]);
108
+ var SIGNATURE_PROVIDERS = /* @__PURE__ */ new Set([
109
+ "anthropic",
110
+ "google",
111
+ "openai"
112
+ ]);
113
+ var OPAQUE_SIGNATURE_MIN_LENGTH = 200;
114
+ var OMIT = /* @__PURE__ */ Symbol("omit-provider-private-value");
115
+ function isRecord2(value) {
116
+ return typeof value === "object" && value !== null && !Array.isArray(value);
117
+ }
118
+ function isPrivateReasoningBlock(value) {
119
+ return typeof value.type === "string" && PRIVATE_REASONING_TYPES.has(value.type.toLowerCase());
120
+ }
121
+ function isPrivateProviderKey(key, value, parent) {
122
+ if (PRIVATE_PROVIDER_KEYS.has(key)) return true;
123
+ if (key !== "signature") return false;
124
+ const provider = typeof parent.provider === "string" ? parent.provider.toLowerCase() : "";
125
+ return "signature_encoding" in parent || SIGNATURE_PROVIDERS.has(provider) || typeof value === "string" && value.length >= OPAQUE_SIGNATURE_MIN_LENGTH;
126
+ }
127
+ function project(value) {
128
+ if (Array.isArray(value)) {
129
+ let changed2 = false;
130
+ const output2 = [];
131
+ for (const item of value) {
132
+ const projected = project(item);
133
+ if (projected === OMIT) {
134
+ changed2 = true;
135
+ continue;
136
+ }
137
+ if (projected !== item) changed2 = true;
138
+ output2.push(projected);
139
+ }
140
+ return changed2 ? output2 : value;
141
+ }
142
+ if (!isRecord2(value)) return value;
143
+ if (isPrivateReasoningBlock(value)) return OMIT;
144
+ let changed = false;
145
+ const output = {};
146
+ for (const [key, child] of Object.entries(value)) {
147
+ if (isPrivateProviderKey(key, child, value)) {
148
+ changed = true;
149
+ continue;
150
+ }
151
+ const projected = project(child);
152
+ if (projected === OMIT) {
153
+ changed = true;
154
+ continue;
155
+ }
156
+ if (projected !== child) changed = true;
157
+ output[key] = projected;
158
+ }
159
+ return changed ? output : value;
160
+ }
161
+ function projectAgentResultForDisplay(value) {
162
+ const projected = project(value);
163
+ return projected === OMIT ? null : projected;
164
+ }
165
+
166
+ export { normalizeMatrxStreamEnvelope, projectAgentResultForDisplay, readMatrxNdjsonStream };
167
+ //# sourceMappingURL=index.js.map
168
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../stream/ndjson.ts","../presentation/result.ts"],"names":["isRecord","changed","output"],"mappings":"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","file":"index.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","/**\n * Creator-facing projection of an agent execution result.\n *\n * Provider reasoning blocks and their signatures are replay material, not\n * workflow data. The execution engine must retain them so a later turn can be\n * continued correctly, but no result renderer, JSON tab, clipboard export, or\n * Content IR classifier should receive them as displayable values.\n *\n * This is a pure copy-on-write projection: values without private material\n * keep their original reference, while affected branches are cloned. Never\n * feed the projected value back into execution or persistence.\n */\n\nconst PRIVATE_REASONING_TYPES: ReadonlySet<string> = new Set([\n \"thinking\",\n \"redacted_thinking\",\n \"reasoning\",\n]);\n\nconst PRIVATE_PROVIDER_KEYS: ReadonlySet<string> = new Set([\n \"thought_signature\",\n \"thoughtSignature\",\n \"google_thought_signature\",\n \"anthropic_signature\",\n \"encrypted_content\",\n \"signature_encoding\",\n]);\n\nconst SIGNATURE_PROVIDERS: ReadonlySet<string> = new Set([\n \"anthropic\",\n \"google\",\n \"openai\",\n]);\n\nconst OPAQUE_SIGNATURE_MIN_LENGTH = 200;\nconst OMIT = Symbol(\"omit-provider-private-value\");\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isPrivateReasoningBlock(value: Record<string, unknown>): boolean {\n return (\n typeof value.type === \"string\" &&\n PRIVATE_REASONING_TYPES.has(value.type.toLowerCase())\n );\n}\n\nfunction isPrivateProviderKey(\n key: string,\n value: unknown,\n parent: Record<string, unknown>,\n): boolean {\n if (PRIVATE_PROVIDER_KEYS.has(key)) return true;\n if (key !== \"signature\") return false;\n\n const provider =\n typeof parent.provider === \"string\" ? parent.provider.toLowerCase() : \"\";\n return (\n \"signature_encoding\" in parent ||\n SIGNATURE_PROVIDERS.has(provider) ||\n (typeof value === \"string\" && value.length >= OPAQUE_SIGNATURE_MIN_LENGTH)\n );\n}\n\nfunction project(value: unknown): unknown | typeof OMIT {\n if (Array.isArray(value)) {\n let changed = false;\n const output: unknown[] = [];\n for (const item of value) {\n const projected = project(item);\n if (projected === OMIT) {\n changed = true;\n continue;\n }\n if (projected !== item) changed = true;\n output.push(projected);\n }\n return changed ? output : value;\n }\n\n if (!isRecord(value)) return value;\n if (isPrivateReasoningBlock(value)) return OMIT;\n\n let changed = false;\n const output: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n if (isPrivateProviderKey(key, child, value)) {\n changed = true;\n continue;\n }\n const projected = project(child);\n if (projected === OMIT) {\n changed = true;\n continue;\n }\n if (projected !== child) changed = true;\n output[key] = projected;\n }\n return changed ? output : value;\n}\n\n/**\n * Remove provider-private reasoning material from a value crossing a\n * Creator-facing presentation or export boundary.\n */\nexport function projectAgentResultForDisplay(value: unknown): unknown {\n const projected = project(value);\n return projected === OMIT ? null : projected;\n}\n"]}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Creator-facing projection of an agent execution result.
3
+ *
4
+ * Provider reasoning blocks and their signatures are replay material, not
5
+ * workflow data. The execution engine must retain them so a later turn can be
6
+ * continued correctly, but no result renderer, JSON tab, clipboard export, or
7
+ * Content IR classifier should receive them as displayable values.
8
+ *
9
+ * This is a pure copy-on-write projection: values without private material
10
+ * keep their original reference, while affected branches are cloned. Never
11
+ * feed the projected value back into execution or persistence.
12
+ */
13
+ /**
14
+ * Remove provider-private reasoning material from a value crossing a
15
+ * Creator-facing presentation or export boundary.
16
+ */
17
+ declare function projectAgentResultForDisplay(value: unknown): unknown;
18
+
19
+ export { projectAgentResultForDisplay };
@@ -0,0 +1,75 @@
1
+ // presentation/result.ts
2
+ var PRIVATE_REASONING_TYPES = /* @__PURE__ */ new Set([
3
+ "thinking",
4
+ "redacted_thinking",
5
+ "reasoning"
6
+ ]);
7
+ var PRIVATE_PROVIDER_KEYS = /* @__PURE__ */ new Set([
8
+ "thought_signature",
9
+ "thoughtSignature",
10
+ "google_thought_signature",
11
+ "anthropic_signature",
12
+ "encrypted_content",
13
+ "signature_encoding"
14
+ ]);
15
+ var SIGNATURE_PROVIDERS = /* @__PURE__ */ new Set([
16
+ "anthropic",
17
+ "google",
18
+ "openai"
19
+ ]);
20
+ var OPAQUE_SIGNATURE_MIN_LENGTH = 200;
21
+ var OMIT = /* @__PURE__ */ Symbol("omit-provider-private-value");
22
+ function isRecord(value) {
23
+ return typeof value === "object" && value !== null && !Array.isArray(value);
24
+ }
25
+ function isPrivateReasoningBlock(value) {
26
+ return typeof value.type === "string" && PRIVATE_REASONING_TYPES.has(value.type.toLowerCase());
27
+ }
28
+ function isPrivateProviderKey(key, value, parent) {
29
+ if (PRIVATE_PROVIDER_KEYS.has(key)) return true;
30
+ if (key !== "signature") return false;
31
+ const provider = typeof parent.provider === "string" ? parent.provider.toLowerCase() : "";
32
+ return "signature_encoding" in parent || SIGNATURE_PROVIDERS.has(provider) || typeof value === "string" && value.length >= OPAQUE_SIGNATURE_MIN_LENGTH;
33
+ }
34
+ function project(value) {
35
+ if (Array.isArray(value)) {
36
+ let changed2 = false;
37
+ const output2 = [];
38
+ for (const item of value) {
39
+ const projected = project(item);
40
+ if (projected === OMIT) {
41
+ changed2 = true;
42
+ continue;
43
+ }
44
+ if (projected !== item) changed2 = true;
45
+ output2.push(projected);
46
+ }
47
+ return changed2 ? output2 : value;
48
+ }
49
+ if (!isRecord(value)) return value;
50
+ if (isPrivateReasoningBlock(value)) return OMIT;
51
+ let changed = false;
52
+ const output = {};
53
+ for (const [key, child] of Object.entries(value)) {
54
+ if (isPrivateProviderKey(key, child, value)) {
55
+ changed = true;
56
+ continue;
57
+ }
58
+ const projected = project(child);
59
+ if (projected === OMIT) {
60
+ changed = true;
61
+ continue;
62
+ }
63
+ if (projected !== child) changed = true;
64
+ output[key] = projected;
65
+ }
66
+ return changed ? output : value;
67
+ }
68
+ function projectAgentResultForDisplay(value) {
69
+ const projected = project(value);
70
+ return projected === OMIT ? null : projected;
71
+ }
72
+
73
+ export { projectAgentResultForDisplay };
74
+ //# sourceMappingURL=result.js.map
75
+ //# sourceMappingURL=result.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../presentation/result.ts"],"names":["changed","output"],"mappings":"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","file":"result.js","sourcesContent":["/**\n * Creator-facing projection of an agent execution result.\n *\n * Provider reasoning blocks and their signatures are replay material, not\n * workflow data. The execution engine must retain them so a later turn can be\n * continued correctly, but no result renderer, JSON tab, clipboard export, or\n * Content IR classifier should receive them as displayable values.\n *\n * This is a pure copy-on-write projection: values without private material\n * keep their original reference, while affected branches are cloned. Never\n * feed the projected value back into execution or persistence.\n */\n\nconst PRIVATE_REASONING_TYPES: ReadonlySet<string> = new Set([\n \"thinking\",\n \"redacted_thinking\",\n \"reasoning\",\n]);\n\nconst PRIVATE_PROVIDER_KEYS: ReadonlySet<string> = new Set([\n \"thought_signature\",\n \"thoughtSignature\",\n \"google_thought_signature\",\n \"anthropic_signature\",\n \"encrypted_content\",\n \"signature_encoding\",\n]);\n\nconst SIGNATURE_PROVIDERS: ReadonlySet<string> = new Set([\n \"anthropic\",\n \"google\",\n \"openai\",\n]);\n\nconst OPAQUE_SIGNATURE_MIN_LENGTH = 200;\nconst OMIT = Symbol(\"omit-provider-private-value\");\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction isPrivateReasoningBlock(value: Record<string, unknown>): boolean {\n return (\n typeof value.type === \"string\" &&\n PRIVATE_REASONING_TYPES.has(value.type.toLowerCase())\n );\n}\n\nfunction isPrivateProviderKey(\n key: string,\n value: unknown,\n parent: Record<string, unknown>,\n): boolean {\n if (PRIVATE_PROVIDER_KEYS.has(key)) return true;\n if (key !== \"signature\") return false;\n\n const provider =\n typeof parent.provider === \"string\" ? parent.provider.toLowerCase() : \"\";\n return (\n \"signature_encoding\" in parent ||\n SIGNATURE_PROVIDERS.has(provider) ||\n (typeof value === \"string\" && value.length >= OPAQUE_SIGNATURE_MIN_LENGTH)\n );\n}\n\nfunction project(value: unknown): unknown | typeof OMIT {\n if (Array.isArray(value)) {\n let changed = false;\n const output: unknown[] = [];\n for (const item of value) {\n const projected = project(item);\n if (projected === OMIT) {\n changed = true;\n continue;\n }\n if (projected !== item) changed = true;\n output.push(projected);\n }\n return changed ? output : value;\n }\n\n if (!isRecord(value)) return value;\n if (isPrivateReasoningBlock(value)) return OMIT;\n\n let changed = false;\n const output: Record<string, unknown> = {};\n for (const [key, child] of Object.entries(value)) {\n if (isPrivateProviderKey(key, child, value)) {\n changed = true;\n continue;\n }\n const projected = project(child);\n if (projected === OMIT) {\n changed = true;\n continue;\n }\n if (projected !== child) changed = true;\n output[key] = projected;\n }\n return changed ? output : value;\n}\n\n/**\n * Remove provider-private reasoning material from a value crossing a\n * Creator-facing presentation or export boundary.\n */\nexport function projectAgentResultForDisplay(value: unknown): unknown {\n const projected = project(value);\n return projected === OMIT ? null : projected;\n}\n"]}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Canonical AI Matrx NDJSON wire kernel.
3
+ *
4
+ * This module is deliberately independent of React, Redux, Next.js, Supabase,
5
+ * and generated application types. Every Matrx client uses it to turn the
6
+ * backend's byte stream into the same normalized `{ event, data }` envelopes.
7
+ * Host runtimes remain responsible for HTTP/auth errors and for deciding what
8
+ * each event means in their state model.
9
+ */
10
+ interface MatrxStreamEnvelope<TData = unknown> {
11
+ event: string;
12
+ data: TData;
13
+ }
14
+ interface MatrxNdjsonIssue {
15
+ line: string;
16
+ error: unknown;
17
+ }
18
+ interface ReadMatrxNdjsonOptions {
19
+ signal?: AbortSignal;
20
+ /** Malformed JSON is non-fatal, but it must never disappear silently. */
21
+ onMalformedLine?: (issue: MatrxNdjsonIssue) => void;
22
+ /** Valid JSON with no recognized Matrx event envelope is also non-fatal. */
23
+ onUnknownEnvelope?: (value: unknown) => void;
24
+ }
25
+ /**
26
+ * Normalize both supported Matrx wire shapes:
27
+ *
28
+ * - full: `{ "event": "chunk", "data": { "text": "..." } }`
29
+ * - compact chunk: `{ "e": "c", "t": "..." }`
30
+ * - compact reasoning: `{ "e": "r", "t": "..." }`
31
+ */
32
+ declare function normalizeMatrxStreamEnvelope(value: unknown): MatrxStreamEnvelope | null;
33
+ /**
34
+ * Read and normalize a Matrx NDJSON response body without applying consumer
35
+ * backpressure to the network reader. The background read-ahead is important:
36
+ * large tool payloads must keep draining even while React or another host is
37
+ * processing the previous event.
38
+ */
39
+ declare function readMatrxNdjsonStream(body: ReadableStream<Uint8Array>, options?: ReadMatrxNdjsonOptions): AsyncGenerator<MatrxStreamEnvelope, void, undefined>;
40
+
41
+ export { type MatrxNdjsonIssue, type MatrxStreamEnvelope, type ReadMatrxNdjsonOptions, normalizeMatrxStreamEnvelope, readMatrxNdjsonStream };
@@ -0,0 +1,96 @@
1
+ // stream/ndjson.ts
2
+ function isRecord(value) {
3
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4
+ }
5
+ function normalizeMatrxStreamEnvelope(value) {
6
+ if (!isRecord(value)) return null;
7
+ if (typeof value.event === "string") {
8
+ return { event: value.event, data: value.data };
9
+ }
10
+ if (value.e === "c" && typeof value.t === "string") {
11
+ return { event: "chunk", data: { text: value.t } };
12
+ }
13
+ if (value.e === "r" && typeof value.t === "string") {
14
+ return { event: "reasoning_chunk", data: { text: value.t } };
15
+ }
16
+ return null;
17
+ }
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();
29
+ const decoder = new TextDecoder();
30
+ const parseLine = (line) => {
31
+ const trimmed = line.trim();
32
+ if (!trimmed) return;
33
+ let parsed;
34
+ try {
35
+ parsed = JSON.parse(trimmed);
36
+ } catch (error) {
37
+ options.onMalformedLine?.({ line: trimmed, error });
38
+ return;
39
+ }
40
+ const envelope = normalizeMatrxStreamEnvelope(parsed);
41
+ if (envelope) {
42
+ enqueue({ kind: "event", value: envelope });
43
+ } else {
44
+ options.onUnknownEnvelope?.(parsed);
45
+ }
46
+ };
47
+ const onAbort = () => {
48
+ void reader.cancel(options.signal?.reason).catch(() => void 0);
49
+ };
50
+ options.signal?.addEventListener("abort", onAbort, { once: true });
51
+ const readerPromise = (async () => {
52
+ let buffer = "";
53
+ try {
54
+ while (!options.signal?.aborted) {
55
+ const { value, done } = await reader.read();
56
+ 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);
61
+ }
62
+ buffer += decoder.decode();
63
+ if (!options.signal?.aborted && buffer.trim()) parseLine(buffer);
64
+ } catch (error) {
65
+ const aborted = options.signal?.aborted || error instanceof Error && error.name === "AbortError";
66
+ if (!aborted) enqueue({ kind: "error", error });
67
+ } finally {
68
+ readerFinished = true;
69
+ reader.releaseLock();
70
+ enqueue({ kind: "done" });
71
+ }
72
+ })();
73
+ try {
74
+ while (true) {
75
+ if (queue.length === 0) {
76
+ await new Promise((resolve) => {
77
+ wakeConsumer = resolve;
78
+ });
79
+ }
80
+ const item = queue.shift();
81
+ if (!item || item.kind === "done") return;
82
+ if (item.kind === "error") throw item.error;
83
+ yield item.value;
84
+ }
85
+ } finally {
86
+ options.signal?.removeEventListener("abort", onAbort);
87
+ if (!readerFinished) {
88
+ await reader.cancel().catch(() => void 0);
89
+ }
90
+ await readerPromise;
91
+ }
92
+ }
93
+
94
+ export { normalizeMatrxStreamEnvelope, readMatrxNdjsonStream };
95
+ //# sourceMappingURL=ndjson.js.map
96
+ //# sourceMappingURL=ndjson.js.map
@@ -0,0 +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"]}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "@ai-matrx/agents",
3
+ "version": "0.1.0",
4
+ "description": "Portable AI Matrx agent stream protocol and safe result-presentation primitives.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "keywords": [
8
+ "agents",
9
+ "ndjson",
10
+ "streaming",
11
+ "ai-matrx"
12
+ ],
13
+ "repository": {
14
+ "type": "git",
15
+ "url": "git+https://github.com/AI-Matrix-Engine/aidream.git",
16
+ "directory": "apps/shared/matrx-agents"
17
+ },
18
+ "homepage": "https://github.com/AI-Matrix-Engine/aidream/tree/main/apps/shared/matrx-agents#readme",
19
+ "bugs": {
20
+ "url": "https://github.com/AI-Matrix-Engine/aidream/issues"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "README.md",
25
+ "LICENSE",
26
+ "CHANGELOG.md"
27
+ ],
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js"
32
+ },
33
+ "./stream/ndjson": {
34
+ "types": "./dist/stream/ndjson.d.ts",
35
+ "import": "./dist/stream/ndjson.js"
36
+ },
37
+ "./presentation/result": {
38
+ "types": "./dist/presentation/result.d.ts",
39
+ "import": "./dist/presentation/result.js"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "devDependencies": {
44
+ "@arethetypeswrong/cli": "^0.18.5",
45
+ "@types/node": "^24.10.1",
46
+ "publint": "^0.3.24",
47
+ "tsup": "^8.5.1",
48
+ "typescript": "^5.9.3",
49
+ "vitest": "^4.1.6"
50
+ },
51
+ "publishConfig": {
52
+ "access": "public",
53
+ "provenance": true,
54
+ "registry": "https://registry.npmjs.org/"
55
+ },
56
+ "engines": {
57
+ "node": ">=20"
58
+ },
59
+ "sideEffects": false,
60
+ "scripts": {
61
+ "build": "tsup",
62
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
63
+ "check:package": "pnpm build && publint && pnpm verify:tarball",
64
+ "typecheck": "tsc --noEmit",
65
+ "test": "vitest run",
66
+ "verify:tarball": "node ./scripts/verify-tarball.mjs"
67
+ }
68
+ }