mirror of
https://github.com/stablyai/orca.git
synced 2026-10-09 00:02:39 +00:00
Fix Remote Host downloads and agent status parity (#6436)
* Fix remote host downloads and agent status parity Co-authored-by: Orca <help@stably.ai> * Address remote download review comments Co-authored-by: Orca <help@stably.ai> * Avoid inefficient SSH chunk fallback Co-authored-by: Orca <help@stably.ai> --------- Co-authored-by: Orca <help@stably.ai>
This commit is contained in:
@@ -77,3 +77,25 @@ describe('MiMo title detection', () => {
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('Pi-compatible title detection', () => {
|
||||
it.each([
|
||||
['\u280b OMP', 'OMP', 'working'],
|
||||
['OMP ready', 'OMP', 'idle'],
|
||||
['OMP - action required', 'OMP', 'permission'],
|
||||
['\u280b Pi', 'Pi', 'working'],
|
||||
['Pi ready', 'Pi', 'idle'],
|
||||
['Pi - action required', 'Pi', 'permission']
|
||||
] as const)('classifies synthesized %s', (title, expectedLabel, expectedStatus) => {
|
||||
expect(getAgentLabel(title)).toBe(expectedLabel)
|
||||
expect(detectAgentStatusFromTitle(title)).toBe(expectedStatus)
|
||||
})
|
||||
|
||||
it.each(['~/omp/working', 'omp-harness ready', '~/pi/working', 'pi-scratch ready'])(
|
||||
'does not classify path or hyphen false positive %s',
|
||||
(title) => {
|
||||
expect(getAgentLabel(title)).toBeNull()
|
||||
expect(detectAgentStatusFromTitle(title)).toBeNull()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
@@ -14,6 +14,10 @@ import {
|
||||
titleHasAgentName,
|
||||
titleHasAnyLegacyAgentName
|
||||
} from './agent-name-token-match'
|
||||
import {
|
||||
getPiCompatibleSyntheticAgentLabel,
|
||||
getPiCompatibleSyntheticAgentStatus
|
||||
} from './pi-compatible-synthetic-title'
|
||||
|
||||
// Re-export so existing `agent-detection` importers keep working.
|
||||
export { AGENT_NAMES, titleHasAgentName } from './agent-name-token-match'
|
||||
@@ -319,6 +323,12 @@ export function getAgentLabel(title: string): string | null {
|
||||
if (isGeminiTerminalTitle(title)) {
|
||||
return 'Gemini CLI'
|
||||
}
|
||||
// Why: Pi-compatible synthetic titles can carry braille spinners, which the
|
||||
// generic agent-title heuristics would otherwise claim first.
|
||||
const piCompatibleSyntheticAgentLabel = getPiCompatibleSyntheticAgentLabel(title)
|
||||
if (piCompatibleSyntheticAgentLabel) {
|
||||
return piCompatibleSyntheticAgentLabel
|
||||
}
|
||||
// Why: Pi working titles include a braille spinner prefix, which would be
|
||||
// mistaken for Claude Code if we checked `isClaudeAgent` first.
|
||||
if (isPiAgentTitle(title)) {
|
||||
@@ -417,6 +427,13 @@ export function detectAgentStatusFromTitle(title: string): AgentStatus | null {
|
||||
return 'idle'
|
||||
}
|
||||
|
||||
// Why: resolve synthetic Pi/OMP permission/idle labels before the broader
|
||||
// Pi and braille-spinner checks below.
|
||||
const piCompatibleSyntheticAgentStatus = getPiCompatibleSyntheticAgentStatus(title)
|
||||
if (piCompatibleSyntheticAgentStatus) {
|
||||
return piCompatibleSyntheticAgentStatus
|
||||
}
|
||||
|
||||
// Claude Code uses ✳ prefix for idle — must check before braille/agent-name
|
||||
// because the title text is the task description, not "Claude Code".
|
||||
if (title.startsWith(`${CLAUDE_IDLE} `) || title === CLAUDE_IDLE) {
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
export type PiCompatibleSyntheticAgentLabel = 'Pi' | 'OMP'
|
||||
export type PiCompatibleSyntheticAgentStatus = 'working' | 'permission' | 'idle'
|
||||
|
||||
const PI_COMPATIBLE_SYNTHETIC_TITLE_RE =
|
||||
/^\s*(?:[\u2800-\u28ff]\s+)?(pi|omp)(?:\s+-\s+action required|\s+(?:ready|idle|done))?\s*$/i
|
||||
const PI_COMPATIBLE_IDLE_RE = /(?<![\w./\\-])(?:ready|idle|done)(?![\w-])/i
|
||||
|
||||
function containsBrailleSpinner(title: string): boolean {
|
||||
for (const char of title) {
|
||||
const codePoint = char.codePointAt(0)
|
||||
if (codePoint !== undefined && codePoint >= 0x2800 && codePoint <= 0x28ff) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export function getPiCompatibleSyntheticAgentLabel(
|
||||
title: string
|
||||
): PiCompatibleSyntheticAgentLabel | null {
|
||||
const match = PI_COMPATIBLE_SYNTHETIC_TITLE_RE.exec(title)
|
||||
if (!match) {
|
||||
return null
|
||||
}
|
||||
return match[1].toLowerCase() === 'omp' ? 'OMP' : 'Pi'
|
||||
}
|
||||
|
||||
export function getPiCompatibleSyntheticAgentStatus(
|
||||
title: string
|
||||
): PiCompatibleSyntheticAgentStatus | null {
|
||||
if (!getPiCompatibleSyntheticAgentLabel(title)) {
|
||||
return null
|
||||
}
|
||||
if (containsBrailleSpinner(title)) {
|
||||
return 'working'
|
||||
}
|
||||
const lower = title.toLowerCase()
|
||||
if (
|
||||
lower.includes('action required') ||
|
||||
lower.includes('permission') ||
|
||||
lower.includes('waiting')
|
||||
) {
|
||||
return 'permission'
|
||||
}
|
||||
if (PI_COMPATIBLE_IDLE_RE.test(title)) {
|
||||
return 'idle'
|
||||
}
|
||||
return null
|
||||
}
|
||||
@@ -327,6 +327,12 @@ export type RuntimeFilePreviewResult = {
|
||||
mimeType?: string
|
||||
}
|
||||
|
||||
export type RuntimeFileReadChunkResult = {
|
||||
contentBase64: string
|
||||
bytesRead: number
|
||||
eof: boolean
|
||||
}
|
||||
|
||||
export type RuntimeTerminalSummary = {
|
||||
handle: string
|
||||
ptyId: string | null
|
||||
|
||||
@@ -20,4 +20,16 @@ describe('synthetic agent titles', () => {
|
||||
expect(getSyntheticAgentTerminalTitle('devin', 'waiting')).toBe('Devin - action required')
|
||||
expect(shouldDriveSyntheticAgentTitleFromHook('devin', 'working')).toBe(true)
|
||||
})
|
||||
|
||||
it('provides Pi-compatible OMP titles for hook-driven status updates', () => {
|
||||
expect(getSyntheticAgentTerminalTitle('omp', 'done')).toBe('OMP ready')
|
||||
expect(getSyntheticAgentTerminalTitle('omp', 'waiting')).toBe('OMP - action required')
|
||||
expect(shouldDriveSyntheticAgentTitleFromHook('omp', 'working')).toBe(true)
|
||||
})
|
||||
|
||||
it('provides Pi titles for hook-driven status updates', () => {
|
||||
expect(getSyntheticAgentTerminalTitle('pi', 'done')).toBe('Pi ready')
|
||||
expect(getSyntheticAgentTerminalTitle('pi', 'waiting')).toBe('Pi - action required')
|
||||
expect(shouldDriveSyntheticAgentTitleFromHook('pi', 'working')).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -26,6 +26,16 @@ export const SYNTHETIC_AGENT_TITLE_PROFILES: Record<string, SyntheticAgentTitleP
|
||||
permissionLabel: 'OpenCode - action required',
|
||||
idleLabel: 'OpenCode ready'
|
||||
},
|
||||
pi: {
|
||||
workingLabel: 'Pi',
|
||||
permissionLabel: 'Pi - action required',
|
||||
idleLabel: 'Pi ready'
|
||||
},
|
||||
omp: {
|
||||
workingLabel: 'OMP',
|
||||
permissionLabel: 'OMP - action required',
|
||||
idleLabel: 'OMP ready'
|
||||
},
|
||||
droid: {
|
||||
workingLabel: 'Droid',
|
||||
permissionLabel: 'Droid - action required',
|
||||
|
||||
Reference in New Issue
Block a user