mirror of
https://github.com/stablyai/orca.git
synced 2026-11-02 10:08:13 +00:00
* fix(native-chat): a /compact sent while the agent works waits in line instead of being refused * test(native-chat): build the admission test's submissions without a type assertion * fix(native-chat): a /clear refused while the agent works says so plainly; a /compact behind an unsent message waits for it quietly * test(native-chat): name the admission test's cases for the sends they model * fix(native-chat): a /compact refused while the agent works reads plainly too; a command card offers no Edit * test(native-chat): a refused /compact reads the plain sentence * fix(native-chat): a refused command card is spent and said once; a command card offers Send while the agent is idle; /compact behind an unsent message is not taken * test(native-chat): keep the queued receipt's narrowing inside the wait * fix(native-chat): spend a command card only when its own turn says why; refuse a queued command without a hand-off, with its reason; a queue send on its way reads as sending * fix(native-chat): a recorded send is no sending card; queue lists land at once; a spent card's wait says to run it again; only /compact or /clear give way to returned text * refactor(native-chat): derive the sending cards inside the queued-messages hook * fix(native-chat): keep protocol-version and the agent-session params under the line limit; the send capabilities get their own module * fix(native-chat): with the agent idle, a command behind this window's own unsent message says it is still being sent * fix(native-chat): the queued-commands capability stays a plain constant beside the others; main's send capabilities back to its text * test(native-chat): keep the rewind suite under its line limit after main's growth * fix(native-chat): one import per module in the command send; a rewind on its way holds commands, tested * test(native-chat): type the rewind module mock with a type import * test(native-chat): a command card cut short by a restart waits or is kept like any card; kept-card captions name only controls shown * fix(native-chat): a held command card, which the queue skips, no longer forces later sends to queue * fix(native-chat): a command's refusal line goes once what it waits on is gone A refusal that names something the chat shows (the agent working, a pending prompt, background tasks, an unsent message) is said only while that still holds, derived each render, and dropped once it ends. Other composer errors are unchanged. * fix(mobile): a command's refusal banner goes once what it waits on is gone The phone's banner keeps a refusal naming the agent working or a pending prompt only while the chat still shows it, dropped each render once it ends. Background tasks, which the phone can't see, and generic errors behave as before. The host-reason mapping is shared with desktop. * fix(native-chat): a refusal behind an earlier message names whether it is being sent or offers Retry Each line now goes when its own state ends: a send that fails stops being sent, and a resend stops offering Retry. * test(native-chat): a Stop behind a typed /compact keeps the taken-back message on screen; the in-doubt case says so * fix(native-chat): a command refused while the queue is about to send reads working, as the pane does * Update held command fixture for the merged queue model * Restart one host at a time in the recovery ordering test * fix: preserve person queue reserve for chat commands
50 lines
2.0 KiB
TypeScript
50 lines
2.0 KiB
TypeScript
// A conversation command refused for a reason the person can act on: said as that refusal is
|
|
// everywhere, so a command's row names what to wait for rather than "try it again".
|
|
|
|
import type { AgentSessionFailureFact } from './agent-session-failure'
|
|
import type { AgentSessionFailureSay } from './agent-session-failure-copy'
|
|
import type { AgentSessionConversationCommand } from './agent-session-conversation-command'
|
|
import { joinSentences } from './sentence-joining'
|
|
|
|
type ReasonWords = (
|
|
say: AgentSessionFailureSay,
|
|
command: AgentSessionConversationCommand | undefined
|
|
) => string | undefined
|
|
|
|
const STILL_WORKING: ReasonWords = (say, command) =>
|
|
command
|
|
? joinSentences([say('agentStillWorking'), say('runCommandWhenDone', { command })])
|
|
: undefined
|
|
|
|
/** A wait the person ends: nothing runs the command after it, so they run it again. */
|
|
const WAIT_THEN_RUN_AGAIN =
|
|
(
|
|
cause: 'backgroundTasksRunning' | 'agentStarting',
|
|
wait: 'waitForBackgroundTasks' | 'waitForStart'
|
|
): ReasonWords =>
|
|
(say, command) =>
|
|
joinSentences([
|
|
say(cause),
|
|
say(wait),
|
|
...(command ? [say('runCommandAgain', { command })] : [])
|
|
])
|
|
|
|
const WORDS_BY_REASON: Partial<Record<string, ReasonWords>> = {
|
|
backgroundTasksRunning: WAIT_THEN_RUN_AGAIN('backgroundTasksRunning', 'waitForBackgroundTasks'),
|
|
handoffInFlight: WAIT_THEN_RUN_AGAIN('agentStarting', 'waitForStart'),
|
|
turnActive: STILL_WORKING,
|
|
messagesUnsettled: STILL_WORKING,
|
|
promptPending: (say, command) => (command ? say('commandAfterAnswer', { command }) : undefined)
|
|
}
|
|
|
|
/** Undefined for a reason with no words of its own: the command's generic sentence says it. */
|
|
export function commandRefusedByReason(
|
|
say: AgentSessionFailureSay,
|
|
{ command }: { command?: AgentSessionConversationCommand },
|
|
fact: AgentSessionFailureFact
|
|
): string | undefined {
|
|
const details = fact.refusal?.details
|
|
const reason = details && 'reason' in details ? details.reason : undefined
|
|
return reason === undefined ? undefined : WORDS_BY_REASON[reason]?.(say, command)
|
|
}
|