@jait/gateway 0.1.550 → 0.1.552

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/routes/chat.d.ts.map +1 -1
  2. package/dist/routes/chat.js +58 -21
  3. package/dist/routes/chat.js.map +1 -1
  4. package/dist/services/thread-router.d.ts.map +1 -1
  5. package/dist/services/thread-router.js +5 -3
  6. package/dist/services/thread-router.js.map +1 -1
  7. package/package.json +1 -1
  8. package/web-dist/assets/{_basePickBy-Dp2NyPAx.js → _basePickBy-CVEA4pai.js} +1 -1
  9. package/web-dist/assets/{_baseUniq-Cv3a4hfc.js → _baseUniq-BGU4pmAf.js} +1 -1
  10. package/web-dist/assets/{arc-CPixogAk.js → arc-CQoXa1S3.js} +1 -1
  11. package/web-dist/assets/{architectureDiagram-2XIMDMQ5-DSvD2ZZi.js → architectureDiagram-2XIMDMQ5-BC5sOE9j.js} +1 -1
  12. package/web-dist/assets/{blockDiagram-WCTKOSBZ-CSzjczoh.js → blockDiagram-WCTKOSBZ-BbZ3-HQp.js} +1 -1
  13. package/web-dist/assets/{c4Diagram-IC4MRINW-HtEHTMAh.js → c4Diagram-IC4MRINW-CPf-b5bp.js} +1 -1
  14. package/web-dist/assets/channel-3sdUC-FF.js +1 -0
  15. package/web-dist/assets/{chunk-4BX2VUAB-Bf-f74ZD.js → chunk-4BX2VUAB-CUdYhXQ6.js} +1 -1
  16. package/web-dist/assets/{chunk-55IACEB6-DjmtjKpi.js → chunk-55IACEB6-pFDdpDjU.js} +1 -1
  17. package/web-dist/assets/{chunk-FMBD7UC4-CfSdN_3Q.js → chunk-FMBD7UC4-C2TpaKpu.js} +1 -1
  18. package/web-dist/assets/{chunk-JSJVCQXG-g7BDCVpe.js → chunk-JSJVCQXG-B9n0SK35.js} +1 -1
  19. package/web-dist/assets/{chunk-KX2RTZJC-D8T-LUIR.js → chunk-KX2RTZJC-DodjJEPK.js} +1 -1
  20. package/web-dist/assets/{chunk-NQ4KR5QH-E1sqN5pn.js → chunk-NQ4KR5QH-DXcK8bx4.js} +1 -1
  21. package/web-dist/assets/{chunk-QZHKN3VN-Bx5hIiz4.js → chunk-QZHKN3VN-DnHlx1h_.js} +1 -1
  22. package/web-dist/assets/{chunk-WL4C6EOR-ByXOkMiV.js → chunk-WL4C6EOR-jjvIQlLf.js} +1 -1
  23. package/web-dist/assets/classDiagram-VBA2DB6C-BASbUOUp.js +1 -0
  24. package/web-dist/assets/classDiagram-v2-RAHNMMFH-BASbUOUp.js +1 -0
  25. package/web-dist/assets/clone-DekVS0s_.js +1 -0
  26. package/web-dist/assets/{cose-bilkent-S5V4N54A-DQJ1rWoS.js → cose-bilkent-S5V4N54A-CtC5UG7N.js} +1 -1
  27. package/web-dist/assets/{dagre-KLK3FWXG-CHh0QVw_.js → dagre-KLK3FWXG-BbYESUgB.js} +1 -1
  28. package/web-dist/assets/{diagram-E7M64L7V-DM1x9aKy.js → diagram-E7M64L7V-pki90goW.js} +1 -1
  29. package/web-dist/assets/{diagram-IFDJBPK2-C0gnOtfS.js → diagram-IFDJBPK2-B_GVmcgP.js} +1 -1
  30. package/web-dist/assets/{diagram-P4PSJMXO-DOICDmQd.js → diagram-P4PSJMXO-CcDWpEfi.js} +1 -1
  31. package/web-dist/assets/{erDiagram-INFDFZHY-eMzR0jJ2.js → erDiagram-INFDFZHY-DJMlGmyB.js} +1 -1
  32. package/web-dist/assets/{flowDiagram-PKNHOUZH-C7H26CoC.js → flowDiagram-PKNHOUZH-Bo5SX3OF.js} +1 -1
  33. package/web-dist/assets/{ganttDiagram-A5KZAMGK-C5wozmPC.js → ganttDiagram-A5KZAMGK-DDblFwUZ.js} +1 -1
  34. package/web-dist/assets/{gitGraphDiagram-K3NZZRJ6-DlLV2W4D.js → gitGraphDiagram-K3NZZRJ6-Dj6RrQfG.js} +1 -1
  35. package/web-dist/assets/{graph-Jatw0BgY.js → graph-qKDG8tJn.js} +1 -1
  36. package/web-dist/assets/{index-DqA2TMw6.js → index-Df7TKlKH.js} +1 -1
  37. package/web-dist/assets/{index-DEu1E_j7.js → index-DoSc5Vdk.js} +1 -1
  38. package/web-dist/assets/{index-ByIT5B0X.js → index-oIGcaRFG.js} +30 -30
  39. package/web-dist/assets/{infoDiagram-LFFYTUFH-DSFBtmB-.js → infoDiagram-LFFYTUFH-DQZPNO5i.js} +1 -1
  40. package/web-dist/assets/{ishikawaDiagram-PHBUUO56-B46mTWHh.js → ishikawaDiagram-PHBUUO56-CG9vPh5U.js} +1 -1
  41. package/web-dist/assets/{journeyDiagram-4ABVD52K-4ASDg60N.js → journeyDiagram-4ABVD52K-BU_DxZzk.js} +1 -1
  42. package/web-dist/assets/{kanban-definition-K7BYSVSG-BYlV4Vtg.js → kanban-definition-K7BYSVSG-BX7s55Hy.js} +1 -1
  43. package/web-dist/assets/{layout-DZD4LK4k.js → layout-bPnDF3nV.js} +1 -1
  44. package/web-dist/assets/{linear-Cr_-2rAF.js → linear-DuqJlc-o.js} +1 -1
  45. package/web-dist/assets/{mindmap-definition-YRQLILUH-B0RQyALT.js → mindmap-definition-YRQLILUH-CmOXzv7l.js} +1 -1
  46. package/web-dist/assets/{pieDiagram-SKSYHLDU-DlqEQkBe.js → pieDiagram-SKSYHLDU-UjPRt51A.js} +1 -1
  47. package/web-dist/assets/{quadrantDiagram-337W2JSQ-TwiaxjYw.js → quadrantDiagram-337W2JSQ-Dxt0_pWa.js} +1 -1
  48. package/web-dist/assets/{requirementDiagram-Z7DCOOCP-LCG5OTze.js → requirementDiagram-Z7DCOOCP-8zPleAzv.js} +1 -1
  49. package/web-dist/assets/{sankeyDiagram-WA2Y5GQK-BQqU31_e.js → sankeyDiagram-WA2Y5GQK-OxSvEGnU.js} +1 -1
  50. package/web-dist/assets/{sequenceDiagram-2WXFIKYE-DIE9LH9s.js → sequenceDiagram-2WXFIKYE-Uo1j1Fqt.js} +1 -1
  51. package/web-dist/assets/{stateDiagram-RAJIS63D-CkVALlUV.js → stateDiagram-RAJIS63D-BwnWpxqg.js} +1 -1
  52. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-y6XzZ78B.js +1 -0
  53. package/web-dist/assets/{timeline-definition-YZTLITO2-UTbg0ItL.js → timeline-definition-YZTLITO2-BlIRtLuG.js} +1 -1
  54. package/web-dist/assets/{treemap-KZPCXAKY-B3ZI07yL.js → treemap-KZPCXAKY-CkqwmuDJ.js} +1 -1
  55. package/web-dist/assets/{vennDiagram-LZ73GAT5-Cpy6iU9G.js → vennDiagram-LZ73GAT5-BZsUV5jE.js} +1 -1
  56. package/web-dist/assets/{xychartDiagram-JWTSCODW--XzABSvu.js → xychartDiagram-JWTSCODW-CSQ_Sf6u.js} +1 -1
  57. package/web-dist/index.html +1 -1
  58. package/web-dist/assets/channel-C8Ypz7L8.js +0 -1
  59. package/web-dist/assets/classDiagram-VBA2DB6C-BgcBXLb4.js +0 -1
  60. package/web-dist/assets/classDiagram-v2-RAHNMMFH-BgcBXLb4.js +0 -1
  61. package/web-dist/assets/clone-D91NotDC.js +0 -1
  62. package/web-dist/assets/stateDiagram-v2-FVOUBMTO-CDJgTjE4.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAgGvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AAyED,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AAscD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;AAmiBD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;IAClD,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KACtD,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,EACjC,iBAAiB,CAAC,EAAE,cAAc,QA6nEnC"}
1
+ {"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,KAAK,EAAE,WAAW,EAA4B,MAAM,uBAAuB,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AACxE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAgCjE,OAAO,KAAK,EAAS,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,sCAAsC,CAAC;AAqHvF,wBAAgB,6BAA6B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAmBrE;AA8FD,wBAAgB,eAAe,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAE3D;AA8cD,wBAAgB,2BAA2B,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,GAAG,IAAI,CAyCtF;AAmiBD,MAAM,WAAW,aAAa;IAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,CAAC,EAAE,eAAe,CAAC;IAClC,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,EAAE,CAAC,EAAE,cAAc,CAAC;IACpB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,oBAAoB,CAAC,EAAE,0BAA0B,CAAC;IAClD,YAAY,CAAC,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,WAAW,EACpB,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,KACtD,OAAO,CAAC,UAAU,CAAC,CAAC;CAC1B;AAED,wBAAgB,kBAAkB,CAChC,GAAG,EAAE,eAAe,EACpB,MAAM,EAAE,SAAS,EACjB,QAAQ,CAAC,EAAE,MAAM,GAAG,aAAa,EACjC,iBAAiB,CAAC,EAAE,cAAc,QAmnEnC"}
@@ -32,6 +32,24 @@ function formatExternalProviderFirstTurn(systemPrompt, userContent, recentContex
32
32
  parts.push("User request:", userContent);
33
33
  return parts.join("\n");
34
34
  }
35
+ const SSE_HEADERS = {
36
+ "Content-Type": "text/event-stream",
37
+ "Cache-Control": "no-cache, no-transform",
38
+ Connection: "keep-alive",
39
+ "X-Accel-Buffering": "no",
40
+ "Content-Encoding": "identity",
41
+ };
42
+ function writeSseHead(reply, headers = {}) {
43
+ reply.raw.writeHead(200, {
44
+ ...SSE_HEADERS,
45
+ ...headers,
46
+ });
47
+ reply.raw.flushHeaders?.();
48
+ }
49
+ function writeSseChunk(reply, chunk) {
50
+ reply.raw.write(chunk);
51
+ reply.raw.flush?.();
52
+ }
35
53
  function normalizeExternalContextContent(content) {
36
54
  if (typeof content === "string")
37
55
  return content;
@@ -131,6 +149,25 @@ function truncateForMemoryBlock(value, max = 220) {
131
149
  function shouldIncludeContactMemories(content) {
132
150
  return /\b(based on what you know|remember|preference|preferences|prefer|my usual|about me|what do you know)\b/i.test(content);
133
151
  }
152
+ function memoryRelevanceTokens(content) {
153
+ return new Set(content
154
+ .toLowerCase()
155
+ .split(/[^a-z0-9_äöüß]+/i)
156
+ .map((token) => token.trim())
157
+ .filter((token) => token.length >= 4)
158
+ .filter((token) => !["this", "that", "with", "from", "have", "your", "what", "when", "where", "which", "there", "their", "about", "should", "would", "could", "please", "help"].includes(token)));
159
+ }
160
+ function hasLexicalMemoryOverlap(query, content) {
161
+ const queryTokens = memoryRelevanceTokens(query);
162
+ if (queryTokens.size === 0)
163
+ return false;
164
+ const contentTokens = memoryRelevanceTokens(content);
165
+ for (const token of queryTokens) {
166
+ if (contentTokens.has(token))
167
+ return true;
168
+ }
169
+ return false;
170
+ }
134
171
  function memorySourceLabel(entry) {
135
172
  if (entry.source.type === "pre_compaction") {
136
173
  return "memory compact";
@@ -170,12 +207,15 @@ async function retrieveRelevantMemoryContext(memoryService, content) {
170
207
  return null;
171
208
  const projectMemories = await memoryService.search(query, 25, "project");
172
209
  const byId = new Map();
210
+ const includeBroadMemory = shouldIncludeContactMemories(query);
173
211
  for (const entry of projectMemories) {
174
212
  if (!isSourceVisible(entry))
175
213
  continue;
214
+ if (!includeBroadMemory && !hasLexicalMemoryOverlap(query, entry.content))
215
+ continue;
176
216
  byId.set(entry.id, entry);
177
217
  }
178
- if (shouldIncludeContactMemories(query)) {
218
+ if (includeBroadMemory) {
179
219
  const contactMemories = await memoryService.search(query, Math.max(0, 25 - byId.size), "contact");
180
220
  for (const entry of contactMemories) {
181
221
  if (!isSourceVisible(entry))
@@ -405,15 +445,22 @@ function parseQueuedChatMessages(raw) {
405
445
  if (!Array.isArray(raw))
406
446
  return [];
407
447
  const queue = [];
448
+ const seenIds = new Set();
408
449
  for (const entry of raw) {
409
450
  if (!entry || typeof entry !== "object")
410
451
  continue;
411
452
  const record = entry;
412
453
  if (typeof record.content !== "string" || !record.content.trim())
413
454
  continue;
455
+ const id = typeof record.id === "string" ? record.id : undefined;
456
+ if (id) {
457
+ if (seenIds.has(id))
458
+ continue;
459
+ seenIds.add(id);
460
+ }
414
461
  const displaySegments = parseUserDisplaySegments(record.displaySegments);
415
462
  queue.push({
416
- id: typeof record.id === "string" ? record.id : undefined,
463
+ id,
417
464
  content: record.content,
418
465
  queuedAt: typeof record.queuedAt === "number" ? record.queuedAt : undefined,
419
466
  mode: isValidChatMode(record.mode) ? record.mode : undefined,
@@ -1414,14 +1461,8 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
1414
1461
  }
1415
1462
  // Set SSE headers (include CORS — reply.raw bypasses @fastify/cors)
1416
1463
  const reqOrigin = request.headers.origin ?? "*";
1417
- reply.raw.writeHead(200, {
1418
- "Content-Type": "text/event-stream",
1419
- "Cache-Control": "no-cache",
1420
- Connection: "keep-alive",
1421
- // Prevent reverse proxies (nginx etc.) from buffering the SSE stream,
1422
- // which would otherwise swallow chunks and let the connection time out.
1423
- "X-Accel-Buffering": "no",
1424
- "Access-Control-Allow-Origin": reqOrigin,
1464
+ writeSseHead(reply, {
1465
+ "Access-Control-Allow-Origin": String(reqOrigin),
1425
1466
  "Access-Control-Allow-Credentials": "true",
1426
1467
  });
1427
1468
  // Build model endpoint for prompt resolution
@@ -1543,7 +1584,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
1543
1584
  const safeWrite = (data) => {
1544
1585
  if (!clientDisconnected) {
1545
1586
  try {
1546
- reply.raw.write(data);
1587
+ writeSseChunk(reply, data);
1547
1588
  }
1548
1589
  catch {
1549
1590
  clientDisconnected = true;
@@ -2639,12 +2680,8 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2639
2680
  const query = request.query;
2640
2681
  const limit = parseMessageLimit(query?.limit);
2641
2682
  const reqOrigin = request.headers.origin ?? "*";
2642
- reply.raw.writeHead(200, {
2643
- "Content-Type": "text/event-stream",
2644
- "Cache-Control": "no-cache",
2645
- Connection: "keep-alive",
2646
- "X-Accel-Buffering": "no",
2647
- "Access-Control-Allow-Origin": reqOrigin,
2683
+ writeSseHead(reply, {
2684
+ "Access-Control-Allow-Origin": String(reqOrigin),
2648
2685
  "Access-Control-Allow-Credentials": "true",
2649
2686
  });
2650
2687
  const isStreaming = activeStreams.has(sessionId);
@@ -2674,7 +2711,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2674
2711
  total = windowed.total;
2675
2712
  hasMore = windowed.hasMore;
2676
2713
  }
2677
- reply.raw.write(`data: ${JSON.stringify({
2714
+ writeSseChunk(reply, `data: ${JSON.stringify({
2678
2715
  type: "snapshot",
2679
2716
  messages: snapshotMessages,
2680
2717
  streaming: isStreaming,
@@ -2685,7 +2722,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2685
2722
  })}\n\n`);
2686
2723
  if (!isStreaming) {
2687
2724
  // Not streaming — send done immediately
2688
- reply.raw.write(`data: ${JSON.stringify({ type: "done", session_id: sessionId, prompt_count: history.filter(m => m.role === "user").length, remaining_prompts: null })}\n\n`);
2725
+ writeSseChunk(reply, `data: ${JSON.stringify({ type: "done", session_id: sessionId, prompt_count: history.filter(m => m.role === "user").length, remaining_prompts: null })}\n\n`);
2689
2726
  reply.raw.end();
2690
2727
  return;
2691
2728
  }
@@ -2715,7 +2752,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2715
2752
  if (closed)
2716
2753
  return;
2717
2754
  try {
2718
- reply.raw.write(`: keepalive\n\n`);
2755
+ writeSseChunk(reply, `: keepalive\n\n`);
2719
2756
  }
2720
2757
  catch {
2721
2758
  closeStream();
@@ -2725,7 +2762,7 @@ export function registerChatRoutes(app, config, depsOrDb, sessionServiceArg) {
2725
2762
  if (closed)
2726
2763
  return;
2727
2764
  try {
2728
- reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
2765
+ writeSseChunk(reply, `data: ${JSON.stringify(event)}\n\n`);
2729
2766
  if (event.type === "done" || event.type === "error") {
2730
2767
  closeStream();
2731
2768
  }