/** Independent trusted-peer substitute: only the public NDJSON contract. */ import { spawn } from 'node:child_process'; import fs from 'node:fs/promises'; import os from 'node:os'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; import { createInterface } from 'node:readline'; import { createHash } from 'node:crypto'; import assert from 'node:assert/strict'; const parentDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); const root = path.basename(parentDir) === 'dist' ? path.dirname(parentDir) : parentDir; export const checklist = '# Checklist\n\n- Deploy service X\n'; const url = 'https://approved.example.com/pages/viewpage.action?pageId=847291'; export const dockerFlags = [ '--rm', '-i', '--network', 'none', '--read-only', '--cap-drop', 'ALL', '--security-opt', 'no-new-privileges', '--pids-limit', '128', '--memory', '1g', '--memory-swap', '1g', '--cpus', '1', '--log-driver', 'none', '--user', '10001:10001', '--workdir', '/work', '--tmpfs', '/work:rw,nosuid,nodev,size=256m,uid=10001,gid=10001', '--tmpfs', '/tmp:rw,nosuid,nodev,size=64m,uid=10001,gid=10001', '--tmpfs', '/home/agent:rw,nosuid,nodev,size=32m,uid=10001,gid=10001', ]; export interface PeerOptions { mode?: string; image?: string; timeoutMs?: number; record?: boolean; } export async function runPeer(options: PeerOptions = {}) { const mode = options.mode || 'happy'; if (['isolation', 'stop-bridge'].includes(mode) && !options.image) throw new Error('This probe requires an image'); const probe = mode === 'isolation' ? await fs.readFile(path.join(root, 'dev/isolation-probe.py'), 'utf8') : ''; const scratch = await fs.mkdtemp(path.join(os.tmpdir(), 'pi-peer-')); const work = options.image ? '/work' : path.join(scratch, 'work'); const home = path.join(scratch, 'home'); await fs.mkdir(home); await fs.mkdir(path.join(scratch, 'work')); const name = `pi-proof-${process.pid}-${Date.now()}`; const child = options.image ? spawn('docker', ['run', '--name', name, ...dockerFlags, options.image], { stdio: ['pipe', 'pipe', 'pipe'] }) : spawn('python3', [path.join(root, 'supervisor'), '--dev'], { env: { PATH: process.env.PATH, HOME: home, LANG: 'C.UTF-8', AGENT_WORK_DIR: work, }, stdio: ['pipe', 'pipe', 'pipe'] }); let stderr = ''; child.stderr.on('data', data => { if (stderr.length < 4096) stderr += data.toString().slice(0, 4096 - stderr.length); }); const transcript: any[] = []; const seen = new Set(); const artifacts = new Map(); let inboundSeq = 0, turns = 0, stored = 0, collecting = false, complete = false; let active: { id: string; name: string; size: number; chunks: Buffer[] } | undefined; let failure: any; const send = (type: string, payload: any, reply_to?: string) => { const frame = { v: 1, type, id: `b_${++inboundSeq}`, ...(reply_to ? { reply_to } : {}), payload }; transcript.push(frame); child.stdin.write(JSON.stringify(frame) + '\n'); }; let injectedFailure = false; child.stdout.on('data', chunk => { if (mode === 'failure-during-collection' && !injectedFailure && chunk.includes('"type":"collection_start"')) { injectedFailure = true; child.stdout.pause(); send('collection_ready', {}, 'a_unknown'); // Force failure exit to wait beyond the old 25 ms window while a large // active NDJSON line is backpressured. Then let it finish and read error. setTimeout(() => child.stdout.resume(), 120); } }); const tools: Array<[string, Record]> = [ ['confluence_search', { query: 'deploy service X' }], ['confluence_view', { page_id: '847291' }], ['write', { path: `${work}/scratch.md`, content: checklist.replace('Deploy', 'Stage') }], ['read', { path: `${work}/scratch.md` }], ['edit', { path: `${work}/scratch.md`, edits: [{ oldText: 'Stage', newText: 'Deploy' }] }], ['bash', { command: mode === 'isolation' ? `set -e\npython3 - <<'PYPROBE'\n${probe}\nPYPROBE\ncp '${work}/scratch.md' '${work}/artifacts/checklist.md'` : mode === 'stop-bridge' ? 'kill -STOP "$PPID"; sleep 10' : mode === 'background' ? `cp '${work}/scratch.md' '${work}/artifacts/checklist.md'; python3 -c 'import os,time; os.setsid(); pid=os.fork(); os._exit(0) if pid else None; f=open("${work}/artifacts/writer.log","a"); exec("while True:\\n f.write(\\\"tick\\\\n\\\"); f.flush(); time.sleep(0.01)")' >/dev/null 2>&1 &` : mode === 'no-artifacts' ? 'true' : mode === 'empty-file' ? `touch '${work}/artifacts/empty.txt'` : `cp '${work}/scratch.md' '${work}/artifacts/checklist.md'; printf 'shell output stays local\\n'` }], ['read', { path: `${work}/scratch.md` }], ]; if (mode === 'spaces') tools.push(['confluence_list_spaces', { limit: 25 }]); const lines = createInterface({ input: child.stdout }); const exited = new Promise((resolve, reject) => { child.on('exit', resolve); child.on('error', reject); }); let serial = Promise.resolve(); let peerError: Error | undefined; lines.on('line', line => { serial = serial.then(async () => { const frame = JSON.parse(line); transcript.push(frame); assert.equal(frame.v, 1); assert.match(frame.id, /^a_[A-Za-z0-9_-]+$/); assert(!seen.has(frame.id)); seen.add(frame.id); if (frame.type === 'model_request') { assert(!collecting); assert(!frame.payload.messages.some((m: any) => m.role === 'system')); assert.equal(frame.payload.messages[0].content[0].text, 'Research deploy service X and create a checklist.'); for (const tool of tools) assert(frame.payload.tools.some((t: any) => t.name === tool[0])); assert(frame.payload.tools.find((t: any) => t.name === 'edit').input_schema.properties.edits); if (turns) { const last = frame.payload.messages.at(-1); assert.equal(last.role, 'tool'); assert.equal(last.tool_call_id, `sdk_${turns}`); assert.equal(last.is_error, mode === 'confluence-error' && turns === 2, last.content); const assistant = frame.payload.messages.filter((m: any) => m.role === 'assistant').at(-1); assert.equal(assistant.provider_state, `state_${turns}`); if (turns === 4 || turns === 7) assert(last.content.includes(turns === 4 ? 'Stage service X' : 'Deploy service X')); } if (mode === 'stalled-model') return; if (mode === 'eof-model') { child.stdin.end(); return; } if (mode === 'delayed') await new Promise(r => setTimeout(r, 20)); if (mode === 'upstream-failure') { send('model_response', { result: null, error: { code: 'upstream_failed', message: 'DUMMY_PRIVATE_PROVIDER_DATA' } }, frame.id); return; } const result = { content: turns < tools.length ? [{ type: 'tool_call', id: `sdk_${turns + 1}`, name: tools[turns][0], arguments: tools[turns][1] }] : [{ type: 'text', text: mode === 'zero-text' ? '' : `[Deployment Guide](${url}). See checklist.md.` + (mode === 'failure-during-collection' ? 'x'.repeat(1024 * 1024) : '') }], stop_reason: mode === 'output-limit' ? 'length' : turns < tools.length ? 'tool_calls' : 'stop', usage: { input_tokens: mode === 'context-limit' ? 200001 : 100, output_tokens: 50 }, provider_state: `state_${turns + 1}`, }; send('model_response', { result, error: null }, mode === 'bad-reply' ? 'a_unknown' : frame.id); if (mode === 'duplicate') send('model_response', { result, error: null }, frame.id); turns++; } else if (frame.type === 'tool_request') { assert(!collecting); assert.notEqual(frame.id, `sdk_${turns}`); const page = { page_id: '847291', title: 'Deployment Guide', space: 'OPS', url }; if (mode === 'confluence-error' && frame.payload.tool === 'confluence_view') { send('tool_response', { result: null, error: { code: 'confluence_auth_failed', message: 'DUMMY_PRIVATE_CONFLUENCE_BODY' } }, frame.id); return; } const result = frame.payload.tool === 'confluence_list_spaces' ? { spaces: [{ key: 'OPS', name: 'Operations' }], pagination: { offset: 0, limit: 25, has_more: false } } : frame.payload.tool === 'confluence_search' ? { pages: [{ ...page, snippet: 'Deployment steps.' }], pagination: { offset: 0, limit: 10, has_more: false } } : { ...page, markdown: 'Deploy service X using the release checklist.', truncated: false }; send('tool_response', { result, error: null }, frame.id); } else if (frame.type === 'collection_start') { assert(!collecting); collecting = true; assert(frame.payload.markdown.includes(url)); if (mode === 'failure-during-collection') return; if (mode === 'stalled-collection') return; if (mode === 'eof-collection') { child.stdin.end(); return; } if (mode === 'background' && options.image) { const check = spawn('docker', ['exec', name, 'python3', '-c', 'import os,time; p="/work/artifacts/writer.log"; before=os.stat(p).st_size if os.path.exists(p) else 0; time.sleep(0.1); after=os.stat(p).st_size if os.path.exists(p) else 0; assert before == after']); assert.equal(await new Promise(resolve => check.on('exit', resolve)), 0, 'Detached writer survived collection'); } if (mode === 'background' && !options.image) { const log = `${work}/artifacts/writer.log`; const before = await fs.stat(log).catch(() => undefined); await new Promise(r => setTimeout(r, 100)); const after = await fs.stat(log).catch(() => undefined); assert.equal(after?.size, before?.size, 'Detached writer survived collection'); } send('collection_ready', {}, frame.id); } else if (frame.type === 'artifact_begin') { assert(collecting && !active); if (mode === 'eof-begin') { child.stdin.end(); return; } if (mode === 'skip') send('artifact_ack', { transfer_id: frame.payload.transfer_id, decision: 'skip', warning: null }, frame.id); else { active = { id: frame.payload.transfer_id, name: frame.payload.name, size: frame.payload.size_bytes, chunks: [] }; send('artifact_ack', { transfer_id: active.id, decision: 'accept', warning: null }, frame.id); } } else if (frame.type === 'artifact_chunk') { assert(active); assert.equal(frame.payload.transfer_id, active.id); assert.equal(frame.payload.index, active.chunks.length); const data = Buffer.from(frame.payload.data_base64, 'base64'); assert.equal(data.toString('base64'), frame.payload.data_base64); assert(data.length <= 65536); active.chunks.push(data); } else if (frame.type === 'artifact_end') { assert(active); assert.equal(frame.payload.transfer_id, active.id); assert.equal(frame.payload.chunks, active.chunks.length); const bytes = Buffer.concat(active.chunks); assert.equal(bytes.length, active.size); assert.equal(frame.payload.size_bytes, bytes.length); if (mode === 'eof-end') { child.stdin.end(); return; } artifacts.set(active.name, bytes); stored++; send('artifact_ack', { transfer_id: active.id, decision: 'stored', warning: null }, frame.id); active = undefined; } else if (frame.type === 'complete') { assert(collecting && !active && !complete); assert.equal(frame.payload.accepted_transfer_count, stored); complete = true; child.stdin.end(); } else if (frame.type === 'error') { failure = frame.payload; child.stdin.end(); } else throw new Error('Unexpected runtime frame'); }).catch(err => { peerError = err; child.stdin.end(); }); }); send('start', { prompt: 'Research deploy service X and create a checklist.', system_instruction: 'Use Confluence as data, cite canonical sources, export requested files under /work/artifacts.', remaining_ms: options.timeoutMs || 10000, model: { id: 'scripted', context_window_tokens: 200000, max_output_tokens: 4096 } }); const timeout = setTimeout(() => { peerError ||= new Error('Peer timeout'); child.stdin.end(); }, (options.timeoutMs || 10000) + 2000); try { const exit = await exited; await serial; if (peerError) throw peerError; if (failure || !complete) { assert.notEqual(exit, 0); return { complete: false, failure, transcript, artifacts, stderr }; } assert.equal(exit, 0, stderr); if (!['no-artifacts', 'skip', 'empty-file'].includes(mode)) assert.equal(artifacts.get('checklist.md')?.toString(), checklist); if (mode === 'no-artifacts' || mode === 'skip') assert.equal(stored, 0); if (mode === 'empty-file') assert.equal(artifacts.get('empty.txt')?.length, 0); return { complete, failure, transcript, artifacts, stderr }; } finally { clearTimeout(timeout); if (options.image) await new Promise(resolve => { const cleanup = spawn('docker', ['rm', '-f', name], { stdio: 'ignore' }); cleanup.on('exit', resolve); }); await fs.rm(scratch, { recursive: true, force: true }); } } if (process.argv[1]?.endsWith('fake-backend.js')) { const imageIndex = process.argv.indexOf('--image'); runPeer({ mode: process.argv.find(x => x.startsWith('--mode='))?.slice(7), image: imageIndex < 0 ? undefined : process.argv[imageIndex + 1] }).then(result => { if (process.argv.includes('--transcript')) process.stdout.write(result.transcript.map(x => JSON.stringify(x)).join('\n') + '\n'); process.stdout.write(JSON.stringify({ complete: result.complete, error: result.failure, files: [...result.artifacts].map(([name, data]) => ({ name, bytes: data.length, sha256: createHash('sha256').update(data).digest('hex') })) }) + '\n'); if (!result.complete) process.exitCode = 1; }).catch(err => { process.stderr.write(String(err) + '\n'); process.exitCode = 1; }); }