mirror of
https://github.com/stablyai/orca.git
synced 2026-11-01 09:37:33 +00:00
181 lines
6.2 KiB
TypeScript
181 lines
6.2 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import {
|
|
agentSessionRefusalFailure,
|
|
agentSessionThrownFailure,
|
|
parseAgentSessionWriteFailure,
|
|
readAgentSessionErrorRefusal
|
|
} from './agent-session-write-failure'
|
|
|
|
const HOST_TEXT = 'Expected runtime fence 1; the session is at 3.'
|
|
|
|
function saved(value: unknown): unknown {
|
|
return JSON.parse(JSON.stringify(value))
|
|
}
|
|
|
|
describe('parseAgentSessionWriteFailure', () => {
|
|
// The shape saved before refusals carried a reason; it loads as it was and reads as its code.
|
|
it('reads back an entry saved with the code alone, unchanged', () => {
|
|
expect(
|
|
parseAgentSessionWriteFailure(saved({ kind: 'refused', code: 'agent_session_conflict' }))
|
|
).toEqual({ kind: 'refused', code: 'agent_session_conflict' })
|
|
expect(parseAgentSessionWriteFailure({ kind: 'failed' })).toEqual({ kind: 'failed' })
|
|
expect(
|
|
parseAgentSessionWriteFailure({
|
|
kind: 'refused',
|
|
code: 'agent_session_conflict',
|
|
message: HOST_TEXT
|
|
})
|
|
).toEqual({ kind: 'refused', code: 'agent_session_conflict' })
|
|
})
|
|
|
|
it.each([
|
|
[
|
|
'a reason',
|
|
{ kind: 'refused', code: 'agent_session_conflict', details: { reason: 'chatStarting' } }
|
|
],
|
|
[
|
|
"a rewind's reason",
|
|
{
|
|
kind: 'refused',
|
|
code: 'agent_session_operation_invalid',
|
|
details: { reason: 'rewindRefused', rewindReason: 'busy' }
|
|
}
|
|
],
|
|
[
|
|
"the owner's verdict",
|
|
{
|
|
kind: 'refused',
|
|
code: 'agent_session_ownership_unknown',
|
|
details: { reason: 'ownerUnproven', ownerVerdict: 'exited' }
|
|
}
|
|
]
|
|
])('keeps %s', (_label, value) => {
|
|
expect(parseAgentSessionWriteFailure(saved(value))).toEqual(value)
|
|
})
|
|
|
|
// A newer build's reason or verdict is dropped, never guessed; the code's words stand.
|
|
it.each([
|
|
[{ reason: 'fromTheFuture' }, undefined],
|
|
[{ reason: 'fromTheFuture', ownerVerdict: 'exited' }, { ownerVerdict: 'exited' }],
|
|
[{ reason: 'ownerUnproven', ownerVerdict: 'gone' }, { reason: 'ownerUnproven' }],
|
|
[{ reason: 'chatStarting' }, undefined]
|
|
])('drops what this build cannot place: %j', (details, kept) => {
|
|
expect(
|
|
parseAgentSessionWriteFailure({
|
|
kind: 'refused',
|
|
code: 'agent_session_ownership_unknown',
|
|
details
|
|
})
|
|
).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_ownership_unknown',
|
|
...(kept ? { details: kept } : {})
|
|
})
|
|
})
|
|
|
|
it.each([
|
|
null,
|
|
'The agent was restarting.',
|
|
{ kind: 'refused' },
|
|
{ kind: 'refused', code: 'agent_session_from_the_future' },
|
|
{ kind: 'something-else' }
|
|
])('drops %j instead of guessing', (value) => {
|
|
expect(parseAgentSessionWriteFailure(value)).toBeUndefined()
|
|
})
|
|
})
|
|
|
|
describe('agentSessionRefusalFailure', () => {
|
|
// What moves with the owner, the question's answer and the host's words are never kept.
|
|
it('keeps only the facts that stay true after a reload', () => {
|
|
expect(
|
|
agentSessionRefusalFailure({
|
|
code: 'agent_session_checkpoint_stale',
|
|
details: { reason: 'fenceStale', currentFence: 3, ownerVerdict: 'exited' }
|
|
})
|
|
).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_checkpoint_stale',
|
|
details: { reason: 'fenceStale' }
|
|
})
|
|
// A prompt's revision and winning answer, and a provider's diagnostic, as a host may send them.
|
|
const answered = JSON.parse(
|
|
JSON.stringify({
|
|
code: 'agent_session_already_resolved',
|
|
details: {
|
|
reason: 'promptAlreadyResolved',
|
|
currentRevision: 2,
|
|
resolution: { state: 'answered', selectedOptionId: 'yes', resolvedBy: 'phone' },
|
|
detail: { text: 'stderr', audience: 'log' }
|
|
}
|
|
})
|
|
)
|
|
expect(agentSessionRefusalFailure(answered)).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_already_resolved',
|
|
details: { reason: 'promptAlreadyResolved' }
|
|
})
|
|
})
|
|
|
|
it('keeps a code from a newer host without reading its details', () => {
|
|
const refusal = JSON.parse('{"code":"agent_session_from_the_future","details":{"reason":"x"}}')
|
|
expect(agentSessionRefusalFailure(refusal)).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_from_the_future'
|
|
})
|
|
})
|
|
})
|
|
|
|
describe('a refusal a failed request carried in its error', () => {
|
|
const refusal = {
|
|
code: 'agent_session_journal_unreadable',
|
|
details: { reason: 'journalCorrupt', stray: 'dropped' }
|
|
}
|
|
const payload = { code: 'runtime_error', message: 'agent_session_journal_unreadable' }
|
|
|
|
it('is read from a thrown RPC error and from a stream payload alike', () => {
|
|
const expected = {
|
|
code: 'agent_session_journal_unreadable',
|
|
details: { reason: 'journalCorrupt' }
|
|
}
|
|
expect(
|
|
readAgentSessionErrorRefusal({ response: { error: { ...payload, data: { refusal } } } })
|
|
).toEqual(expected)
|
|
expect(readAgentSessionErrorRefusal(saved({ ...payload, data: { refusal } }))).toEqual(expected)
|
|
})
|
|
|
|
it.each([
|
|
['an older host', payload],
|
|
['a thrown error without a response', new Error('agent_session_journal_unreadable')],
|
|
['a code this build does not know', { ...payload, data: { refusal: { code: 'from_later' } } }],
|
|
['nothing', undefined]
|
|
])('is absent from %s', (_label, error) => {
|
|
expect(readAgentSessionErrorRefusal(error)).toBeUndefined()
|
|
})
|
|
|
|
it("words the refusal when there is one, else what the request's error code proves", () => {
|
|
expect(agentSessionThrownFailure({ ...payload, data: { refusal } }, 'runtime_error')).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_journal_unreadable',
|
|
details: { reason: 'journalCorrupt' }
|
|
})
|
|
expect(agentSessionThrownFailure(payload, 'runtime_error')).toEqual({ kind: 'unconfirmed' })
|
|
expect(agentSessionThrownFailure(payload, 'method_not_found')).toEqual({
|
|
kind: 'refused',
|
|
code: 'structured_agent_session_unsupported'
|
|
})
|
|
})
|
|
|
|
it("degrades a reason another build added to the code's own words", () => {
|
|
const newer = {
|
|
code: 'agent_session_journal_unreadable',
|
|
details: { reason: 'journalFromTheFuture' }
|
|
}
|
|
expect(
|
|
agentSessionThrownFailure({ ...payload, data: { refusal: newer } }, 'runtime_error')
|
|
).toEqual({
|
|
kind: 'refused',
|
|
code: 'agent_session_journal_unreadable'
|
|
})
|
|
})
|
|
})
|