mirror of
https://github.com/stablyai/orca.git
synced 2026-11-05 19:47:27 +00:00
* fix(mobile): show skill commands you ran in the chat Claude records a skill run (/simplify, /review-pr 123) as a command envelope, which the noise filter hides. Desktop surfaces it as the typed `/name args` before folding; the phone only normalised image markers, so the turn vanished and the reply answered nothing. Both apps now prepare a terminal agent's transcript through one shared prepareNativeChatMessages: skill envelopes, reporting-command output and image marker turns. * fix(native-chat): keep a streamed sentence from coming back after a tool or thought row Both chats hide the live preview once the transcript shows it, but each only compared the preview with the last row. When a tool call or thought landed below the sentence, the last row had no words and the earlier sentence came back at the bottom as a live message. latestNativeChatReplyText reads back past those rows to the newest assistant words in the turn; desktop's preview check and the phone's streaming gate both use it. * fix(mobile): draw errors, warnings and status notices as notices, not agent replies The phone drew every system row through the agent's markdown, so an API retry warning, a sign-in failure, "Context compacted" or "Stopped manually" read as the agent's own words. Only the clear boundary and two host notices were special-cased. Desktop's notice rules move to shared native-chat-notice: which block of a system row is its notice, and the look it gets (divider, command output, host status, plan, aside, or a toned line). Desktop's notice row switches on it with no change in what it draws; the phone's new notice row draws the same looks, with words in faint type when a row has no notice. * fix(native-chat): show a new reply that follows a tool call on desktop The earlier fix read back past a tool call or thought to the newest assistant words, then kept desktop's length rule. Commentary written before the tool is often longer than the reply after it, so a new, shorter reply stayed hidden until the transcript caught up. The last-row rule is back as it was. Reading back now only hides the preview when the earlier words already contain it, which is the sentence still on screen while the tool runs. The phone's gate reads only rows that landed after the current reply began, so it was not affected. * fix(mobile): open the actions sheet from a long press on a plan's link A plan card's Markdown was drawn without the row's long-press handler, so on Android holding a link or file path inside a plan no longer opened Copy message / Select text, as it did before plans were drawn as notices. The notice row now passes the handler to the plan's Markdown.
74 lines
2.8 KiB
TypeScript
74 lines
2.8 KiB
TypeScript
// How a chat draws a row the agent did not write in its own words: compaction and clear markers,
|
|
// command output, host status, plans, and warnings or errors. Desktop translates these words (they
|
|
// are its fallbacks); the phone shows them as they are.
|
|
|
|
import {
|
|
isAgentSessionHostStatusPresentation,
|
|
type AgentSessionHostStatusPresentation
|
|
} from './agent-session-host-status-rows'
|
|
import { AGENT_SESSION_ORCA_STOP_PRESENTATION } from './agent-session-orca-stop'
|
|
import { NATIVE_CHAT_STOPPED_BEFORE_START_PRESENTATION } from './native-chat-stopped-before-start'
|
|
import type { NativeChatBlock, NativeChatTextBlock } from './native-chat-types'
|
|
|
|
export const NATIVE_CHAT_NOTICE_COPY = {
|
|
compaction: 'Context compacted',
|
|
contextCleared: 'Context cleared',
|
|
plan: 'Plan'
|
|
} as const
|
|
|
|
export type NativeChatNoticeTone = 'warning' | 'error' | 'notice'
|
|
|
|
export type NativeChatNoticeLook =
|
|
/** A rule across the chat with its label. */
|
|
| { kind: 'divider'; label: 'compaction' | 'contextCleared' }
|
|
/** Laid out in columns, so drawn in monospace. */
|
|
| { kind: 'command-output' }
|
|
/** The host's line in the reader's words, drawn faint. */
|
|
| { kind: 'host-status'; presentation: AgentSessionHostStatusPresentation }
|
|
| { kind: 'plan' }
|
|
/** Faint, as a system row with no notice of its own is. */
|
|
| { kind: 'aside' }
|
|
/** A boxed line with its icon when it has a tone; plain text when it has none. */
|
|
| { kind: 'line'; tone: NativeChatNoticeTone | null }
|
|
|
|
/** The block a system row draws as its notice. A system row without one reads as a faint aside. */
|
|
export function nativeChatNoticeBlock(
|
|
blocks: readonly NativeChatBlock[]
|
|
): NativeChatTextBlock | undefined {
|
|
return blocks.find(
|
|
(block): block is NativeChatTextBlock =>
|
|
block.type === 'text' && (block.presentation !== undefined || block.tone !== undefined)
|
|
)
|
|
}
|
|
|
|
export function nativeChatNoticeLook(block: NativeChatTextBlock): NativeChatNoticeLook {
|
|
const { presentation } = block
|
|
if (presentation === 'compaction') {
|
|
return { kind: 'divider', label: 'compaction' }
|
|
}
|
|
if (presentation === 'context-cleared') {
|
|
return { kind: 'divider', label: 'contextCleared' }
|
|
}
|
|
if (presentation === 'command-output') {
|
|
return { kind: 'command-output' }
|
|
}
|
|
if (isAgentSessionHostStatusPresentation(presentation)) {
|
|
return { kind: 'host-status', presentation }
|
|
}
|
|
if (presentation === 'plan-document') {
|
|
return { kind: 'plan' }
|
|
}
|
|
if (presentation === NATIVE_CHAT_STOPPED_BEFORE_START_PRESENTATION) {
|
|
return { kind: 'aside' }
|
|
}
|
|
// Orca stopped the reply, not the agent: stored red for clients that predate it, read as a notice.
|
|
if (presentation === AGENT_SESSION_ORCA_STOP_PRESENTATION) {
|
|
return { kind: 'line', tone: 'notice' }
|
|
}
|
|
const { tone } = block
|
|
return {
|
|
kind: 'line',
|
|
tone: tone === 'warning' || tone === 'error' || tone === 'notice' ? tone : null
|
|
}
|
|
}
|