/** Worker final-result presence and bounded model-facing excerpts. */ /** * R-EXEC-3: a run is complete when the child emitted `agent_settled` and a * non-empty final assistant message exists. Markdown shape is deliberately not * part of completion: useful free-form prose is a valid result. */ export function hasSemanticCompletion(settled: boolean, finalAssistantText: string | null): boolean { return settled && finalAssistantText !== null && finalAssistantText.trim().length > 0; } /** Longest prefix that fits without splitting a Unicode code point. */ function prefixToBytes(text: string, maxBytes: number): string { if (maxBytes <= 0) return ""; if (Buffer.byteLength(text, "utf8") <= maxBytes) return text; let bytes = 0; let end = 0; for (const codePoint of text) { const next = Buffer.byteLength(codePoint, "utf8"); if (bytes + next > maxBytes) break; bytes += next; end += codePoint.length; } return text.slice(0, end); } /** Longest suffix that fits without splitting a Unicode code point. */ function suffixToBytes(text: string, maxBytes: number): string { if (maxBytes <= 0) return ""; if (Buffer.byteLength(text, "utf8") <= maxBytes) return text; let bytes = 0; let start = text.length; while (start > 0) { let nextStart = start - 1; const code = text.charCodeAt(nextStart); if (code >= 0xdc00 && code <= 0xdfff && nextStart > 0) { const previous = text.charCodeAt(nextStart - 1); if (previous >= 0xd800 && previous <= 0xdbff) nextStart -= 1; } const next = Buffer.byteLength(text.slice(nextStart, start), "utf8"); if (bytes + next > maxBytes) break; bytes += next; start = nextStart; } return text.slice(start); } /** * R-WORK-10. `result.md` keeps the full final text. When model-visible content * must be bounded, preserve both the beginning and end of arbitrary prose and * point to the durable full result. No headings or outcome tokens are assumed. */ export function truncateReport(text: string, maxBytes: number, resultPath: string): string { if (Buffer.byteLength(text, "utf8") <= maxBytes) return text; if (maxBytes <= 0) return ""; const fullPointer = `\n\n[… truncated; full result: ${resultPath} …]\n\n`; const boundedPointer = "\n\n[… truncated; inspect the full run result …]\n\n"; // Content is the point of this projection. Include the exact path only when it // leaves at least half the budget for useful report head/tail; otherwise status // and tool details retain the exact durable path programmatically. const contentReserve = Math.max(2, Math.floor(maxBytes / 2)); let pointer = Buffer.byteLength(fullPointer, "utf8") <= maxBytes - contentReserve ? fullPointer : boundedPointer; if (Buffer.byteLength(pointer, "utf8") > maxBytes - 2) pointer = "…"; const pointerBytes = Buffer.byteLength(pointer, "utf8"); if (pointerBytes > maxBytes) return prefixToBytes(text, maxBytes); const contentBytes = maxBytes - pointerBytes; const headBytes = Math.ceil(contentBytes / 2); const tailBytes = contentBytes - headBytes; return `${prefixToBytes(text, headBytes)}${pointer}${suffixToBytes(text, tailBytes)}`; }