mirror of
https://github.com/stablyai/orca.git
synced 2026-10-18 00:03:20 +00:00
fix: harden dispatch status prompt compaction
This commit is contained in:
@@ -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('')
|
||||
|
||||
@@ -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 ||
|
||||
|
||||
Reference in New Issue
Block a user