@animalabs/agent-framework 0.6.10 → 0.7.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.
- package/dist/src/agent.d.ts +2 -0
- package/dist/src/agent.d.ts.map +1 -1
- package/dist/src/agent.js +3 -0
- package/dist/src/agent.js.map +1 -1
- package/dist/src/code-execution/index.d.ts +14 -0
- package/dist/src/code-execution/index.d.ts.map +1 -0
- package/dist/src/code-execution/index.js +13 -0
- package/dist/src/code-execution/index.js.map +1 -0
- package/dist/src/code-execution/py-runner.d.ts +91 -0
- package/dist/src/code-execution/py-runner.d.ts.map +1 -0
- package/dist/src/code-execution/py-runner.js +364 -0
- package/dist/src/code-execution/py-runner.js.map +1 -0
- package/dist/src/code-execution/runtime-py.d.ts +32 -0
- package/dist/src/code-execution/runtime-py.d.ts.map +1 -0
- package/dist/src/code-execution/runtime-py.js +265 -0
- package/dist/src/code-execution/runtime-py.js.map +1 -0
- package/dist/src/code-execution/tool-definition.d.ts +16 -0
- package/dist/src/code-execution/tool-definition.d.ts.map +1 -0
- package/dist/src/code-execution/tool-definition.js +45 -0
- package/dist/src/code-execution/tool-definition.js.map +1 -0
- package/dist/src/framework.d.ts +157 -15
- package/dist/src/framework.d.ts.map +1 -1
- package/dist/src/framework.js +1068 -104
- package/dist/src/framework.js.map +1 -1
- package/dist/src/index.d.ts +2 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/mcpl/channel-registry.d.ts +99 -7
- package/dist/src/mcpl/channel-registry.d.ts.map +1 -1
- package/dist/src/mcpl/channel-registry.js +374 -49
- package/dist/src/mcpl/channel-registry.js.map +1 -1
- package/dist/src/mcpl/prose-grammar.d.ts +24 -0
- package/dist/src/mcpl/prose-grammar.d.ts.map +1 -0
- package/dist/src/mcpl/prose-grammar.js +33 -0
- package/dist/src/mcpl/prose-grammar.js.map +1 -0
- package/dist/src/mcpl/prose-stream-router.d.ts +58 -0
- package/dist/src/mcpl/prose-stream-router.d.ts.map +1 -0
- package/dist/src/mcpl/prose-stream-router.js +168 -0
- package/dist/src/mcpl/prose-stream-router.js.map +1 -0
- package/dist/src/modules/workspace/index.d.ts.map +1 -1
- package/dist/src/modules/workspace/index.js +13 -4
- package/dist/src/modules/workspace/index.js.map +1 -1
- package/dist/src/types/agent.d.ts +17 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/framework.d.ts +33 -0
- package/dist/src/types/framework.d.ts.map +1 -1
- package/dist/src/types/trace.d.ts +32 -0
- package/dist/src/types/trace.d.ts.map +1 -1
- package/dist/test/channel-registry-routing.test.js +186 -10
- package/dist/test/channel-registry-routing.test.js.map +1 -1
- package/dist/test/code-execution.test.d.ts +11 -0
- package/dist/test/code-execution.test.d.ts.map +1 -0
- package/dist/test/code-execution.test.js +412 -0
- package/dist/test/code-execution.test.js.map +1 -0
- package/dist/test/explicit-prose-routing.test.d.ts +11 -0
- package/dist/test/explicit-prose-routing.test.d.ts.map +1 -0
- package/dist/test/explicit-prose-routing.test.js +247 -0
- package/dist/test/explicit-prose-routing.test.js.map +1 -0
- package/dist/test/present-while-acting.test.js +85 -8
- package/dist/test/present-while-acting.test.js.map +1 -1
- package/dist/test/prose-stream-router.test.d.ts +2 -0
- package/dist/test/prose-stream-router.test.d.ts.map +1 -0
- package/dist/test/prose-stream-router.test.js +87 -0
- package/dist/test/prose-stream-router.test.js.map +1 -0
- package/dist/test/trunk-channel-routing.test.js +2 -2
- package/dist/test/trunk-channel-routing.test.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/agent.ts +3 -0
- package/src/code-execution/index.ts +19 -0
- package/src/code-execution/py-runner.ts +433 -0
- package/src/code-execution/runtime-py.ts +265 -0
- package/src/code-execution/tool-definition.ts +52 -0
- package/src/framework.ts +1160 -107
- package/src/index.ts +17 -0
- package/src/mcpl/channel-registry.ts +454 -54
- package/src/mcpl/prose-grammar.ts +40 -0
- package/src/mcpl/prose-stream-router.ts +161 -0
- package/src/modules/workspace/index.ts +13 -4
- package/src/types/agent.ts +18 -0
- package/src/types/framework.ts +35 -0
- package/src/types/trace.ts +47 -1
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side programmatic tool calling (code_execution) tests.
|
|
3
|
+
*
|
|
4
|
+
* PyRunner tests spawn a REAL python3 subprocess — the protocol, top-level
|
|
5
|
+
* await, tool-function injection, timeout, and deadline behavior are all
|
|
6
|
+
* exercised end-to-end. Framework tests drive a full agent turn through the
|
|
7
|
+
* MockMembrane and assert the load-bearing invariant: inner tool results
|
|
8
|
+
* reach the running script but never the model-facing tool_result.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, it } from 'node:test';
|
|
11
|
+
import assert from 'node:assert';
|
|
12
|
+
import { mkdtempSync, rmSync } from 'node:fs';
|
|
13
|
+
import { tmpdir } from 'node:os';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
import { AgentFramework, PyRunner, buildInjectedTools } from '../src/index.js';
|
|
16
|
+
import { createMockResponse, MockMembrane } from './helpers/mock-membrane.js';
|
|
17
|
+
const ECHO_TOOLS = [
|
|
18
|
+
{ pyName: 'test__echo', toolName: 'test--echo' },
|
|
19
|
+
];
|
|
20
|
+
describe('buildInjectedTools', () => {
|
|
21
|
+
it('sanitizes -- to __ and keeps valid identifiers', () => {
|
|
22
|
+
const injected = buildInjectedTools(['mcpl--discord--send_message', 'think']);
|
|
23
|
+
assert.deepStrictEqual(injected, [
|
|
24
|
+
{ pyName: 'mcpl__discord__send_message', toolName: 'mcpl--discord--send_message' },
|
|
25
|
+
{ pyName: 'think', toolName: 'think' },
|
|
26
|
+
]);
|
|
27
|
+
});
|
|
28
|
+
it('skips names that do not sanitize to valid python identifiers', () => {
|
|
29
|
+
const logs = [];
|
|
30
|
+
const injected = buildInjectedTools(['bad-name', 'ok_name'], (m) => logs.push(m));
|
|
31
|
+
assert.deepStrictEqual(injected, [{ pyName: 'ok_name', toolName: 'ok_name' }]);
|
|
32
|
+
assert.strictEqual(logs.length, 1);
|
|
33
|
+
assert.match(logs[0], /bad-name/);
|
|
34
|
+
});
|
|
35
|
+
it('skips colliding sanitized names loudly (first wins)', () => {
|
|
36
|
+
const logs = [];
|
|
37
|
+
const injected = buildInjectedTools(['a--b', 'a__b'], (m) => logs.push(m));
|
|
38
|
+
assert.deepStrictEqual(injected, [{ pyName: 'a__b', toolName: 'a--b' }]);
|
|
39
|
+
assert.strictEqual(logs.length, 1);
|
|
40
|
+
assert.match(logs[0], /collides/);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
describe('PyRunner (real python3)', () => {
|
|
44
|
+
it('runs a script and returns stdout', async () => {
|
|
45
|
+
const runner = new PyRunner({ onToolCall: async () => '' });
|
|
46
|
+
try {
|
|
47
|
+
const result = await runner.exec('print("hello from python")', []);
|
|
48
|
+
assert.strictEqual(result.returnCode, 0);
|
|
49
|
+
assert.match(result.stdout, /hello from python/);
|
|
50
|
+
assert.strictEqual(result.stderr, '');
|
|
51
|
+
}
|
|
52
|
+
finally {
|
|
53
|
+
runner.dispose();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
it('round-trips a tool call as an awaited async function', async () => {
|
|
57
|
+
const calls = [];
|
|
58
|
+
const runner = new PyRunner({
|
|
59
|
+
onToolCall: async (name, args) => {
|
|
60
|
+
calls.push({ name, args });
|
|
61
|
+
return JSON.stringify({ echoed: args });
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
try {
|
|
65
|
+
const result = await runner.exec([
|
|
66
|
+
'import json',
|
|
67
|
+
'r = json.loads(await test__echo({"message": "alpha"}))',
|
|
68
|
+
'print("echoed:", r["echoed"]["message"])',
|
|
69
|
+
].join('\n'), ECHO_TOOLS);
|
|
70
|
+
assert.strictEqual(result.returnCode, 0, result.stderr);
|
|
71
|
+
assert.match(result.stdout, /echoed: alpha/);
|
|
72
|
+
assert.deepStrictEqual(calls, [{ name: 'test--echo', args: { message: 'alpha' } }]);
|
|
73
|
+
}
|
|
74
|
+
finally {
|
|
75
|
+
runner.dispose();
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
it('supports the exact-name tools[...] escape hatch', async () => {
|
|
79
|
+
const runner = new PyRunner({
|
|
80
|
+
onToolCall: async (_name, args) => `got:${String(args.v)}`,
|
|
81
|
+
});
|
|
82
|
+
try {
|
|
83
|
+
const result = await runner.exec('print(await tools["test--echo"]({"v": 7}))', ECHO_TOOLS);
|
|
84
|
+
assert.strictEqual(result.returnCode, 0, result.stderr);
|
|
85
|
+
assert.match(result.stdout, /got:7/);
|
|
86
|
+
}
|
|
87
|
+
finally {
|
|
88
|
+
runner.dispose();
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
it('runs parallel tool calls via asyncio.gather', async () => {
|
|
92
|
+
let inFlight = 0;
|
|
93
|
+
let maxInFlight = 0;
|
|
94
|
+
const runner = new PyRunner({
|
|
95
|
+
onToolCall: async (_name, args) => {
|
|
96
|
+
inFlight++;
|
|
97
|
+
maxInFlight = Math.max(maxInFlight, inFlight);
|
|
98
|
+
await new Promise((r) => setTimeout(r, 150));
|
|
99
|
+
inFlight--;
|
|
100
|
+
return String(args.i);
|
|
101
|
+
},
|
|
102
|
+
});
|
|
103
|
+
try {
|
|
104
|
+
const result = await runner.exec([
|
|
105
|
+
'import asyncio',
|
|
106
|
+
'results = await asyncio.gather(*(test__echo({"i": i}) for i in range(3)))',
|
|
107
|
+
'print(",".join(results))',
|
|
108
|
+
].join('\n'), ECHO_TOOLS);
|
|
109
|
+
assert.strictEqual(result.returnCode, 0, result.stderr);
|
|
110
|
+
assert.match(result.stdout, /0,1,2/);
|
|
111
|
+
assert.ok(maxInFlight >= 2, `expected parallel dispatch, max in flight was ${maxInFlight}`);
|
|
112
|
+
}
|
|
113
|
+
finally {
|
|
114
|
+
runner.dispose();
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
it('persists interpreter state across execs (container-reuse semantics)', async () => {
|
|
118
|
+
const runner = new PyRunner({ onToolCall: async () => '' });
|
|
119
|
+
try {
|
|
120
|
+
const first = await runner.exec('x = 41', []);
|
|
121
|
+
assert.strictEqual(first.returnCode, 0, first.stderr);
|
|
122
|
+
const second = await runner.exec('print(x + 1)', []);
|
|
123
|
+
assert.strictEqual(second.returnCode, 0, second.stderr);
|
|
124
|
+
assert.match(second.stdout, /42/);
|
|
125
|
+
}
|
|
126
|
+
finally {
|
|
127
|
+
runner.dispose();
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
it('reports script exceptions as a traceback with return_code 1', async () => {
|
|
131
|
+
const runner = new PyRunner({ onToolCall: async () => '' });
|
|
132
|
+
try {
|
|
133
|
+
const result = await runner.exec('raise ValueError("boom")', []);
|
|
134
|
+
assert.strictEqual(result.returnCode, 1);
|
|
135
|
+
assert.match(result.stderr, /ValueError: boom/);
|
|
136
|
+
assert.match(result.stderr, /Traceback/);
|
|
137
|
+
}
|
|
138
|
+
finally {
|
|
139
|
+
runner.dispose();
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
it('delivers tool errors as plain strings the script can handle', async () => {
|
|
143
|
+
const runner = new PyRunner({
|
|
144
|
+
onToolCall: async () => 'Error: Query timeout - table lock exceeded',
|
|
145
|
+
});
|
|
146
|
+
try {
|
|
147
|
+
const result = await runner.exec([
|
|
148
|
+
'r = await test__echo({})',
|
|
149
|
+
'if r.startswith("Error:"):',
|
|
150
|
+
' print("handled:", r)',
|
|
151
|
+
].join('\n'), ECHO_TOOLS);
|
|
152
|
+
assert.strictEqual(result.returnCode, 0, result.stderr);
|
|
153
|
+
assert.match(result.stdout, /handled: Error: Query timeout/);
|
|
154
|
+
}
|
|
155
|
+
finally {
|
|
156
|
+
runner.dispose();
|
|
157
|
+
}
|
|
158
|
+
});
|
|
159
|
+
it('raises TimeoutError inside the script when a tool call gets no response', async () => {
|
|
160
|
+
const runner = new PyRunner({
|
|
161
|
+
toolCallTimeoutMs: 1000,
|
|
162
|
+
onToolCall: () => new Promise((resolve) => setTimeout(() => resolve('late'), 5000)),
|
|
163
|
+
});
|
|
164
|
+
try {
|
|
165
|
+
const result = await runner.exec('await test__echo({})', ECHO_TOOLS);
|
|
166
|
+
assert.strictEqual(result.returnCode, 1);
|
|
167
|
+
assert.match(result.stderr, /TimeoutError: Calling tool \['test--echo'\] timed out/);
|
|
168
|
+
}
|
|
169
|
+
finally {
|
|
170
|
+
runner.dispose();
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
it('cancels a script that exceeds the deadline', async () => {
|
|
174
|
+
const runner = new PyRunner({
|
|
175
|
+
scriptTimeoutMs: 1000,
|
|
176
|
+
onToolCall: async () => '',
|
|
177
|
+
});
|
|
178
|
+
try {
|
|
179
|
+
const started = Date.now();
|
|
180
|
+
const result = await runner.exec('import asyncio\nawait asyncio.sleep(60)', []);
|
|
181
|
+
assert.strictEqual(result.returnCode, 1);
|
|
182
|
+
assert.match(result.stderr, /cancelled by host/);
|
|
183
|
+
assert.ok(Date.now() - started < 15_000, 'deadline cancel took too long');
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
runner.dispose();
|
|
187
|
+
}
|
|
188
|
+
});
|
|
189
|
+
it('abort() settles a running script and reclaims the interpreter', async () => {
|
|
190
|
+
const runner = new PyRunner({ onToolCall: async () => '' });
|
|
191
|
+
try {
|
|
192
|
+
const pending = runner.exec('import asyncio\nawait asyncio.sleep(60)', []);
|
|
193
|
+
// Let the exec actually start before aborting.
|
|
194
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
195
|
+
assert.strictEqual(runner.busy, true);
|
|
196
|
+
runner.abort('test abort');
|
|
197
|
+
const result = await pending;
|
|
198
|
+
assert.strictEqual(result.aborted, true);
|
|
199
|
+
assert.match(result.stderr, /aborted by host: test abort/);
|
|
200
|
+
// Runner remains usable after reclaim (fresh interpreter, state gone).
|
|
201
|
+
const after = await runner.exec('print("alive")', []);
|
|
202
|
+
assert.strictEqual(after.returnCode, 0, after.stderr);
|
|
203
|
+
assert.match(after.stdout, /alive/);
|
|
204
|
+
}
|
|
205
|
+
finally {
|
|
206
|
+
runner.dispose();
|
|
207
|
+
}
|
|
208
|
+
});
|
|
209
|
+
it('rejects concurrent execs on one runner', async () => {
|
|
210
|
+
const runner = new PyRunner({ onToolCall: async () => '' });
|
|
211
|
+
try {
|
|
212
|
+
const first = runner.exec('import asyncio\nawait asyncio.sleep(2)', []);
|
|
213
|
+
await new Promise((r) => setTimeout(r, 300));
|
|
214
|
+
const second = await runner.exec('print("nope")', []);
|
|
215
|
+
assert.strictEqual(second.returnCode, 1);
|
|
216
|
+
assert.match(second.stderr, /already running/);
|
|
217
|
+
runner.abort('cleanup');
|
|
218
|
+
await first;
|
|
219
|
+
}
|
|
220
|
+
finally {
|
|
221
|
+
runner.dispose();
|
|
222
|
+
}
|
|
223
|
+
});
|
|
224
|
+
it('fails gracefully when the python binary is missing', async () => {
|
|
225
|
+
const runner = new PyRunner({
|
|
226
|
+
pythonPath: '/definitely/not/a/python',
|
|
227
|
+
onToolCall: async () => '',
|
|
228
|
+
});
|
|
229
|
+
try {
|
|
230
|
+
const result = await runner.exec('print(1)', []);
|
|
231
|
+
assert.strictEqual(result.returnCode, 1);
|
|
232
|
+
assert.match(result.stderr, /Failed to start python runtime|exited before becoming ready/);
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
runner.dispose();
|
|
236
|
+
}
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
// ---------------------------------------------------------------------------
|
|
240
|
+
// Framework integration
|
|
241
|
+
// ---------------------------------------------------------------------------
|
|
242
|
+
class ScriptToolModule {
|
|
243
|
+
name = 'test';
|
|
244
|
+
calls = [];
|
|
245
|
+
async start(_ctx) { }
|
|
246
|
+
async stop() { }
|
|
247
|
+
getTools() {
|
|
248
|
+
return [
|
|
249
|
+
{
|
|
250
|
+
name: 'echo',
|
|
251
|
+
description: 'Echo input. Returns JSON: {"echoed": <input>}.',
|
|
252
|
+
inputSchema: { type: 'object', properties: { message: { type: 'string' } } },
|
|
253
|
+
},
|
|
254
|
+
{
|
|
255
|
+
name: 'finish',
|
|
256
|
+
description: 'End the turn.',
|
|
257
|
+
inputSchema: { type: 'object', properties: {} },
|
|
258
|
+
},
|
|
259
|
+
];
|
|
260
|
+
}
|
|
261
|
+
async handleToolCall(call) {
|
|
262
|
+
this.calls.push(call);
|
|
263
|
+
const baseName = call.name.includes('--')
|
|
264
|
+
? call.name.slice(call.name.lastIndexOf('--') + 2)
|
|
265
|
+
: call.name;
|
|
266
|
+
if (baseName === 'finish') {
|
|
267
|
+
return { success: true, data: { finished: true }, endTurn: true };
|
|
268
|
+
}
|
|
269
|
+
return { success: true, data: { echoed: call.input } };
|
|
270
|
+
}
|
|
271
|
+
async onProcess(_event, _state) {
|
|
272
|
+
return {};
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
function tempStorePath(prefix) {
|
|
276
|
+
const tempDir = mkdtempSync(join(tmpdir(), prefix));
|
|
277
|
+
return { tempDir, storePath: join(tempDir, 'store.chronicle') };
|
|
278
|
+
}
|
|
279
|
+
async function createFrameworkWithCodeExecution(storePath, membrane, module) {
|
|
280
|
+
return AgentFramework.create({
|
|
281
|
+
storePath,
|
|
282
|
+
membrane: membrane.asMembrane(),
|
|
283
|
+
agents: [],
|
|
284
|
+
modules: [module],
|
|
285
|
+
syncIntervalMs: 0,
|
|
286
|
+
codeExecution: { enabled: true },
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
describe('framework code_execution integration (real python3)', () => {
|
|
290
|
+
it('synthesizes the tool only when enabled', async () => {
|
|
291
|
+
const { tempDir, storePath } = tempStorePath('pytc-tools-');
|
|
292
|
+
const membrane = new MockMembrane();
|
|
293
|
+
const framework = await AgentFramework.create({
|
|
294
|
+
storePath,
|
|
295
|
+
membrane: membrane.asMembrane(),
|
|
296
|
+
agents: [],
|
|
297
|
+
modules: [new ScriptToolModule()],
|
|
298
|
+
syncIntervalMs: 0,
|
|
299
|
+
});
|
|
300
|
+
try {
|
|
301
|
+
assert.ok(!framework.getAllTools().some((t) => t.name === 'code_execution'));
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
await framework.stop();
|
|
305
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
306
|
+
}
|
|
307
|
+
const { tempDir: tempDir2, storePath: storePath2 } = tempStorePath('pytc-tools2-');
|
|
308
|
+
const membrane2 = new MockMembrane();
|
|
309
|
+
const framework2 = await createFrameworkWithCodeExecution(storePath2, membrane2, new ScriptToolModule());
|
|
310
|
+
try {
|
|
311
|
+
const tool = framework2.getAllTools().find((t) => t.name === 'code_execution');
|
|
312
|
+
assert.ok(tool, 'code_execution tool should be synthesized');
|
|
313
|
+
assert.match(tool.description, /async Python function/);
|
|
314
|
+
assert.match(tool.description, /__/);
|
|
315
|
+
}
|
|
316
|
+
finally {
|
|
317
|
+
await framework2.stop();
|
|
318
|
+
rmSync(tempDir2, { recursive: true, force: true });
|
|
319
|
+
}
|
|
320
|
+
});
|
|
321
|
+
it('runs a script that calls module tools; intermediates never reach the model', async () => {
|
|
322
|
+
const { tempDir, storePath } = tempStorePath('pytc-run-');
|
|
323
|
+
const membrane = new MockMembrane();
|
|
324
|
+
const module = new ScriptToolModule();
|
|
325
|
+
const code = [
|
|
326
|
+
'import json',
|
|
327
|
+
'names = []',
|
|
328
|
+
'for m in ["alpha", "beta"]:',
|
|
329
|
+
' r = json.loads(await test__echo({"message": m}))',
|
|
330
|
+
' names.append(r["echoed"]["message"].upper())',
|
|
331
|
+
'print("summary:", "+".join(names))',
|
|
332
|
+
].join('\n');
|
|
333
|
+
membrane.pushResponse(createMockResponse([
|
|
334
|
+
{ type: 'text', text: 'Let me fan out.' },
|
|
335
|
+
{ type: 'tool_use', id: 'call_ce_1', name: 'code_execution', input: { code } },
|
|
336
|
+
], 'tool_use'));
|
|
337
|
+
membrane.pushResponse(createMockResponse([
|
|
338
|
+
{ type: 'text', text: 'Final answer.' },
|
|
339
|
+
]));
|
|
340
|
+
const framework = await createFrameworkWithCodeExecution(storePath, membrane, module);
|
|
341
|
+
try {
|
|
342
|
+
const created = await framework.createEphemeralAgent({
|
|
343
|
+
name: 'worker',
|
|
344
|
+
model: 'test-model',
|
|
345
|
+
systemPrompt: 'Do the task.',
|
|
346
|
+
allowedTools: 'all',
|
|
347
|
+
});
|
|
348
|
+
created.contextManager.addMessage('user', [{ type: 'text', text: 'Go.' }]);
|
|
349
|
+
const promise = framework.runEphemeralToCompletion(created.agent, created.contextManager);
|
|
350
|
+
framework.start();
|
|
351
|
+
const result = await promise;
|
|
352
|
+
assert.strictEqual(result.speech, 'Final answer.');
|
|
353
|
+
// The module saw both inner calls, dispatched with pytc- IDs (waiter
|
|
354
|
+
// path), not the model's call ID.
|
|
355
|
+
const echoCalls = module.calls.filter((c) => c.name.endsWith('--echo') || c.name === 'echo');
|
|
356
|
+
assert.strictEqual(echoCalls.length, 2);
|
|
357
|
+
for (const call of echoCalls) {
|
|
358
|
+
assert.match(String(call.id), /^pytc-/);
|
|
359
|
+
}
|
|
360
|
+
// The model-facing tool_result carries the script's stdout...
|
|
361
|
+
const stream = membrane.lastStream;
|
|
362
|
+
assert.strictEqual(stream.receivedToolResults.length, 1);
|
|
363
|
+
const wireResult = stream.receivedToolResults[0][0];
|
|
364
|
+
assert.strictEqual(wireResult.toolUseId, 'call_ce_1');
|
|
365
|
+
assert.match(wireResult.content, /summary: ALPHA\+BETA/);
|
|
366
|
+
assert.match(wireResult.content, /"return_code":\s*0/);
|
|
367
|
+
// ...and NOT the intermediate tool results.
|
|
368
|
+
assert.ok(!wireResult.content.includes('"echoed"'), 'intermediate tool results must not reach the model-facing result');
|
|
369
|
+
}
|
|
370
|
+
finally {
|
|
371
|
+
await framework.stop();
|
|
372
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
it('defers endTurn from inner calls to the code_execution result', async () => {
|
|
376
|
+
const { tempDir, storePath } = tempStorePath('pytc-endturn-');
|
|
377
|
+
const membrane = new MockMembrane();
|
|
378
|
+
const module = new ScriptToolModule();
|
|
379
|
+
const code = [
|
|
380
|
+
'r = await test__finish({})',
|
|
381
|
+
'print("after finish:", r)',
|
|
382
|
+
].join('\n');
|
|
383
|
+
membrane.pushResponse(createMockResponse([
|
|
384
|
+
{ type: 'text', text: 'Finishing via script.' },
|
|
385
|
+
{ type: 'tool_use', id: 'call_ce_2', name: 'code_execution', input: { code } },
|
|
386
|
+
], 'tool_use'));
|
|
387
|
+
// No further response: endTurn must settle the turn without another round.
|
|
388
|
+
const framework = await createFrameworkWithCodeExecution(storePath, membrane, module);
|
|
389
|
+
try {
|
|
390
|
+
const created = await framework.createEphemeralAgent({
|
|
391
|
+
name: 'finisher',
|
|
392
|
+
model: 'test-model',
|
|
393
|
+
systemPrompt: 'Finish.',
|
|
394
|
+
allowedTools: 'all',
|
|
395
|
+
});
|
|
396
|
+
created.contextManager.addMessage('user', [{ type: 'text', text: 'Wrap up.' }]);
|
|
397
|
+
const promise = framework.runEphemeralToCompletion(created.agent, created.contextManager);
|
|
398
|
+
framework.start();
|
|
399
|
+
const result = await promise;
|
|
400
|
+
// The script ran to completion (endTurn was deferred, not applied
|
|
401
|
+
// mid-script), and the turn then ended without another model round.
|
|
402
|
+
const finishCalls = module.calls.filter((c) => c.name.endsWith('--finish') || c.name === 'finish');
|
|
403
|
+
assert.strictEqual(finishCalls.length, 1);
|
|
404
|
+
assert.strictEqual(result.toolCallsCount, 1); // one model-visible call: code_execution
|
|
405
|
+
}
|
|
406
|
+
finally {
|
|
407
|
+
await framework.stop();
|
|
408
|
+
rmSync(tempDir, { recursive: true, force: true });
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
});
|
|
412
|
+
//# sourceMappingURL=code-execution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"code-execution.test.js","sourceRoot":"","sources":["../../test/code-execution.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit prose routing (docs/explicit-prose-routing.md).
|
|
3
|
+
*
|
|
4
|
+
* The model names every destination in-band (`>>` prefixes); unprefixed prose
|
|
5
|
+
* is NEVER delivered — it bounces to a clipboard for a prefixed resend. The
|
|
6
|
+
* laria regression (2026-07-24): a DM reply generated while the host-inferred
|
|
7
|
+
* locus pointed at a guild channel was misdelivered there. In explicit mode
|
|
8
|
+
* that class is structurally impossible: the worst case is a bounce.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=explicit-prose-routing.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"explicit-prose-routing.test.d.ts","sourceRoot":"","sources":["../../test/explicit-prose-routing.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|