import { describe, expect, it } from 'vitest' import type { AgentJournalItemIdentity } from '../../shared/agent-session-journal-types' import { createCodexDispatchEchoes, readCodexDispatchEcho, MAX_CODEX_PENDING_DISPATCH_ECHOES } from './codex-structured-dispatch-echo' const CODEX_IDENTITY: AgentJournalItemIdentity = { provider: 'codex', threadId: 'thread-1', turnId: 'turn-1', ordinal: 3 } describe('codex dispatch echoes', () => { it('settles by client message id rather than arrival order', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.arm('client-2') // Codex coalesces both sends into one turn, and the second can be echoed // first. Queue position would settle the wrong submission here. expect(echoes.settle('client-2')).toBe(true) expect(echoes.settle('client-1')).toBe(true) expect(echoes.size).toBe(0) }) it('reads each submission instant by client message id', () => { const echoes = createCodexDispatchEchoes() echoes.arm('stale-unknown', 100) echoes.arm('later-turn', 200) expect(echoes.requestOrigin('later-turn')).toEqual({ requestedAt: 200, sequence: 1 }) expect(echoes.requestOrigin('stale-unknown')).toEqual({ requestedAt: 100, sequence: 0 }) expect(echoes.requestOrigin('never-armed')).toBeNull() expect(echoes.latestSequence()).toBe(1) }) it('keeps one causal sequence when an unconfirmed send retries', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1', 100) echoes.arm('client-1', 200) expect(echoes.requestOrigin('client-1')).toEqual({ requestedAt: 100, sequence: 0 }) expect(echoes.latestSequence()).toBe(0) }) it('refuses an echo this session never armed', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') expect(echoes.settle('client-from-history')).toBe(false) expect(echoes.size).toBe(1) }) it('settles a send exactly once', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') expect(echoes.settle('client-1')).toBe(true) expect(echoes.settle('client-1')).toBe(false) }) it('drops a send whose write never reached the provider', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.disarm('client-1') expect(echoes.settle('client-1')).toBe(false) }) it('clears every armed send', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.arm('client-2') echoes.clear() expect(echoes.size).toBe(0) expect(echoes.settle('client-1')).toBe(false) }) it('refuses new correlations at capacity without dropping an older send', () => { const echoes = createCodexDispatchEchoes() for (let index = 0; index < MAX_CODEX_PENDING_DISPATCH_ECHOES; index += 1) { expect(echoes.arm(`client-${index}`)).toBe(true) } expect(echoes.arm(`client-${MAX_CODEX_PENDING_DISPATCH_ECHOES}`)).toBe(false) expect(echoes.size).toBe(MAX_CODEX_PENDING_DISPATCH_ECHOES) expect(echoes.settle('client-0')).toBe(true) expect(echoes.settle(`client-${MAX_CODEX_PENDING_DISPATCH_ECHOES}`)).toBe(false) }) }) describe('readCodexDispatchEcho', () => { it('reads the client message id off a user message', () => { expect( readCodexDispatchEcho( { type: 'userMessage', id: 'item-1', clientId: 'client-1' }, CODEX_IDENTITY ) ).toEqual({ clientMessageId: 'client-1', providerIdentity: CODEX_IDENTITY }) }) it('ignores an item that is not a user message', () => { expect( readCodexDispatchEcho( { type: 'agentMessage', id: 'item-1', clientId: 'client-1' }, CODEX_IDENTITY ) ).toBeNull() }) it('ignores a user message Codex did not correlate', () => { expect(readCodexDispatchEcho({ type: 'userMessage', id: 'item-1' }, CODEX_IDENTITY)).toBeNull() }) it('ignores an item with no durable Codex identity', () => { expect( readCodexDispatchEcho( { type: 'userMessage', id: 'item-1', clientId: 'client-1' }, { provider: 'orca', clientMessageId: 'codex-item:thread-1:item-1' } ) ).toBeNull() }) }) describe('the turn Codex answered a send into but has not opened', () => { const NONE_OPEN = new Set() it('is the turn the latest armed send was answered into', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.bindTurn('client-1', 'thread-1', 'turn-1', 'start') echoes.arm('client-2') echoes.bindTurn('client-2', 'thread-1', 'turn-2', 'start') expect(echoes.answeredUnopenedTurn('thread-1', NONE_OPEN)).toBe('turn-2') }) it('is none once Codex opened that turn', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.bindTurn('client-1', 'thread-1', 'turn-1', 'start') expect(echoes.answeredUnopenedTurn('thread-1', new Set(['turn-1']))).toBeNull() }) it('is none once that turn ended, even with its send still armed for an echo', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.bindTurn('client-1', 'thread-1', 'turn-1', 'start') // A completed end leaves its unechoed send armed. expect(echoes.endTurn('thread-1', 'turn-1', { status: 'completed' })).toEqual([]) expect(echoes.answeredUnopenedTurn('thread-1', NONE_OPEN)).toBeNull() }) it('skips a turn a wait left unopened, and still names an earlier one', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.bindTurn('client-1', 'thread-1', 'turn-1', 'start') echoes.arm('client-2') echoes.bindTurn('client-2', 'thread-1', 'turn-2', 'start') echoes.leftUnopened('thread-1', 'turn-2') expect(echoes.answeredUnopenedTurn('thread-1', NONE_OPEN)).toBe('turn-1') }) it('is none for a send not yet answered, or answered on another thread', () => { const echoes = createCodexDispatchEchoes() echoes.arm('client-1') echoes.arm('client-2') echoes.bindTurn('client-2', 'thread-2', 'turn-2', 'start') expect(echoes.answeredUnopenedTurn('thread-1', NONE_OPEN)).toBeNull() }) })