blob: 240a11c2b35a638613c8efb00b6056e90267f907 [file]
import assert from 'node:assert/strict';
import test from 'node:test';
import type { LanguageModelV4StreamPart, LanguageModelV4Usage } from '@ai-sdk/provider';
import {
createExternalExecutionBoundary,
createManagedExecutionBoundary,
createWorkspaceWritePermissionProfile,
type LlmConnection,
type SandboxBoundaryRequest,
type SessionEvent,
type SessionHeader,
} from '@maka/core';
import { MockLanguageModelV4, convertArrayToReadableStream } from 'ai/test';
import { z } from 'zod';
import type { AiSdkBackendInput } from '../ai-sdk-backend.js';
import { buildMcpTools } from '../mcp-tools.js';
import type { ToolArtifactRecorderInput } from '../tool-artifacts.js';
import type { MakaTool } from '../tool-runtime.js';
import type { RuntimeCommitSink, ToolPreparedCommit } from '../runtime-commit-sink.js';
import { createTestAiSdkBackend } from './execution-boundary-test-helpers.js';
const ZERO_USAGE: LanguageModelV4Usage = {
inputTokens: { total: 0, noCache: 0, cacheRead: 0, cacheWrite: 0 },
outputTokens: { total: 0, text: 0, reasoning: 0 },
};
test('adds exec only for the explicit code_mode provider surface', async () => {
const directSurface: string[][] = [];
const codeSurface: string[][] = [];
await drain(
backend(capturingModel(directSurface)).send({
turnId: 'turn-direct',
text: 'inspect',
context: [],
}),
);
await drain(
backend(capturingModel(codeSurface)).send({
turnId: 'turn-code',
text: 'inspect',
context: [],
toolMode: 'code_mode',
}),
);
assert.deepEqual(directSurface[0], ['lookup']);
assert.deepEqual(codeSurface[0], ['exec', 'lookup']);
});
test('allows a custom exec tool in direct mode', async () => {
const surface: string[][] = [];
await drain(
backend(capturingModel(surface), [], undefined, {
tools: [
{
name: 'exec',
description: 'caller tool',
parameters: z.object({}),
impl: () => null,
},
],
}).send({ turnId: 'turn-direct-exec', text: 'inspect', context: [], toolMode: 'direct' }),
);
assert.deepEqual(surface[0], ['exec']);
});
test('rejects an invalid runtime tool mode instead of enabling Code Mode', async () => {
await assert.rejects(
drain(
backend(capturingModel([])).send({
turnId: 'turn-invalid-mode',
text: 'inspect',
context: [],
toolMode: 'legacy_mode' as never,
}),
),
/invalid tool mode/i,
);
});
test('keeps the default and explicit direct provider surfaces byte-identical', async () => {
const captured: string[] = [];
const model = () =>
new MockLanguageModelV4({
doStream: async ({ tools }) => {
captured.push(JSON.stringify(tools ?? []));
return {
stream: convertArrayToReadableStream<LanguageModelV4StreamPart>([
{ type: 'stream-start', warnings: [] },
{
type: 'finish',
finishReason: { unified: 'stop', raw: 'stop' },
usage: ZERO_USAGE,
},
]),
};
},
});
await drain(backend(model()).send({ turnId: 'turn-default', text: 'inspect', context: [] }));
await drain(
backend(model()).send({
turnId: 'turn-direct',
text: 'inspect',
context: [],
toolMode: 'direct',
}),
);
assert.equal(captured[0], captured[1]);
});
test('denies a nested MCP call before invoking its provider', async () => {
const boundary = createManagedExecutionBoundary(createWorkspaceWritePermissionProfile(), 0);
let pendingRequest: SandboxBoundaryRequest | undefined;
let providerCalls = 0;
const tools = buildMcpTools({
tools: () => [
{
serverId: 'catalog',
name: 'lookup',
inputSchema: { type: 'object' },
},
],
callTool: async () => {
providerCalls += 1;
return { content: [] };
},
});
const instance = backend(
execThenStopModel('return await tools.mcp__catalog__lookup({ id: "mcp-1" })'),
[],
undefined,
{
tools,
readExecutionBoundary: async () => boundary,
createSandboxBoundaryRequest: async (input) => {
pendingRequest = {
...input,
status: 'pending',
baseRevision: 0,
createdAt: 1,
};
return pendingRequest;
},
settleSandboxBoundaryRequest: async () => {
assert.ok(pendingRequest);
return {
request: { ...pendingRequest, status: 'denied', settledAt: 2 },
boundary,
changed: false,
};
},
},
);
const iterator = instance
.send({
turnId: 'turn-code',
text: 'look it up through MCP',
context: [],
toolMode: 'code_mode',
})
[Symbol.asyncIterator]();
let request: Extract<SessionEvent, { type: 'sandbox_boundary_request' }> | undefined;
while (!request) {
const item = await iterator.next();
assert.equal(item.done, false, 'nested MCP call completed without requesting network access');
if (item.value.type === 'sandbox_boundary_request') request = item.value;
}
await instance.respondToSandboxBoundary({ requestId: request.requestId, decision: 'deny' });
for (;;) {
const item = await iterator.next();
if (item.done) break;
}
assert.equal(providerCalls, 0);
});
test('routes a nested cell call back through ToolRuntime', async () => {
const implementationCalls: unknown[] = [];
const events = await collect(
backend(execThenStopModel(), implementationCalls).send({
turnId: 'turn-code',
text: 'look it up',
context: [],
toolMode: 'code_mode',
}),
);
assert.deepEqual(implementationCalls, [{ id: 'nested' }]);
assert.deepEqual(
events
.filter(
(event): event is Extract<SessionEvent, { type: 'tool_start' }> =>
event.type === 'tool_start',
)
.map((event) => event.toolName),
['exec', 'lookup'],
);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.ok(execResult);
assert.match(JSON.stringify(execResult.content), /"ok":true/);
});
test('does not materialize hidden nested image results', async () => {
let attachmentReads = 0;
const imageTool: MakaTool = {
name: 'read_image',
description: 'Read an image',
parameters: z.object({}),
impl: () => ({
kind: 'image' as const,
mimeType: 'image/png',
ref: { kind: 'session_file' as const, sessionId: 'session-1', relativePath: 'image.png' },
}),
};
const events = await collect(
backend(execThenStopModel('return await tools.read_image({})'), [], undefined, {
tools: [imageTool],
supportsVision: true,
readAttachmentBytes: async () => {
attachmentReads += 1;
return { ok: true, bytes: new Uint8Array([1]) };
},
}).send({
turnId: 'turn-code',
text: 'read it',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(attachmentReads, 0);
assert.ok(events.some((event) => event.type === 'tool_result' && event.toolUseId === 'exec-1'));
});
test('links nested activity to the durable outer exec operation', async () => {
const prepared: ToolPreparedCommit[] = [];
let seq = 0;
const sink: RuntimeCommitSink = {
commitToolPrepared: async (input) => {
prepared.push(input);
return { created: true, runtimeEventSeq: ++seq };
},
commitToolOutcome: async () => ({ created: true, runtimeEventSeq: ++seq }),
};
const events = await collect(
backend(execThenStopModel(), [], sink).send({
invocationId: 'inv-1',
runId: 'run-1',
turnId: 'turn-code',
text: 'look it up',
context: [],
toolMode: 'code_mode',
}),
);
const starts = events.filter(
(event): event is Extract<SessionEvent, { type: 'tool_start' }> => event.type === 'tool_start',
);
const outer = starts.find((event) => event.toolName === 'exec');
const nested = starts.find((event) => event.toolName === 'lookup');
const nestedDurable = prepared.find((commit) => commit.toolName === 'lookup')?.runtimeEvent;
assert.ok(outer?.operationId);
assert.equal(nested?.parentOperationId, outer.operationId);
assert.equal(nestedDurable?.refs?.parentOperationId, outer.operationId);
assert.equal(nestedDurable?.refs?.parentToolCallId, 'exec-1');
assert.equal(nestedDurable?.modelVisibility, 'hidden');
});
test('propagates nested durable commit failures out of the outer exec', async () => {
const outcomes: number[] = [];
const sink: RuntimeCommitSink = {
commitToolPrepared: async (input) => {
if (input.toolName === 'lookup') throw new Error('nested T1 unavailable');
return { created: true, runtimeEventSeq: 1 };
},
commitToolOutcome: async () => {
outcomes.push(1);
return { created: true, runtimeEventSeq: 2 };
},
};
const events = await collect(
backend(execThenStopModel(), [], sink).send({
invocationId: 'inv-1',
runId: 'run-1',
turnId: 'turn-code',
text: 'look it up',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(
events.some((event) => event.type === 'error' && event.recoverable === false),
true,
);
assert.equal(
events.some((event) => event.type === 'tool_result' && event.toolUseId === 'exec-1'),
false,
);
assert.deepEqual(outcomes, []);
});
test('keeps direct-only tools out of the cell snapshot', async () => {
let implementationCalls = 0;
const tools: MakaTool[] = [
{
name: 'secret_control',
description: 'Direct control tool',
parameters: z.object({}),
nesting: 'direct_only',
impl: () => {
implementationCalls += 1;
return { exposed: true };
},
},
];
const events = await collect(
backend(execThenStopModel('return await tools.secret_control({})'), [], undefined, {
tools,
}).send({
turnId: 'turn-code',
text: 'try direct control',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(implementationCalls, 0);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.match(JSON.stringify(execResult?.content), /unknown_tool/);
});
test('keeps provider-native tools out of the cell snapshot', async () => {
let implementationCalls = 0;
const tools: MakaTool[] = [
{
name: 'native_search',
description: 'Search through the model provider',
parameters: z.object({}),
providerTool: { kind: 'openai-web-search' },
impl: () => {
implementationCalls += 1;
return { exposed: true };
},
},
];
const events = await collect(
backend(execThenStopModel('return await tools.native_search({})'), [], undefined, {
tools,
}).send({
turnId: 'turn-code',
text: 'try native search',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(implementationCalls, 0);
assert.equal(
events.some((event) => event.type === 'tool_start' && event.toolName === 'native_search'),
false,
);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.match(JSON.stringify(execResult?.content), /unknown_tool/);
});
test('validates nested arguments before ToolRuntime implementation dispatch', async () => {
let implementationCalls = 0;
const tools: MakaTool[] = [
{
name: 'typed_lookup',
description: 'Look up a typed node',
parameters: z.object({ id: z.string() }),
impl: () => {
implementationCalls += 1;
return { ok: true };
},
},
];
const events = await collect(
backend(execThenStopModel('return await tools.typed_lookup({ id: 42 })'), [], undefined, {
tools,
}).send({
turnId: 'turn-code',
text: 'use invalid arguments',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(implementationCalls, 0);
assert.equal(
events.some((event) => event.type === 'tool_start' && event.toolName === 'typed_lookup'),
false,
);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.match(JSON.stringify(execResult?.content), /invalid arguments/i);
});
test('routes active MCP tools through the nested Runtime path', async () => {
const calls: Array<{
serverId: string;
toolName: string;
input: unknown;
signal: AbortSignal | undefined;
}> = [];
const tools = buildMcpTools({
tools: () => [
{
serverId: 'catalog',
name: 'lookup',
description: 'Look up a catalog item',
inputSchema: {
$schema: 'https://json-schema.org/draft/2020-12/schema',
type: 'object',
properties: { id: { type: 'string' } },
},
},
],
callTool: async (serverId, toolName, input, options) => {
calls.push({ serverId, toolName, input, signal: options?.signal });
return { content: [{ type: 'text', text: 'ok' }], structuredContent: { id: input.id } };
},
});
const events = await collect(
backend(
execThenStopModel('return await tools.mcp__catalog__lookup({ id: "mcp-1" })'),
[],
undefined,
{ tools },
).send({
turnId: 'turn-code',
text: 'look it up through MCP',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(calls.length, 1);
assert.deepEqual(calls[0] && { ...calls[0], signal: undefined }, {
serverId: 'catalog',
toolName: 'lookup',
input: { id: 'mcp-1' },
signal: undefined,
});
assert.ok(calls[0]?.signal instanceof AbortSignal);
assert.ok(
events.some(
(event) => event.type === 'tool_start' && event.toolName === 'mcp__catalog__lookup',
),
);
});
test('rejects invalid MCP arguments before nested Runtime dispatch', async () => {
let implementationCalls = 0;
const tools = buildMcpTools({
tools: () => [
{
serverId: 'catalog',
name: 'lookup',
description: 'Look up a catalog item',
inputSchema: {
$schema: 'https://json-schema.org/draft-07/schema#',
type: 'object',
properties: { id: { type: 'string' } },
required: ['id'],
additionalProperties: false,
},
},
],
callTool: async () => {
implementationCalls += 1;
return { content: [{ type: 'text', text: 'unexpected' }] };
},
});
const events = await collect(
backend(
execThenStopModel('return await tools.mcp__catalog__lookup({ id: 42 })'),
[],
undefined,
{ tools },
).send({
turnId: 'turn-code',
text: 'use invalid MCP arguments',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(implementationCalls, 0);
assert.equal(
events.some(
(event) => event.type === 'tool_start' && event.toolName === 'mcp__catalog__lookup',
),
false,
);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.match(JSON.stringify(execResult?.content), /invalid arguments/i);
});
test('records artifacts produced by a nested tool', async () => {
const artifacts: ToolArtifactRecorderInput[] = [];
const tools: MakaTool[] = [
{
name: 'Write',
description: 'Write a file',
parameters: z.object({ path: z.string(), content: z.string() }),
impl: (input: { path: string }) => ({ path: input.path, bytes: 2 }),
},
];
await collect(
backend(
execThenStopModel('return await tools.Write({ path: "/tmp/maka/out.txt", content: "ok" })'),
[],
undefined,
{
tools,
recordToolArtifacts: (input) => {
artifacts.push(input);
},
},
).send({
turnId: 'turn-code',
text: 'write it',
context: [],
toolMode: 'code_mode',
}),
);
assert.equal(artifacts.length, 1);
assert.equal(artifacts[0]?.toolName, 'Write');
assert.equal(artifacts[0]?.candidates[0]?.sourcePath, '/tmp/maka/out.txt');
});
test('parks a nested sandbox request and settles the outer exec after denial', async () => {
let pendingRequest: SandboxBoundaryRequest | undefined;
let sideEffects = 0;
const tools: MakaTool[] = [
{
name: 'network_task',
description: 'Request network authority',
parameters: z.object({}),
categoryHint: 'network_send',
impl: async (_input, context) => {
assert.ok(context.requestSandboxBoundary);
const result = await context.requestSandboxBoundary(
{ network: { enabled: true } },
'Fetch the requested catalog record.',
);
if (result.request.status !== 'approved') return result;
sideEffects += 1;
return result;
},
},
];
const instance = backend(
execThenStopModel('return await tools.network_task({})'),
[],
undefined,
{
tools,
createSandboxBoundaryRequest: async (input) => {
pendingRequest = {
...input,
status: 'pending',
baseRevision: 0,
createdAt: 1,
};
return pendingRequest;
},
settleSandboxBoundaryRequest: async (input) => {
assert.ok(pendingRequest);
return {
request: {
...pendingRequest,
status: input.decision === 'allow' ? 'approved' : 'denied',
settledAt: 2,
},
boundary: createExternalExecutionBoundary(),
changed: false,
};
},
},
);
const iterator = instance
.send({
turnId: 'turn-code',
text: 'use the network',
context: [],
toolMode: 'code_mode',
})
[Symbol.asyncIterator]();
const events: SessionEvent[] = [];
let request: Extract<SessionEvent, { type: 'sandbox_boundary_request' }> | undefined;
while (!request) {
const item = await iterator.next();
assert.equal(item.done, false);
events.push(item.value);
if (item.value.type === 'sandbox_boundary_request') request = item.value;
}
await instance.respondToSandboxBoundary({ requestId: request.requestId, decision: 'deny' });
for (;;) {
const item = await iterator.next();
if (item.done) break;
events.push(item.value);
}
assert.ok(
events.some(
(event) =>
event.type === 'sandbox_boundary_decision_ack' &&
event.requestId === request?.requestId &&
event.decision === 'deny',
),
);
assert.ok(events.some((event) => event.type === 'tool_result' && event.toolUseId === 'exec-1'));
assert.equal(sideEffects, 0);
});
test('aborting a parked nested sandbox request releases the outer exec', async () => {
let markCreated: (() => void) | undefined;
const created = new Promise<void>((resolve) => {
markCreated = resolve;
});
let sideEffects = 0;
const tools: MakaTool[] = [
{
name: 'network_task',
description: 'Request network authority',
parameters: z.object({}),
categoryHint: 'network_send',
impl: async (_input, context) => {
assert.ok(context.requestSandboxBoundary);
const result = await context.requestSandboxBoundary(
{ network: { enabled: true } },
'Fetch the requested catalog record.',
);
if (result.request.status === 'approved') sideEffects += 1;
return result;
},
},
];
const instance = backend(
execThenStopModel('return await tools.network_task({})'),
[],
undefined,
{
tools,
createSandboxBoundaryRequest: async (input) => {
markCreated?.();
return { ...input, status: 'pending', baseRevision: 0, createdAt: 1 };
},
settleSandboxBoundaryRequest: async (input) => ({
request: {
sessionId: 'session-1',
requestId: input.requestId,
turnId: 'turn-code',
expansion: { network: { enabled: true } },
justification: 'Fetch the requested catalog record.',
status: 'denied',
baseRevision: 0,
createdAt: 1,
settledAt: 2,
},
boundary: createExternalExecutionBoundary(),
changed: false,
}),
},
);
const eventsPromise = collect(
instance.send({
turnId: 'turn-code',
text: 'use the network',
context: [],
toolMode: 'code_mode',
}),
);
await created;
await instance.stop('user_stop');
const events = await Promise.race([
eventsPromise,
new Promise<never>((_resolve, reject) =>
setTimeout(() => reject(new Error('aborted nested boundary did not settle')), 100),
),
]);
assert.equal(sideEffects, 0);
assert.ok(events.some((event) => event.type === 'tool_result' && event.toolUseId === 'exec-1'));
});
test('aborts an owned nested tool when the outer exec is stopped', async () => {
let markStarted: (() => void) | undefined;
const started = new Promise<void>((resolve) => {
markStarted = resolve;
});
let markAborted: (() => void) | undefined;
const aborted = new Promise<void>((resolve) => {
markAborted = resolve;
});
let releaseTool: (() => void) | undefined;
const toolRelease = new Promise<void>((resolve) => {
releaseTool = resolve;
});
let nestedAborted = false;
let nestedSettled = false;
const tools: MakaTool[] = [
{
name: 'slow_task',
description: 'Wait until stopped',
parameters: z.object({}),
impl: async (_input, context) => {
markStarted?.();
await new Promise<void>((resolve) => {
context.abortSignal.addEventListener(
'abort',
() => {
nestedAborted = true;
markAborted?.();
resolve();
},
{ once: true },
);
});
await toolRelease;
nestedSettled = true;
throw context.abortSignal.reason;
},
},
];
const instance = backend(execThenStopModel('return await tools.slow_task({})'), [], undefined, {
tools,
});
let eventsSettled = false;
const eventsPromise = collect(
instance.send({
turnId: 'turn-code',
text: 'start it',
context: [],
toolMode: 'code_mode',
}),
).then((events) => {
eventsSettled = true;
return events;
});
await started;
const stopPromise = instance.stop('user_stop');
await aborted;
await new Promise<void>((resolve) => setImmediate(resolve));
const settledBeforeTool = eventsSettled;
releaseTool?.();
await stopPromise;
await eventsPromise;
assert.equal(nestedAborted, true);
assert.equal(settledBeforeTool, false);
assert.equal(nestedSettled, true);
});
test('bounds aggregate nested live output under the outer exec', async () => {
const emitted = 'x'.repeat(1024 * 1024 + 1);
const tools: MakaTool[] = [
{
name: 'stream_task',
description: 'Emit output',
parameters: z.object({}),
impl: (_input, context) => {
context.emitOutput('stdout', emitted);
return { ok: true };
},
},
];
const events = await collect(
backend(execThenStopModel('return await tools.stream_task({})'), [], undefined, { tools }).send(
{
turnId: 'turn-code',
text: 'stream it',
context: [],
toolMode: 'code_mode',
},
),
);
const outputBytes = events
.filter(
(event): event is Extract<SessionEvent, { type: 'tool_output_delta' }> =>
event.type === 'tool_output_delta',
)
.reduce((total, event) => total + Buffer.byteLength(event.chunk), 0);
const execResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'exec-1',
);
assert.ok(outputBytes <= 1024 * 1024);
assert.match(JSON.stringify(execResult?.content), /output byte limit/i);
});
test('admits exec exclusively while allowing its nested calls', async () => {
const implementationCalls: unknown[] = [];
const events = await collect(
backend(execAndDirectToolModel(), implementationCalls).send({
turnId: 'turn-code',
text: 'run both',
context: [],
toolMode: 'code_mode',
}),
);
assert.deepEqual(implementationCalls, [{ id: 'nested' }]);
const directResult = events.find(
(event): event is Extract<SessionEvent, { type: 'tool_result' }> =>
event.type === 'tool_result' && event.toolUseId === 'lookup-direct',
);
assert.equal(directResult?.isError, true);
assert.match(JSON.stringify(directResult?.content), /cannot share an assistant step|exclusive/i);
});
function backend(
model: MockLanguageModelV4,
implementationCalls: unknown[] = [],
runtimeCommitSink?: RuntimeCommitSink,
overrides: Partial<
Pick<
AiSdkBackendInput,
| 'tools'
| 'readExecutionBoundary'
| 'createSandboxBoundaryRequest'
| 'settleSandboxBoundaryRequest'
| 'recordToolArtifacts'
| 'supportsVision'
| 'readAttachmentBytes'
| 'maxProviderImageRequestBytes'
>
> = {},
) {
let id = 0;
const tools: MakaTool[] = [
{
name: 'lookup',
description: 'Look up a node',
parameters: z.object({ id: z.string() }),
impl: (input: { id: string }) => {
implementationCalls.push(input);
return input;
},
},
];
return createTestAiSdkBackend({
sessionId: 'session-1',
header: header(),
appendMessage: async () => {},
connection: connection(),
apiKey: 'sk-test',
modelId: 'mock-model-id',
modelFactory: () => model,
tools,
maxSteps: 1,
...(runtimeCommitSink ? { runtimeCommitSink } : {}),
newId: () => `id-${++id}`,
now: () => 1,
...overrides,
});
}
function execThenStopModel(
code = 'return await tools.lookup({ id: "nested" })',
): MockLanguageModelV4 {
let step = 0;
return new MockLanguageModelV4({
doStream: async () => {
step += 1;
const parts: LanguageModelV4StreamPart[] =
step === 1
? [
{ type: 'stream-start', warnings: [] },
{
type: 'tool-call',
toolCallId: 'exec-1',
toolName: 'exec',
input: JSON.stringify({ code }),
},
{
type: 'finish',
finishReason: { unified: 'tool-calls', raw: 'tool_calls' },
usage: ZERO_USAGE,
},
]
: [
{ type: 'stream-start', warnings: [] },
{
type: 'finish',
finishReason: { unified: 'stop', raw: 'stop' },
usage: ZERO_USAGE,
},
];
return { stream: convertArrayToReadableStream(parts) };
},
});
}
function capturingModel(captured: string[][]): MockLanguageModelV4 {
return new MockLanguageModelV4({
doStream: async ({ tools }) => {
captured.push((tools ?? []).map((tool) => tool.name).sort());
const parts: LanguageModelV4StreamPart[] = [
{ type: 'stream-start', warnings: [] },
{ type: 'finish', finishReason: { unified: 'stop', raw: 'stop' }, usage: ZERO_USAGE },
];
return { stream: convertArrayToReadableStream(parts) };
},
});
}
function execAndDirectToolModel(): MockLanguageModelV4 {
return new MockLanguageModelV4({
doStream: async () => ({
stream: convertArrayToReadableStream<LanguageModelV4StreamPart>([
{ type: 'stream-start', warnings: [] },
{
type: 'tool-call',
toolCallId: 'exec-1',
toolName: 'exec',
input: JSON.stringify({
code: 'return await tools.lookup({ id: "nested" })',
}),
},
{
type: 'tool-call',
toolCallId: 'lookup-direct',
toolName: 'lookup',
input: JSON.stringify({ id: 'direct' }),
},
{
type: 'finish',
finishReason: { unified: 'tool-calls', raw: 'tool_calls' },
usage: ZERO_USAGE,
},
]),
}),
});
}
async function drain(iterable: AsyncIterable<unknown>): Promise<void> {
for await (const item of iterable) void item;
}
async function collect(iterable: AsyncIterable<SessionEvent>): Promise<SessionEvent[]> {
const events: SessionEvent[] = [];
for await (const event of iterable) events.push(event);
return events;
}
function header(): SessionHeader {
return {
id: 'session-1',
workspaceRoot: '/tmp/maka',
cwd: '/tmp/maka',
createdAt: 1,
lastUsedAt: 1,
name: 'Test',
titleIsManual: true,
isFlagged: false,
labels: [],
isArchived: false,
status: 'active',
statusUpdatedAt: 1,
hasUnread: false,
backend: 'ai-sdk',
llmConnectionSlug: 'c',
connectionLocked: true,
model: 'm',
permissionMode: 'ask',
schemaVersion: 1,
};
}
function connection(): LlmConnection {
return {
slug: 'c',
name: 'OpenAI',
providerType: 'openai',
defaultModel: 'mock-model-id',
enabled: true,
createdAt: 1,
updatedAt: 1,
};
}