/** * Normalize QVAC completion stream events for cap-chunk (keep under NMH ~1 MB). */ const MAX_DELTA = 64 * 1024; function clip(s) { const t = s == null ? '' : String(s); if (t.length <= MAX_DELTA) return t; return t.slice(0, MAX_DELTA); } function eventDelta(ev) { if (ev == null) return ''; if (typeof ev === 'string' || typeof ev === 'number' || typeof ev === 'boolean') return clip(ev); return clip(ev.text || ev.delta || ev.content || ev.chunk || ''); } const THINK_OPEN = ''; const THINK_CLOSE = ''; function trailingPartial(buf, marker) { const max = Math.min(buf.length, marker.length - 1); for (let len = max; len > 0; len--) { if (marker.startsWith(buf.slice(buf.length - len))) return len; } return 0; } function expandThinkEvents(n, state) { const st = state && typeof state === 'object' ? state : { inThink: false, carry: '' }; if (!n) return { events: [], state: st }; if (n.type === 'thinkingDelta') { const delta = n.delta || ''; return { events: delta ? [n] : [], state: st }; } if (n.type !== 'contentDelta') return { events: [n], state: st }; let rest = String(st.carry || '') + String(n.delta || ''); const events = []; let inThink = !!st.inThink; while (rest) { const marker = inThink ? THINK_CLOSE : THINK_OPEN; const idx = rest.indexOf(marker); if (idx < 0) { const partial = trailingPartial(rest, marker); const emit = partial ? rest.slice(0, rest.length - partial) : rest; const carry = partial ? rest.slice(rest.length - partial) : ''; if (emit) events.push({ type: inThink ? 'thinkingDelta' : 'contentDelta', delta: emit }); return { events, state: { inThink, carry } }; } const before = rest.slice(0, idx); if (before) events.push({ type: inThink ? 'thinkingDelta' : 'contentDelta', delta: before }); rest = rest.slice(idx + marker.length); inThink = !inThink; } return { events, state: { inThink, carry: '' } }; } function normalizeCompletionEvent(ev) { if (!ev || !ev.type) return null; if (ev.type === 'contentDelta') { return { type: 'contentDelta', delta: eventDelta(ev) }; } if (ev.type === 'thinkingDelta') { return { type: 'thinkingDelta', delta: eventDelta(ev) }; } if (ev.type === 'toolCall') { const call = ev.call || ev.toolCall || ev; return { type: 'toolCall', call: { id: call.id, name: call.name, arguments: call.arguments != null ? call.arguments : call.args, }, }; } if (ev.type === 'rawDelta') { return { type: 'rawDelta', delta: clip(ev.delta) }; } return { type: ev.type, delta: ev.delta != null ? clip(ev.delta) : undefined, call: ev.call }; } module.exports = { normalizeCompletionEvent, expandThinkEvents, eventDelta, MAX_DELTA };