- userland/bundle.nu builds the userland and assembles target/userland/bin (bin names, tools.txt aliases, brush as sh and bash). - run and sh take --userland (default SAUSAGE_USERLAND); /bin is read-only. - The console's bash tool runs through the process table with the conversation id; large output spills to the world's /tmp. - sausage run starts the services supervisor. P1 exit session (openai/gpt-6.1-sol, fresh world): write, read, edit, git init/add/commit/diff/log, grep -rn, rg, find and a sed|sort|uniq|wc pipeline.
71 lines
3.9 KiB
TypeScript
71 lines
3.9 KiB
TypeScript
// Faux-provider integration test. The Rust test checks VFS effects and Exec arguments.
|
|
import { BACKGROUND_CONTEXT as context } from '@earendil-works/chord/context';
|
|
import { createModels } from '@earendil-works/pi-ai/models';
|
|
import { fauxProvider, fauxAssistantMessage, fauxToolCall, fauxText } from '@earendil-works/pi-ai/providers/faux';
|
|
import { Harness, createRegistry } from '@earendil-works/pi-durable';
|
|
import { CodingTools } from '@earendil-works/pi-durable/tools';
|
|
import { environment } from './environment';
|
|
import { openStorage } from './sqlite';
|
|
const models = createModels();
|
|
const crash = globalThis.testCrash;
|
|
const faux = fauxProvider({ tokensPerSecond: crash === 'model' ? 1 : 100000 });
|
|
models.setProvider(faux.provider);
|
|
faux.setResponses([
|
|
fauxAssistantMessage([
|
|
fauxToolCall('write', { path: '/test.txt', content: 'before\n' }, { id: 'write' }),
|
|
...(globalThis.testP1 ? [
|
|
fauxToolCall('write', { path: '/parallel/a', content: 'a' }, { id: 'parallel-a' }),
|
|
fauxToolCall('write', { path: '/parallel/b', content: 'b' }, { id: 'parallel-b' }),
|
|
] : []),
|
|
], { stopReason: 'toolUse' }),
|
|
fauxAssistantMessage([fauxToolCall('read', { path: '/test.txt' }, { id: 'read' })], { stopReason: 'toolUse' }),
|
|
fauxAssistantMessage([fauxToolCall('edit', { path: '/test.txt', edits: [{ oldText: 'before', newText: 'after' }] }, { id: 'edit' })], { stopReason: 'toolUse' }),
|
|
fauxAssistantMessage([fauxToolCall('bash', { command: globalThis.testP1 ? 'echo streamed stdout; echo streamed stderr >&2' : 'echo test' }, { id: 'bash' })], { stopReason: 'toolUse' }),
|
|
...(globalThis.testP1 ? [fauxAssistantMessage([fauxToolCall('bash', { command: 'seq 1 10000' }, { id: 'large' })], { stopReason: 'toolUse' })] : []),
|
|
fauxAssistantMessage([fauxText('done')]),
|
|
]);
|
|
if (crash) {
|
|
faux.setResponses(crash === 'tool' ? [
|
|
fauxAssistantMessage([fauxToolCall('bash', { command: 'echo test' }, { id: 'crash' })], { stopReason: 'toolUse' }),
|
|
] : crash === 'model' ? [
|
|
fauxAssistantMessage([fauxText('A long response that the test interrupts before it completes.')]),
|
|
] : [fauxAssistantMessage([fauxText('resumed done')])]);
|
|
}
|
|
if (globalThis.testP1) {
|
|
const failed = await environment('/').exec([], {}, context);
|
|
if (failed.ok || !(failed.error instanceof Error) || !failed.error.message) {
|
|
throw new Error('Execution failures must preserve their error message');
|
|
}
|
|
}
|
|
const registry = createRegistry();
|
|
registry.install(CodingTools);
|
|
const harness = await Harness.open(await openStorage(globalThis.storagePath), { models, registry, env: (target: any) => environment('/', target.conversationId) }, context);
|
|
const root = await harness.root(context, { agent: { model: { provider: 'faux', modelId: 'faux-1' }, extensions: [CodingTools], cwd: '/' } });
|
|
if (crash === 'model') {
|
|
const progress = await root.watch(context);
|
|
let ready = false;
|
|
progress.start((event: any) => {
|
|
if (event.kind !== 'value' || ready) return;
|
|
const message = event.value.docs['pi.live']?.generation?.message;
|
|
if (message?.content?.some((block: any) => block.type === 'text' && block.text.length > 0)) {
|
|
ready = true;
|
|
console.log('CRASH_READY');
|
|
}
|
|
});
|
|
}
|
|
harness.resume();
|
|
const result = await (await root.submit({ type: 'input', content: 'Exercise tools', requestId: 'test' }, context)).wait(context);
|
|
if (result.status !== 'done') throw new Error(JSON.stringify(result));
|
|
await harness.waitForIdle(context);
|
|
const watch = await root.watch(context);
|
|
const transcript = JSON.stringify(watch.value.entries);
|
|
if (!crash && transcript.includes('"isError":true')) throw new Error(transcript);
|
|
for (const expected of crash ? ['resumed done'] : ['before', 'after', 'streamed stdout', 'streamed stderr', 'done']) {
|
|
if (!transcript.includes(expected)) throw new Error(`Missing ${expected}: ${transcript}`);
|
|
}
|
|
if (globalThis.testP1) {
|
|
if (!transcript.includes('Full output: /tmp/bash-')) throw new Error('Missing spill diagnostic');
|
|
}
|
|
await watch.stop();
|
|
await harness.close(context);
|