Files
orca/src/shared/structured-agent-session-status-block.ts
T
Brennan Benson 4a33cd8e73 fix(native-chat): a usage limit reads as a pause with its reset time and a Continue, not a failure (#30396)
* fix(native-chat): a usage limit reads as a pause with its reset time and a Continue, not a failure

Claude, Codex and Grok chats that hit the account's usage limit now end the
turn on one warning row that names the limit and, in the reader's clock,
when it resets, with Continue to pick the turn back up. Each adapter reads
its protocol's typed limit signal into a `usageLimitReached` failure fact;
older clients keep the host's sentence.

* fix(native-chat): keep the failure words and chat session files within their line budgets

Moves the attachment-problem sentences to their own file and hands the composer's send straight to Continue.

* fix(native-chat): drop a check the shown branch already rules out

* fix(i18n): ship the usage-limit failure words in the runtime catalog

* fix(native-chat): reconcile usage failures by owning turn and typed cause

* fix(codex): keep snapshot import type-only

* fix(claude): open refusal turns without opening empty placeholders

* fix(native-chat): bind usage Continue to the latest idle failed turn

* test(native-chat): isolate stale Continue from ordinary delivery progress

* test(native-chat): use a braced journal assertion

* test(native-chat): build failure rows through their word factory

* fix(claude): retain terminal failure evidence through result reconciliation

* fix(native-chat): complete usage Continue through the composer sender

* test(native-chat): provide the composer options surface in Continue coverage

* test(native-chat): use typed failure words in renderer fixtures

* test(native-chat): match the remote send payload apart from transport options

* fix(native-chat): replace the previous sender notice on Continue

* fix(native-chat): clear superseded Continue notices before rendering

* fix(native-chat): preserve ordinary composer send arguments

* fix(claude): resolve terminal ownership and preserve resultless quota failures

* fix(claude): keep repeated terminal detail unchanged and complete test fixtures

* fix(claude): resolve deferred terminal replays after owning journal writes

* refactor(native-chat): share tombstone append within the sink line budget

* fix(claude): retain both input and echo correlation on the live turn

* fix(claude): preserve unowned result completion after terminal resolution

* fix(claude): allow unassociated successful goal completion

* fix(claude): keep terminal completion on the live turn

* fix(claude): keep typed notices separate from quota failures

* fix(claude): preserve context-limit failures as ordinary errors

* fix(native-chat): keep quota failures visible in collapsed turns

* fix(native-chat): return keyboard Continue focus to the composer

* test(native-chat): keep quota fixture context stable

* test(native-chat): hoist quota context to module scope

* fix(i18n): use one Chinese word for the agent in both Continue tooltips
2026-10-19 14:43:16 -07:00

44 lines
1.7 KiB
TypeScript

import { readWholeAgentSessionFailureFact } from './agent-session-failure'
import type { AgentJournalStatusItem, AgentJournalTurnScope } from './agent-session-journal-types'
import { readAgentSessionOrcaStop } from './agent-session-orca-stop'
import type { NativeChatTextBlock } from './native-chat-types'
import {
AGENT_SESSION_COMPACTION_SKIPPED_PRESENTATION,
isAgentSessionLegacyCompactionResult
} from './agent-session-compaction'
/** A status row as the line a chat paints: named fields only, so a host-only key never leaks. */
export function structuredAgentSessionStatusBlock(
body: AgentJournalStatusItem,
turnScope?: AgentJournalTurnScope,
itemId?: string
): NativeChatTextBlock {
const failure = readWholeAgentSessionFailureFact(body.failure)
const orcaStop = readAgentSessionOrcaStop(body.orcaStop)
const presentation =
body.presentation ??
(body.tone === 'warning' && itemId !== undefined && isAgentSessionLegacyCompactionResult(itemId)
? AGENT_SESSION_COMPACTION_SKIPPED_PRESENTATION
: undefined)
return {
type: 'text',
text: body.text,
...(presentation !== undefined ? { presentation } : {}),
...(body.contextClear !== undefined ? { contextClear: body.contextClear } : {}),
...(body.tone !== undefined ? { tone: body.tone } : {}),
...(body.providerFrame ? { providerFrame: body.providerFrame } : {}),
...(failure ? { failure } : {}),
...(failure?.kind === 'usageLimitReached' && turnScope?.kind === 'turn'
? { usageLimitTurnItemId: turnScope.turnItemId }
: {}),
...(orcaStop
? {
orcaStop: {
...orcaStop,
...(turnScope?.kind === 'turn' ? { turnItemId: turnScope.turnItemId } : {})
}
}
: {})
}
}