Files
EJClaw/src/paired-turn-fallback.test.ts
2026-04-06 20:38:10 +09:00

147 lines
4.1 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { resolveCodexFallbackHandoff } from './paired-turn-fallback.js';
describe('resolveCodexFallbackHandoff', () => {
it('returns a reviewer codex handoff plan for reviewer auth failures', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'reviewer',
effectiveAgentType: 'claude-code',
hasReviewer: true,
fallbackEnabled: true,
reason: 'auth-expired',
sawVisibleOutput: false,
prompt: 'please review',
startSeq: 10,
endSeq: 12,
});
expect(result).toEqual({
type: 'handoff',
plan: {
handoff: {
source_role: 'reviewer',
target_role: 'reviewer',
source_agent_type: 'claude-code',
target_agent_type: 'codex',
prompt: 'please review',
start_seq: 10,
end_seq: 12,
reason: 'reviewer-claude-auth-expired',
intended_role: 'reviewer',
},
logMessage:
'Claude reviewer unavailable, handed off review turn to codex-review',
},
});
});
it('returns an arbiter codex handoff plan for arbiter auth failures', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'arbiter',
effectiveAgentType: 'claude-code',
hasReviewer: true,
fallbackEnabled: true,
reason: '429',
sawVisibleOutput: false,
prompt: 'please arbitrate',
});
expect(result).toEqual({
type: 'handoff',
plan: {
handoff: {
source_role: 'arbiter',
target_role: 'arbiter',
source_agent_type: 'claude-code',
target_agent_type: 'codex',
prompt: 'please arbitrate',
start_seq: null,
end_seq: null,
reason: 'arbiter-claude-429',
intended_role: 'arbiter',
},
logMessage:
'Claude arbiter unavailable, handed off arbiter turn to codex',
},
});
});
it('returns an owner codex handoff plan and failover activation for owner failures', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'owner',
effectiveAgentType: 'claude-code',
hasReviewer: true,
fallbackEnabled: true,
reason: 'session-failure',
sawVisibleOutput: false,
prompt: 'please continue',
});
expect(result).toEqual({
type: 'handoff',
plan: {
handoff: {
source_role: 'owner',
target_role: 'owner',
source_agent_type: 'claude-code',
target_agent_type: 'codex',
prompt: 'please continue',
start_seq: null,
end_seq: null,
reason: 'claude-session-failure',
intended_role: 'owner',
},
activateOwnerFailoverReason: 'claude-session-failure',
logMessage:
'Claude unavailable, handed off current owner turn to codex fallback',
},
});
});
it('skips handoff when fallback is disabled for the role', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'owner',
effectiveAgentType: 'claude-code',
hasReviewer: true,
fallbackEnabled: false,
reason: 'usage-exhausted',
sawVisibleOutput: false,
prompt: 'please continue',
});
expect(result).toEqual({
type: 'skip',
logMessage: 'Fallback disabled for role, skipping handoff',
});
});
it('returns none when visible output was already emitted', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'reviewer',
effectiveAgentType: 'claude-code',
hasReviewer: true,
fallbackEnabled: true,
reason: 'auth-expired',
sawVisibleOutput: true,
prompt: 'please review',
});
expect(result).toEqual({ type: 'none' });
});
it('returns none when no reviewer is configured for the room', () => {
const result = resolveCodexFallbackHandoff({
activeRole: 'owner',
effectiveAgentType: 'claude-code',
hasReviewer: false,
fallbackEnabled: true,
reason: '429',
sawVisibleOutput: false,
prompt: 'please continue',
});
expect(result).toEqual({ type: 'none' });
});
});