@animalabs/agent-framework 0.5.7 → 0.6.2

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.
Files changed (179) hide show
  1. package/dist/src/agent.d.ts +4 -0
  2. package/dist/src/agent.d.ts.map +1 -1
  3. package/dist/src/agent.js +15 -0
  4. package/dist/src/agent.js.map +1 -1
  5. package/dist/src/framework.d.ts +243 -0
  6. package/dist/src/framework.d.ts.map +1 -1
  7. package/dist/src/framework.js +1378 -114
  8. package/dist/src/framework.js.map +1 -1
  9. package/dist/src/gate/event-gate.d.ts +64 -2
  10. package/dist/src/gate/event-gate.d.ts.map +1 -1
  11. package/dist/src/gate/event-gate.js +212 -12
  12. package/dist/src/gate/event-gate.js.map +1 -1
  13. package/dist/src/gate/gate-script-worker.d.ts +2 -0
  14. package/dist/src/gate/gate-script-worker.d.ts.map +1 -0
  15. package/dist/src/gate/gate-script-worker.js +69 -0
  16. package/dist/src/gate/gate-script-worker.js.map +1 -0
  17. package/dist/src/gate/gate-script.d.ts +44 -0
  18. package/dist/src/gate/gate-script.d.ts.map +1 -0
  19. package/dist/src/gate/gate-script.js +164 -0
  20. package/dist/src/gate/gate-script.js.map +1 -0
  21. package/dist/src/gate/types.d.ts +18 -3
  22. package/dist/src/gate/types.d.ts.map +1 -1
  23. package/dist/src/index.d.ts +3 -0
  24. package/dist/src/index.d.ts.map +1 -1
  25. package/dist/src/index.js +4 -0
  26. package/dist/src/index.js.map +1 -1
  27. package/dist/src/mcpl/channel-registry.d.ts +60 -2
  28. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  29. package/dist/src/mcpl/channel-registry.js +114 -9
  30. package/dist/src/mcpl/channel-registry.js.map +1 -1
  31. package/dist/src/mcpl/checkpoint-manager.d.ts +7 -0
  32. package/dist/src/mcpl/checkpoint-manager.d.ts.map +1 -1
  33. package/dist/src/mcpl/checkpoint-manager.js +15 -0
  34. package/dist/src/mcpl/checkpoint-manager.js.map +1 -1
  35. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  36. package/dist/src/mcpl/push-handler.js +5 -0
  37. package/dist/src/mcpl/push-handler.js.map +1 -1
  38. package/dist/src/mcpl/server-connection.d.ts +64 -30
  39. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  40. package/dist/src/mcpl/server-connection.js +247 -210
  41. package/dist/src/mcpl/server-connection.js.map +1 -1
  42. package/dist/src/mcpl/transport.d.ts +98 -0
  43. package/dist/src/mcpl/transport.d.ts.map +1 -0
  44. package/dist/src/mcpl/transport.js +281 -0
  45. package/dist/src/mcpl/transport.js.map +1 -0
  46. package/dist/src/mcpl/types.d.ts +59 -3
  47. package/dist/src/mcpl/types.d.ts.map +1 -1
  48. package/dist/src/mcpl/types.js.map +1 -1
  49. package/dist/src/module-registry.d.ts +17 -1
  50. package/dist/src/module-registry.d.ts.map +1 -1
  51. package/dist/src/module-registry.js +101 -6
  52. package/dist/src/module-registry.js.map +1 -1
  53. package/dist/src/prose-segments.d.ts +18 -0
  54. package/dist/src/prose-segments.d.ts.map +1 -0
  55. package/dist/src/prose-segments.js +39 -0
  56. package/dist/src/prose-segments.js.map +1 -0
  57. package/dist/src/runtime/liveness-watchdog-worker.d.ts +2 -0
  58. package/dist/src/runtime/liveness-watchdog-worker.d.ts.map +1 -0
  59. package/dist/src/runtime/liveness-watchdog-worker.js +57 -0
  60. package/dist/src/runtime/liveness-watchdog-worker.js.map +1 -0
  61. package/dist/src/runtime/liveness-watchdog.d.ts +36 -0
  62. package/dist/src/runtime/liveness-watchdog.d.ts.map +1 -0
  63. package/dist/src/runtime/liveness-watchdog.js +106 -0
  64. package/dist/src/runtime/liveness-watchdog.js.map +1 -0
  65. package/dist/src/types/agent.d.ts +47 -0
  66. package/dist/src/types/agent.d.ts.map +1 -1
  67. package/dist/src/types/framework.d.ts +14 -0
  68. package/dist/src/types/framework.d.ts.map +1 -1
  69. package/dist/src/types/module.d.ts +58 -0
  70. package/dist/src/types/module.d.ts.map +1 -1
  71. package/dist/src/types/trace.d.ts +42 -0
  72. package/dist/src/types/trace.d.ts.map +1 -1
  73. package/dist/test/agent-cache-ttl.test.d.ts +2 -0
  74. package/dist/test/agent-cache-ttl.test.d.ts.map +1 -0
  75. package/dist/test/agent-cache-ttl.test.js +25 -0
  76. package/dist/test/agent-cache-ttl.test.js.map +1 -0
  77. package/dist/test/channel-registry-routing.test.js +108 -1
  78. package/dist/test/channel-registry-routing.test.js.map +1 -1
  79. package/dist/test/checkpoint-attribution.test.d.ts +2 -0
  80. package/dist/test/checkpoint-attribution.test.d.ts.map +1 -0
  81. package/dist/test/checkpoint-attribution.test.js +40 -0
  82. package/dist/test/checkpoint-attribution.test.js.map +1 -0
  83. package/dist/test/conversation-fork-injection-scoping.test.d.ts +2 -0
  84. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +1 -0
  85. package/dist/test/conversation-fork-injection-scoping.test.js +184 -0
  86. package/dist/test/conversation-fork-injection-scoping.test.js.map +1 -0
  87. package/dist/test/event-gate-policy-mutation.test.d.ts +2 -0
  88. package/dist/test/event-gate-policy-mutation.test.d.ts.map +1 -0
  89. package/dist/test/event-gate-policy-mutation.test.js +137 -0
  90. package/dist/test/event-gate-policy-mutation.test.js.map +1 -0
  91. package/dist/test/event-gate-script.test.d.ts +2 -0
  92. package/dist/test/event-gate-script.test.d.ts.map +1 -0
  93. package/dist/test/event-gate-script.test.js +95 -0
  94. package/dist/test/event-gate-script.test.js.map +1 -0
  95. package/dist/test/event-gate-tags.test.d.ts +2 -0
  96. package/dist/test/event-gate-tags.test.d.ts.map +1 -0
  97. package/dist/test/event-gate-tags.test.js +76 -0
  98. package/dist/test/event-gate-tags.test.js.map +1 -0
  99. package/dist/test/gather-context-timeout.test.d.ts +2 -0
  100. package/dist/test/gather-context-timeout.test.d.ts.map +1 -0
  101. package/dist/test/gather-context-timeout.test.js +120 -0
  102. package/dist/test/gather-context-timeout.test.js.map +1 -0
  103. package/dist/test/inference-exhaustion-rewind.test.d.ts +2 -0
  104. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +1 -0
  105. package/dist/test/inference-exhaustion-rewind.test.js +181 -0
  106. package/dist/test/inference-exhaustion-rewind.test.js.map +1 -0
  107. package/dist/test/inference-failure-observability.test.js +4 -0
  108. package/dist/test/inference-failure-observability.test.js.map +1 -1
  109. package/dist/test/liveness-watchdog.test.d.ts +2 -0
  110. package/dist/test/liveness-watchdog.test.d.ts.map +1 -0
  111. package/dist/test/liveness-watchdog.test.js +78 -0
  112. package/dist/test/liveness-watchdog.test.js.map +1 -0
  113. package/dist/test/mcpl-reconnect-events.test.d.ts +2 -0
  114. package/dist/test/mcpl-reconnect-events.test.d.ts.map +1 -0
  115. package/dist/test/mcpl-reconnect-events.test.js +119 -0
  116. package/dist/test/mcpl-reconnect-events.test.js.map +1 -0
  117. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +2 -0
  118. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +1 -0
  119. package/dist/test/mcpl-reconnect-reregistration.test.js +181 -0
  120. package/dist/test/mcpl-reconnect-reregistration.test.js.map +1 -0
  121. package/dist/test/mcpl-request-timeout.test.d.ts +2 -0
  122. package/dist/test/mcpl-request-timeout.test.d.ts.map +1 -0
  123. package/dist/test/mcpl-request-timeout.test.js +123 -0
  124. package/dist/test/mcpl-request-timeout.test.js.map +1 -0
  125. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +7 -0
  126. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +1 -0
  127. package/dist/test/mcpl-runtime-lifecycle.test.js +142 -0
  128. package/dist/test/mcpl-runtime-lifecycle.test.js.map +1 -0
  129. package/dist/test/mcpl-ws-transport.test.d.ts +2 -0
  130. package/dist/test/mcpl-ws-transport.test.d.ts.map +1 -0
  131. package/dist/test/mcpl-ws-transport.test.js +155 -0
  132. package/dist/test/mcpl-ws-transport.test.js.map +1 -0
  133. package/dist/test/prose-segments.test.d.ts +2 -0
  134. package/dist/test/prose-segments.test.d.ts.map +1 -0
  135. package/dist/test/prose-segments.test.js +52 -0
  136. package/dist/test/prose-segments.test.js.map +1 -0
  137. package/dist/test/refusal-rewind.test.d.ts +2 -0
  138. package/dist/test/refusal-rewind.test.d.ts.map +1 -0
  139. package/dist/test/refusal-rewind.test.js +108 -0
  140. package/dist/test/refusal-rewind.test.js.map +1 -0
  141. package/dist/test/state-scaling-e2e.test.d.ts +22 -0
  142. package/dist/test/state-scaling-e2e.test.d.ts.map +1 -0
  143. package/dist/test/state-scaling-e2e.test.js +200 -0
  144. package/dist/test/state-scaling-e2e.test.js.map +1 -0
  145. package/dist/test/state-scaling.test.d.ts +12 -0
  146. package/dist/test/state-scaling.test.d.ts.map +1 -0
  147. package/dist/test/state-scaling.test.js +243 -0
  148. package/dist/test/state-scaling.test.js.map +1 -0
  149. package/dist/test/tool-result-content.test.d.ts +2 -0
  150. package/dist/test/tool-result-content.test.d.ts.map +1 -0
  151. package/dist/test/tool-result-content.test.js +37 -0
  152. package/dist/test/tool-result-content.test.js.map +1 -0
  153. package/dist/test/trunk-channel-routing.test.d.ts +19 -0
  154. package/dist/test/trunk-channel-routing.test.d.ts.map +1 -0
  155. package/dist/test/trunk-channel-routing.test.js +175 -0
  156. package/dist/test/trunk-channel-routing.test.js.map +1 -0
  157. package/dist/tsconfig.tsbuildinfo +1 -1
  158. package/package.json +4 -3
  159. package/src/agent.ts +16 -0
  160. package/src/framework.ts +1576 -121
  161. package/src/gate/event-gate.ts +209 -12
  162. package/src/gate/gate-script-worker.ts +73 -0
  163. package/src/gate/gate-script.ts +180 -0
  164. package/src/gate/types.ts +19 -3
  165. package/src/index.ts +10 -0
  166. package/src/mcpl/channel-registry.ts +143 -8
  167. package/src/mcpl/checkpoint-manager.ts +16 -0
  168. package/src/mcpl/push-handler.ts +5 -0
  169. package/src/mcpl/server-connection.ts +262 -227
  170. package/src/mcpl/transport.ts +307 -0
  171. package/src/mcpl/types.ts +68 -3
  172. package/src/module-registry.ts +126 -6
  173. package/src/prose-segments.ts +42 -0
  174. package/src/runtime/liveness-watchdog-worker.ts +66 -0
  175. package/src/runtime/liveness-watchdog.ts +122 -0
  176. package/src/types/agent.ts +48 -0
  177. package/src/types/framework.ts +15 -0
  178. package/src/types/module.ts +65 -0
  179. package/src/types/trace.ts +51 -0
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Regression gates for the set-rewrite quadratic-states fixes (2026-07-08
3
+ * scaling campaign, Finding 2): persisted record size must be independent of
4
+ * accumulated content.
5
+ *
6
+ * Families covered:
7
+ * - framework/inference-log — appended, not Set-rewritten
8
+ * - framework/turn-checkpoints/* — per-agent slots, not one global map
9
+ * - modules/<name>/<log> — ModuleContext log-state API
10
+ */
11
+ import { describe, it, beforeEach, afterEach } from 'node:test';
12
+ import assert from 'node:assert';
13
+ import { tmpdir } from 'node:os';
14
+ import { mkdtempSync, rmSync } from 'node:fs';
15
+ import { join } from 'node:path';
16
+ import { JsStore } from '@animalabs/chronicle';
17
+ import { AgentFramework } from '../src/index.js';
18
+ import { MockMembrane } from './helpers/mock-membrane.js';
19
+ const INFERENCE_LOG_ID = 'framework/inference-log';
20
+ const TURN_CHECKPOINTS_ID = 'framework/turn-checkpoints';
21
+ const TURN_CHECKPOINTS_TREE_ID = 'framework/turn-checkpoints/tree';
22
+ /**
23
+ * Payload sizes of all state_update records for states matching `match`,
24
+ * in append order.
25
+ */
26
+ function stateUpdateSizes(store, match) {
27
+ const sizes = [];
28
+ for (const id of store.getRecordIdsByType('state_update')) {
29
+ const record = store.getRecord(id);
30
+ if (!record)
31
+ continue;
32
+ const update = JSON.parse(record.payload.toString());
33
+ if (match(update.state_id))
34
+ sizes.push(record.payload.length);
35
+ }
36
+ return sizes;
37
+ }
38
+ /** Assert the record family isn't growing: last record ≈ first record. */
39
+ function assertFlat(sizes, label, tolerance = 1.5) {
40
+ assert.ok(sizes.length >= 2, `${label}: expected ≥2 records, got ${sizes.length}`);
41
+ const first = sizes[0];
42
+ const last = sizes[sizes.length - 1];
43
+ assert.ok(last <= first * tolerance, `${label}: record size grew ${first} → ${last} bytes over ${sizes.length} records — ` +
44
+ `looks like accumulated content is being rewritten per update`);
45
+ }
46
+ describe('state scaling regression gates', () => {
47
+ let tempDir;
48
+ let membrane;
49
+ beforeEach(() => {
50
+ tempDir = mkdtempSync(join(tmpdir(), 'af-state-scaling-'));
51
+ membrane = new MockMembrane();
52
+ });
53
+ afterEach(() => {
54
+ rmSync(tempDir, { recursive: true, force: true });
55
+ });
56
+ async function createFramework(storePath) {
57
+ return AgentFramework.create({
58
+ storePath,
59
+ membrane: membrane.asMembrane(),
60
+ agents: [{ name: 'assistant', model: 'test-model', systemPrompt: 'test' }],
61
+ modules: [],
62
+ });
63
+ }
64
+ it('inference log: Nth record size is independent of N', async () => {
65
+ const storePath = join(tempDir, 'inference.chronicle');
66
+ const framework = await createFramework(storePath);
67
+ const store = framework.getStore();
68
+ const N = 30;
69
+ for (let i = 0; i < N; i++) {
70
+ framework.logInference({
71
+ timestamp: Date.now(),
72
+ agentName: 'assistant',
73
+ requestId: `req-${i}`,
74
+ success: true,
75
+ durationMs: 100,
76
+ request: { i },
77
+ response: { ok: true },
78
+ });
79
+ }
80
+ const entries = store.getStateJson(INFERENCE_LOG_ID);
81
+ assert.strictEqual(entries.length, N, 'all entries readable back');
82
+ const sizes = stateUpdateSizes(store, (id) => id === INFERENCE_LOG_ID);
83
+ assertFlat(sizes, INFERENCE_LOG_ID);
84
+ await framework.stop();
85
+ });
86
+ it('inference log: appends compose with a legacy Set-written array', async () => {
87
+ const storePath = join(tempDir, 'legacy-log.chronicle');
88
+ // Write the state the old way: whole-array Set, as pre-fix stores did.
89
+ {
90
+ const store = JsStore.openOrCreate({ path: storePath });
91
+ store.registerState({
92
+ id: INFERENCE_LOG_ID,
93
+ strategy: 'append_log',
94
+ deltaSnapshotEvery: 100,
95
+ fullSnapshotEvery: 20,
96
+ });
97
+ store.setStateJson(INFERENCE_LOG_ID, [
98
+ { timestamp: 1, agentName: 'old', requestId: 'legacy-0', success: true },
99
+ { timestamp: 2, agentName: 'old', requestId: 'legacy-1', success: false },
100
+ ]);
101
+ store.close();
102
+ }
103
+ const framework = await createFramework(storePath);
104
+ framework.logInference({
105
+ timestamp: 3,
106
+ agentName: 'assistant',
107
+ requestId: 'new-0',
108
+ success: true,
109
+ durationMs: 5,
110
+ });
111
+ const entries = framework.getStore().getStateJson(INFERENCE_LOG_ID);
112
+ assert.strictEqual(entries.length, 3);
113
+ assert.strictEqual(entries[0].requestId, 'legacy-0');
114
+ assert.strictEqual(entries[2].requestId, 'new-0');
115
+ await framework.stop();
116
+ });
117
+ it('turn checkpoints: record size and state count independent of agents-ever-spawned', async () => {
118
+ const storePath = join(tempDir, 'checkpoints.chronicle');
119
+ const framework = await createFramework(storePath);
120
+ const store = framework.getStore();
121
+ // M spawn-and-dispose subagents, several turns each.
122
+ const M = 25;
123
+ for (let m = 0; m < M; m++) {
124
+ const name = `spawn-task-d1-${1000 + m}`;
125
+ for (let turn = 0; turn < 3; turn++) {
126
+ framework.recordTurnCheckpoint(name);
127
+ }
128
+ framework.evictTurnCheckpoints(name);
129
+ }
130
+ // A persistent agent keeps taking turns throughout.
131
+ for (let turn = 0; turn < 5; turn++) {
132
+ framework.recordTurnCheckpoint('assistant');
133
+ }
134
+ // Every write is one tree op (path + blob hash): flat across the whole
135
+ // run even though M unique agents came and went.
136
+ const sizes = stateUpdateSizes(store, (id) => id === TURN_CHECKPOINTS_TREE_ID);
137
+ assertFlat(sizes, TURN_CHECKPOINTS_TREE_ID, 4);
138
+ // Disposal removed the key outright — the tree holds only live agents...
139
+ for (let m = 0; m < M; m++) {
140
+ assert.strictEqual(store.treeGet(TURN_CHECKPOINTS_TREE_ID, `spawn-task-d1-${1000 + m}`), null, 'disposed agent key removed from checkpoint tree');
141
+ }
142
+ assert.strictEqual(framework.getTurnCheckpoints('assistant').length, 5);
143
+ // ...and no per-agent state registration leaked into the state index —
144
+ // chronicle has no deregistration and rewrites + fsyncs the index on
145
+ // every sync tick, so index entries must not scale with spawns-ever.
146
+ const checkpointStates = store.listStates().filter((s) => s.id.startsWith(TURN_CHECKPOINTS_ID));
147
+ assert.strictEqual(checkpointStates.length, 1, 'exactly one checkpoint state registered');
148
+ await framework.stop();
149
+ });
150
+ it('turn checkpoints: legacy single-map stores are readable, migrate on save, and evict without ghosts', async () => {
151
+ const storePath = join(tempDir, 'legacy-checkpoints.chronicle');
152
+ {
153
+ const store = JsStore.openOrCreate({ path: storePath });
154
+ store.registerState({ id: TURN_CHECKPOINTS_ID, strategy: 'snapshot' });
155
+ store.setStateJson(TURN_CHECKPOINTS_ID, {
156
+ assistant: [
157
+ { agentName: 'assistant', turnIndex: 0, sequenceBefore: 1, branchName: 'main', timestamp: 1 },
158
+ ],
159
+ 'spawn-ghost-d1-1234': [
160
+ { agentName: 'spawn-ghost-d1-1234', turnIndex: 3, sequenceBefore: 9, branchName: 'main', timestamp: 2 },
161
+ ],
162
+ });
163
+ store.close();
164
+ }
165
+ const framework = await createFramework(storePath);
166
+ const store = framework.getStore();
167
+ // Legacy entry visible through the fallback read...
168
+ const before = framework.getTurnCheckpoints('assistant');
169
+ assert.strictEqual(before.length, 1);
170
+ assert.strictEqual(before[0].turnIndex, 0);
171
+ // ...and the first new turn migrates the list into the tree.
172
+ framework.recordTurnCheckpoint('assistant');
173
+ const entry = store.treeGet(TURN_CHECKPOINTS_TREE_ID, 'assistant');
174
+ assert.ok(entry, 'tree entry created on first save');
175
+ const migrated = framework.getTurnCheckpoints('assistant');
176
+ assert.strictEqual(migrated.length, 2);
177
+ assert.strictEqual(migrated[0].turnIndex, 0);
178
+ // Evicting an agent whose checkpoints live only in the legacy map writes
179
+ // an empty tombstone — a later agent reusing the name must NOT inherit
180
+ // the dead agent's checkpoints through the fallback.
181
+ framework.evictTurnCheckpoints('spawn-ghost-d1-1234');
182
+ assert.deepStrictEqual(framework.getTurnCheckpoints('spawn-ghost-d1-1234'), []);
183
+ // Idempotent: a second evict doesn't rewrite the tombstone (blob "[]" is
184
+ // content-addressed, but the tree op record would still be new).
185
+ const recordsBefore = store.getRecordIdsByType('state_update').length;
186
+ framework.evictTurnCheckpoints('spawn-ghost-d1-1234');
187
+ assert.strictEqual(store.getRecordIdsByType('state_update').length, recordsBefore);
188
+ await framework.stop();
189
+ });
190
+ it('module log states: append/edit records are O(item), state is reconstructable', async () => {
191
+ const storePath = join(tempDir, 'module-log.chronicle');
192
+ let capturedCtx = null;
193
+ const logModule = {
194
+ name: 'logtest',
195
+ async start(ctx) {
196
+ capturedCtx = ctx;
197
+ ctx.registerLogState('log');
198
+ },
199
+ async stop() { },
200
+ getTools() { return []; },
201
+ async handleToolCall(_call) {
202
+ return { success: true };
203
+ },
204
+ async onProcess(_event, _state) {
205
+ return {};
206
+ },
207
+ };
208
+ const framework = await AgentFramework.create({
209
+ storePath,
210
+ membrane: membrane.asMembrane(),
211
+ agents: [{ name: 'assistant', model: 'test-model', systemPrompt: 'test' }],
212
+ modules: [logModule],
213
+ });
214
+ const ctx = capturedCtx;
215
+ const store = framework.getStore();
216
+ const N = 30;
217
+ for (let i = 0; i < N; i++) {
218
+ ctx.appendToLog('log', { id: `item-${i}`, content: 'x'.repeat(50) });
219
+ }
220
+ assert.strictEqual(ctx.getLogLength('log'), N);
221
+ // Point-edit keeps the record O(item), not O(log).
222
+ ctx.editLogItem('log', 3, { id: 'item-3', content: 'edited' });
223
+ const items = ctx.getLog('log');
224
+ assert.strictEqual(items.length, N);
225
+ assert.strictEqual(items[3].content, 'edited');
226
+ assert.strictEqual(items[4].id, 'item-4');
227
+ const sizes = stateUpdateSizes(store, (id) => id === 'modules/logtest/log');
228
+ assertFlat(sizes, 'modules/logtest/log');
229
+ // Idempotent re-registration must not throw (restart path).
230
+ ctx.registerLogState('log');
231
+ // Reserved / invalid names are rejected.
232
+ assert.throws(() => ctx.registerLogState('state'));
233
+ assert.throws(() => ctx.appendToLog('nested/name', {}));
234
+ // Writes to a never-registered name fail immediately — chronicle would
235
+ // accept the append but never snapshot the state, turning a typo into a
236
+ // silent full-chain-replay-on-restore trap.
237
+ assert.throws(() => ctx.appendToLog('lgo', { oops: true }), /not registered/);
238
+ assert.throws(() => ctx.editLogItem('lgo', 0, {}), /not registered/);
239
+ assert.strictEqual(ctx.getLogLength('log'), N, 'registered log still intact');
240
+ await framework.stop();
241
+ });
242
+ });
243
+ //# sourceMappingURL=state-scaling.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-scaling.test.js","sourceRoot":"","sources":["../../test/state-scaling.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=tool-result-content.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-content.test.d.ts","sourceRoot":"","sources":["../../test/tool-result-content.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * toMembraneToolResult (6.6): JSON.stringify(undefined) returns the VALUE
3
+ * undefined, not a string — a tool returning `{ success: true }` with no data
4
+ * plus a configured maxChars cap used to throw a TypeError on content.length
5
+ * mid-turn. It must degrade to a safe empty string instead.
6
+ */
7
+ import { test } from 'node:test';
8
+ import assert from 'node:assert/strict';
9
+ import { AgentFramework } from '../src/framework.js';
10
+ function makeFw() {
11
+ return Object.create(AgentFramework.prototype);
12
+ }
13
+ test('undefined data + maxChars cap: no throw, content is a safe string', () => {
14
+ const fw = makeFw();
15
+ const result = fw.toMembraneToolResult('call-1', { success: true }, 1000);
16
+ assert.equal(result.toolUseId, 'call-1');
17
+ assert.equal(result.isError, false);
18
+ assert.equal(result.content, '');
19
+ });
20
+ test('undefined data without a cap also yields a string (never the value undefined)', () => {
21
+ const fw = makeFw();
22
+ const result = fw.toMembraneToolResult('call-2', { success: true, data: undefined });
23
+ assert.equal(typeof result.content, 'string');
24
+ });
25
+ test('normal data is still stringified and truncated by the cap', () => {
26
+ const fw = makeFw();
27
+ const result = fw.toMembraneToolResult('call-3', { success: true, data: { v: 'y'.repeat(500) } }, 100);
28
+ assert.equal(typeof result.content, 'string');
29
+ assert.match(result.content, /\[truncated — original was \d+ chars\]/);
30
+ });
31
+ test('error results pass through unchanged', () => {
32
+ const fw = makeFw();
33
+ const result = fw.toMembraneToolResult('call-4', { success: false, error: 'boom', isError: true }, 100);
34
+ assert.equal(result.isError, true);
35
+ assert.equal(result.content, 'boom');
36
+ });
37
+ //# sourceMappingURL=tool-result-content.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-result-content.test.js","sourceRoot":"","sources":["../../test/tool-result-content.test.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,SAAS,MAAM;IACb,OAAO,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,SAAS,CAAQ,CAAC;AACxD,CAAC;AAED,IAAI,CAAC,mEAAmE,EAAE,GAAG,EAAE;IAC7E,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC;IAC1E,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,EAAE,QAAQ,CAAC,CAAC;IACzC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACpC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AACnC,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,+EAA+E,EAAE,GAAG,EAAE;IACzF,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;IACrF,MAAM,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACrE,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC;IACvG,MAAM,CAAC,KAAK,CAAC,OAAO,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC9C,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,wCAAwC,CAAC,CAAC;AACzE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,sCAAsC,EAAE,GAAG,EAAE;IAChD,MAAM,EAAE,GAAG,MAAM,EAAE,CAAC;IACpB,MAAM,MAAM,GAAG,EAAE,CAAC,oBAAoB,CAAC,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IACxG,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AACvC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Item-3 redux: single-TRUNK output routing.
3
+ *
4
+ * These tests cover the FRAMEWORK-side plumbing that feeds the ChannelRegistry's
5
+ * `activeChannelResolver` (the routing DECISION itself is covered in
6
+ * channel-registry-routing.test.ts):
7
+ * - derivePushEventChannel() reconstructs the MCPL composite channel for a
8
+ * push event (Discord DMs arrive this way), preferring an explicit
9
+ * origin.mcplChannelId.
10
+ * - a channel-incoming turn records its triggering channel per-agent.
11
+ * - a DM push-event turn records the reconstructed DM channel per-agent.
12
+ * - a batched wake picks the MOST-RECENT triggering channel.
13
+ *
14
+ * connectome-host runs every agent as a single trunk (it never sets
15
+ * `conversations`), so no fork/home exists — the active triggering channel is
16
+ * the only thing that keeps a reply in the channel it is answering.
17
+ */
18
+ export {};
19
+ //# sourceMappingURL=trunk-channel-routing.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trunk-channel-routing.test.d.ts","sourceRoot":"","sources":["../../test/trunk-channel-routing.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG"}
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Item-3 redux: single-TRUNK output routing.
3
+ *
4
+ * These tests cover the FRAMEWORK-side plumbing that feeds the ChannelRegistry's
5
+ * `activeChannelResolver` (the routing DECISION itself is covered in
6
+ * channel-registry-routing.test.ts):
7
+ * - derivePushEventChannel() reconstructs the MCPL composite channel for a
8
+ * push event (Discord DMs arrive this way), preferring an explicit
9
+ * origin.mcplChannelId.
10
+ * - a channel-incoming turn records its triggering channel per-agent.
11
+ * - a DM push-event turn records the reconstructed DM channel per-agent.
12
+ * - a batched wake picks the MOST-RECENT triggering channel.
13
+ *
14
+ * connectome-host runs every agent as a single trunk (it never sets
15
+ * `conversations`), so no fork/home exists — the active triggering channel is
16
+ * the only thing that keeps a reply in the channel it is answering.
17
+ */
18
+ import { describe, it, beforeEach, afterEach } from 'node:test';
19
+ import assert from 'node:assert/strict';
20
+ import { tmpdir } from 'node:os';
21
+ import { mkdtempSync, rmSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ import { AgentFramework } from '../src/index.js';
24
+ import { MockMembrane, createMockResponse } from './helpers/mock-membrane.js';
25
+ /** Reach the private per-turn triggering-channel map + the pure channel-deriver. */
26
+ function internals(framework) {
27
+ return framework;
28
+ }
29
+ function channelIncoming(channelId, text) {
30
+ return {
31
+ type: 'mcpl:channel-incoming',
32
+ serverId: 'discord',
33
+ channelId,
34
+ messageId: `m-${Math.random().toString(36).slice(2)}`,
35
+ author: { id: 'U1', name: 'antra' },
36
+ content: [{ type: 'text', text }],
37
+ timestamp: new Date().toISOString(),
38
+ metadata: {},
39
+ triggerInference: true,
40
+ };
41
+ }
42
+ /** A Discord DM as discord-mcpl forwards it: a push/event whose origin carries
43
+ * the raw channel (guildId null) — no channels/incoming, no open channel. */
44
+ function dmPushEvent(rawChannelId, text) {
45
+ return {
46
+ type: 'mcpl:push-event',
47
+ serverId: 'discord',
48
+ featureSet: 'discord.messaging',
49
+ eventId: `discord_msg_${Math.random().toString(36).slice(2)}`,
50
+ content: [{ type: 'text', text }],
51
+ origin: {
52
+ source: 'discord',
53
+ channelId: rawChannelId,
54
+ guildId: null,
55
+ channelName: undefined,
56
+ isDM: true,
57
+ },
58
+ timestamp: new Date().toISOString(),
59
+ inferenceId: `inf-${Math.random().toString(36).slice(2)}`,
60
+ triggerInference: true,
61
+ };
62
+ }
63
+ describe('Trunk channel routing (item-3 redux)', () => {
64
+ let tempDir;
65
+ let membrane;
66
+ beforeEach(() => {
67
+ tempDir = mkdtempSync(join(tmpdir(), 'trunk-routing-test-'));
68
+ membrane = new MockMembrane();
69
+ });
70
+ afterEach(() => {
71
+ rmSync(tempDir, { recursive: true, force: true });
72
+ });
73
+ async function makeFramework() {
74
+ // NO `conversations` — this is connectome-host's single-trunk mode.
75
+ return AgentFramework.create({
76
+ storePath: join(tempDir, 'test.chronicle'),
77
+ membrane: membrane.asMembrane(),
78
+ agents: [{ name: 'scout', model: 'test-model', systemPrompt: 'You are scout.' }],
79
+ modules: [],
80
+ });
81
+ }
82
+ it('derivePushEventChannel prefers an explicit origin.mcplChannelId', async () => {
83
+ const framework = await makeFramework();
84
+ const got = internals(framework).derivePushEventChannel({
85
+ source: 'discord',
86
+ mcplChannelId: 'discord:dm:999',
87
+ channelName: 'DM with Antra',
88
+ channelId: '999',
89
+ });
90
+ assert.deepEqual(got, { channelId: 'discord:dm:999', label: 'DM with Antra' });
91
+ await framework.stop();
92
+ });
93
+ it('derivePushEventChannel reconstructs a Discord DM composite (guildId null -> dm)', async () => {
94
+ const framework = await makeFramework();
95
+ const got = internals(framework).derivePushEventChannel({
96
+ source: 'discord',
97
+ channelId: '42',
98
+ guildId: null,
99
+ isDM: true,
100
+ });
101
+ assert.deepEqual(got, { channelId: 'discord:dm:42', label: undefined });
102
+ await framework.stop();
103
+ });
104
+ it('derivePushEventChannel reconstructs a non-open guild channel composite', async () => {
105
+ const framework = await makeFramework();
106
+ const got = internals(framework).derivePushEventChannel({
107
+ source: 'discord',
108
+ channelId: 'C7',
109
+ guildId: 'G1',
110
+ });
111
+ assert.deepEqual(got, { channelId: 'discord:G1:C7', label: undefined });
112
+ await framework.stop();
113
+ });
114
+ it('derivePushEventChannel returns undefined for a channel-less push (heartbeat)', async () => {
115
+ const framework = await makeFramework();
116
+ const i = internals(framework);
117
+ assert.equal(i.derivePushEventChannel(undefined), undefined);
118
+ assert.equal(i.derivePushEventChannel({ source: 'heartbeat', kind: 'tick' }), undefined);
119
+ await framework.stop();
120
+ });
121
+ it('a channel-incoming trunk turn records its triggering channel', async () => {
122
+ membrane.pushResponse(createMockResponse([{ type: 'text', text: 'the date is ...' }]));
123
+ const framework = await makeFramework();
124
+ framework.pushEvent(channelIncoming('discord:guild:chanA', 'A: sleep && date'));
125
+ await framework.runUntilIdle();
126
+ assert.equal(membrane.calls.length, 1, 'the trunk should have run one turn');
127
+ assert.equal(internals(framework).activeTriggerChannels.get('scout'), 'discord:guild:chanA', 'the turn must be routed to the channel that triggered it');
128
+ await framework.stop();
129
+ });
130
+ it('a DM push-event turn records the reconstructed DM channel (item-3 redux DM sub-case)', async () => {
131
+ membrane.pushResponse(createMockResponse([{ type: 'text', text: 'hi in the DM' }]));
132
+ const framework = await makeFramework();
133
+ framework.pushEvent(dmPushEvent('42', 'hey scout, ping'));
134
+ await framework.runUntilIdle();
135
+ assert.equal(membrane.calls.length, 1, 'the trunk should wake for the DM');
136
+ assert.equal(internals(framework).activeTriggerChannels.get('scout'), 'discord:dm:42', 'the DM reply must route to the DM channel, not the global locus');
137
+ await framework.stop();
138
+ });
139
+ it('the triggering channel tracks the CURRENT turn, never a stale one', async () => {
140
+ const framework = await makeFramework();
141
+ const i = internals(framework);
142
+ // A channel-A turn sets the active channel... (push the response right before
143
+ // each turn: MockMembrane's stream consumes ALL queued responses at once.)
144
+ membrane.pushResponse(createMockResponse([{ type: 'text', text: 'ans A' }]));
145
+ framework.pushEvent(channelIncoming('discord:guild:chanA', 'A: hi'));
146
+ await framework.runUntilIdle();
147
+ assert.equal(i.activeTriggerChannels.get('scout'), 'discord:guild:chanA');
148
+ // ...then a DM turn OVERWRITES it — the next turn's reply must never inherit
149
+ // the previous turn's channel (the concurrency hazard this fix removes).
150
+ membrane.pushResponse(createMockResponse([{ type: 'text', text: 'ans DM' }]));
151
+ framework.pushEvent(dmPushEvent('42', 'now in a DM'));
152
+ await framework.runUntilIdle();
153
+ assert.equal(membrane.calls.length, 2, 'both turns should have run');
154
+ assert.equal(i.activeTriggerChannels.get('scout'), 'discord:dm:42', 'the map must reflect the CURRENT turn’s channel, not chanA');
155
+ await framework.stop();
156
+ });
157
+ it('startAgentStream clears the triggering channel for a no-channel (heartbeat) turn', async () => {
158
+ membrane.pushResponse(createMockResponse([{ type: 'text', text: 'tick' }]));
159
+ const framework = await makeFramework();
160
+ const i = internals(framework);
161
+ // Simulate a stale channel left by a prior turn, then run a heartbeat/timer
162
+ // turn (an InferenceRequest with no channelId). startAgentStream must clear
163
+ // the entry up front so routeSpeech falls back to the global locus rather
164
+ // than replaying the stale channel.
165
+ i.activeTriggerChannels.set('scout', 'discord:guild:stale');
166
+ const scout = framework.getAgent('scout');
167
+ await framework.startAgentStream(scout, {
168
+ agentName: 'scout', reason: 'heartbeat', source: 'timer', timestamp: Date.now(),
169
+ });
170
+ await framework.runUntilIdle();
171
+ assert.equal(i.activeTriggerChannels.has('scout'), false, 'a no-trigger turn must clear any stale triggering channel');
172
+ await framework.stop();
173
+ });
174
+ });
175
+ //# sourceMappingURL=trunk-channel-routing.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trunk-channel-routing.test.js","sourceRoot":"","sources":["../../test/trunk-channel-routing.test.ts"],"names":[],"mappings":"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"}