mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 00:27:39 +00:00
* Replace assistant-prose heuristic with explicit turn lifecycle markers Extract provider-authored turn boundaries (completion, interruption) directly from Claude/Codex transcripts so the chat view knows when work ends without guessing from message presence. Reconciles live hook state with transcript lifecycle: when a terminal boundary lands, it settles a dropped Stop hook instead of letting prose mislead the UI into showing 'working' after done. * fix(review): cover Claude terminal stop_reasons and RPC lifecycle frames Treat max_tokens/stop_sequence/refusal as completed markers so capable hosts do not stay working after a dropped Stop, and assert lifecycle payloads on runtime subscribe/read frames plus mid-turn non-terminal stop_reason cases. * test(native-chat): clarify that lifecycle field is optional Add type assertion and comment documenting that lifecycle field is optional and can be omitted in truncation-gating test fixtures. * fix(native-chat): settle status on interruption despite working subagent When Claude's turn is explicitly interrupted, the session should show ready immediately — even if background subagents are still running. Add an interruption check before consulting the hook's working-subagents flag so interruptions take precedence. Also normalize omitted lifecycle timestamps to null instead of leaving them undefined, and add test coverage for both cases. * fix(native-chat): settle loading spinner on explicit turn boundaries Explicit transcript turn-lifecycle markers now fully replace the prose-fallback settlement path. Remove the now-unused `turnLifecycleCapable` flag and wire lifecycle to suppress spinner even when hook status lingers. Refine Claude lifecycle detection to distinguish terminal stops from mid-turn tool_use rows, exclude harness noise from new-generation detection, and apply clock-skew slack over SSH/relay. Serialize PTY sends per line to prevent rapid prompts from gluing before Enter, clearing unsubmitted input on cancel. Update working suppression to detect epoch rollovers so interrupt+next-turn without a ready gap resets the spinner correctly.
27 lines
1.2 KiB
TypeScript
27 lines
1.2 KiB
TypeScript
// Shared detection of provider-authored turn boundaries. The message decoders
|
|
// render a visible status row from these lines; the lifecycle decoders settle
|
|
// the chat spinner from the same lines. Keeping the predicates here means the
|
|
// two consumers can never disagree about which JSONL line is an interrupt/abort
|
|
// or a turn boundary — updating a provider's format touches one place, so a
|
|
// rename can't leave a visible "interrupted" row that never settles (or vice
|
|
// versa).
|
|
|
|
import { extractString } from '../ai-vault/session-scanner-values'
|
|
|
|
/**
|
|
* The `interruptedMessageId` on a Claude user row when that row is Claude's
|
|
* injected interrupt notice rather than a real user prompt. Returns undefined
|
|
* for genuine user turns.
|
|
*/
|
|
export function claudeInterruptedMessageId(record: Record<string, unknown>): string | undefined {
|
|
if (record.type !== 'user') {
|
|
return undefined
|
|
}
|
|
return extractString(record.interruptedMessageId) ?? undefined
|
|
}
|
|
|
|
/** Codex `event_msg` payload types that bound a turn's lifecycle. */
|
|
export const CODEX_EVENT_TURN_STARTED = 'task_started'
|
|
export const CODEX_EVENT_TURN_COMPLETE = 'task_complete'
|
|
export const CODEX_EVENT_TURN_ABORTED = 'turn_aborted'
|