|
|
@@ -1,11 +1,12 @@
|
|
|
/**
|
|
|
* Decode an SSE byte stream into event `data` payloads. Framing — chunk
|
|
|
* reassembly, UTF-8/CRLF/BOM handling, comment and non-data field skipping,
|
|
|
- * multi-`data:` joining — is `eventsource-parser`'s; this module keeps only
|
|
|
- * the DeepSeek protocol: the literal `[DONE]` is yielded so the caller owns
|
|
|
- * final flushing, and EOF before it raises {@link LlmError}. Framing is
|
|
|
- * spec-strict: an event dispatches only on its blank-line terminator, so an
|
|
|
- * unterminated tail at EOF is truncation, not a flushable payload.
|
|
|
+ * multi-`data:` joining — is `eventsource-parser`'s. Comments are reported
|
|
|
+ * only through an optional transport-activity callback. This module keeps the
|
|
|
+ * DeepSeek protocol: the literal `[DONE]` is yielded so the caller owns final
|
|
|
+ * flushing, and EOF before it raises {@link LlmError}. Framing is spec-strict:
|
|
|
+ * an event dispatches only on its blank-line terminator, so an unterminated
|
|
|
+ * tail at EOF is truncation, not a flushable payload.
|
|
|
*
|
|
|
* @module dsh-llm-deepseek/sse
|
|
|
*/
|
|
|
@@ -21,12 +22,16 @@ export const DONE = '[DONE]'
|
|
|
* value and returns; throws `LlmError('STREAM_CLOSED')` when the stream ends
|
|
|
* without it (truncated response — the model call cannot be trusted).
|
|
|
* @param stream - raw SSE bytes; reads may split anywhere, including mid-UTF-8 sequence.
|
|
|
+ * @param onComment - optional transport-activity callback; comments never enter the yielded payload stream.
|
|
|
* @returns each event's data payload in arrival order, the `[DONE]` sentinel last.
|
|
|
*/
|
|
|
-export async function* parseSse(stream: ReadableStream<BufferSource>): AsyncGenerator<string> {
|
|
|
+export async function* parseSse(
|
|
|
+ stream: ReadableStream<BufferSource>,
|
|
|
+ onComment?: (comment: string) => void,
|
|
|
+): AsyncGenerator<string> {
|
|
|
const events = stream
|
|
|
.pipeThrough(new TextDecoderStream())
|
|
|
- .pipeThrough(new EventSourceParserStream())
|
|
|
+ .pipeThrough(new EventSourceParserStream({ onComment }))
|
|
|
for await (const { data } of events) {
|
|
|
yield data
|
|
|
if (data === DONE) return
|