mirror of
https://github.com/stablyai/orca.git
synced 2026-10-31 00:57:45 +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
76 lines
2.9 KiB
TypeScript
76 lines
2.9 KiB
TypeScript
import type { AgentSessionFailureFact } from './agent-session-failure'
|
|
import type { AgentSessionFailureSentence } from './agent-session-failure-words'
|
|
import type { AgentSessionQueuedSendReceipt } from './agent-session-wire'
|
|
|
|
export type AgentSessionConversationCommand = 'clear' | 'compact'
|
|
|
|
/** How long a client waits for a conversation command: the host may first start an agent at rest. */
|
|
export const AGENT_SESSION_CONVERSATION_COMMAND_TIMEOUT_MS = 195_000
|
|
|
|
export type AgentSessionConversationCommandResult = {
|
|
command: AgentSessionConversationCommand
|
|
state: 'completed' | 'unknown'
|
|
replacementSessionId?: string
|
|
/** A /compact the host holds as a card behind work in flight, with `state: 'completed'`: the
|
|
* card is its one surface from here. Only clients that sent `delivery` receive it. */
|
|
queued?: AgentSessionQueuedSendReceipt
|
|
} &
|
|
/** `error`: a sentence for a person; released clients print it as it is. */
|
|
(
|
|
| { error?: string; failure?: undefined }
|
|
/** What failed, typed, beside its sentence, both from `agentSessionFailureWords`; `failure` is
|
|
* absent from older hosts. */
|
|
| { error: AgentSessionFailureSentence; failure: AgentSessionFailureFact }
|
|
)
|
|
|
|
export type AgentSessionConversationCommandRecord = AgentSessionConversationCommandResult & {
|
|
runtimeFence?: number
|
|
operationId: string
|
|
callerKey: string
|
|
phase: 'prepared' | 'committed'
|
|
}
|
|
|
|
/** A newer host may answer with a command this build doesn't know. */
|
|
export function isAgentSessionConversationCommand(
|
|
value: unknown
|
|
): value is AgentSessionConversationCommand {
|
|
return value === 'clear' || value === 'compact'
|
|
}
|
|
|
|
export function isAgentSessionConversationCommandResult(
|
|
value: unknown
|
|
): value is AgentSessionConversationCommandResult {
|
|
if (!value || typeof value !== 'object') {
|
|
return false
|
|
}
|
|
const row = value as AgentSessionConversationCommandResult
|
|
return (
|
|
isAgentSessionConversationCommand(row.command) &&
|
|
(row.state === 'completed' || row.state === 'unknown') &&
|
|
(row.replacementSessionId === undefined ||
|
|
(typeof row.replacementSessionId === 'string' &&
|
|
/^[A-Za-z0-9_-]{8,128}$/.test(row.replacementSessionId))) &&
|
|
(row.error === undefined || (typeof row.error === 'string' && row.error.length <= 4096))
|
|
)
|
|
}
|
|
|
|
export function isAgentSessionConversationCommandRecord(
|
|
value: unknown
|
|
): value is AgentSessionConversationCommandRecord {
|
|
if (!isAgentSessionConversationCommandResult(value)) {
|
|
return false
|
|
}
|
|
const row = value as AgentSessionConversationCommandRecord
|
|
return (
|
|
(row.phase === 'prepared' || row.phase === 'committed') &&
|
|
(row.runtimeFence === undefined ||
|
|
(Number.isSafeInteger(row.runtimeFence) && row.runtimeFence >= 0)) &&
|
|
typeof row.operationId === 'string' &&
|
|
row.operationId.length > 0 &&
|
|
row.operationId.length <= 512 &&
|
|
typeof row.callerKey === 'string' &&
|
|
row.callerKey.length > 0 &&
|
|
row.callerKey.length <= 512
|
|
)
|
|
}
|