{"version":3,"file":"stream.mjs","names":[],"sources":["../../src/summary/stream.ts"],"sourcesContent":["import type {\n\tAssistantMessage,\n\tAssistantMessageEvent,\n\tContext,\n\tSimpleStreamOptions,\n} from '@earendil-works/pi-ai';\n\nimport type { ResolvedSummarizer, RunDeps, SummaryProgress } from '@live-compaction/types';\n\nexport async function completeWithResolvedSummarizer(\n\tsummarizer: ResolvedSummarizer,\n\tcontext: Context,\n\toptions: SimpleStreamOptions,\n\tdeps: RunDeps,\n\tprogress?: SummaryProgress,\n\ttokensBefore = 0,\n): Promise<AssistantMessage> {\n\tconst modelLabel = `${summarizer.model.provider}/${summarizer.model.id}`;\n\tprogress?.start(modelLabel, tokensBefore);\n\ttry {\n\t\tconst streamFactory = summarizer.streamSimple ?? deps.streamSimple;\n\t\tif (!streamFactory) {\n\t\t\treturn await deps.complete(summarizer.model, context, options);\n\t\t}\n\n\t\tconst stream = streamFactory(summarizer.model, context, options);\n\t\tconst maybeAsyncStream = stream as ReturnType<typeof streamFactory> & {\n\t\t\t[Symbol.asyncIterator]?: () => AsyncIterator<AssistantMessageEvent>;\n\t\t};\n\t\tif (!maybeAsyncStream[Symbol.asyncIterator]) {\n\t\t\treturn await stream.result();\n\t\t}\n\n\t\tlet streamedText = '';\n\t\tlet finalMessage: AssistantMessage | undefined;\n\t\tlet errorMessage: AssistantMessage | undefined;\n\n\t\ttry {\n\t\t\tfor await (const event of maybeAsyncStream as AsyncIterable<AssistantMessageEvent>) {\n\t\t\t\tswitch (event.type) {\n\t\t\t\t\tcase 'text_delta':\n\t\t\t\t\t\tstreamedText += event.delta;\n\t\t\t\t\t\tprogress?.update(streamedText);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'text_end':\n\t\t\t\t\t\tstreamedText = event.content;\n\t\t\t\t\t\tprogress?.update(streamedText);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'done':\n\t\t\t\t\t\tfinalMessage = event.message;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'error':\n\t\t\t\t\t\terrorMessage = event.error;\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tconst recovered = recoverStreamedSummary(summarizer, streamedText, error);\n\t\t\tif (recovered) return recovered;\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (errorMessage) {\n\t\t\tconst recovered = recoverStreamedSummary(summarizer, streamedText, errorMessage.errorMessage);\n\t\t\tif (recovered) return recovered;\n\t\t\treturn errorMessage;\n\t\t}\n\t\tif (finalMessage) return finalMessage;\n\t\ttry {\n\t\t\treturn await stream.result();\n\t\t} catch (error) {\n\t\t\tconst recovered = recoverStreamedSummary(summarizer, streamedText, error);\n\t\t\tif (recovered) return recovered;\n\t\t\tthrow error;\n\t\t}\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tprogress?.fail(message);\n\t\tthrow error;\n\t}\n}\n\nfunction recoverStreamedSummary(\n\tsummarizer: ResolvedSummarizer,\n\tstreamedText: string,\n\terror: unknown,\n): AssistantMessage | undefined {\n\tconst text = streamedText.trim();\n\tif (!text) return undefined;\n\n\tconst message = error instanceof Error ? error.message : String(error ?? 'stream failed');\n\treturn {\n\t\trole: 'assistant',\n\t\tcontent: [{ type: 'text', text }],\n\t\tapi: summarizer.model.api,\n\t\tprovider: summarizer.model.provider,\n\t\tmodel: summarizer.model.id,\n\t\tdiagnostics: [\n\t\t\t{\n\t\t\t\ttype: 'live-compaction-stream-recovered',\n\t\t\t\ttimestamp: Date.now(),\n\t\t\t\terror: { message },\n\t\t\t},\n\t\t] as AssistantMessage['diagnostics'],\n\t\tusage: {\n\t\t\tinput: 0,\n\t\t\toutput: 0,\n\t\t\tcacheRead: 0,\n\t\t\tcacheWrite: 0,\n\t\t\ttotalTokens: 0,\n\t\t\tcost: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotal: 0,\n\t\t\t},\n\t\t},\n\t\tstopReason: 'stop',\n\t\ttimestamp: Date.now(),\n\t};\n}\n\nexport function getTextFromAssistantResponse(response: AssistantMessage): string {\n\treturn response.content\n\t\t.filter((c): c is { type: 'text'; text: string } => c.type === 'text')\n\t\t.map((c) => c.text)\n\t\t.join('\\n');\n}\n\nexport function stripLeakedInternals(summary: string): string {\n\treturn summary\n\t\t.split('\\n')\n\t\t.filter((line) => {\n\t\t\tconst trimmed = line.trimStart();\n\t\t\treturn (\n\t\t\t\t!trimmed.startsWith('[Assistant thinking]:') &&\n\t\t\t\t!trimmed.startsWith('[Assistant tool calls]:') &&\n\t\t\t\t!trimmed.startsWith('[Tool result]:')\n\t\t\t);\n\t\t})\n\t\t.join('\\n');\n}\n"],"mappings":";AASA,eAAsB,+BACrB,YACA,SACA,SACA,MACA,UACA,eAAe,GACa;CAC5B,MAAM,aAAa,GAAG,WAAW,MAAM,SAAS,GAAG,WAAW,MAAM;CACpE,UAAU,MAAM,YAAY,YAAY;CACxC,IAAI;EACH,MAAM,gBAAgB,WAAW,gBAAgB,KAAK;EACtD,IAAI,CAAC,eACJ,OAAO,MAAM,KAAK,SAAS,WAAW,OAAO,SAAS,OAAO;EAG9D,MAAM,SAAS,cAAc,WAAW,OAAO,SAAS,OAAO;EAC/D,MAAM,mBAAmB;EAGzB,IAAI,CAAC,iBAAiB,OAAO,gBAC5B,OAAO,MAAM,OAAO,OAAO;EAG5B,IAAI,eAAe;EACnB,IAAI;EACJ,IAAI;EAEJ,IAAI;GACH,WAAW,MAAM,SAAS,kBACzB,QAAQ,MAAM,MAAd;IACC,KAAK;KACJ,gBAAgB,MAAM;KACtB,UAAU,OAAO,YAAY;KAC7B;IACD,KAAK;KACJ,eAAe,MAAM;KACrB,UAAU,OAAO,YAAY;KAC7B;IACD,KAAK;KACJ,eAAe,MAAM;KACrB;IACD,KAAK;KACJ,eAAe,MAAM;KACrB;GACF;EAEF,SAAS,OAAO;GACf,MAAM,YAAY,uBAAuB,YAAY,cAAc,KAAK;GACxE,IAAI,WAAW,OAAO;GACtB,MAAM;EACP;EAEA,IAAI,cAAc;GACjB,MAAM,YAAY,uBAAuB,YAAY,cAAc,aAAa,YAAY;GAC5F,IAAI,WAAW,OAAO;GACtB,OAAO;EACR;EACA,IAAI,cAAc,OAAO;EACzB,IAAI;GACH,OAAO,MAAM,OAAO,OAAO;EAC5B,SAAS,OAAO;GACf,MAAM,YAAY,uBAAuB,YAAY,cAAc,KAAK;GACxE,IAAI,WAAW,OAAO;GACtB,MAAM;EACP;CACD,SAAS,OAAO;EACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;EACrE,UAAU,KAAK,OAAO;EACtB,MAAM;CACP;AACD;AAEA,SAAS,uBACR,YACA,cACA,OAC+B;CAC/B,MAAM,OAAO,aAAa,KAAK;CAC/B,IAAI,CAAC,MAAM,OAAO,KAAA;CAElB,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,SAAS,eAAe;CACxF,OAAO;EACN,MAAM;EACN,SAAS,CAAC;GAAE,MAAM;GAAQ;EAAK,CAAC;EAChC,KAAK,WAAW,MAAM;EACtB,UAAU,WAAW,MAAM;EAC3B,OAAO,WAAW,MAAM;EACxB,aAAa,CACZ;GACC,MAAM;GACN,WAAW,KAAK,IAAI;GACpB,OAAO,EAAE,QAAQ;EAClB,CACD;EACA,OAAO;GACN,OAAO;GACP,QAAQ;GACR,WAAW;GACX,YAAY;GACZ,aAAa;GACb,MAAM;IACL,OAAO;IACP,QAAQ;IACR,WAAW;IACX,YAAY;IACZ,OAAO;GACR;EACD;EACA,YAAY;EACZ,WAAW,KAAK,IAAI;CACrB;AACD;AAEA,SAAgB,6BAA6B,UAAoC;CAChF,OAAO,SAAS,QACd,QAAQ,MAA2C,EAAE,SAAS,MAAM,CAAC,CACrE,KAAK,MAAM,EAAE,IAAI,CAAC,CAClB,KAAK,IAAI;AACZ;AAEA,SAAgB,qBAAqB,SAAyB;CAC7D,OAAO,QACL,MAAM,IAAI,CAAC,CACX,QAAQ,SAAS;EACjB,MAAM,UAAU,KAAK,UAAU;EAC/B,OACC,CAAC,QAAQ,WAAW,uBAAuB,KAC3C,CAAC,QAAQ,WAAW,yBAAyB,KAC7C,CAAC,QAAQ,WAAW,gBAAgB;CAEtC,CAAC,CAAC,CACD,KAAK,IAAI;AACZ"}