mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
fix(runtime): retire terminal snapshot probes before waiter timeout (#16149)
* refactor(renderer): use terminal paste sanitizer directly * fix(runtime): order visible probe timeout settlement * fix(runtime): skip unorderable visible probes
This commit is contained in:
@@ -35600,23 +35600,36 @@ export class OrcaRuntimeService {
|
||||
* later transition. A provider screen that is still working when this fires
|
||||
* resolves through the poll, not here. */
|
||||
private startTuiIdleVisibleReadProbe(waiter: TerminalWaiter, waiterTimeoutMs: number): void {
|
||||
const snapshotTimeoutMs = Math.min(
|
||||
VISIBLE_TERMINAL_SNAPSHOT_TIMEOUT_MS,
|
||||
Math.max(0, waiterTimeoutMs - 1)
|
||||
const settleMarginMs = Math.min(
|
||||
TUI_IDLE_VISIBLE_PROBE_SETTLE_MARGIN_MS,
|
||||
Math.max(1, Math.floor(waiterTimeoutMs / 3))
|
||||
)
|
||||
const probeTimeoutMs = Math.min(
|
||||
VISIBLE_TERMINAL_SNAPSHOT_TIMEOUT_MS + settleMarginMs,
|
||||
Math.max(0, waiterTimeoutMs - settleMarginMs)
|
||||
)
|
||||
const providerTimeoutMs = Math.min(
|
||||
VISIBLE_TERMINAL_SNAPSHOT_TIMEOUT_MS,
|
||||
Math.max(0, probeTimeoutMs - settleMarginMs)
|
||||
)
|
||||
// Node clamps sub-millisecond timers to 1ms, so no distinct retirement deadline exists.
|
||||
if (providerTimeoutMs < 1) {
|
||||
return
|
||||
}
|
||||
// Retire the provider before the detached probe and waiter can settle.
|
||||
void withTimeout(
|
||||
this.readTerminal(
|
||||
waiter.handle,
|
||||
{},
|
||||
{
|
||||
timeoutMs: snapshotTimeoutMs,
|
||||
timeoutMs: providerTimeoutMs,
|
||||
retireOnTimeout: true,
|
||||
// Why: the ready banner stays in scrollback for the whole session, so
|
||||
// classifying history would call a working agent idle (#15569 review).
|
||||
visibleScreenOnly: true
|
||||
}
|
||||
),
|
||||
snapshotTimeoutMs,
|
||||
probeTimeoutMs,
|
||||
null
|
||||
)
|
||||
.then((read) => {
|
||||
@@ -38641,6 +38654,7 @@ const MAX_TERMINAL_PREVIEW_CHARS = 32 * 1024
|
||||
export const AUTHORITATIVE_TERMINAL_SNAPSHOT_TIMEOUT_MS = 8_000
|
||||
const VISIBLE_TERMINAL_SNAPSHOT_TIMEOUT_MS = 750
|
||||
const VISIBLE_TERMINAL_SNAPSHOT_RETRY_MS = 1_000
|
||||
const TUI_IDLE_VISIBLE_PROBE_SETTLE_MARGIN_MS = 10
|
||||
const MAX_PREVIEW_LINES = 6
|
||||
const MAX_PREVIEW_CHARS = 300
|
||||
const WORKTREE_STATUS_PRIORITY: Record<RuntimeWorktreeStatus, number> = {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { RuntimeTerminalSend, RuntimeTerminalWait } from '../../../shared/runtime-types'
|
||||
import { sanitizeTerminalPasteText } from '@/components/terminal-pane/terminal-bracketed-paste'
|
||||
import { useAppStore } from '@/store'
|
||||
import { callRuntimeRpc, getActiveRuntimeTarget } from '@/runtime/runtime-rpc-client'
|
||||
import { getSettingsForWorktreeRuntimeOwner } from '@/lib/worktree-runtime-owner'
|
||||
@@ -10,8 +11,7 @@ import {
|
||||
import {
|
||||
BRACKETED_PASTE_BEGIN,
|
||||
BRACKETED_PASTE_END,
|
||||
POST_PASTE_SUBMIT_DELAY_MS,
|
||||
sanitizeBracketedPasteContent
|
||||
POST_PASTE_SUBMIT_DELAY_MS
|
||||
} from './agent-paste-draft'
|
||||
import type { ActiveAgentNotesSendResult } from './active-agent-note-send-result'
|
||||
import {
|
||||
@@ -182,7 +182,7 @@ async function sendPromptWithGuardedPasteAndEnter(
|
||||
return { status: initialAgentStatus.status }
|
||||
}
|
||||
|
||||
const pastePayload = `${BRACKETED_PASTE_BEGIN}${sanitizeBracketedPasteContent(prompt)}${BRACKETED_PASTE_END}`
|
||||
const pastePayload = `${BRACKETED_PASTE_BEGIN}${sanitizeTerminalPasteText(prompt)}${BRACKETED_PASTE_END}`
|
||||
try {
|
||||
const { send } = await callRuntimeRpc<{ send: RuntimeTerminalSend }>(
|
||||
runtimeTarget,
|
||||
|
||||
@@ -9,8 +9,7 @@ import {
|
||||
} from '@/runtime/runtime-terminal-inspection'
|
||||
import {
|
||||
BRACKETED_PASTE_END,
|
||||
BRACKETED_PASTE_START,
|
||||
sanitizeTerminalPasteText
|
||||
BRACKETED_PASTE_START
|
||||
} from '@/components/terminal-pane/terminal-bracketed-paste'
|
||||
import { runTerminalPtyInputTransaction } from '@/components/terminal-pane/terminal-pty-input-transaction'
|
||||
import { waitForAgentReady } from './agent-ready-wait'
|
||||
@@ -36,10 +35,6 @@ export const BRACKETED_PASTE_BEGIN = BRACKETED_PASTE_START
|
||||
export { BRACKETED_PASTE_END }
|
||||
export const POST_PASTE_SUBMIT_DELAY_MS = 50
|
||||
|
||||
export function sanitizeBracketedPasteContent(content: string): string {
|
||||
return sanitizeTerminalPasteText(content)
|
||||
}
|
||||
|
||||
// Why: "the tab has a PTY" and "the agent's composer accepts input" are separate
|
||||
// states with separate failure modes, so they get separate budgets. A PTY that
|
||||
// hasn't appeared in 8s means the launch itself failed — waiting the (longer)
|
||||
|
||||
Reference in New Issue
Block a user