@animalabs/agent-framework 0.9.0 → 0.11.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.
Files changed (109) hide show
  1. package/dist/src/agent.d.ts +1 -1
  2. package/dist/src/agent.d.ts.map +1 -1
  3. package/dist/src/agent.js.map +1 -1
  4. package/dist/src/framework.d.ts +72 -4
  5. package/dist/src/framework.d.ts.map +1 -1
  6. package/dist/src/framework.js +699 -48
  7. package/dist/src/framework.js.map +1 -1
  8. package/dist/src/gate/event-gate.d.ts +62 -7
  9. package/dist/src/gate/event-gate.d.ts.map +1 -1
  10. package/dist/src/gate/event-gate.js +333 -22
  11. package/dist/src/gate/event-gate.js.map +1 -1
  12. package/dist/src/gate/types.d.ts +56 -0
  13. package/dist/src/gate/types.d.ts.map +1 -1
  14. package/dist/src/mcpl/prose-grammar.d.ts +11 -0
  15. package/dist/src/mcpl/prose-grammar.d.ts.map +1 -1
  16. package/dist/src/mcpl/prose-grammar.js +21 -0
  17. package/dist/src/mcpl/prose-grammar.js.map +1 -1
  18. package/dist/src/mcpl/prose-stream-router.d.ts +2 -2
  19. package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -1
  20. package/dist/src/mcpl/prose-stream-router.js +57 -13
  21. package/dist/src/mcpl/prose-stream-router.js.map +1 -1
  22. package/dist/src/modules/discord/index.d.ts.map +1 -1
  23. package/dist/src/modules/discord/index.js +21 -5
  24. package/dist/src/modules/discord/index.js.map +1 -1
  25. package/dist/src/modules/workspace/index.d.ts +23 -0
  26. package/dist/src/modules/workspace/index.d.ts.map +1 -1
  27. package/dist/src/modules/workspace/index.js +53 -3
  28. package/dist/src/modules/workspace/index.js.map +1 -1
  29. package/dist/src/modules/workspace/sync.d.ts +11 -2
  30. package/dist/src/modules/workspace/sync.d.ts.map +1 -1
  31. package/dist/src/modules/workspace/sync.js +27 -11
  32. package/dist/src/modules/workspace/sync.js.map +1 -1
  33. package/dist/src/modules/workspace/watcher.d.ts.map +1 -1
  34. package/dist/src/modules/workspace/watcher.js +9 -6
  35. package/dist/src/modules/workspace/watcher.js.map +1 -1
  36. package/dist/src/queue.d.ts.map +1 -1
  37. package/dist/src/queue.js +9 -2
  38. package/dist/src/queue.js.map +1 -1
  39. package/dist/src/tool-result-history.d.ts +12 -2
  40. package/dist/src/tool-result-history.d.ts.map +1 -1
  41. package/dist/src/tool-result-history.js +12 -2
  42. package/dist/src/tool-result-history.js.map +1 -1
  43. package/dist/src/types/agent.d.ts +6 -1
  44. package/dist/src/types/agent.d.ts.map +1 -1
  45. package/dist/src/types/framework.d.ts +1 -1
  46. package/dist/src/types/trace.d.ts +7 -0
  47. package/dist/src/types/trace.d.ts.map +1 -1
  48. package/dist/test/busy-agent-scheduler.test.js +29 -0
  49. package/dist/test/busy-agent-scheduler.test.js.map +1 -1
  50. package/dist/test/discord-history-delete-window.test.d.ts +2 -0
  51. package/dist/test/discord-history-delete-window.test.d.ts.map +1 -0
  52. package/dist/test/discord-history-delete-window.test.js +81 -0
  53. package/dist/test/discord-history-delete-window.test.js.map +1 -0
  54. package/dist/test/discord-history-sync.test.d.ts +2 -0
  55. package/dist/test/discord-history-sync.test.d.ts.map +1 -0
  56. package/dist/test/discord-history-sync.test.js +56 -0
  57. package/dist/test/discord-history-sync.test.js.map +1 -0
  58. package/dist/test/event-gate-passthrough.test.d.ts +15 -0
  59. package/dist/test/event-gate-passthrough.test.d.ts.map +1 -0
  60. package/dist/test/event-gate-passthrough.test.js +289 -0
  61. package/dist/test/event-gate-passthrough.test.js.map +1 -0
  62. package/dist/test/explicit-prose-routing.test.js +179 -7
  63. package/dist/test/explicit-prose-routing.test.js.map +1 -1
  64. package/dist/test/framework.test.js +33 -0
  65. package/dist/test/framework.test.js.map +1 -1
  66. package/dist/test/prose-stream-router.test.js +43 -0
  67. package/dist/test/prose-stream-router.test.js.map +1 -1
  68. package/dist/test/provider-acceleration-cooldown.test.d.ts +2 -0
  69. package/dist/test/provider-acceleration-cooldown.test.d.ts.map +1 -0
  70. package/dist/test/provider-acceleration-cooldown.test.js +286 -0
  71. package/dist/test/provider-acceleration-cooldown.test.js.map +1 -0
  72. package/dist/test/puppet-tool-call.test.d.ts +2 -0
  73. package/dist/test/puppet-tool-call.test.d.ts.map +1 -0
  74. package/dist/test/puppet-tool-call.test.js +106 -0
  75. package/dist/test/puppet-tool-call.test.js.map +1 -0
  76. package/dist/test/release-changelog.test.d.ts +2 -0
  77. package/dist/test/release-changelog.test.d.ts.map +1 -0
  78. package/dist/test/release-changelog.test.js +159 -0
  79. package/dist/test/release-changelog.test.js.map +1 -0
  80. package/dist/test/tool-result-spill.test.d.ts +1 -1
  81. package/dist/test/tool-result-spill.test.js +18 -9
  82. package/dist/test/tool-result-spill.test.js.map +1 -1
  83. package/dist/test/workspace-path-containment.test.d.ts +19 -0
  84. package/dist/test/workspace-path-containment.test.d.ts.map +1 -0
  85. package/dist/test/workspace-path-containment.test.js +91 -0
  86. package/dist/test/workspace-path-containment.test.js.map +1 -0
  87. package/dist/test/workspace-watcher.test.js +15 -3
  88. package/dist/test/workspace-watcher.test.js.map +1 -1
  89. package/dist/test/xml-round-persist.test.d.ts +19 -0
  90. package/dist/test/xml-round-persist.test.d.ts.map +1 -0
  91. package/dist/test/xml-round-persist.test.js +235 -0
  92. package/dist/test/xml-round-persist.test.js.map +1 -0
  93. package/dist/tsconfig.tsbuildinfo +1 -1
  94. package/package.json +2 -1
  95. package/src/agent.ts +1 -1
  96. package/src/framework.ts +733 -48
  97. package/src/gate/event-gate.ts +355 -24
  98. package/src/gate/types.ts +58 -0
  99. package/src/mcpl/prose-grammar.ts +21 -0
  100. package/src/mcpl/prose-stream-router.ts +48 -14
  101. package/src/modules/discord/index.ts +24 -6
  102. package/src/modules/workspace/index.ts +53 -3
  103. package/src/modules/workspace/sync.ts +39 -10
  104. package/src/modules/workspace/watcher.ts +9 -6
  105. package/src/queue.ts +8 -2
  106. package/src/tool-result-history.ts +12 -2
  107. package/src/types/agent.ts +6 -1
  108. package/src/types/framework.ts +1 -1
  109. package/src/types/trace.ts +13 -0
@@ -0,0 +1,286 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { mkdtempSync, rmSync } from 'node:fs';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import { MembraneError } from '@animalabs/membrane';
7
+ import { AgentFramework } from '../src/index.js';
8
+ import { MockMembrane, MockYieldingStream, createMockResponse } from './helpers/mock-membrane.js';
9
+ class InputModule {
10
+ name = 'input';
11
+ ctx = null;
12
+ async start(ctx) { this.ctx = ctx; }
13
+ async stop() { this.ctx = null; }
14
+ getTools() { return []; }
15
+ async handleToolCall(_call) { return { success: false, isError: true, error: 'none' }; }
16
+ async onProcess(event, _state) {
17
+ if (event.type !== 'external-message')
18
+ return {};
19
+ return { addMessages: [{ participant: 'User', content: [{ type: 'text', text: String(event.content) }] }], requestInference: true };
20
+ }
21
+ }
22
+ class ErrorStream {
23
+ error;
24
+ isWaitingForTools = false;
25
+ pendingToolCallIds = [];
26
+ toolDepth = 0;
27
+ isCancelled = false;
28
+ constructor(error) {
29
+ this.error = error;
30
+ }
31
+ provideToolResults() { throw new Error('not waiting'); }
32
+ cancel() { this.isCancelled = true; }
33
+ async *[Symbol.asyncIterator]() {
34
+ yield { type: 'error', error: this.error };
35
+ }
36
+ }
37
+ class AccelerationThenSuccessMembrane extends MockMembrane {
38
+ n = 0;
39
+ streamYielding(request) {
40
+ this.calls.push(request);
41
+ this.n++;
42
+ if (this.n === 1) {
43
+ return new ErrorStream(new MembraneError({
44
+ type: 'rate_limit', retryable: true, httpStatus: 429,
45
+ message: "This request would exceed your organization's maximum usage increase rate for input tokens per minute",
46
+ rawError: { status: 429 }, rawRequest: request,
47
+ }));
48
+ }
49
+ return new MockYieldingStream([createMockResponse([{ type: 'text', text: 'recovered' }])]);
50
+ }
51
+ }
52
+ class GenericRateLimitThenSuccessMembrane extends MockMembrane {
53
+ n = 0;
54
+ streamYielding(request) {
55
+ this.calls.push(request);
56
+ this.n++;
57
+ if (this.n === 1)
58
+ return new ErrorStream(new MembraneError({
59
+ type: 'rate_limit', retryable: true, httpStatus: 429,
60
+ message: "This request would exceed your organization's rate limit for input tokens per minute; retry after 1", retryAfterMs: 1,
61
+ rawError: { status: 429 }, rawRequest: request,
62
+ }));
63
+ return new MockYieldingStream([createMockResponse([{ type: 'text', text: 'ordinary retry' }])]);
64
+ }
65
+ }
66
+ class AlwaysSuccessMembrane extends MockMembrane {
67
+ streamYielding(request) {
68
+ this.calls.push(request);
69
+ return new MockYieldingStream([createMockResponse([{ type: 'text', text: 'ok' }])]);
70
+ }
71
+ }
72
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
73
+ function textOf(request) {
74
+ return request.messages.flatMap((m) => m.content)
75
+ .filter((b) => b.type === 'text')
76
+ .map((b) => b.text).join('\n');
77
+ }
78
+ test('organization acceleration 429 defers one fresh compile, includes arrivals, and avoids failure breaker', async () => {
79
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-cooldown-'));
80
+ const membrane = new AccelerationThenSuccessMembrane();
81
+ const framework = await AgentFramework.create({
82
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
83
+ agents: [{ name: 'resident', model: 'test-model', systemPrompt: 'system' }],
84
+ modules: [new InputModule()], syncIntervalMs: 0, maintenanceIntervalMs: 0,
85
+ });
86
+ const internal = framework;
87
+ internal.providerAccelerationDefaultCooldownMs = 1_000;
88
+ internal.providerAccelerationJitterMs = 0;
89
+ try {
90
+ framework.pushEvent({ type: 'external-message', source: 'test', content: 'first', metadata: {} });
91
+ await framework.runUntilIdle();
92
+ assert.equal(membrane.calls.length, 1, 'no immediate same-window retry');
93
+ assert.equal(internal.consecutiveInferenceFailures.get('resident') ?? 0, 0, 'capacity does not enter hard-down streak');
94
+ assert.equal(internal.providerAccelerationCooldowns.size, 1);
95
+ framework.pushEvent({ type: 'external-message', source: 'test', content: 'arrived during cooldown', metadata: {} });
96
+ await framework.runUntilIdle();
97
+ assert.equal(membrane.calls.length, 1, 'new arrival is held, not separately inferred');
98
+ assert.equal(internal.providerAccelerationCooldowns.get('resident')?.heldRequests.length, 2);
99
+ await sleep(1_100);
100
+ await framework.runUntilIdle();
101
+ assert.equal(membrane.calls.length, 2, 'one deferred primary attempt');
102
+ assert.match(textOf(membrane.calls[1]), /first/);
103
+ assert.match(textOf(membrane.calls[1]), /arrived during cooldown/);
104
+ const messages = framework.getAgent('resident').getContextManager().queryMessages({}).messages;
105
+ const failed = messages.filter((m) => m.metadata?.kind === 'inference-failed');
106
+ const authoredReceipt = messages.filter((m) => m.metadata?.kind === 'provider-acceleration-recovered');
107
+ assert.equal(failed.length, 0, 'no poisoned-history/failure marker');
108
+ assert.equal(authoredReceipt.length, 0, 'provider admission never authors resident memory');
109
+ const recovery = internal.providerAccelerationLastRecovery.get('resident');
110
+ assert.ok(recovery, 'operational recovery receipt is exposed outside Chronicle');
111
+ assert.ok(recovery.waitedMs >= recovery.cooldownMs);
112
+ assert.equal(recovery.heldRequests, 2);
113
+ assert.ok(recovery.messageCount > 0);
114
+ assert.equal(recovery.stopReason, 'end_turn');
115
+ }
116
+ finally {
117
+ await framework.stop();
118
+ rmSync(dir, { recursive: true, force: true });
119
+ }
120
+ });
121
+ test('dynamic conversation forks are excluded from provider cooldown ownership', async () => {
122
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-conversation-'));
123
+ const membrane = new AccelerationThenSuccessMembrane();
124
+ const framework = await AgentFramework.create({
125
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
126
+ agents: [{ name: 'resident', model: 'test-model', systemPrompt: 'system' }],
127
+ modules: [], syncIntervalMs: 0, maintenanceIntervalMs: 0,
128
+ });
129
+ const internal = framework;
130
+ internal.conversationAgentHomes.set('resident', 'world:test');
131
+ try {
132
+ const error = new MembraneError({
133
+ type: 'rate_limit', retryable: true, httpStatus: 429,
134
+ message: "This request would exceed your organization's maximum usage increase rate for input tokens per minute",
135
+ rawError: { status: 429 },
136
+ });
137
+ const held = internal.holdProviderAcceleration(framework.getAgent('resident'), error, {
138
+ agentName: 'resident', reason: 'conversation', source: 'test', timestamp: Date.now(),
139
+ });
140
+ assert.equal(held, false, 'conversation fork retains its existing provider policy');
141
+ assert.equal(internal.providerAccelerationCooldowns.size, 0);
142
+ assert.equal(internal.providerGates.size, 0, 'generation-unique conversation name allocates no provider gate');
143
+ }
144
+ finally {
145
+ await framework.stop();
146
+ rmSync(dir, { recursive: true, force: true });
147
+ }
148
+ });
149
+ test('a resident waiting behind auxiliary work does not block another resident', async () => {
150
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-cross-agent-'));
151
+ const membrane = new AlwaysSuccessMembrane();
152
+ const framework = await AgentFramework.create({
153
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
154
+ agents: [
155
+ { name: 'resident', model: 'test-model', systemPrompt: 'system' },
156
+ { name: 'other', model: 'test-model', systemPrompt: 'system' },
157
+ ],
158
+ modules: [], syncIntervalMs: 0, maintenanceIntervalMs: 0,
159
+ });
160
+ const internal = framework;
161
+ let finish;
162
+ const auxiliary = internal.withAuxiliaryAdmission('resident', () => new Promise((resolve) => {
163
+ finish = resolve;
164
+ }));
165
+ try {
166
+ await internal.startAgentStream(framework.getAgent('resident'));
167
+ await internal.startAgentStream(framework.getAgent('other'));
168
+ await sleep(20);
169
+ assert.equal(membrane.calls.length, 1, 'the other resident reaches the provider while the first waits');
170
+ finish();
171
+ await auxiliary;
172
+ await sleep(20);
173
+ assert.equal(membrane.calls.length, 2, 'the waiting resident resumes after auxiliary settlement');
174
+ }
175
+ finally {
176
+ finish();
177
+ await auxiliary;
178
+ await framework.stop();
179
+ rmSync(dir, { recursive: true, force: true });
180
+ }
181
+ });
182
+ test('shutdown aborts a primary waiting behind in-flight auxiliary work', async () => {
183
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-stop-aux-'));
184
+ const membrane = new MockMembrane();
185
+ const framework = await AgentFramework.create({
186
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
187
+ agents: [{ name: 'resident', model: 'test-model', systemPrompt: 'system' }],
188
+ modules: [new InputModule()], syncIntervalMs: 0, maintenanceIntervalMs: 0,
189
+ });
190
+ const internal = framework;
191
+ let finish;
192
+ const auxiliary = internal.withAuxiliaryAdmission('resident', () => new Promise((resolve) => {
193
+ finish = resolve;
194
+ }));
195
+ let stopped = false;
196
+ try {
197
+ framework.pushEvent({ type: 'external-message', source: 'test', content: 'first', metadata: {} });
198
+ const draining = framework.runUntilIdle();
199
+ await sleep(20);
200
+ assert.equal(membrane.calls.length, 0, 'primary waits behind the admitted auxiliary');
201
+ await Promise.race([
202
+ framework.stop().then(() => { stopped = true; }),
203
+ sleep(250).then(() => { throw new Error('shutdown left the primary waiting behind auxiliary work'); }),
204
+ ]);
205
+ await draining;
206
+ assert.equal(membrane.calls.length, 0, 'shutdown does not start a late primary against the closed store');
207
+ }
208
+ finally {
209
+ finish();
210
+ await auxiliary;
211
+ if (!stopped)
212
+ await framework.stop();
213
+ rmSync(dir, { recursive: true, force: true });
214
+ }
215
+ });
216
+ test('ordinary 429 keeps the existing retry policy instead of entering acceleration cooldown', async () => {
217
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-generic-'));
218
+ const membrane = new GenericRateLimitThenSuccessMembrane();
219
+ const framework = await AgentFramework.create({
220
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
221
+ agents: [{ name: 'resident', model: 'test-model', systemPrompt: 'system' }],
222
+ modules: [new InputModule()], syncIntervalMs: 0, maintenanceIntervalMs: 0,
223
+ });
224
+ try {
225
+ framework.pushEvent({ type: 'external-message', source: 'test', content: 'ordinary', metadata: {} });
226
+ await framework.runUntilIdle();
227
+ assert.equal(membrane.calls.length, 2);
228
+ const internal = framework;
229
+ assert.equal(internal.providerAccelerationCooldowns.size, 0);
230
+ }
231
+ finally {
232
+ await framework.stop();
233
+ rmSync(dir, { recursive: true, force: true });
234
+ }
235
+ });
236
+ test('local provider gate settles in-flight auxiliary work and parks later auxiliary admission', async () => {
237
+ const dir = mkdtempSync(join(tmpdir(), 'af-provider-gate-'));
238
+ const membrane = new MockMembrane();
239
+ const framework = await AgentFramework.create({
240
+ storePath: join(dir, 'store.chronicle'), membrane: membrane.asMembrane(),
241
+ agents: [{ name: 'resident', model: 'test-model', systemPrompt: 'system' }], modules: [],
242
+ syncIntervalMs: 0, maintenanceIntervalMs: 0,
243
+ });
244
+ const internal = framework;
245
+ try {
246
+ let finish;
247
+ const inFlight = internal.withAuxiliaryAdmission('resident', () => new Promise((resolve) => {
248
+ finish = () => resolve(3);
249
+ }));
250
+ internal.acquirePrimaryProviderGate('resident');
251
+ let primaryReady = false;
252
+ const wait = internal.waitForAuxiliaryIdle('resident').then(() => { primaryReady = true; });
253
+ let laterRan = false;
254
+ const later = internal.withAuxiliaryAdmission('resident', async () => { laterRan = true; return 7; });
255
+ await sleep(10);
256
+ assert.equal(primaryReady, false, 'primary observes the already in-flight auxiliary');
257
+ assert.equal(laterRan, false, 'new auxiliary is parked');
258
+ finish();
259
+ assert.equal(await inFlight, 3);
260
+ await wait;
261
+ assert.equal(primaryReady, true);
262
+ assert.equal(laterRan, false, 'parked auxiliary still waits for primary settlement');
263
+ internal.releasePrimaryProviderGate('resident');
264
+ assert.equal(await later, 7);
265
+ assert.equal(internal.providerGates.get('resident')?.deferredAuxiliary, 0, 'completed wait no longer reports backlog');
266
+ // The real Context Manager door is the wrapped auxiliary Membrane, not
267
+ // merely the helper tested above.
268
+ internal.acquirePrimaryProviderGate('resident');
269
+ const cm = framework.getAgent('resident').getContextManager();
270
+ const request = {
271
+ messages: [], tools: [], config: { model: 'test-model', maxTokens: 16 },
272
+ };
273
+ const before = membrane.calls.length;
274
+ const throughCm = cm.membrane.complete(request);
275
+ await sleep(10);
276
+ assert.equal(membrane.calls.length, before, 'Context Manager provider call is parked');
277
+ internal.releasePrimaryProviderGate('resident');
278
+ await throughCm;
279
+ assert.equal(membrane.calls.length, before + 1, 'Context Manager call resumes once');
280
+ }
281
+ finally {
282
+ await framework.stop();
283
+ rmSync(dir, { recursive: true, force: true });
284
+ }
285
+ });
286
+ //# sourceMappingURL=provider-acceleration-cooldown.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"provider-acceleration-cooldown.test.js","sourceRoot":"","sources":["../../test/provider-acceleration-cooldown.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=puppet-tool-call.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppet-tool-call.test.d.ts","sourceRoot":"","sources":["../../test/puppet-tool-call.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,106 @@
1
+ import { test } from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { AgentFramework } from '../src/framework.js';
4
+ function puppetHarness(opts) {
5
+ const stored = [];
6
+ const traces = [];
7
+ const executed = [];
8
+ const status = opts?.status ?? 'idle';
9
+ const surface = opts?.surface ?? ['mcpl--eido--look'];
10
+ // Real MCPL results are MCP content arrays — the helper renders them plain.
11
+ const result = opts?.result ?? {
12
+ success: true,
13
+ data: [{ type: 'text', text: 'You are "p" in world "w".' }],
14
+ isError: false,
15
+ };
16
+ const agent = {
17
+ name: 'princess',
18
+ state: { status },
19
+ canUseTool: (name) => surface.includes(name),
20
+ getContextManager: () => ({
21
+ addMessage: (participant, content) => {
22
+ stored.push({ participant, content });
23
+ return `msg-${stored.length}`;
24
+ },
25
+ }),
26
+ };
27
+ const framework = Object.create(AgentFramework.prototype);
28
+ framework.agents =
29
+ new Map([['princess', agent]]);
30
+ framework.getToolsForAgent =
31
+ () => surface.map((name) => ({ name }));
32
+ framework.executeToolCall =
33
+ async (call) => {
34
+ executed.push(call);
35
+ return result;
36
+ };
37
+ framework.resolveToolResultInlineCap =
38
+ () => ({ cap: undefined });
39
+ framework.emitTrace =
40
+ (e) => { traces.push(e); };
41
+ return { framework, stored, traces, executed };
42
+ }
43
+ test('puppetToolCall executes with agent provenance and stores the pair', async () => {
44
+ const { framework, stored, traces, executed } = puppetHarness();
45
+ const quiet = console.log;
46
+ console.log = () => { };
47
+ try {
48
+ const { toolUseId, result } = await framework.puppetToolCall('princess', 'mcpl--eido--look', {});
49
+ assert.match(toolUseId, /^toolu_01[A-Za-z0-9]{22}$/, 'anthropic-shaped id');
50
+ assert.equal(result.success, true);
51
+ assert.equal(executed.length, 1);
52
+ assert.equal(executed[0].callerAgentName, 'princess', 'executes AS the agent');
53
+ assert.equal(executed[0].id, toolUseId, 'wire call carries the stored id');
54
+ assert.equal(stored.length, 2, 'exactly the pair, nothing else');
55
+ const [use, res] = stored;
56
+ assert.equal(use.participant, 'princess', 'tool_use is the agent turn');
57
+ assert.equal(use.content.length, 1, 'bare tool_use — no fabricated text/thinking');
58
+ assert.equal(use.content[0].type, 'tool_use');
59
+ assert.equal(use.content[0].id, toolUseId);
60
+ assert.equal(res.participant, 'user', 'tool_result rides a user message');
61
+ assert.equal(res.content[0].type, 'tool_result');
62
+ assert.equal(res.content[0].toolUseId, toolUseId, 'result pairs with the call');
63
+ assert.equal(res.content[0].toolName, 'mcpl--eido--look');
64
+ assert.equal(res.content[0].isError, false);
65
+ assert.match(String(res.content[0].content), /You are "p"/, 'real result text stored');
66
+ assert.equal(traces.length, 1);
67
+ assert.equal(traces[0].type, 'puppet:tool-call');
68
+ assert.equal(traces[0].agentName, 'princess');
69
+ }
70
+ finally {
71
+ console.log = quiet;
72
+ }
73
+ });
74
+ test('puppetToolCall refuses a non-idle agent', async () => {
75
+ const { framework, stored } = puppetHarness({ status: 'streaming' });
76
+ await assert.rejects(() => framework.puppetToolCall('princess', 'mcpl--eido--look', {}), /requires idle/);
77
+ assert.equal(stored.length, 0, 'nothing stored on refusal');
78
+ });
79
+ test('puppetToolCall refuses a tool off the agent surface', async () => {
80
+ const { framework, stored, executed } = puppetHarness();
81
+ await assert.rejects(() => framework.puppetToolCall('princess', 'mcpl--other--nuke', {}), /not on princess's surface/);
82
+ assert.equal(executed.length, 0, 'never executed');
83
+ assert.equal(stored.length, 0, 'nothing stored');
84
+ });
85
+ test('puppetToolCall refuses an unknown agent', async () => {
86
+ const { framework } = puppetHarness();
87
+ await assert.rejects(() => framework.puppetToolCall('ghost', 'mcpl--eido--look', {}), /Unknown agent/);
88
+ });
89
+ test('puppetToolCall stores an error result as isError, still paired', async () => {
90
+ const { framework, stored } = puppetHarness({
91
+ result: { success: false, error: 'MCPL server unreachable', isError: true },
92
+ });
93
+ const quiet = console.log;
94
+ console.log = () => { };
95
+ try {
96
+ const { result } = await framework.puppetToolCall('princess', 'mcpl--eido--look', {});
97
+ assert.equal(result.isError, true);
98
+ assert.equal(stored.length, 2, 'error results are stored too — same as a real turn');
99
+ assert.equal(stored[1].content[0].isError, true);
100
+ assert.match(String(stored[1].content[0].content), /unreachable/);
101
+ }
102
+ finally {
103
+ console.log = quiet;
104
+ }
105
+ });
106
+ //# sourceMappingURL=puppet-tool-call.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"puppet-tool-call.test.js","sourceRoot":"","sources":["../../test/puppet-tool-call.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=release-changelog.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-changelog.test.d.ts","sourceRoot":"","sources":["../../test/release-changelog.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,159 @@
1
+ // Black-box coverage of scripts/release-changelog.mjs: each case runs the
2
+ // real script in a throwaway directory, so assembly, validation, and the
3
+ // deletion of consumed fragments are all exercised exactly as `npm version`
4
+ // would run them.
5
+ import { test } from "node:test";
6
+ import assert from "node:assert/strict";
7
+ import { execFileSync } from "node:child_process";
8
+ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, writeFileSync, } from "node:fs";
9
+ import { tmpdir } from "node:os";
10
+ import { dirname, join } from "node:path";
11
+ import { fileURLToPath } from "node:url";
12
+ const SCRIPT = fileURLToPath(new URL("../../scripts/release-changelog.mjs", import.meta.url));
13
+ const BASE_CHANGELOG = [
14
+ "# Changelog",
15
+ "",
16
+ "Intro that mentions ## Unreleased inline, which must not count as a heading.",
17
+ "",
18
+ "## Unreleased",
19
+ "",
20
+ "## 1.0.0 — 2026-01-01",
21
+ "",
22
+ "### Fixed",
23
+ "",
24
+ "- Old entry.",
25
+ "",
26
+ ].join("\n");
27
+ function setup(f) {
28
+ const dir = mkdtempSync(join(tmpdir(), "release-changelog-"));
29
+ writeFileSync(join(dir, "package.json"), JSON.stringify({ name: "fixture", version: f.version ?? "1.1.0" }));
30
+ writeFileSync(join(dir, "CHANGELOG.md"), f.changelog ?? BASE_CHANGELOG);
31
+ mkdirSync(join(dir, "changelog.d"));
32
+ writeFileSync(join(dir, "changelog.d", "README.md"), "# Pending fragments\n");
33
+ for (const [name, body] of Object.entries(f.fragments ?? {})) {
34
+ const path = join(dir, "changelog.d", name);
35
+ mkdirSync(dirname(path), { recursive: true });
36
+ writeFileSync(path, body);
37
+ }
38
+ return dir;
39
+ }
40
+ function run(dir) {
41
+ try {
42
+ const stdout = execFileSync(process.execPath, [SCRIPT], {
43
+ cwd: dir,
44
+ encoding: "utf8",
45
+ stdio: ["ignore", "pipe", "pipe"],
46
+ });
47
+ return { status: 0, stdout, stderr: "" };
48
+ }
49
+ catch (e) {
50
+ const err = e;
51
+ return { status: err.status, stdout: err.stdout ?? "", stderr: err.stderr ?? "" };
52
+ }
53
+ }
54
+ function section(text, version) {
55
+ const lines = text.split("\n");
56
+ const start = lines.findIndex((l) => l.startsWith(`## ${version} — `));
57
+ assert.notEqual(start, -1, `no '## ${version}' section in:\n${text}`);
58
+ const rest = lines.slice(start + 1);
59
+ const end = rest.findIndex((l) => l.startsWith("## "));
60
+ return rest.slice(0, end === -1 ? undefined : end).join("\n").trim();
61
+ }
62
+ const changelog = (dir) => readFileSync(join(dir, "CHANGELOG.md"), "utf8");
63
+ const pending = (dir) => readdirSync(join(dir, "changelog.d")).sort();
64
+ test("folds fragments into a versioned section in canonical order and deletes them", () => {
65
+ const dir = setup({
66
+ fragments: {
67
+ "z-later.fixed.md": "- Fixed thing.\n",
68
+ "a-first.added.md": "- Added thing,\n continued on an indented line.\n",
69
+ "m.breaking.md": "- **Module authors:** breaking thing.\n",
70
+ },
71
+ });
72
+ const r = run(dir);
73
+ assert.equal(r.status, 0, r.stderr);
74
+ const text = changelog(dir);
75
+ assert.equal(section(text, "1.1.0"), [
76
+ "### Breaking",
77
+ "",
78
+ "- **Module authors:** breaking thing.",
79
+ "",
80
+ "### Added",
81
+ "",
82
+ "- Added thing,",
83
+ " continued on an indented line.",
84
+ "",
85
+ "### Fixed",
86
+ "",
87
+ "- Fixed thing.",
88
+ ].join("\n"));
89
+ assert.match(text, /^## Unreleased\n\n## 1\.1\.0 — \d{4}-\d{2}-\d{2}\n/m, "fresh empty Unreleased above the cut");
90
+ assert.ok(text.startsWith("# Changelog\n\nIntro that mentions"), "file header preserved");
91
+ assert.equal(section(text, "1.0.0"), "### Fixed\n\n- Old entry.", "older section untouched");
92
+ assert.deepEqual(pending(dir), ["README.md"], "consumed fragments deleted, README kept");
93
+ });
94
+ test("merges fragments into directly-filed Unreleased entries, reordering subsections canonically", () => {
95
+ const dir = setup({
96
+ changelog: BASE_CHANGELOG.replace("## Unreleased\n", "## Unreleased\n\n### Fixed\n\n- Manual fix.\n\n### Added\n\n- Manual add.\n"),
97
+ fragments: { "x.fixed.md": "- Fragment fix.\n" },
98
+ });
99
+ const r = run(dir);
100
+ assert.equal(r.status, 0, r.stderr);
101
+ assert.equal(section(changelog(dir), "1.1.0"), "### Added\n\n- Manual add.\n\n### Fixed\n\n- Manual fix.\n\n- Fragment fix.");
102
+ });
103
+ test("breaking fragments join an audience-qualified Breaking heading", () => {
104
+ const dir = setup({
105
+ changelog: BASE_CHANGELOG.replace("## Unreleased\n", "## Unreleased\n\n### Fixed\n\n- Manual fix.\n\n### Breaking (module authors only)\n\n- Manual break.\n"),
106
+ fragments: { "b.breaking.md": "- Fragment break.\n" },
107
+ });
108
+ const r = run(dir);
109
+ assert.equal(r.status, 0, r.stderr);
110
+ assert.equal(section(changelog(dir), "1.1.0"), "### Breaking (module authors only)\n\n- Manual break.\n\n- Fragment break.\n\n### Fixed\n\n- Manual fix.");
111
+ });
112
+ test("accepts nested bullets and multi-line continuations", () => {
113
+ const dir = setup({
114
+ fragments: { "n.fixed.md": "- one\n - nested\n more text\n- two\n" },
115
+ });
116
+ const r = run(dir);
117
+ assert.equal(r.status, 0, r.stderr);
118
+ assert.equal(section(changelog(dir), "1.1.0"), "### Fixed\n\n- one\n - nested\n more text\n- two");
119
+ });
120
+ test("accepts bullet content that merely resembles headings or rules", () => {
121
+ const body = "- **Module authors:** bold opener.\n- -1 is now the sentinel.\n- #123 is referenced inline.\n- ***emphasis*** then text.\n";
122
+ const dir = setup({ fragments: { "r.fixed.md": body } });
123
+ const r = run(dir);
124
+ assert.equal(r.status, 0, r.stderr);
125
+ assert.equal(section(changelog(dir), "1.1.0"), `### Fixed\n\n${body.trim()}`);
126
+ });
127
+ const refusals = [
128
+ ["nothing to release", {}, /nothing to release as 1\.1\.0/],
129
+ ["duplicate version section", { version: "1.0.0", fragments: { "a.fixed.md": "- x\n" } }, /'## 1\.0\.0' section already exists/],
130
+ ["unrecognized category suffix", { fragments: { "oops.md": "- x\n" } }, /changelog\.d\/oops\.md: unrecognized file/],
131
+ ["stray non-markdown file", { fragments: { "notes.txt": "hi\n", "a.fixed.md": "- x\n" } }, /changelog\.d\/notes\.txt: unrecognized file/],
132
+ ["empty fragment", { fragments: { "e.fixed.md": "\n" } }, /changelog\.d\/e\.fixed\.md: empty fragment/],
133
+ ["fragment nested under a branch-name directory", { fragments: { "fix/foo.fixed.md": "- x\n", "a.fixed.md": "- y\n" } }, /changelog\.d\/fix: not a file/],
134
+ ["plain prose", { fragments: { "p.fixed.md": "prose only\n" } }, /offending line: 'prose only'/],
135
+ ["prose after a valid bullet", { fragments: { "p.fixed.md": "- ok\nrogue prose\n" } }, /offending line: 'rogue prose'/],
136
+ ["top-level heading after a bullet", { fragments: { "h.fixed.md": "- ok\n\n## 9.9.9 — fake\n" } }, /offending line: '## 9\.9\.9 — fake'/],
137
+ ["indented ATX heading", { fragments: { "h.fixed.md": "- ok\n ## 8.8.8 — injected\n - beneath\n" } }, /offending line: ' ## 8\.8\.8 — injected'/],
138
+ ["indented setext underline / rule", { fragments: { "s.fixed.md": "- ok\n ---\n" } }, /offending line: ' ---'/],
139
+ ["spaced thematic break shaped like a bullet", { fragments: { "s.fixed.md": "- ok\n- - -\n" } }, /offending line: '- - -'/],
140
+ ["asterisk thematic break with spaces", { fragments: { "s.fixed.md": "- ok\n* * *\n" } }, /offending line: '\* \* \*'/],
141
+ ["rule as bullet content", { fragments: { "s.fixed.md": "- ---\n" } }, /offending line: '- ---'/],
142
+ ["heading as bullet content", { fragments: { "h.fixed.md": "- ## 9.9.9 — embedded heading\n" } }, /offending line: '- ## 9\.9\.9 — embedded heading'/],
143
+ ["heading as nested bullet content", { fragments: { "h.fixed.md": "- ok\n - ### nested heading\n" } }, /offending line: ' - ### nested heading'/],
144
+ ["tab-indented continuation", { fragments: { "t.fixed.md": "- ok\n\tcontinued\n" } }, /offending line: '\tcontinued'/],
145
+ ["no Unreleased heading", { changelog: "# Changelog\n\n## 1.0.0 — 2026-01-01\n\n- x\n", fragments: { "a.fixed.md": "- x\n" } }, /no '## Unreleased' section/],
146
+ ["two Unreleased headings", { changelog: BASE_CHANGELOG + "\n## Unreleased\n\n- stranded\n", fragments: { "a.fixed.md": "- x\n" } }, /2 '## Unreleased' headings/],
147
+ ];
148
+ for (const [name, fixture, message] of refusals) {
149
+ test(`refuses ${name} without touching anything`, () => {
150
+ const dir = setup(fixture);
151
+ const before = { changelog: changelog(dir), pending: pending(dir) };
152
+ const r = run(dir);
153
+ assert.equal(r.status, 1, `expected refusal, got exit ${r.status}:\n${r.stdout}${r.stderr}`);
154
+ assert.match(r.stderr, message);
155
+ assert.equal(changelog(dir), before.changelog, "CHANGELOG.md must be untouched");
156
+ assert.deepEqual(pending(dir), before.pending, "no fragment may be deleted on refusal");
157
+ });
158
+ }
159
+ //# sourceMappingURL=release-changelog.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"release-changelog.test.js","sourceRoot":"","sources":["../../test/release-changelog.test.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  * Oversized tool-result spill — completion coverage for issue #89.
3
3
  *
4
4
  * The mechanism (spill to workspace file + bounded preview) landed in
5
- * f231bbf; these tests pin the completion semantics: the house-safe 5000
5
+ * f231bbf; these tests pin the completion semantics: the house-safe 24000
6
6
  * default (no more 42k accidental ingests), the durable
7
7
  * FrameworkConfig.toolResultInlineMaxChars cap, hot-override provenance and
8
8
  * restart behavior, error results under the same policy, the explicit