nolo-cli 0.54.0-alpha.2 → 0.61.0-alpha.2

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 (172) hide show
  1. package/README.md +3 -3
  2. package/{_executeModel-ANY4SIAS.js → _executeModel-CKT6RGTL.js} +58 -49
  3. package/{action-Q4W5JPI5.js → action-76JX3JX3.js} +9 -8
  4. package/{addContentAction-O25HFR37.js → addContentAction-V3NAZRTJ.js} +9 -7
  5. package/{addDialogAgentAction-GH7AUPPB.js → addDialogAgentAction-RZOAF46K.js} +11 -9
  6. package/{agentDeleteCommand-JWIKNWWI.js → agentDeleteCommand-VN7NPXQ4.js} +37 -32
  7. package/{agentEmailCommands-PL22BEU5.js → agentEmailCommands-F2TNAV4A.js} +73 -65
  8. package/{agentGrantCommands-2LEZDADN.js → agentGrantCommands-R3VQEZJR.js} +1 -1
  9. package/{agentListCommands-6NR7AQEK.js → agentListCommands-OSM2ANI3.js} +78 -39
  10. package/{agentMachineCommands-TASPU6OA.js → agentMachineCommands-MTPWYVRV.js} +38 -33
  11. package/{agentPullCommand-M552CYSI.js → agentPullCommand-N7L2CT7L.js} +2 -2
  12. package/agentRecordCommands-VWAWTVVC.js +122 -0
  13. package/agentRunCommand-PLZOBNVK.js +149 -0
  14. package/{agentRunControl-4GHHSXFZ.js → agentRunControl-WECMOO6O.js} +13 -6
  15. package/{agentRuntimeLocal-PCJJ56J2.js → agentRuntimeLocal-XCJLRWQE.js} +35 -28
  16. package/{agentSlice-KYLDUSNN.js → agentSlice-F6DOP4IW.js} +10 -9
  17. package/{appDeleteCommands-WLHMJAVT.js → appDeleteCommands-3BCFTRFJ.js} +37 -32
  18. package/{appDeployCommands-CKON7N2E.js → appDeployCommands-B4GMHCYA.js} +37 -32
  19. package/{appDeployStatusCommands-PXRLDASH.js → appDeployStatusCommands-4MN36WIG.js} +37 -32
  20. package/{appGetCommands-RAB5RM4M.js → appGetCommands-4GJIEUAX.js} +37 -32
  21. package/{appListCommands-GU57FB62.js → appListCommands-CHU53GSX.js} +37 -32
  22. package/{authCommand-QOPOEYEK.js → authCommand-WOTWLJNF.js} +38 -32
  23. package/{authCommands-SBQVTD6V.js → authCommands-ILTBI6JV.js} +8 -6
  24. package/{chatQueueReduxAdapter-5O2WLITN.js → chatQueueReduxAdapter-HNSQXNIR.js} +29 -24
  25. package/{chunk-WL3UOGYO.js → chunk-22BTGNSP.js} +151 -155
  26. package/{chunk-7CH6U3FL.js → chunk-2GRGFCF6.js} +2 -4
  27. package/{chunk-V4KZGLOI.js → chunk-2HPRMEEZ.js} +3059 -1079
  28. package/{chunk-UNZDCI3O.js → chunk-2KDR4CWE.js} +35 -4
  29. package/{chunk-VRZIH5JO.js → chunk-2PGGC63K.js} +1 -1
  30. package/{chunk-T27IEBNQ.js → chunk-2QDDKFG5.js} +74 -1
  31. package/{chunk-7K5VMB4Q.js → chunk-37QVS7BU.js} +21 -8
  32. package/{chunk-UITMHBVK.js → chunk-37XDGCY7.js} +1 -1
  33. package/chunk-3BLB7QKO.js +433 -0
  34. package/{chunk-NQ4N4IGO.js → chunk-3JQ2NRYU.js} +33 -10
  35. package/{chunk-UW4INMD2.js → chunk-3JWKQDA4.js} +2 -2
  36. package/{chunk-IKTHA3JH.js → chunk-3QGUVVX5.js} +2 -2
  37. package/{chunk-WHVQA7PJ.js → chunk-45YO6H7P.js} +97 -35
  38. package/chunk-4C4ST2YE.js +20015 -0
  39. package/{chunk-32I5RVMY.js → chunk-4NJEIGBQ.js} +5 -5
  40. package/{chunk-KUUTWU4I.js → chunk-5ZYA4JJ3.js} +90 -22
  41. package/chunk-6YTOJY35.js +352 -0
  42. package/{chunk-INXBNYCG.js → chunk-7A3RRUCQ.js} +155 -12
  43. package/{chunk-GV35EHNA.js → chunk-7O7KH4X5.js} +1262 -971
  44. package/{chunk-Y7LNKP32.js → chunk-7UF7CQ6B.js} +4 -6
  45. package/{chunk-2BWU4ORW.js → chunk-AQMVUA7N.js} +2 -1
  46. package/{chunk-LA4IDAK7.js → chunk-AVE2YR4F.js} +1056 -3591
  47. package/{chunk-TI5BCZCH.js → chunk-B7DXRX7F.js} +59 -121
  48. package/chunk-BFU6C242.js +66 -0
  49. package/{chunk-FA4SY4F5.js → chunk-BYEJ7K2Z.js} +1 -1
  50. package/chunk-BYXBJQAS.js +0 -0
  51. package/{chunk-IA3A5373.js → chunk-C3FZR5EC.js} +1 -1
  52. package/{chunk-IWUMSAQF.js → chunk-CJCJF5XB.js} +26 -3
  53. package/{chunk-PAHILFNT.js → chunk-CP7VIDZ7.js} +4 -4
  54. package/{chunk-OYNDYVSE.js → chunk-CTCW7U7N.js} +1 -1
  55. package/{chunk-BJLYCOZK.js → chunk-D5XKNNUV.js} +135 -795
  56. package/{chunk-AV6KQCM5.js → chunk-DNNSCSA2.js} +19 -14
  57. package/{chunk-3AOLVADY.js → chunk-DVINR3PL.js} +1 -1
  58. package/{chunk-NI2BS6UD.js → chunk-DWUCB2A3.js} +1 -1
  59. package/{chunk-AA564GBL.js → chunk-DZZL7UBV.js} +1 -1
  60. package/{chunk-6FGXGFAH.js → chunk-E6RGHPDR.js} +6 -4
  61. package/chunk-EDKF7RX4.js +30 -0
  62. package/{chunk-6SZ52ORL.js → chunk-ES6CVKVD.js} +24 -30
  63. package/{chunk-DQLYEGP7.js → chunk-FHAGENAS.js} +3 -4
  64. package/{chunk-56W233KG.js → chunk-FKFMIBTT.js} +5 -1
  65. package/{chunk-INZZJSQF.js → chunk-FZGV4FGK.js} +24 -12
  66. package/{chunk-D3JQPONH.js → chunk-GAL47RNP.js} +1 -1
  67. package/{chunk-6FQ2552G.js → chunk-HBPV76EK.js} +1085 -1150
  68. package/{chunk-LN3OQJGG.js → chunk-HLU5Q2GV.js} +4 -4
  69. package/{chunk-U2A47SVI.js → chunk-HQP7HJDL.js} +7 -7
  70. package/{chunk-H2G6JXTR.js → chunk-HQUORJTM.js} +1 -1
  71. package/{chunk-3Z3DXZBD.js → chunk-IYCUMIYS.js} +24 -20
  72. package/{chunk-7APQB6R6.js → chunk-JX5PJCWS.js} +8 -6
  73. package/{chunk-LYGNQHUW.js → chunk-JYYZCK2Z.js} +2 -4
  74. package/{chunk-PYKV6FSC.js → chunk-KWSQR2KK.js} +16 -31
  75. package/{chunk-VULELK4T.js → chunk-L7B47JXR.js} +37 -64
  76. package/{chunk-4NN3EK7H.js → chunk-LAFC3B2I.js} +1 -1
  77. package/{chunk-VRJUIUIY.js → chunk-LJKICKVC.js} +2 -2
  78. package/chunk-M3JEW6N6.js +193 -0
  79. package/chunk-MBOEV4L2.js +301 -0
  80. package/{chunk-QDHZCAH3.js → chunk-MMZ6ZTVO.js} +229 -74
  81. package/{chunk-JDSUTNYY.js → chunk-MP64VFGD.js} +2 -2
  82. package/{chunk-U5Z7LFZF.js → chunk-MXUDQZXQ.js} +47 -8
  83. package/chunk-N4G4PKQ6.js +23 -0
  84. package/{chunk-SVEUG45B.js → chunk-NHRQCXIQ.js} +0 -24
  85. package/{chunk-KXKQO4Q6.js → chunk-NTW5GWDM.js} +58 -1
  86. package/chunk-ONXOABJR.js +215 -0
  87. package/{chunk-BANYWEYY.js → chunk-OZX2IPKM.js} +8 -3
  88. package/{chunk-Q24S4NDF.js → chunk-P7OOB7QP.js} +1 -1
  89. package/{chunk-GLGD2JGY.js → chunk-PEZJEQAO.js} +7 -7
  90. package/{chunk-GBADO3SM.js → chunk-PQDIDWGX.js} +1 -1
  91. package/chunk-PSCNXBYA.js +11 -0
  92. package/chunk-QEFJJS2I.js +508 -0
  93. package/{chunk-757BGY6Y.js → chunk-QEW2MFDQ.js} +1 -1
  94. package/{chunk-SP3DPVBH.js → chunk-RDBARW6T.js} +8 -3
  95. package/{chunk-TNPCQNGQ.js → chunk-RJ2SAFB5.js} +83 -41
  96. package/{chunk-FGEYVPPR.js → chunk-RVWRKFUB.js} +8 -65
  97. package/{chunk-43CXXVJD.js → chunk-RXX4GDIH.js} +1 -1
  98. package/chunk-SEJ5OS6F.js +49 -0
  99. package/{chunk-MFI4FGHX.js → chunk-SOJM57FX.js} +5 -2
  100. package/{chunk-EKLRRZIN.js → chunk-SPAQ4PVV.js} +0 -5
  101. package/{chunk-L7NG2M6H.js → chunk-TRV2MIDW.js} +89 -74
  102. package/chunk-UAD2WT54.js +64 -0
  103. package/{chunk-RTLJUGQH.js → chunk-UZPQSVM6.js} +2 -2
  104. package/{chunk-3QJTD6DO.js → chunk-VMWYBIXG.js} +9 -7
  105. package/{chunk-ZHXJ6M7T.js → chunk-W7XHHYWM.js} +4 -0
  106. package/{chunk-5WADL4O7.js → chunk-XAVSS3KE.js} +21 -3
  107. package/{chunk-CVT7L2WZ.js → chunk-XOKOSO35.js} +13 -22
  108. package/{chunk-6BYAXNH5.js → chunk-XTJTN3RW.js} +57 -4
  109. package/{chunk-T5HJEUQN.js → chunk-YCDWJX45.js} +1 -1
  110. package/{chunk-MRWGHF56.js → chunk-YDH3FDFQ.js} +12 -356
  111. package/{chunk-H4RYESI6.js → chunk-Z4QSJILV.js} +85 -13
  112. package/chunk-ZJ7UHBJS.js +89 -0
  113. package/{chunk-O5FLGN2L.js → chunk-ZRSJ3JEH.js} +6 -2
  114. package/{cliExecutor-BBUVQU4L.js → cliExecutor-HG3S345O.js} +1 -1
  115. package/{codingSkills-BCQXRZOI.js → codingSkills-VDXQYWX4.js} +2 -2
  116. package/contentThunks-7YG2ZYQC.js +73 -0
  117. package/{cooldownCommands-GI5NNWGL.js → cooldownCommands-BSCH2W7P.js} +2 -2
  118. package/{createAgentAutomationAction-UJLNFFFC.js → createAgentAutomationAction-PJQSCAIO.js} +32 -26
  119. package/createDialogAction-SFEJX6SP.js +64 -0
  120. package/{createPageAction-N3IYABHV.js → createPageAction-B7WRHOQO.js} +35 -28
  121. package/{dbSlice-D5CNGWPD.js → dbSlice-IBVOBVMS.js} +7 -6
  122. package/{deleteFile-44TUM34Y.js → deleteFile-FWP2PSBG.js} +4 -3
  123. package/{dialogCommands-35M6RBAC.js → dialogCommands-VL2X22QC.js} +38 -33
  124. package/{dialogSlice-KO7ADD7H.js → dialogSlice-ANMACABO.js} +29 -24
  125. package/{docCreateCommands-VXHZWQ3P.js → docCreateCommands-ITLGZ5YI.js} +40 -35
  126. package/{docDeleteCommands-4WFAJR6A.js → docDeleteCommands-LH3YNL4C.js} +37 -32
  127. package/{docReadCommands-OYREEFAR.js → docReadCommands-YAJ77F36.js} +36 -31
  128. package/{docStore-5BU76DFK.js → docStore-D4HGHPWI.js} +9 -33
  129. package/{docUpdateCommands-A7QERSME.js → docUpdateCommands-DQBOMH2G.js} +40 -35
  130. package/{fetchMessages-KZQVBXKY.js → fetchMessages-DRABNDPZ.js} +3 -3
  131. package/{getPricing-HAU62AFM.js → getPricing-NM3NUTAS.js} +5 -5
  132. package/handleSendMessageAction-DF2OABGW.js +675 -0
  133. package/index.js +79 -88
  134. package/{lib-2ZTNRXR4.js → lib-FRRS27KN.js} +63 -28
  135. package/{localDialogRead-NQ33HBSI.js → localDialogRead-PUQKFI73.js} +1 -1
  136. package/{localRuntimeAuthority-KQDAE64E.js → localRuntimeAuthority-R5UBODT3.js} +6 -4
  137. package/{localRuntimeDb-PF7CFKDL.js → localRuntimeDb-P37ZTX55.js} +1 -1
  138. package/{machineCommands-J43U3TX5.js → machineCommands-JXDYQ5LB.js} +309 -87
  139. package/{machineWsRunDispatch-Z2Z6STXZ.js → machineWsRunDispatch-3QHI7JX5.js} +67 -59
  140. package/memberThunks-VZI6G7YZ.js +640 -0
  141. package/{models-4QF4BJVY.js → models-FAMINFZ7.js} +2 -2
  142. package/package.json +3 -2
  143. package/{read-RGNPI5H2.js → read-2BYWW7AA.js} +4 -3
  144. package/{readDocTool-6ESWKTXD.js → readDocTool-LC3A7QTB.js} +1 -1
  145. package/{readlineWorkspace-YRPV6JPN.js → readlineWorkspace-KVZTEAHB.js} +4609 -2698
  146. package/{removeDialogAgentAction-JYT73FU2.js → removeDialogAgentAction-SFYZXHNK.js} +14 -12
  147. package/{runAgentClientLoop-5YM5WMAY.js → runAgentClientLoop-KGTEL7ZP.js} +60 -50
  148. package/{runtimeDoctorCommands-JKTTN723.js → runtimeDoctorCommands-CROTMULY.js} +7 -5
  149. package/{setDialogExtraReferencesAction-D564LMYQ.js → setDialogExtraReferencesAction-Q32RGFTA.js} +10 -8
  150. package/{setPrimaryDialogAgentAction-ACY3BLYA.js → setPrimaryDialogAgentAction-BFYJHUJS.js} +14 -12
  151. package/{settingSlice-MKI3MNZJ.js → settingSlice-IRUU4VFB.js} +8 -7
  152. package/{skillDiscovery-GPUDHDTZ.js → skillDiscovery-NTRLM6KP.js} +3 -3
  153. package/{spaceCommands-MY26V52L.js → spaceCommands-KNAYWMCZ.js} +40 -220
  154. package/{streamAgentChatTurn-XV5X5TNQ.js → streamAgentChatTurn-FLYPTXKZ.js} +140 -95
  155. package/{switchDialogAgentAction-CJ5H6SAR.js → switchDialogAgentAction-L2KOKCGG.js} +11 -9
  156. package/{tableCommands-R6WFRDYF.js → tableCommands-SUNTHAYX.js} +1 -1
  157. package/{toolApiClient-B2MFXMEG.js → toolApiClient-VGYUB4P5.js} +4 -2
  158. package/{tools-MIMELA2Y.js → tools-CVLUXK6P.js} +46 -38
  159. package/{tuiSummaryLlmCaller-XJ5BKNNS.js → tuiSummaryLlmCaller-F3DPFFZM.js} +20 -16
  160. package/{updateCommands-IYKLF3JX.js → updateCommands-AJYSD73Y.js} +2 -2
  161. package/{updateDialogTitleAction-EIZUSWHR.js → updateDialogTitleAction-HWJIZEIV.js} +33 -27
  162. package/agentRecordCommands-Z64TA63M.js +0 -114
  163. package/agentRunCommand-4QJQLPRW.js +0 -134
  164. package/agentSuperviseCommands-VB6BUS5H.js +0 -640
  165. package/chunk-6BGAQ3KR.js +0 -7081
  166. package/chunk-FD36SCCD.js +0 -105
  167. package/chunk-J3UALFHL.js +0 -370
  168. package/chunk-RU5D3B22.js +0 -230
  169. package/chunk-YBV6QJKM.js +0 -441
  170. package/createDialogAction-TJCX6GUE.js +0 -58
  171. package/handleSendMessageAction-OSGQJQ45.js +0 -406
  172. package/spaceSlice-JUIXC365.js +0 -127
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  sanitizeForOutbound
3
- } from "./chunk-T27IEBNQ.js";
3
+ } from "./chunk-2QDDKFG5.js";
4
4
  import {
5
5
  accumulateToolCallDelta,
6
6
  createThinkParserState,
@@ -15,15 +15,17 @@ import {
15
15
  processThinkChunk
16
16
  } from "./chunk-N7J63Q6C.js";
17
17
  import {
18
+ collectStablePromptPrefix,
18
19
  convertMessagesToResponsesInput,
19
20
  extractTextFromResponseOutput,
20
21
  extractToolCallsFromResponseOutput,
21
22
  getUsageRequestOptions,
22
23
  hasImageParts,
23
24
  shouldStripReasoningContentForOutbound,
25
+ stablePromptCacheKey,
24
26
  toOpenAiCompatibleMessages,
25
27
  toResponsesTools
26
- } from "./chunk-6BYAXNH5.js";
28
+ } from "./chunk-XTJTN3RW.js";
27
29
  import {
28
30
  buildProviderExecutionPlan,
29
31
  canUsePlatformChatProvider,
@@ -33,13 +35,15 @@ import {
33
35
  resolvePlatformAuthToken,
34
36
  resolvePlatformServerUrl,
35
37
  resolveProviderTransportDecision
36
- } from "./chunk-SP3DPVBH.js";
38
+ } from "./chunk-RDBARW6T.js";
37
39
  import {
38
- clipCompactText
39
- } from "./chunk-H4RYESI6.js";
40
+ clipCompactText,
41
+ isMeaningfulChatCompletionOutput,
42
+ isMeaningfulResponsesOutput
43
+ } from "./chunk-Z4QSJILV.js";
40
44
  import {
41
45
  NOLO_CLIENT_VERSION_HEADER
42
- } from "./chunk-WL3UOGYO.js";
46
+ } from "./chunk-22BTGNSP.js";
43
47
  import {
44
48
  isRecord
45
49
  } from "./chunk-KUG52IAP.js";
@@ -239,6 +243,11 @@ function finalizeResponsesToolCalls(calls) {
239
243
  }
240
244
 
241
245
  // packages/agent-runtime/processChatCompletionDelta.ts
246
+ function observeFirstMeaningfulChatCompletionDelta(state) {
247
+ if (!state.onMeaningfulDelta || state.sawMeaningfulDelta) return;
248
+ state.sawMeaningfulDelta = true;
249
+ state.onMeaningfulDelta();
250
+ }
242
251
  function extractChatCompletionStreamError(parsed) {
243
252
  const raw = parsed?.error;
244
253
  if (!raw) return null;
@@ -281,6 +290,9 @@ function applyChatCompletionDelta(parsed, state) {
281
290
  }
282
291
  const delta = parsed?.choices?.[0]?.delta;
283
292
  if (!delta || typeof delta !== "object") return false;
293
+ if (isMeaningfulChatCompletionOutput(delta)) {
294
+ observeFirstMeaningfulChatCompletionDelta(state);
295
+ }
284
296
  const reasoningChunk = typeof delta.reasoning_content === "string" ? delta.reasoning_content : typeof delta.reasoning === "string" ? delta.reasoning : "";
285
297
  if (reasoningChunk) {
286
298
  state.reasoning += reasoningChunk;
@@ -353,6 +365,16 @@ async function* readSseFrames(response) {
353
365
  boundary = findSseFrameBoundary(buffer);
354
366
  }
355
367
  }
368
+ const remaining = decoder.decode();
369
+ if (remaining) {
370
+ buffer += remaining;
371
+ let boundary = findSseFrameBoundary(buffer);
372
+ while (boundary) {
373
+ yield buffer.slice(0, boundary.index);
374
+ buffer = buffer.slice(boundary.index + boundary.separatorLength);
375
+ boundary = findSseFrameBoundary(buffer);
376
+ }
377
+ }
356
378
  if (buffer.trim()) yield buffer;
357
379
  }
358
380
  function findSseFrameBoundary(buffer) {
@@ -378,6 +400,16 @@ async function* streamSseDataValues(response, parse) {
378
400
  if (parsed) yield parsed;
379
401
  }
380
402
  }
403
+ const remaining = decoder.decode();
404
+ if (remaining) {
405
+ buffer += remaining;
406
+ const lines = buffer.split("\n");
407
+ buffer = lines.pop() ?? "";
408
+ for (const line of lines) {
409
+ const parsed = parse(line);
410
+ if (parsed) yield parsed;
411
+ }
412
+ }
381
413
  if (buffer.trim()) {
382
414
  const parsed = parse(buffer);
383
415
  if (parsed) yield parsed;
@@ -392,6 +424,45 @@ async function readSseDataValues(response, parse) {
392
424
  }
393
425
 
394
426
  // packages/agent-runtime/platformChatProvider.ts
427
+ var PlatformStreamInterruptedError = class extends Error {
428
+ code = "PLATFORM_STREAM_INTERRUPTED";
429
+ name = "PlatformStreamInterrupted";
430
+ phase;
431
+ httpStatus;
432
+ frameCount;
433
+ textChars;
434
+ sawDone;
435
+ sawUsage;
436
+ sawFinishReason;
437
+ elapsedMs;
438
+ constructor(args) {
439
+ super(
440
+ args.message ?? `Platform LLM stream interrupted (${args.phase}, frames=${args.frameCount ?? 0}, chars=${args.textChars ?? 0})`,
441
+ args.cause !== void 0 ? { cause: args.cause } : void 0
442
+ );
443
+ this.name = "PlatformStreamInterrupted";
444
+ this.phase = args.phase;
445
+ this.httpStatus = args.httpStatus ?? (args.phase === "streaming" ? 200 : 0);
446
+ this.frameCount = args.frameCount ?? 0;
447
+ this.textChars = args.textChars ?? 0;
448
+ this.sawDone = args.sawDone ?? false;
449
+ this.sawUsage = args.sawUsage ?? false;
450
+ this.sawFinishReason = args.sawFinishReason ?? false;
451
+ this.elapsedMs = args.elapsedMs ?? 0;
452
+ if (args.cause !== void 0 && this.cause === void 0) {
453
+ this.cause = args.cause;
454
+ }
455
+ }
456
+ };
457
+ function isAbortOrTimeoutError(error) {
458
+ if (typeof DOMException !== "undefined" && error instanceof DOMException) {
459
+ return error.name === "AbortError" || error.name === "TimeoutError";
460
+ }
461
+ if (error instanceof Error) {
462
+ return error.name === "AbortError" || error.name === "TimeoutError";
463
+ }
464
+ return false;
465
+ }
395
466
  var CHAT_PROXY_PATH = "/api/v1/chat";
396
467
  function shouldDisableThinking(providerConfig) {
397
468
  return providerConfig.provider.toLowerCase() === "mimo" || /xiaomimimo\.com/i.test(providerConfig.endpoint);
@@ -477,7 +548,8 @@ function buildPlatformChatCompletionRequest(args) {
477
548
  },
478
549
  stream: args.stream ?? false,
479
550
  ...args.stream ? getUsageRequestOptions(args.providerConfig.usageProvider ?? args.providerConfig.provider, {
480
- api: usesResponsesApi ? "responses" : "chat-completions"
551
+ api: usesResponsesApi ? "responses" : "chat-completions",
552
+ endpoint: usesResponsesApi ? null : args.providerConfig.endpoint
481
553
  }) : {},
482
554
  ...requestOptions,
483
555
  ...args.tools && args.tools.length > 0 ? {
@@ -485,6 +557,23 @@ function buildPlatformChatCompletionRequest(args) {
485
557
  ...usesResponsesApi ? {} : { tool_choice: "auto" }
486
558
  } : {},
487
559
  ...shouldDisableThinking(args.providerConfig) ? { thinking: { type: "disabled" } } : {},
560
+ // 缓存路由亲和提示:托管上游是多副本共享池,前缀缓存是节点本地的,
561
+ // 请求落到另一副本就整条 miss(实测占该线全部 miss token 的 52%,
562
+ // 依据见 promptCacheKey.ts)。键只取跨轮稳定的部分(model + system 稳定
563
+ // 前缀 + 工具定义),历史增长不参与,否则键每轮都变等于没有键。
564
+ // 已实测 RunInfra 接受该字段且不破坏既有命中;效果待上线后按
565
+ // promptCacheKey.ts 末尾的口径复测。
566
+ prompt_cache_key: stablePromptCacheKey(
567
+ [
568
+ args.providerConfig.model,
569
+ // 只从消息里取:本 builder 只拿得到 providerConfig,没有 agentConfig,
570
+ // agent prompt 早已由 localLoop 的 buildMessages 拼进 system 稳定前缀,
571
+ // 所以 sanitizedMessages 里的 system 就是完整取材,无需 fallback。
572
+ collectStablePromptPrefix(sanitizedMessages),
573
+ args.tools ?? []
574
+ ],
575
+ "nolo-chat"
576
+ ),
488
577
  url: args.providerConfig.endpoint,
489
578
  provider: args.providerConfig.provider,
490
579
  agentKey: args.providerConfig.agentKey,
@@ -500,6 +589,18 @@ function buildPlatformChatCompletionRequest(args) {
500
589
  headers: {
501
590
  "Content-Type": "application/json",
502
591
  Authorization: `Bearer ${args.providerConfig.authToken}`,
592
+ ...args.requestId ? { "x-request-id": args.requestId } : {},
593
+ // 流式请求显式放弃压缩协商。实测记录(2026-09-01,glm-5-3-flash 经
594
+ // nolo.chat):某个时间窗内 SSE 响应带 content-encoding: gzip 返回,
595
+ // 整条流被攒成 1 个 chunk,首字节 = 总生成时长(5.8/10.6/16.3s);
596
+ // 同一分钟交替发起的 identity 请求为 123-138 chunks、首字节
597
+ // 1.2-3.6s。即压缩中间件一旦介入,流式的首个输出收益归零。
598
+ // 该窗口之后线上不再压缩 SSE(同一探针 6/6 未压缩),具体是哪一跳
599
+ // 压的没有定论;边缘侧已把流式路径排除出 encode
600
+ // (configureCaddyProxy.sh),这里是不依赖任何中间跳行为的客户端兜底
601
+ // ——用户侧本地代理同样可能压。SSE 正文只有几十 KB,放弃压缩的带宽
602
+ // 代价可忽略。
603
+ ...args.stream ? { "Accept-Encoding": "identity" } : {},
503
604
  // 客户端版本闸门第 2 层:与鉴权头同处一处统一注入,避免某条命令路径
504
605
  // 漏发。server 据此拒绝「该客户端认不了 wire 的托管模型」;不发这个头
505
606
  // 的旧客户端在 server 侧 fail-open(已知局限)。
@@ -653,15 +754,24 @@ function processPlatformChatSseEvent(event, state) {
653
754
  if (dsml.content) {
654
755
  state.content += dsml.content;
655
756
  state.onTextDelta?.(dsml.content);
757
+ if (isMeaningfulResponsesOutput(parsed)) {
758
+ observeFirstMeaningfulChatCompletionDelta(state);
759
+ }
656
760
  }
657
761
  continue;
658
762
  }
659
763
  if (eventType === "response.reasoning_text.delta" && typeof parsed?.delta === "string") {
660
764
  state.reasoning += parsed.delta;
661
765
  state.onReasoningDelta?.(parsed.delta);
766
+ if (isMeaningfulResponsesOutput(parsed)) {
767
+ observeFirstMeaningfulChatCompletionDelta(state);
768
+ }
662
769
  continue;
663
770
  }
664
771
  if (eventType === "response.output_item.added" || eventType === "response.output_item.done" || eventType === "response.function_call_arguments.delta" || eventType === "response.function_call_arguments.done") {
772
+ if (isMeaningfulResponsesOutput(parsed)) {
773
+ observeFirstMeaningfulChatCompletionDelta(state);
774
+ }
665
775
  applyResponsesToolEvent(state.responsesToolCalls, parsed);
666
776
  continue;
667
777
  }
@@ -671,6 +781,8 @@ function processPlatformChatSseEvent(event, state) {
671
781
  }
672
782
  }
673
783
  async function readPlatformChatSseCompletion(args) {
784
+ const startedAtMs = Date.now();
785
+ let frameCount = 0;
674
786
  const state = {
675
787
  content: "",
676
788
  reasoning: "",
@@ -679,6 +791,7 @@ async function readPlatformChatSseCompletion(args) {
679
791
  usesResponsesApi: args.usesResponsesApi,
680
792
  onTextDelta: args.onTextDelta,
681
793
  onReasoningDelta: args.onReasoningDelta,
794
+ ...args.onMeaningfulDelta ? { onMeaningfulDelta: args.onMeaningfulDelta } : {},
682
795
  completedResponsesPayload: void 0,
683
796
  responsesToolCalls: createResponsesToolAccumulator(),
684
797
  dsmlToolCallState: createDsmlParserState(),
@@ -689,8 +802,35 @@ async function readPlatformChatSseCompletion(args) {
689
802
  finishReason: void 0,
690
803
  sawDone: false
691
804
  };
692
- for await (const frame of readSseFrames(args.response)) {
693
- processPlatformChatSseEvent(frame, state);
805
+ try {
806
+ for await (const frame of readSseFrames(args.response)) {
807
+ frameCount += 1;
808
+ processPlatformChatSseEvent(frame, state);
809
+ }
810
+ } catch (cause) {
811
+ if (cause instanceof PlatformStreamInterruptedError) {
812
+ throw cause;
813
+ }
814
+ if (isAbortOrTimeoutError(cause)) {
815
+ throw cause;
816
+ }
817
+ const elapsedMs = Date.now() - startedAtMs;
818
+ const textChars = state.content.length;
819
+ const sawDone = state.sawDone;
820
+ const sawUsage = Boolean(state.usage);
821
+ const sawFinishReason = Boolean(state.finishReason);
822
+ throw new PlatformStreamInterruptedError({
823
+ message: cause instanceof Error ? cause.message : "Platform chat SSE stream interrupted",
824
+ phase: "streaming",
825
+ httpStatus: 200,
826
+ frameCount,
827
+ textChars,
828
+ sawDone,
829
+ sawUsage,
830
+ sawFinishReason,
831
+ elapsedMs,
832
+ cause
833
+ });
694
834
  }
695
835
  flushChatCompletionStream(state);
696
836
  if (state.usesResponsesApi) {
@@ -706,6 +846,8 @@ async function readPlatformChatSseCompletion(args) {
706
846
  if (dsml.content) state.content += dsml.content;
707
847
  }
708
848
  throwIfChatCompletionStreamFailed(state);
849
+ const streamComplete = state.sawDone || Boolean(state.usage) || Boolean(state.finishReason);
850
+ const streamTruncated = !streamComplete;
709
851
  if (state.usesResponsesApi) {
710
852
  const response = state.completedResponsesPayload;
711
853
  const completedToolCalls = response ? extractToolCallsFromResponseOutput(response) : [];
@@ -721,13 +863,13 @@ async function readPlatformChatSseCompletion(args) {
721
863
  );
722
864
  const tool_calls2 = completedToolCalls.length > 0 ? completedToolCalls : normalizedDsmlCalls.length > 0 ? normalizedDsmlCalls : completionsToolCalls.length > 0 ? completionsToolCalls : finalizeResponsesToolCalls(state.responsesToolCalls);
723
865
  const finalUsage2 = mergeBillingIntoUsage(state.usage, state.billing);
724
- const streamComplete2 = state.sawDone || !!state.usage || !!state.finishReason;
725
866
  return {
726
867
  content: normalizedFinal.content || state.content,
727
868
  ...state.reasoning ? { reasoning_content: state.reasoning } : {},
728
869
  ...tool_calls2.length > 0 ? { tool_calls: tool_calls2 } : {},
729
870
  ...finalUsage2 ? { usage: finalUsage2 } : {},
730
- ...streamComplete2 ? { stream_complete: true } : {},
871
+ ...streamComplete ? { stream_complete: true } : {},
872
+ ...streamTruncated ? { streamTruncated: true } : {},
731
873
  // finish_reason 供 executePlatformChatCompletion 穿透给 localLoop 的
732
874
  // 空轮/截断判定;此前 reader 从不回传,流式路径恒缺。
733
875
  ...state.finishReason ? { finish_reason: state.finishReason } : {}
@@ -735,13 +877,13 @@ async function readPlatformChatSseCompletion(args) {
735
877
  }
736
878
  const tool_calls = finalizeAccumulatedToolCalls(state.accumulatedToolCalls);
737
879
  const finalUsage = mergeBillingIntoUsage(state.usage, state.billing);
738
- const streamComplete = state.sawDone || !!state.usage || !!state.finishReason;
739
880
  return {
740
881
  content: state.content,
741
882
  ...state.reasoning ? { reasoning_content: state.reasoning } : {},
742
883
  ...tool_calls.length > 0 ? { tool_calls } : {},
743
884
  ...finalUsage ? { usage: finalUsage } : {},
744
885
  ...streamComplete ? { stream_complete: true } : {},
886
+ ...streamTruncated ? { streamTruncated: true } : {},
745
887
  ...state.finishReason ? { finish_reason: state.finishReason } : {}
746
888
  };
747
889
  }
@@ -785,6 +927,7 @@ export {
785
927
  createResponsesToolAccumulator,
786
928
  applyResponsesToolEvent,
787
929
  finalizeResponsesToolCalls,
930
+ PlatformStreamInterruptedError,
788
931
  resolvePlatformChatProviderConfig,
789
932
  buildPlatformChatCompletionRequest,
790
933
  parsePlatformChatCompletionData,