mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 17:17:38 +00:00
* Keep clear in the same chat and reset its provider context * Derive clear pauses only from journal membership and cover older rewind clients * Point queued command rewind test at the structured hook * Group queue consume errors and rewind replay assertions
173 lines
6.0 KiB
TypeScript
173 lines
6.0 KiB
TypeScript
import { describe, expect, it } from 'vitest'
|
|
import type {
|
|
AgentJournalItemBody,
|
|
AgentJournalRenderItem,
|
|
AgentJournalSubmission,
|
|
AgentJournalThreadGoal
|
|
} from './agent-session-journal-types'
|
|
import {
|
|
agentSessionCurrentContextRows,
|
|
isAgentSessionContextClear,
|
|
isNativeChatContextClear,
|
|
latestAgentSessionContextClearSequence
|
|
} from './agent-session-context-clear'
|
|
import {
|
|
currentAgentSessionThreadGoal,
|
|
currentAgentSessionThreadGoalBySequence
|
|
} from './agent-session-thread-goal'
|
|
import {
|
|
activeStructuredAgentSessionTurnId,
|
|
newestStructuredAgentSessionTurn
|
|
} from './structured-agent-session-live-turn'
|
|
import {
|
|
projectStructuredAgentSessionStatusState,
|
|
projectStructuredItemToNativeChat
|
|
} from './structured-agent-session-projection'
|
|
import {
|
|
latestStructuredAgentContextFacts,
|
|
selectStructuredAgentContextUsage
|
|
} from './structured-agent-session-context-usage'
|
|
import { owesStructuredAgentSessionWork } from './structured-agent-session-owed-work'
|
|
|
|
const boundary = { operationId: 'clear', afterFence: 3, clearedAt: 100 }
|
|
const row = (sequence: number, body: AgentJournalItemBody): AgentJournalRenderItem => ({
|
|
itemId: `row-${sequence}`,
|
|
sequence,
|
|
revision: 1,
|
|
observedAt: sequence,
|
|
body
|
|
})
|
|
const clear = row(5, {
|
|
kind: 'status',
|
|
text: 'Localized fallback',
|
|
presentation: 'context-cleared',
|
|
contextClear: boundary
|
|
})
|
|
const oldSend: AgentJournalSubmission = {
|
|
clientMessageId: 'old-send',
|
|
fence: 3,
|
|
payloadFingerprint: 'same',
|
|
dispatchState: 'unknown',
|
|
providerItemId: null,
|
|
reason: null,
|
|
submittedAt: 1,
|
|
resolvedAt: null,
|
|
acceptedSequence: 2
|
|
}
|
|
const user = row(1, {
|
|
kind: 'message',
|
|
role: 'user',
|
|
blocks: [{ type: 'text', text: 'Prior prompt' }]
|
|
})
|
|
const running = row(3, { kind: 'turn', turnId: 'old-turn', state: 'running' })
|
|
const oldPrompt = row(4, {
|
|
kind: 'question',
|
|
question: 'Old question',
|
|
options: [],
|
|
resolution: { state: 'pending', selectedOptionId: null, resolvedBy: null, resolvedAt: null }
|
|
})
|
|
const goal: AgentJournalThreadGoal = {
|
|
objective: 'Old goal',
|
|
status: 'active',
|
|
tokenBudget: null,
|
|
tokensUsed: 1,
|
|
timeUsedSeconds: 1,
|
|
createdAt: 1,
|
|
updatedAt: 1
|
|
}
|
|
const goalRow = row(2, { kind: 'status', text: 'Goal set', threadGoal: { state: 'set', goal } })
|
|
const usageRow = row(3, {
|
|
kind: 'turn',
|
|
turnId: 'old-turn',
|
|
state: 'completed',
|
|
contextUsage: {
|
|
window: { tokens: 200_000, capturedAt: 1 },
|
|
used: {
|
|
kind: 'estimate',
|
|
capturedAt: 1,
|
|
usage: {
|
|
inputTokens: 100,
|
|
cacheCreationInputTokens: 0,
|
|
cacheReadInputTokens: 0,
|
|
outputTokens: 0
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
describe('completed context clear projections', () => {
|
|
it('uses typed metadata and carries it through the shared desktop and mobile row', () => {
|
|
expect(isAgentSessionContextClear(clear.body)).toBe(true)
|
|
expect(
|
|
isAgentSessionContextClear({
|
|
kind: 'status',
|
|
text: 'Context cleared',
|
|
presentation: 'context-cleared'
|
|
})
|
|
).toBe(false)
|
|
const message = projectStructuredItemToNativeChat(clear)!
|
|
expect(message).toMatchObject({
|
|
role: 'system',
|
|
blocks: [{ text: 'Localized fallback', contextClear: boundary }]
|
|
})
|
|
expect(isNativeChatContextClear(message)).toBe(true)
|
|
})
|
|
|
|
it('leaves earlier rows and uncertainty visible while clearing current work and prompts', () => {
|
|
const rows = [user, running, oldPrompt, clear]
|
|
const state = projectStructuredAgentSessionStatusState(rows, [oldSend], 3)
|
|
expect(state.summary).toEqual({ status: 'idle', latestPrompt: 'Prior prompt' })
|
|
expect(state.latestRequest).toBeNull()
|
|
expect(state.pendingPromptIds).toEqual([])
|
|
expect(state.owesWork).toBe(false)
|
|
expect(owesStructuredAgentSessionWork(rows, [oldSend], 3)).toBe(false)
|
|
expect(activeStructuredAgentSessionTurnId(rows)).toBeNull()
|
|
expect(newestStructuredAgentSessionTurn(rows)).toBeNull()
|
|
expect(rows).toHaveLength(4)
|
|
expect(oldSend.dispatchState).toBe('unknown')
|
|
})
|
|
|
|
it('includes new sends but excludes older unknown sends even at the current fence', () => {
|
|
const currentSend = { ...oldSend, clientMessageId: 'new-send', acceptedSequence: 6 }
|
|
const rows = [user, clear, row(7, { kind: 'turn', turnId: 'new-turn', state: 'running' })]
|
|
expect(agentSessionCurrentContextRows(rows, [oldSend, currentSend])).toEqual({
|
|
items: [rows[2]],
|
|
submissions: [currentSend]
|
|
})
|
|
expect(activeStructuredAgentSessionTurnId(rows)).toBe('new-turn')
|
|
expect(owesStructuredAgentSessionWork(rows, [oldSend, currentSend], 3)).toBe(true)
|
|
})
|
|
|
|
it('resets the current goal in sorted snapshots and unordered host maps', () => {
|
|
expect(currentAgentSessionThreadGoal([goalRow, clear])).toBeNull()
|
|
expect(currentAgentSessionThreadGoalBySequence([clear, goalRow])).toBeNull()
|
|
const newGoal = row(6, {
|
|
kind: 'status',
|
|
text: 'Goal set',
|
|
threadGoal: { state: 'set', goal: { ...goal, objective: 'New goal' } }
|
|
})
|
|
expect(currentAgentSessionThreadGoalBySequence([newGoal, goalRow, clear])?.objective).toBe(
|
|
'New goal'
|
|
)
|
|
expect(currentAgentSessionThreadGoal([goalRow], clear.sequence)).toBeUndefined()
|
|
})
|
|
|
|
it('does not use earlier usage or stale whole-journal facts after a loaded clear', () => {
|
|
const old = latestStructuredAgentContextFacts([usageRow])
|
|
expect(selectStructuredAgentContextUsage([usageRow, clear], old)).toBeNull()
|
|
expect(latestStructuredAgentContextFacts([clear, usageRow])).toEqual({})
|
|
const newUsage = { ...usageRow, itemId: 'new-usage', sequence: 6 }
|
|
expect(latestStructuredAgentContextFacts([newUsage, clear, usageRow])).toEqual(old)
|
|
expect(selectStructuredAgentContextUsage([usageRow], undefined, clear.sequence)).toBeNull()
|
|
})
|
|
|
|
it('chooses the newest clear independent of map order and scopes off-page rows', () => {
|
|
const again = { ...clear, itemId: 'clear-again', sequence: 8 }
|
|
expect(latestAgentSessionContextClearSequence([again, user, clear])).toBe(8)
|
|
expect(agentSessionCurrentContextRows([user], [oldSend], 5)).toEqual({
|
|
items: [],
|
|
submissions: []
|
|
})
|
|
})
|
|
})
|