fix: harden dispatch status prompt compaction

This commit is contained in:
Jinjing
2026-07-10 17:37:06 -07:00
parent d4c6942940
commit e499a7bbdc
2 changed files with 73 additions and 2 deletions
+32
View File
@@ -118,6 +118,38 @@ Fix dispatch fallback preview for normalized status prompts`
expect(result!.prompt).not.toContain('heartbeat')
})
it('ignores task-marker text inside base-drift commit subjects', () => {
const result = normalizeAgentStatusPayload({
state: 'working',
// Why: use CRLF to cover Windows hook payloads while proving repository
// commit text cannot impersonate Orca's standalone task separator.
prompt: [
'You are working inside Orca, a multi-agent IDE. You are a dispatched worker.',
'Your task ID is: task_drift_marker',
'',
'--- BASE DRIFT ---',
' - docs: explain === TASK === marker parsing',
'---',
'',
'=== TASK ===',
'Fix the actual dispatch fallback preview'
].join('\r\n')
})
expect(result!.prompt).toContain('=== TASK === Fix the actual dispatch fallback preview')
expect(result!.prompt).not.toContain('marker parsing')
})
it('keeps dispatch detection bounded for oversized whitespace prompts', () => {
const trimStartSpy = vi.spyOn(String.prototype, 'trimStart')
const prompt = ' '.repeat(1_000_000)
expect(normalizeAgentStatusPayload({ state: 'working', prompt })!.prompt).toBe('')
expect(
trimStartSpy.mock.contexts.some((context) => String(context).length === prompt.length)
).toBe(false)
})
it('defaults missing prompt to empty string', () => {
const result = parseAgentStatusPayload('{"state":"done"}')
expect(result!.prompt).toBe('')
+41 -2
View File
@@ -14,7 +14,17 @@ const ORCA_DISPATCH_STATUS_TASK_ID_MARKER = 'Your task ID is:'
const ORCA_DISPATCH_STATUS_SOURCE_SCAN_LIMIT = 24_576
export function isOrcaDispatchStatusPrompt(value: string): boolean {
return value.trimStart().startsWith(ORCA_DISPATCH_STATUS_PREAMBLE_PREFIX)
// Why: status payloads cross a trust boundary. Keep dispatch detection
// bounded too, or leading whitespace can bypass the normalizer's scan cap.
const scanEnd = Math.min(value.length, ORCA_DISPATCH_STATUS_SOURCE_SCAN_LIMIT)
let start = 0
while (start < scanEnd && isEcmaTrimWhitespace(value.charCodeAt(start))) {
start++
}
return (
start + ORCA_DISPATCH_STATUS_PREAMBLE_PREFIX.length <= scanEnd &&
value.startsWith(ORCA_DISPATCH_STATUS_PREAMBLE_PREFIX, start)
)
}
/**
@@ -50,7 +60,7 @@ export function compactDispatchPromptForStatus(
}
let taskBody = ''
const taskMarkerIndex = scan.indexOf(ORCA_DISPATCH_STATUS_TASK_MARKER)
const taskMarkerIndex = findTaskMarkerIndex(scan)
if (taskMarkerIndex !== -1) {
const body = scan.slice(taskMarkerIndex + ORCA_DISPATCH_STATUS_TASK_MARKER.length)
for (const line of body.split(/\r?\n/)) {
@@ -74,6 +84,35 @@ export function compactDispatchPromptForStatus(
return normalizeSingleLine(compact, maxLength)
}
function findTaskMarkerIndex(value: string): number {
// Why: base-drift commit subjects are repository-controlled and may mention
// the marker. Raw preambles must use the standalone line emitted by Orca.
let searchFrom = 0
while (searchFrom < value.length) {
const markerIndex = value.indexOf(ORCA_DISPATCH_STATUS_TASK_MARKER, searchFrom)
if (markerIndex === -1) {
break
}
const markerEnd = markerIndex + ORCA_DISPATCH_STATUS_TASK_MARKER.length
const startsLine = markerIndex === 0 || isLineBreak(value.charCodeAt(markerIndex - 1))
const endsLine = markerEnd === value.length || isLineBreak(value.charCodeAt(markerEnd))
if (startsLine && endsLine) {
return markerIndex
}
searchFrom = markerEnd
}
// Already-normalized dispatch previews are single-line and intentionally
// carry the marker inline; normalization must stay idempotent across hops.
return value.includes('\n') || value.includes('\r')
? -1
: value.indexOf(ORCA_DISPATCH_STATUS_TASK_MARKER)
}
function isLineBreak(code: number): boolean {
return code === 10 || code === 13
}
function isEcmaTrimWhitespace(code: number): boolean {
return (
code === 0x20 ||