(body)
| 32 | const HISTORY_MARKER = '# Conversation history (JSONL)' |
| 33 | const CURRENT_MESSAGE_MARKER = '# Current message' |
| 34 | |
| 35 | const byteLength = (value) => Buffer.byteLength(String(value || ''), 'utf8') |
| 36 | |
| 37 | const truncateUtf8 = (value, maxBytes, fromEnd = false) => { |
| 38 | const buffer = Buffer.from(String(value || ''), 'utf8') |
| 39 | if (buffer.length <= maxBytes) return buffer.toString('utf8') |
| 40 | const slice = fromEnd |
| 41 | ? buffer.subarray(Math.max(0, buffer.length - maxBytes)) |
| 42 | : buffer.subarray(0, maxBytes) |
| 43 | return slice.toString('utf8').replace(/^\uFFFD|\uFFFD$/g, '') |
| 44 | } |
| 45 | |
| 46 | const truncateUtf8HeadTail = ( |
| 47 | value, |
| 48 | maxBytes, |
| 49 | headRatio = 0.55, |
| 50 | separator = '\n...[inline context compacted; complete copy is in the attachment]...\n' |
| 51 | ) => { |
| 52 | const text = String(value || '') |
| 53 | const buffer = Buffer.from(text, 'utf8') |
| 54 | const limit = Math.max(0, Number(maxBytes) || 0) |
| 55 | if (buffer.length <= limit) return text |
| 56 | if (limit === 0) return '' |
| 57 | |
| 58 | const separatorBytes = byteLength(separator) |
| 59 | if (limit <= separatorBytes + 2) return truncateUtf8(text, limit) |
| 60 | |
| 61 | const contentBudget = limit - separatorBytes |
| 62 | const headBytes = Math.max(1, Math.floor(contentBudget * headRatio)) |
| 63 | const tailBytes = Math.max(1, contentBudget - headBytes) |
| 64 | return `${truncateUtf8(text, headBytes)}${separator}${truncateUtf8(text, tailBytes, true)}` |
| 65 | } |
| 66 | |
| 67 | const parseAgentEnvelope = (value) => { |
| 68 | const text = String(value || '') |
| 69 | const historyIndex = text.indexOf(HISTORY_MARKER) |
| 70 | const currentIndex = text.lastIndexOf(CURRENT_MESSAGE_MARKER) |
| 71 | if (historyIndex < 0) { |
| 72 | if (currentIndex >= 0) { |
| 73 | return { |
| 74 | prefix: text.slice(0, currentIndex).trim(), |
| 75 | history: '', |
| 76 | current: text.slice(currentIndex).trim(), |
| 77 | entries: [] |
| 78 | } |
| 79 | } |
| 80 | return { prefix: text, history: '', current: '', entries: [] } |
| 81 | } |
| 82 | |
| 83 | const historyStart = historyIndex + HISTORY_MARKER.length |
| 84 | const hasCurrent = currentIndex > historyStart |
| 85 | const history = text.slice(historyStart, hasCurrent ? currentIndex : text.length).trim() |
| 86 | const entries = [] |
| 87 | for (const line of history.split('\n')) { |
| 88 | const raw = line.trim() |
| 89 | if (!raw) continue |
| 90 | try { |
| 91 | const parsed = JSON.parse(raw) |
no test coverage detected