import test from 'brittle' import { readFileSync } from 'node:fs' const STATE = readFileSync( new URL('../lib/agent/agent-state.js', import.meta.url), 'utf8' ) const TOOLS = readFileSync(new URL('../lib/agent/agent-tools.js', import.meta.url), 'utf8') + readFileSync( new URL('../lib/agent/agent-tool-definitions.js', import.meta.url), 'utf8' ) + readFileSync( new URL('../lib/agent/agent-tool-dispatch.js', import.meta.url), 'utf8' ) const OPENAI = readFileSync( new URL('../lib/agent/agent-openai.js', import.meta.url), 'utf8' ) const TUI = readFileSync( new URL('../lib/agent/agent-tui.js', import.meta.url), 'utf8' ) const CLI = readFileSync(new URL('../src/agent.js', import.meta.url), 'utf8') test('agent-state exposes QVAC backend config keys', async (t) => { for (const key of [ 'backend', 'qvac_model', 'qvac_profile', 'qvac_ctx_size', 'qvac_device', 'qvac_main_gpu', 'qvac_gpu_layers' ]) { t.ok(STATE.includes(key), 'missing QVAC key in agent-state.js: ' + key) } t.ok(STATE.includes("backend: 'qvac'"), 'default backend should be qvac') t.ok(STATE.includes("provider: 'qvac'"), 'default provider should be qvac') t.ok(STATE.includes('QWEN3_1_7B_INST_Q4'), 'default qvac model id') }) test('agent-tui wizard offers QVAC vs REST and backend-specific setup', async (t) => { t.ok(TUI.includes('Backend [1=QVAC, 2=REST]')) t.ok(TUI.includes('bareAgentSetupRestFieldsPlain')) t.ok(TUI.includes('bareAgentSetupQvacFieldsPlain')) t.ok(TUI.includes('Provider [1=Groq, 2=xAI, 3=OpenAI, 4=Custom]')) t.ok(TUI.includes('API key (required, input hidden)')) t.ok(TUI.includes('Base URL [')) t.ok(TUI.includes('QVAC model profile')) t.ok(!TUI.includes('Enable autonomous coding mode?')) t.ok(TUI.includes('bareOsQvacComplete')) t.ok(TUI.includes("backendIter === 'qvac'")) t.ok( TUI.includes('bareAgentInteractiveSetupTui'), 'setup prefers ctx.tui.form' ) t.ok(TUI.includes('ctx.tui.form.run'), 'setup form run') t.ok(TUI.includes('bareAgentSanitizeConfigForBackend')) }) test('agent-tools merge patch allows backend / qvac keys', async (t) => { t.ok(TOOLS.includes("'backend'")) t.ok(TOOLS.includes("'qvac_model'")) t.ok(TOOLS.includes("'qvac_profile'")) t.ok(TOOLS.includes("'qvac_ctx_size'")) t.ok(TOOLS.includes("'qvac_device'")) t.ok(TOOLS.includes("'qvac_main_gpu'")) t.ok(TUI.includes('bareAgentQvacResolveDeviceOpts')) }) test('agent-state exposes bridge policy keys', async (t) => { for (const key of [ 'allow_bridge_mutations', 'allow_host_notifications', 'allow_host_actions', 'emergency_stop_mutations', 'access_policy', 'command_deny', 'mutate_deny_prefixes' ]) { t.ok(STATE.includes(key), 'missing key in agent-state.js: ' + key) } }) test('agent-state exposes autonomous mode config keys', async (t) => { for (const key of [ 'autonomous_mode_enabled', 'autonomous_max_runtime_ms', 'autonomous_completion_required_checks', 'autonomous_allow_paths', 'autonomous_deny_ops', 'autonomous_active', 'autonomous_started_at_ms', 'autonomous_stop_requested', 'autonomous_goal', 'autonomous_status', 'autonomous_last_error', 'plan_mode_active', 'todo_nudge_enabled', 'access_policy', 'command_deny', 'mutate_deny_prefixes' ]) { t.ok( STATE.includes(key), 'missing autonomous key in agent-state.js: ' + key ) } }) test('agent-tools exposes agent ops tools', async (t) => { for (const toolName of [ 'list_services', 'service_status', 'list_timers', 'read_cron_log', 'read_audit_log', 'read_boot_policy', 'read_kernel_extension_resolution', 'get_initd_graph', 'read_unit_journal', 'inspect_ipc_backpressure', 'get_network_summary', 'tail_telemetry_streams', 'pkg_index_lookup', 'list_verification_scripts', 'run_maintenance_gate', 'run_contract_checks', 'summarize_build_drift', 'get_hrpc_bridge_health', 'get_hrpc_allowlist_status', 'emit_host_notification', 'request_host_action', 'autonomous_run', 'autonomous_run_status', 'autonomous_run_stop', 'verification_hints', 'runtime_diagnostic_bundle', 'search_replace', 'glob_files', 'todo_write', 'memory_search', 'memory_get', 'enter_plan_mode', 'exit_plan_mode', 'ask_user_question', 'grep', 'apply_patch', 'update_goal', 'web_search', 'git_status', 'memory_append', 'list_skills', 'schedule_task', 'unschedule_task', 'list_scheduled', 'fuzzy_find', 'read_many', 'wait_for', 'undo_last_edit', 'git_diff', 'history_search', 'git_log', 'git_show', 'git_blame', 'copy_path', 'diff_files', 'find_symbol', 'create_skill', 'remember', 'rewind_session', 'export_session' ]) { t.ok( TOOLS.includes("name: '" + toolName + "'"), 'missing tool definition: ' + toolName ) } }) test('agent-openai parses reasoning deltas when present', async (t) => { t.ok(OPENAI.includes('delta_reasoning')) t.ok(OPENAI.includes('reasoning_content')) t.ok(OPENAI.includes('response.reasoning_summary_text.delta')) t.ok(OPENAI.includes('response_shape_keys')) }) test('agent-tui contains groq provider profile/request shaping', async (t) => { t.ok(TUI.includes("spec.id === 'groq'") || TUI.includes("provider === 'groq'")) t.ok(TUI.includes('https://api.groq.com/openai/v1')) t.ok(TUI.includes('body.parallel_tool_calls')) t.ok(TUI.includes('body.max_completion_tokens')) }) test('agent-tui contains autonomous loop controls and completion gates', async (t) => { t.ok(TUI.includes('bareAgentAutonomousSettings')) t.ok(TUI.includes('autonomous run stopped by request')) t.ok(TUI.includes('autonomous run stopped (timebox expired)')) t.ok(TUI.includes('Autonomous completion gates failed for checks')) t.ok(TUI.includes('autonomous completion gates passed')) t.ok(TUI.includes('bareAgentAutonomousShouldContinue')) t.ok(TUI.includes('bareAgentAutonomousContinuationPrompt')) t.ok(TUI.includes('bareAgentBeginAutonomousRun')) t.ok(TUI.includes('internalGate: true')) t.ok(TUI.includes('enter_plan_mode')) t.ok(TUI.includes('todo_write')) }) test('agent-tui embeds operating contract appendix', async (t) => { t.ok(TUI.includes('BARE_AGENT_OPERATING_CONTRACT')) t.ok(TUI.includes('BARE_AGENT_DISCORD_REPLY_FORMAT')) t.ok(TUI.includes('BARE_OS_AGENT_DISCORD')) t.ok(TUI.includes('verification_hints')) t.ok(TUI.includes('NEVER ASK')) t.ok(TUI.includes('Lead with tools')) t.ok(TUI.includes('TOOL DISCIPLINE')) t.ok(TUI.includes('WORK POLICY')) t.ok(TUI.includes('apply_patch')) t.ok(TUI.includes('overrides the TTY plain-text rule')) t.ok(!TUI.includes('ASK FIRST')) t.ok(!TUI.includes('Prefer least-privilege')) }) test('agent CLI exposes production flags and inspect subcommands', async (t) => { t.ok(CLI.includes('--plan')) t.ok(CLI.includes('--max-turns')) t.ok(CLI.includes('--model')) t.ok(CLI.includes('--system')) t.ok(CLI.includes('--new')) t.ok(CLI.includes('--compact')) t.ok(CLI.includes("sub === 'skills'")) t.ok(CLI.includes("sub === 'todos'")) t.ok(CLI.includes("sub === 'undo'")) t.ok(CLI.includes("sub === 'hooks'")) t.ok(CLI.includes("sub === 'history'")) t.ok(CLI.includes("sub === 'rewind'")) t.ok(CLI.includes("sub === 'export'")) t.ok(CLI.includes("sub === 'remember'")) t.ok(CLI.includes("sub === 'recap'")) t.ok(TUI.includes('planMode')) t.ok(TUI.includes('modelOverride')) t.ok(TUI.includes('extraSystemFile')) }) test('agent defaults are full guest admin (denylist, not allowlist)', async (t) => { t.ok(STATE.includes("access_policy: 'full'")) t.ok(STATE.includes('allow_delete: true')) t.ok(STATE.includes('allow_bridge_mutations: true')) t.ok(STATE.includes('allow_host_notifications: true')) t.ok(STATE.includes('allow_host_actions: true')) t.ok(STATE.includes('autonomous_mode_enabled: true')) t.ok(STATE.includes('autonomous_deny_ops: []')) t.ok(STATE.includes('command_deny: []')) t.ok(TOOLS.includes("error: 'command_denied'")) t.ok(!TOOLS.includes("error: 'autonomous_command_denied'")) })