import { describe, expect, it } from 'vitest'; import { isActionRequiredOpenCodeRuntimeDeliveryReason, selectOpenCodeRuntimeDeliveryReason, } from '../../../../src/main/services/team/opencode/delivery/OpenCodeRuntimeDeliveryDiagnostics'; describe('OpenCodeRuntimeDeliveryDiagnostics', () => { it('treats OpenRouter key limit errors as action-required delivery failures', () => { const reason = 'Key limit exceeded (total limit). Manage it using https://openrouter.ai/settings/keys'; expect(isActionRequiredOpenCodeRuntimeDeliveryReason(reason)).toBe(true); }); it('does not treat protocol proof repair reasons as action-required provider failures', () => { expect(isActionRequiredOpenCodeRuntimeDeliveryReason('visible_reply_still_required')).toBe( false ); }); it('selects a concrete OpenCode runtime delivery diagnostic before generic fallback text', () => { const record = { diagnostics: [ 'Latest assistant message for opencode session abc failed with APIError - Key limit exceeded (total limit). Manage it using https://openrouter.ai/settings/keys', ], lastReason: 'OpenCode runtime delivery failed', responseState: 'session_error', status: 'accepted', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toContain('Key limit exceeded'); }); it('selects OpenCode free usage exhaustion before empty assistant fallback text', () => { const record = { diagnostics: [ 'OpenCode session status retry - attempt=1 - Free usage exceeded, subscribe to Go https://opencode.ai/go - next=2026-05-18T00:00:00.267Z', 'empty_assistant_turn', ], lastReason: 'empty_assistant_turn', responseState: 'empty_assistant_turn', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toContain('Free usage exceeded'); expect( isActionRequiredOpenCodeRuntimeDeliveryReason(selectOpenCodeRuntimeDeliveryReason(record)) ).toBe(true); }); it('ignores positive OpenCode delivery breadcrumbs before fallback text', () => { const record = { diagnostics: [ 'OpenCode app MCP is connected for message delivery.', 'OpenCode prompt_async accepted; response observation will continue through durable app-side ledger reconciliation.', 'prompt_delivered_no_assistant_message', ], lastReason: 'prompt_delivered_no_assistant_message', responseState: 'prompt_delivered_no_assistant_message', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( 'OpenCode accepted the prompt, but no assistant turn was recorded.' ); }); it('prioritizes local disk-full diagnostics over secondary aborted assistant errors', () => { const record = { diagnostics: [ "OpenCode message bridge failed: ENOSPC: no space left on device, open '/tmp/.auth.json.tmp'", "ENOSPC: no space left on device, open '/tmp/.auth.json.tmp'", 'OpenCode app MCP was reattached before message delivery.', 'Latest assistant message msg_1 failed with MessageAbortedError - Aborted', 'empty_assistant_turn', ], lastReason: 'empty_assistant_turn', responseState: 'empty_assistant_turn', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( 'Local disk is full (ENOSPC). Free disk space and retry OpenCode delivery.' ); }); it('formats non-visible tool progress failures without exposing the internal reason code', () => { const record = { diagnostics: ['non_visible_tool_without_task_progress'], lastReason: 'non_visible_tool_without_task_progress', responseState: 'responded_non_visible_tool', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( 'OpenCode used tools, but did not create a visible reply or task progress proof.' ); }); it('formats visible replies missing taskRefs without exposing the internal reason code', () => { const record = { diagnostics: ['visible_reply_missing_task_refs'], lastReason: 'visible_reply_missing_task_refs', responseState: 'responded_visible_message', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( 'OpenCode created a reply without the required taskRefs metadata.' ); }); it('formats taskRefs merge verification failures without exposing internal diagnostics', () => { const record = { diagnostics: ['visible_reply_missing_task_refs_after_merge'], lastReason: 'visible_reply_ack_only_still_requires_answer', responseState: 'responded_visible_message', status: 'failed_terminal', } as Parameters[0]; expect(selectOpenCodeRuntimeDeliveryReason(record)).toBe( 'OpenCode created a reply without the required taskRefs metadata.' ); }); });