@animalabs/agent-framework 0.6.0 → 0.6.3

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 (115) 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 +235 -2
  6. package/dist/src/framework.d.ts.map +1 -1
  7. package/dist/src/framework.js +1141 -92
  8. package/dist/src/framework.js.map +1 -1
  9. package/dist/src/gate/event-gate.d.ts +20 -1
  10. package/dist/src/gate/event-gate.d.ts.map +1 -1
  11. package/dist/src/gate/event-gate.js +60 -4
  12. package/dist/src/gate/event-gate.js.map +1 -1
  13. package/dist/src/index.d.ts +3 -0
  14. package/dist/src/index.d.ts.map +1 -1
  15. package/dist/src/index.js +4 -0
  16. package/dist/src/index.js.map +1 -1
  17. package/dist/src/mcpl/channel-registry.d.ts +17 -1
  18. package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
  19. package/dist/src/mcpl/channel-registry.js +34 -3
  20. package/dist/src/mcpl/channel-registry.js.map +1 -1
  21. package/dist/src/mcpl/push-handler.d.ts.map +1 -1
  22. package/dist/src/mcpl/push-handler.js +4 -0
  23. package/dist/src/mcpl/push-handler.js.map +1 -1
  24. package/dist/src/mcpl/server-connection.d.ts +29 -0
  25. package/dist/src/mcpl/server-connection.d.ts.map +1 -1
  26. package/dist/src/mcpl/server-connection.js +102 -4
  27. package/dist/src/mcpl/server-connection.js.map +1 -1
  28. package/dist/src/mcpl/types.d.ts +17 -1
  29. package/dist/src/mcpl/types.d.ts.map +1 -1
  30. package/dist/src/mcpl/types.js.map +1 -1
  31. package/dist/src/module-registry.d.ts +15 -1
  32. package/dist/src/module-registry.d.ts.map +1 -1
  33. package/dist/src/module-registry.js +92 -4
  34. package/dist/src/module-registry.js.map +1 -1
  35. package/dist/src/types/agent.d.ts +37 -0
  36. package/dist/src/types/agent.d.ts.map +1 -1
  37. package/dist/src/types/framework.d.ts +40 -0
  38. package/dist/src/types/framework.d.ts.map +1 -1
  39. package/dist/src/types/module.d.ts +46 -0
  40. package/dist/src/types/module.d.ts.map +1 -1
  41. package/dist/src/types/trace.d.ts +51 -0
  42. package/dist/src/types/trace.d.ts.map +1 -1
  43. package/dist/test/agent-cache-ttl.test.d.ts +2 -0
  44. package/dist/test/agent-cache-ttl.test.d.ts.map +1 -0
  45. package/dist/test/agent-cache-ttl.test.js +25 -0
  46. package/dist/test/agent-cache-ttl.test.js.map +1 -0
  47. package/dist/test/conversation-fork-injection-scoping.test.d.ts +2 -0
  48. package/dist/test/conversation-fork-injection-scoping.test.d.ts.map +1 -0
  49. package/dist/test/conversation-fork-injection-scoping.test.js +184 -0
  50. package/dist/test/conversation-fork-injection-scoping.test.js.map +1 -0
  51. package/dist/test/gather-context-timeout.test.d.ts +2 -0
  52. package/dist/test/gather-context-timeout.test.d.ts.map +1 -0
  53. package/dist/test/gather-context-timeout.test.js +120 -0
  54. package/dist/test/gather-context-timeout.test.js.map +1 -0
  55. package/dist/test/inference-exhaustion-rewind.test.d.ts +2 -0
  56. package/dist/test/inference-exhaustion-rewind.test.d.ts.map +1 -0
  57. package/dist/test/inference-exhaustion-rewind.test.js +181 -0
  58. package/dist/test/inference-exhaustion-rewind.test.js.map +1 -0
  59. package/dist/test/inference-failure-observability.test.js +9 -0
  60. package/dist/test/inference-failure-observability.test.js.map +1 -1
  61. package/dist/test/maintenance-timer.test.d.ts +2 -0
  62. package/dist/test/maintenance-timer.test.d.ts.map +1 -0
  63. package/dist/test/maintenance-timer.test.js +114 -0
  64. package/dist/test/maintenance-timer.test.js.map +1 -0
  65. package/dist/test/mcpl-reconnect-events.test.d.ts +2 -0
  66. package/dist/test/mcpl-reconnect-events.test.d.ts.map +1 -0
  67. package/dist/test/mcpl-reconnect-events.test.js +119 -0
  68. package/dist/test/mcpl-reconnect-events.test.js.map +1 -0
  69. package/dist/test/mcpl-reconnect-reregistration.test.d.ts +2 -0
  70. package/dist/test/mcpl-reconnect-reregistration.test.d.ts.map +1 -0
  71. package/dist/test/mcpl-reconnect-reregistration.test.js +181 -0
  72. package/dist/test/mcpl-reconnect-reregistration.test.js.map +1 -0
  73. package/dist/test/mcpl-request-timeout.test.d.ts +2 -0
  74. package/dist/test/mcpl-request-timeout.test.d.ts.map +1 -0
  75. package/dist/test/mcpl-request-timeout.test.js +123 -0
  76. package/dist/test/mcpl-request-timeout.test.js.map +1 -0
  77. package/dist/test/mcpl-runtime-lifecycle.test.d.ts +7 -0
  78. package/dist/test/mcpl-runtime-lifecycle.test.d.ts.map +1 -0
  79. package/dist/test/mcpl-runtime-lifecycle.test.js +142 -0
  80. package/dist/test/mcpl-runtime-lifecycle.test.js.map +1 -0
  81. package/dist/test/ops-alert.test.d.ts +2 -0
  82. package/dist/test/ops-alert.test.d.ts.map +1 -0
  83. package/dist/test/ops-alert.test.js +152 -0
  84. package/dist/test/ops-alert.test.js.map +1 -0
  85. package/dist/test/refusal-rewind.test.d.ts +2 -0
  86. package/dist/test/refusal-rewind.test.d.ts.map +1 -0
  87. package/dist/test/refusal-rewind.test.js +108 -0
  88. package/dist/test/refusal-rewind.test.js.map +1 -0
  89. package/dist/test/state-scaling-e2e.test.d.ts +22 -0
  90. package/dist/test/state-scaling-e2e.test.d.ts.map +1 -0
  91. package/dist/test/state-scaling-e2e.test.js +200 -0
  92. package/dist/test/state-scaling-e2e.test.js.map +1 -0
  93. package/dist/test/state-scaling.test.d.ts +12 -0
  94. package/dist/test/state-scaling.test.d.ts.map +1 -0
  95. package/dist/test/state-scaling.test.js +243 -0
  96. package/dist/test/state-scaling.test.js.map +1 -0
  97. package/dist/test/tool-result-content.test.d.ts +2 -0
  98. package/dist/test/tool-result-content.test.d.ts.map +1 -0
  99. package/dist/test/tool-result-content.test.js +37 -0
  100. package/dist/test/tool-result-content.test.js.map +1 -0
  101. package/dist/tsconfig.tsbuildinfo +1 -1
  102. package/package.json +3 -2
  103. package/src/agent.ts +16 -0
  104. package/src/framework.ts +1339 -99
  105. package/src/gate/event-gate.ts +56 -4
  106. package/src/index.ts +10 -0
  107. package/src/mcpl/channel-registry.ts +34 -3
  108. package/src/mcpl/push-handler.ts +4 -0
  109. package/src/mcpl/server-connection.ts +110 -4
  110. package/src/mcpl/types.ts +19 -1
  111. package/src/module-registry.ts +113 -4
  112. package/src/types/agent.ts +38 -0
  113. package/src/types/framework.ts +44 -0
  114. package/src/types/module.ts +52 -0
  115. package/src/types/trace.ts +67 -0
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Runtime MCPL server lifecycle — connectMcplServer / disconnectMcplServer /
3
+ * restartMcplServer on a live framework, including lazy MCPL subsystem
4
+ * initialization when the framework started with zero configured servers.
5
+ */
6
+ import { test } from 'node:test';
7
+ import assert from 'node:assert';
8
+ import { tmpdir } from 'node:os';
9
+ import { mkdtempSync, rmSync } from 'node:fs';
10
+ import { join } from 'node:path';
11
+ import { WebSocketServer } from 'ws';
12
+ import { AgentFramework } from '../src/index.js';
13
+ import { MockMembrane } from './helpers/mock-membrane.js';
14
+ // A tiny stdio MCPL server (same shape as mcpl-ws-transport.test.ts): reads
15
+ // NDJSON on stdin, answers initialize / tools/list / tools/call on stdout.
16
+ const STDIO_SERVER = `
17
+ let buf = '';
18
+ process.stdin.on('data', (c) => {
19
+ buf += c.toString('utf8');
20
+ let i;
21
+ while ((i = buf.indexOf('\\n')) >= 0) {
22
+ const line = buf.slice(0, i); buf = buf.slice(i + 1);
23
+ if (!line.trim()) continue;
24
+ let m; try { m = JSON.parse(line); } catch { continue; }
25
+ const reply = (result) => process.stdout.write(JSON.stringify({ jsonrpc: '2.0', id: m.id, result }) + '\\n');
26
+ if (m.method === 'initialize') reply({ capabilities: { experimental: { mcpl: { version: '0.4', pushEvents: true } } } });
27
+ else if (m.method === 'tools/list') reply({ tools: [{ name: 'echo', description: 'e', inputSchema: { type: 'object' } }] });
28
+ else if (m.method === 'tools/call') reply({ content: [{ type: 'text', text: String((m.params && m.params.arguments && m.params.arguments.text) || '') }] });
29
+ }
30
+ });
31
+ `;
32
+ function serverConfig(id, extra) {
33
+ return { id, command: process.execPath, args: ['-e', STDIO_SERVER], ...extra };
34
+ }
35
+ async function withFramework(withServer, fn) {
36
+ const tempDir = mkdtempSync(join(tmpdir(), 'mcpl-lifecycle-'));
37
+ const membrane = new MockMembrane();
38
+ const framework = await AgentFramework.create({
39
+ storePath: join(tempDir, 'test.chronicle'),
40
+ membrane: membrane.asMembrane(),
41
+ agents: [{ name: 'assistant', model: 'test-model', systemPrompt: 'test' }],
42
+ modules: [],
43
+ ...(withServer ? { mcplServers: [serverConfig('first')] } : {}),
44
+ });
45
+ try {
46
+ await fn(framework);
47
+ }
48
+ finally {
49
+ await framework.stop();
50
+ rmSync(tempDir, { recursive: true, force: true });
51
+ }
52
+ }
53
+ test('connectMcplServer lazily initializes MCPL on a zero-server framework and exposes tools', async () => {
54
+ await withFramework(false, async (framework) => {
55
+ assert.deepEqual(framework.listMcplServers(), [], 'no servers configured at start');
56
+ await framework.connectMcplServer(serverConfig('dyn'));
57
+ const servers = framework.listMcplServers();
58
+ assert.equal(servers.length, 1);
59
+ assert.equal(servers[0].id, 'dyn');
60
+ assert.equal(servers[0].connected, true);
61
+ assert.equal(servers[0].toolCount, 1);
62
+ const toolNames = framework.getAllTools().map(t => t.name);
63
+ assert.ok(toolNames.includes('mcpl--dyn--echo'), `expected mcpl--dyn--echo in ${toolNames}`);
64
+ });
65
+ });
66
+ test('disconnectMcplServer removes the server and its tools', async () => {
67
+ await withFramework(true, async (framework) => {
68
+ assert.ok(framework.getAllTools().some(t => t.name === 'mcpl--first--echo'), 'startup server tools present');
69
+ await framework.disconnectMcplServer('first');
70
+ assert.deepEqual(framework.listMcplServers(), [], 'server gone from list');
71
+ assert.ok(!framework.getAllTools().some(t => t.name.startsWith('mcpl--first--')), 'tools removed after disconnect');
72
+ });
73
+ });
74
+ test('restartMcplServer respawns the server and keeps tools available', async () => {
75
+ await withFramework(true, async (framework) => {
76
+ await framework.restartMcplServer('first');
77
+ const servers = framework.listMcplServers();
78
+ assert.equal(servers.length, 1);
79
+ assert.equal(servers[0].connected, true);
80
+ assert.equal(servers[0].toolCount, 1);
81
+ assert.ok(framework.getAllTools().some(t => t.name === 'mcpl--first--echo'));
82
+ });
83
+ });
84
+ test('restartMcplServer accepts an updated config (new toolPrefix)', async () => {
85
+ await withFramework(true, async (framework) => {
86
+ await framework.restartMcplServer('first', serverConfig('first', { toolPrefix: 'renamed' }));
87
+ const toolNames = framework.getAllTools().map(t => t.name);
88
+ assert.ok(toolNames.includes('renamed--echo'), `expected renamed--echo in ${toolNames}`);
89
+ assert.ok(!toolNames.some(n => n.startsWith('mcpl--first--')), 'old prefix gone');
90
+ });
91
+ });
92
+ test('connectMcplServer rejects a duplicate id and a colliding prefix', async () => {
93
+ await withFramework(true, async (framework) => {
94
+ await assert.rejects(framework.connectMcplServer(serverConfig('first')), /already registered/);
95
+ await assert.rejects(framework.connectMcplServer(serverConfig('second', { toolPrefix: 'mcpl--first' })), /collides with server "first"/);
96
+ });
97
+ });
98
+ test('connectMcplServer hot-connects a network-only (WebSocket) MCPL server', async () => {
99
+ // Minimal in-process MCPL server over WebSocket (same shape as
100
+ // mcpl-ws-transport.test.ts) — no child process involved.
101
+ const wss = new WebSocketServer({ port: 0, host: '127.0.0.1' });
102
+ wss.on('connection', (ws) => {
103
+ ws.on('message', (data) => {
104
+ let msg;
105
+ try {
106
+ msg = JSON.parse(String(data));
107
+ }
108
+ catch {
109
+ return;
110
+ }
111
+ const reply = (result) => ws.send(JSON.stringify({ jsonrpc: '2.0', id: msg.id, result }));
112
+ if (msg.method === 'initialize')
113
+ reply({ capabilities: { experimental: { mcpl: { version: '0.4', pushEvents: true } } } });
114
+ else if (msg.method === 'tools/list')
115
+ reply({ tools: [{ name: 'echo', description: 'e', inputSchema: { type: 'object' } }] });
116
+ });
117
+ });
118
+ await new Promise((resolve) => (wss.address() ? resolve() : wss.once('listening', () => resolve())));
119
+ const url = `ws://127.0.0.1:${wss.address().port}/mcpl`;
120
+ try {
121
+ await withFramework(false, async (framework) => {
122
+ await framework.connectMcplServer({ id: 'netsrv', url });
123
+ const servers = framework.listMcplServers();
124
+ assert.equal(servers.length, 1);
125
+ assert.equal(servers[0].connected, true);
126
+ assert.equal(servers[0].url, url);
127
+ assert.ok(framework.getAllTools().some(t => t.name === 'mcpl--netsrv--echo'));
128
+ await framework.disconnectMcplServer('netsrv');
129
+ assert.ok(!framework.getAllTools().some(t => t.name.startsWith('mcpl--netsrv--')));
130
+ });
131
+ }
132
+ finally {
133
+ wss.close();
134
+ }
135
+ });
136
+ test('disconnecting an unknown server is a no-op (routing state cleared, no throw)', async () => {
137
+ await withFramework(true, async (framework) => {
138
+ await framework.disconnectMcplServer('nope');
139
+ assert.equal(framework.listMcplServers().length, 1, 'existing server untouched');
140
+ });
141
+ });
142
+ //# sourceMappingURL=mcpl-runtime-lifecycle.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcpl-runtime-lifecycle.test.js","sourceRoot":"","sources":["../../test/mcpl-runtime-lifecycle.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=ops-alert.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops-alert.test.d.ts","sourceRoot":"","sources":["../../test/ops-alert.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,152 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { AgentFramework } from '../src/framework.js';
4
+ /**
5
+ * opsAlert() is the single escalation path for "a human should hear about
6
+ * this": failures.log record + ops:alert trace + cooldown-throttled Discord
7
+ * webhook. It and noteRefusal() are private and the full framework is heavy
8
+ * to construct, so — like inference-failure-observability.test.ts — we
9
+ * exercise them on a prototype instance with just the touched fields stubbed.
10
+ */
11
+ function makeHarness() {
12
+ const fw = Object.create(AgentFramework.prototype);
13
+ fw.opsAlertLastSent = new Map();
14
+ fw.opsAlertCooldownMs = 15 * 60_000;
15
+ fw.refusalStats = new Map();
16
+ fw.refusalStreak = new Map();
17
+ fw.consecutiveInferenceFailures = new Map();
18
+ fw.inferenceFailureEscalationThreshold = 3;
19
+ fw.exhaustionRewinds = new Map();
20
+ fw.lastInferenceAt = new Map();
21
+ fw.pendingRequests = [];
22
+ fw.activeStreams = new Map(); // healthSnapshot reads its keys
23
+ fw.agents = new Map([['cairn', {
24
+ state: { status: 'idle' },
25
+ getContextManager: () => ({ addMessage: () => { } }),
26
+ }]]);
27
+ // Capture instead of touching the filesystem — logFailure's file mechanics
28
+ // are trivial and shared with the legacy exhaustion path.
29
+ const logged = [];
30
+ fw.logFailure = (r) => logged.push(r);
31
+ // Capture traces.
32
+ const traces = [];
33
+ fw.traceListeners = [(e) => traces.push(e)];
34
+ // Capture webhook posts.
35
+ const posts = [];
36
+ const origFetch = globalThis.fetch;
37
+ globalThis.fetch = ((url, init) => {
38
+ posts.push({ url: String(url), body: JSON.parse(init?.body ?? 'null') });
39
+ return Promise.resolve(new Response('ok'));
40
+ });
41
+ // Silence + capture stderr.
42
+ const errs = [];
43
+ const origErr = console.error;
44
+ console.error = (...a) => { errs.push(a.join(' ')); };
45
+ const restore = () => {
46
+ globalThis.fetch = origFetch;
47
+ console.error = origErr;
48
+ delete process.env.CONNECTOME_OPS_WEBHOOK;
49
+ };
50
+ return { fw, logged, traces, posts, errs, restore };
51
+ }
52
+ test('opsAlert: one webhook post per (agent,kind) per cooldown; trace + log always', () => {
53
+ const { fw, logged, traces, posts, restore } = makeHarness();
54
+ process.env.CONNECTOME_OPS_WEBHOOK = 'https://discord.example/hook';
55
+ try {
56
+ fw.opsAlert('hard-down', 'cairn', 'reason A');
57
+ fw.opsAlert('hard-down', 'cairn', 'reason B'); // same key → suppressed
58
+ assert.equal(posts.length, 1, 'second post within cooldown is suppressed');
59
+ assert.match(posts[0].body.content, /\*\*cairn\*\* hard-down: reason A/);
60
+ fw.opsAlert('refusal', 'cairn', 'different kind'); // different key → posts
61
+ assert.equal(posts.length, 2);
62
+ fw.opsAlert('hard-down', 'lena', 'different agent'); // different key → posts
63
+ assert.equal(posts.length, 3);
64
+ // Cooldown expiry re-arms the key.
65
+ fw.opsAlertLastSent.set('cairn:hard-down', Date.now() - 16 * 60_000);
66
+ fw.opsAlert('hard-down', 'cairn', 'reason C');
67
+ assert.equal(posts.length, 4, 'posts again after the cooldown window');
68
+ // The durable + wire records are NOT throttled: every call logs + traces
69
+ // (5 calls — including the webhook-suppressed one).
70
+ assert.equal(traces.filter(t => t.type === 'ops:alert').length, 5);
71
+ assert.equal(logged.length, 5, 'failures.log record on every call (no skipLog)');
72
+ assert.equal(logged[0].kind, 'hard-down');
73
+ }
74
+ finally {
75
+ restore();
76
+ }
77
+ });
78
+ test('opsAlert: no webhook env → no fetch, still logs and traces', () => {
79
+ const { fw, logged, traces, posts, restore } = makeHarness();
80
+ try {
81
+ fw.opsAlert('mcpl-down', 'discord', 'unreachable');
82
+ assert.equal(posts.length, 0);
83
+ assert.equal(logged.length, 1);
84
+ assert.equal(traces.filter(t => t.type === 'ops:alert').length, 1);
85
+ }
86
+ finally {
87
+ restore();
88
+ }
89
+ });
90
+ test('hard-down routes through opsAlert: one post at threshold, retries suppressed', () => {
91
+ const { fw, posts, restore } = makeHarness();
92
+ process.env.CONNECTOME_OPS_WEBHOOK = 'https://discord.example/hook';
93
+ try {
94
+ for (let i = 0; i < 5; i++)
95
+ fw.noteInferenceExhausted('cairn', 'boom');
96
+ assert.equal(posts.length, 1, 'streaks 3,4,5 within cooldown → exactly one post');
97
+ assert.match(posts[0].body.content, /hard-down: 3 consecutive inference failures/);
98
+ }
99
+ finally {
100
+ restore();
101
+ }
102
+ });
103
+ test('noteRefusal: stats + streak + per-refusal log; alert only from streak 2', () => {
104
+ const { fw, logged, posts, restore } = makeHarness();
105
+ process.env.CONNECTOME_OPS_WEBHOOK = 'https://discord.example/hook';
106
+ try {
107
+ const s1 = fw.noteRefusal('cairn', 'cyber', { input: 200_000, output: 12 });
108
+ assert.equal(s1, 1);
109
+ assert.equal(posts.length, 0, 'a single refusal does not page anyone');
110
+ const s2 = fw.noteRefusal('cairn', 'bio');
111
+ assert.equal(s2, 2);
112
+ assert.equal(posts.length, 1, 'second consecutive refusal alerts');
113
+ assert.match(posts[0].body.content, /refusal streak 2, category=bio/);
114
+ // Every refusal gets a durable record (kind, category, streak, tokens).
115
+ assert.equal(logged.length, 2);
116
+ assert.equal(logged[0].kind, 'refusal');
117
+ assert.equal(logged[0].category, 'cyber');
118
+ assert.equal(logged[0].streak, 1);
119
+ assert.deepEqual(logged[0].tokens, { input: 200_000, output: 12 });
120
+ assert.equal(logged[1].streak, 2);
121
+ // Stats accumulate per category and are exposed via healthSnapshot.
122
+ const snap = fw.healthSnapshot();
123
+ const cairn = snap.agents.find((a) => a.name === 'cairn');
124
+ assert.equal(cairn.refusalStats.total, 2);
125
+ assert.deepEqual(cairn.refusalStats.byCategory, { cyber: 1, bio: 1 });
126
+ assert.equal(cairn.refusalStats.lastCategory, 'bio');
127
+ // Agents that never refused expose null (mixed-fleet compat: consumers
128
+ // treat missing/null as "n/a").
129
+ fw.agents.set('lena', { state: { status: 'idle' } });
130
+ const lena = fw.healthSnapshot().agents.find((a) => a.name === 'lena');
131
+ assert.equal(lena.refusalStats, null);
132
+ }
133
+ finally {
134
+ restore();
135
+ }
136
+ });
137
+ test('refusal streak resets independently of stats (driver clears it on any clean turn)', () => {
138
+ const { fw, posts, restore } = makeHarness();
139
+ process.env.CONNECTOME_OPS_WEBHOOK = 'https://discord.example/hook';
140
+ try {
141
+ fw.noteRefusal('cairn', 'cyber');
142
+ // The stream driver's non-refusal branch does exactly this:
143
+ fw.refusalStreak.delete('cairn');
144
+ fw.noteRefusal('cairn', 'cyber');
145
+ assert.equal(posts.length, 0, 'streak restarted at 1 — no alert');
146
+ assert.equal(fw.refusalStats.get('cairn').total, 2, 'lifetime stats keep counting');
147
+ }
148
+ finally {
149
+ restore();
150
+ }
151
+ });
152
+ //# sourceMappingURL=ops-alert.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ops-alert.test.js","sourceRoot":"","sources":["../../test/ops-alert.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=refusal-rewind.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal-rewind.test.d.ts","sourceRoot":"","sources":["../../test/refusal-rewind.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,108 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { AgentFramework } from '../src/framework.js';
4
+ /**
5
+ * The refusal auto-rewind sheds the newest turn (in sequence, newest first,
6
+ * INCLUDING the agent's own turns) as a COMPLETE exchange — a tool_result is
7
+ * removed together with its paired tool_use turn, so no orphaned tool_use /
8
+ * signed thinking block is left behind. It maintains exactly ONE consolidated
9
+ * marker per episode. These exercise the private primitives on a prototype
10
+ * instance with a minimal in-memory ContextManager stub.
11
+ */
12
+ function makeAgentHarness(messages) {
13
+ const removed = [];
14
+ const added = [];
15
+ const edited = [];
16
+ const cm = {
17
+ getAllMessages: () => messages,
18
+ removeMessage: (id) => {
19
+ removed.push(id);
20
+ const i = messages.findIndex((m) => m.id === id);
21
+ if (i >= 0)
22
+ messages.splice(i, 1);
23
+ },
24
+ addMessage: (participant, content, meta) => {
25
+ const id = `marker-${added.length}`;
26
+ added.push({ participant, content, meta });
27
+ messages.push({ id, participant, content, metadata: meta });
28
+ return id;
29
+ },
30
+ editMessage: (id, content) => {
31
+ edited.push({ id, content });
32
+ const m = messages.find((x) => x.id === id);
33
+ if (m)
34
+ m.content = content;
35
+ },
36
+ };
37
+ const fw = Object.create(AgentFramework.prototype);
38
+ fw.rewindEpisode = new Map();
39
+ const agent = { name: 'labclaude', getContextManager: () => cm };
40
+ return { fw, agent, removed, added, edited, messages };
41
+ }
42
+ test('shed: tool_result removes its paired tool_use turn too (complete exchange)', () => {
43
+ const msgs = [
44
+ { id: 'u1', participant: 'simulect', content: [{ type: 'text', text: 'do it' }], metadata: { messageId: '1' } },
45
+ { id: 'a1', participant: 'labclaude', content: [{ type: 'thinking', thinking: '…' }, { type: 'tool_use', name: 'shell', id: 't1' }] },
46
+ { id: 'r1', participant: 'user', content: [{ type: 'tool_result', toolUseId: 't1', content: 'X'.repeat(320 * 1024) }] },
47
+ ];
48
+ const { fw, agent, removed, added } = makeAgentHarness(msgs);
49
+ const rec = fw.shedNewestTurn(agent);
50
+ assert.equal(rec.kind, 'tool');
51
+ assert.deepEqual([...removed].sort(), ['a1', 'r1'], 'removes the tool_result AND its tool_use turn — no orphan');
52
+ assert.deepEqual([...rec.removedIds].sort(), ['a1', 'r1']);
53
+ assert.equal(added.length, 0, 'shedNewestTurn must not add a marker');
54
+ });
55
+ test('shed: human message → kind=human + discordRef, single removal', () => {
56
+ const msgs = [
57
+ { id: 'a0', participant: 'labclaude', content: [{ type: 'text', text: 'hi' }] },
58
+ { id: 'm2', participant: 'simulect', content: [{ type: 'text', text: 'sketchy' }], metadata: { messageId: '999', channelId: 'discord:g:c' } },
59
+ ];
60
+ const { fw, agent, removed } = makeAgentHarness(msgs);
61
+ const rec = fw.shedNewestTurn(agent);
62
+ assert.equal(rec.kind, 'human');
63
+ assert.deepEqual(removed, ['m2']);
64
+ assert.deepEqual(rec.discordRef, { channelId: 'discord:g:c', messageId: '999' });
65
+ });
66
+ test('shed: agent turns ARE shed too (newest-first includes the agent own turns)', () => {
67
+ const msgs = [
68
+ { id: 'u1', participant: 'simulect', content: [{ type: 'text', text: 'q' }], metadata: { messageId: '1' } },
69
+ { id: 'a1', participant: 'labclaude', content: [{ type: 'text', text: 'my narration' }] },
70
+ ];
71
+ const { fw, agent, removed } = makeAgentHarness(msgs);
72
+ const rec = fw.shedNewestTurn(agent);
73
+ assert.ok(rec, 'sheds the agent turn (no longer skipped)');
74
+ assert.deepEqual(removed, ['a1']);
75
+ });
76
+ test('shed: skips the episode marker and sheds the real turn beneath it', () => {
77
+ const msgs = [
78
+ { id: 'm1', participant: 'simulect', content: [{ type: 'text', text: 'real msg' }], metadata: { messageId: '1' } },
79
+ { id: 'mk', participant: 'user', content: [{ type: 'text', text: '[refusal-rewind] ...' }], metadata: { system: true, kind: 'refusal-rewind' } },
80
+ ];
81
+ const { fw, agent, removed } = makeAgentHarness(msgs);
82
+ const rec = fw.shedNewestTurn(agent);
83
+ assert.ok(rec);
84
+ assert.deepEqual(removed, ['m1']);
85
+ });
86
+ test('shed: null when only the episode marker remains', () => {
87
+ const msgs = [{ id: 'mk', participant: 'user', content: [{ type: 'text', text: 'x' }], metadata: { system: true } }];
88
+ const { fw, agent } = makeAgentHarness(msgs);
89
+ assert.equal(fw.shedNewestTurn(agent), null);
90
+ });
91
+ test('marker: six rewinds produce ONE marker, updated in place (not six)', () => {
92
+ const msgs = [{ id: 'm1', participant: 'labclaude', content: [{ type: 'text', text: 'a' }] }];
93
+ const { fw, agent, added, edited } = makeAgentHarness(msgs);
94
+ const c1 = fw.updateRewindMarker(agent, 'cyber');
95
+ const c2 = fw.updateRewindMarker(agent, 'cyber');
96
+ fw.updateRewindMarker(agent, 'cyber');
97
+ fw.updateRewindMarker(agent, 'cyber');
98
+ fw.updateRewindMarker(agent, 'cyber');
99
+ const c6 = fw.updateRewindMarker(agent, 'cyber');
100
+ assert.equal(c1, 1);
101
+ assert.equal(c2, 2);
102
+ assert.equal(c6, 6);
103
+ assert.equal(added.length, 1, 'exactly ONE marker message added for the whole episode');
104
+ assert.equal(edited.length, 5, 'subsequent rewinds edit that one marker in place');
105
+ assert.match(edited[edited.length - 1].content[0].text, /6 most recent turn/, 'marker reflects the running total');
106
+ assert.equal(added[0].meta.kind, 'refusal-rewind');
107
+ });
108
+ //# sourceMappingURL=refusal-rewind.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refusal-rewind.test.js","sourceRoot":"","sources":["../../test/refusal-rewind.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Whole-store scaling sweep (scaling campaign Finding 2, end-to-end gate).
3
+ *
4
+ * The unit gates in state-scaling.test.ts pin the four known writers by
5
+ * calling them directly. This test validates the REGIME instead: it drives a
6
+ * synthetic workload through the framework's public surface — external
7
+ * messages with tool rounds, ephemeral spawn-and-dispose cycles, process
8
+ * logging on — then sweeps EVERY state family the store accumulated and
9
+ * asserts none of them grows superlinearly. A quadratic writer added anywhere
10
+ * (the way logProcessEvent silently duplicated logInference's bug) fails this
11
+ * test the day it's introduced, without anyone having to know to test it.
12
+ *
13
+ * Family classification:
14
+ * - capped families (per-agent turn-checkpoint slots) legitimately ramp to
15
+ * a fixed cap and plateau — small-N slope fits are noisy on that shape
16
+ * (a ramp-heavy window fits as "rising"), so they get a hard max-record-
17
+ * size bound instead, which is the stronger invariant anyway.
18
+ * - everything else with enough records gets a log-log slope fit of
19
+ * bytes-per-record vs index; flat ≈ healthy, ≈1 ≈ quadratic aggregate.
20
+ */
21
+ export {};
22
+ //# sourceMappingURL=state-scaling-e2e.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state-scaling-e2e.test.d.ts","sourceRoot":"","sources":["../../test/state-scaling-e2e.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG"}