import { describe, expect, test } from 'bun:test' import { ExecutorRole } from '../src/roles/ExecutorRole.js' class NativeToolRuntime { turns = 0 calls: Array<{ name: string; args: Record }> = [] emit() {} heartbeat() {} checkpoint() {} async call_llm() { this.turns++ if (this.turns === 1) { return { content: '', tool_calls: [{ id: 'tu_1', name: 'fs.write', arguments: { path: 'a.txt', content: 'X' } }] } } return { content: 'DONE' } } async call_tool(name: string, args: Record) { this.calls.push({ name, args }) return { call_id: 'c', type: 'text' as const, content: { ok: true } } } } class VerificationFailRuntime { turns = 0 checkpointed = false emit() {} heartbeat() {} checkpoint() { this.checkpointed = true } async call_llm() { this.turns++ if (this.turns === 1) { return { content: '', tool_calls: [{ id: 'tu_main', name: 'fs.write', arguments: { path: 'main.cpp', content: 'int main(){return 0;}' } }] } } return { content: 'DONE' } } async call_tool(name: string, _args: Record) { if (name === 'fs.write') return { call_id: 'w', type: 'text' as const, content: { ok: true } } if (name === 'shell.run') return { call_id: 's', type: 'error' as const, content: { exit_code: 1, stderr: 'compile failed' } } return { call_id: 'x', type: 'error' as const, content: { message: 'unexpected tool' } } } } describe('ExecutorRole structured tool execution', () => { test('executes native tool_calls instead of regex text parsing', async () => { const runtime = new NativeToolRuntime() const result = await new ExecutorRole(runtime as any).run({ id: 't1', title: 'create file', description: 'create a file', acceptance_criteria: ['file exists'], }) expect(result.status).toBe('completed') expect(runtime.calls).toEqual([{ name: 'fs.write', args: { path: 'a.txt', content: 'X' } }]) }) test('does not complete executable tasks when verification fails', async () => { const runtime = new VerificationFailRuntime() const result = await new ExecutorRole(runtime as any).run({ id: 't2', title: 'compile cpp', description: 'write and compile C++', acceptance_criteria: ['must compile'], }) expect(result.status).not.toBe('completed') expect(runtime.checkpointed).toBe(false) expect(result.changes).toEqual([{ file: 'main.cpp', type: 'create' }]) }) })