@fudrouter/fsrouter 0.6.72 → 0.6.74

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 (314) hide show
  1. package/dist/lib/headroom/detect.js +97 -7
  2. package/dist/lib/headroom/process.js +136 -4
  3. package/dist/open-sse/config/appConstants.js +23 -79
  4. package/dist/open-sse/config/cliFingerprints.js +1 -1
  5. package/dist/open-sse/config/errorConfig.js +0 -11
  6. package/dist/open-sse/config/grokCli.js +10 -0
  7. package/dist/open-sse/config/kiroConstants.js +99 -46
  8. package/dist/open-sse/config/runtimeConfig.js +2 -0
  9. package/dist/open-sse/config/ttsModels.js +2 -0
  10. package/dist/open-sse/executors/antigravity.js +250 -164
  11. package/dist/open-sse/executors/base.js +16 -11
  12. package/dist/open-sse/executors/codex.js +269 -1108
  13. package/dist/open-sse/executors/commandCode.js +1 -1
  14. package/dist/open-sse/executors/commandcode.js +10 -4
  15. package/dist/open-sse/executors/cursor.js +96 -203
  16. package/dist/open-sse/executors/default.js +146 -244
  17. package/dist/open-sse/executors/github.js +128 -73
  18. package/dist/open-sse/executors/grok-cli.js +527 -94
  19. package/dist/open-sse/executors/grok-web.js +5 -7
  20. package/dist/open-sse/executors/index.js +12 -0
  21. package/dist/open-sse/executors/kiro.js +150 -61
  22. package/dist/open-sse/executors/opencode-go.js +12 -4
  23. package/dist/open-sse/executors/opencode.js +1 -1
  24. package/dist/open-sse/executors/perplexity-web.js +20 -96
  25. package/dist/open-sse/executors/qoder.js +28 -18
  26. package/dist/open-sse/executors/vertex.js +53 -7
  27. package/dist/open-sse/executors/xiaomi-tokenplan.js +6 -5
  28. package/dist/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  29. package/dist/open-sse/handlers/chatCore/requestDetail.js +32 -8
  30. package/dist/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  31. package/dist/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  32. package/dist/open-sse/handlers/chatCore.js +35 -41
  33. package/dist/open-sse/handlers/embeddingProviders/index.js +1 -0
  34. package/dist/open-sse/handlers/embeddingProviders/openai.js +8 -16
  35. package/dist/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  36. package/dist/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  37. package/dist/open-sse/handlers/imageProviders/codex.js +2 -20
  38. package/dist/open-sse/handlers/imageProviders/comfyui.js +5 -18
  39. package/dist/open-sse/handlers/imageProviders/falAi.js +2 -22
  40. package/dist/open-sse/handlers/imageProviders/gemini.js +2 -16
  41. package/dist/open-sse/handlers/imageProviders/huggingface.js +2 -17
  42. package/dist/open-sse/handlers/imageProviders/index.js +3 -4
  43. package/dist/open-sse/handlers/imageProviders/leonardo.js +1 -1
  44. package/dist/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  45. package/dist/open-sse/handlers/imageProviders/openai.js +15 -43
  46. package/dist/open-sse/handlers/imageProviders/runwayml.js +2 -26
  47. package/dist/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  48. package/dist/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  49. package/dist/open-sse/handlers/imageProviders/weavy.js +1 -1
  50. package/dist/open-sse/handlers/search/chatSearch.js +60 -14
  51. package/dist/open-sse/handlers/ttsProviders/gemini.js +14 -3
  52. package/dist/open-sse/handlers/ttsProviders/index.js +4 -2
  53. package/dist/open-sse/handlers/ttsProviders/openai.js +4 -1
  54. package/dist/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  55. package/dist/open-sse/handlers/videoCore.js +166 -0
  56. package/dist/open-sse/handlers/videoProviders/weavy.js +1 -1
  57. package/dist/open-sse/mcp-server/catalog.js +1 -1
  58. package/dist/open-sse/mcp-server/server.js +2 -2
  59. package/dist/open-sse/mcp-server/tools/advancedTools.js +2 -2
  60. package/dist/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  61. package/dist/open-sse/mcp-server/tools/compressionTools.js +4 -4
  62. package/dist/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  63. package/dist/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  64. package/dist/open-sse/mcp-server/tools/memoryTools.js +3 -3
  65. package/dist/open-sse/mcp-server/tools/notionTools.js +2 -2
  66. package/dist/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  67. package/dist/open-sse/mcp-server/tools/pickFastestModel.js +1 -1
  68. package/dist/open-sse/mcp-server/tools/pluginTools.js +4 -4
  69. package/dist/open-sse/mcp-server/tools/skillTools.js +2 -2
  70. package/dist/open-sse/providers/capabilities.js +24 -4
  71. package/dist/open-sse/providers/registry/alicode-intl.js +1 -1
  72. package/dist/open-sse/providers/registry/anthropic.js +1 -8
  73. package/dist/open-sse/providers/registry/codex.js +0 -9
  74. package/dist/open-sse/providers/registry/cohere.js +0 -2
  75. package/dist/open-sse/providers/registry/gemini.js +0 -2
  76. package/dist/open-sse/providers/registry/github.js +9 -6
  77. package/dist/open-sse/providers/registry/grok-cli.js +28 -18
  78. package/dist/open-sse/providers/registry/index.js +74 -80
  79. package/dist/open-sse/providers/registry/kiro.js +12 -0
  80. package/dist/open-sse/providers/registry/mistral.js +0 -3
  81. package/dist/open-sse/providers/registry/openai.js +0 -3
  82. package/dist/open-sse/providers/registry/perplexity.js +0 -2
  83. package/dist/open-sse/providers/registry/xai.js +5 -3
  84. package/dist/open-sse/rtk/autodetect.js +10 -2
  85. package/dist/open-sse/rtk/caveman.js +2 -93
  86. package/dist/open-sse/rtk/cavemanPrompts.js +34 -2
  87. package/dist/open-sse/rtk/constants.js +7 -2
  88. package/dist/open-sse/rtk/headroom.js +133 -0
  89. package/dist/open-sse/rtk/ponytail.js +1 -1
  90. package/dist/open-sse/rtk/registry.js +2 -0
  91. package/dist/open-sse/services/accountFallback.js +0 -108
  92. package/dist/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  93. package/dist/open-sse/services/combo/quotaShareStrategy.js +1 -1
  94. package/dist/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  95. package/dist/open-sse/services/combo/sessionStickiness.js +1 -1
  96. package/dist/open-sse/services/combo/targetSorters.js +2 -2
  97. package/dist/open-sse/services/combo/validateQuality.js +1 -1
  98. package/dist/open-sse/services/comboConfig.js +1 -1
  99. package/dist/open-sse/services/emergencyFallback.js +1 -1
  100. package/dist/open-sse/services/grokCliModels.js +127 -0
  101. package/dist/open-sse/services/model.js +7 -1
  102. package/dist/open-sse/services/provider.js +1 -1
  103. package/dist/open-sse/services/proxyAutoSelector.js +1 -1
  104. package/dist/open-sse/services/tokenRefresh/providers.js +3 -3
  105. package/dist/open-sse/services/usage/codex.js +148 -214
  106. package/dist/open-sse/services/usage/grok-cli.js +61 -7
  107. package/dist/open-sse/services/usage/misc.js +0 -19
  108. package/dist/open-sse/services/usage.js +0 -2
  109. package/dist/open-sse/translator/concerns/paramSupport.js +2 -2
  110. package/dist/open-sse/translator/concerns/thinkingUnified.js +6 -0
  111. package/dist/open-sse/translator/index.js +97 -59
  112. package/dist/open-sse/translator/request/claude-to-kiro.js +67 -40
  113. package/dist/open-sse/translator/request/openai-responses.js +1 -0
  114. package/dist/open-sse/translator/request/openai-to-commandcode.js +0 -4
  115. package/dist/open-sse/translator/request/openai-to-kiro.js +49 -20
  116. package/dist/open-sse/translator/response/commandcode-to-openai.js +0 -4
  117. package/dist/open-sse/utils/bypassHandler.js +18 -3
  118. package/dist/open-sse/utils/claudeCloaking.js +15 -5
  119. package/dist/open-sse/utils/cursorImages.js +1 -1
  120. package/dist/open-sse/utils/error.js +0 -17
  121. package/dist/open-sse/utils/keepaliveThreshold.js +4 -4
  122. package/dist/open-sse/utils/kiroSessionReplay.js +125 -0
  123. package/dist/open-sse/utils/noThinkingAlias.js +1 -1
  124. package/dist/open-sse/utils/proxyFetch.js +0 -1
  125. package/dist/open-sse/utils/reasoningContentInjector.js +4 -7
  126. package/dist/open-sse/utils/responsesStatePolicy.js +1 -1
  127. package/dist/open-sse/utils/responsesStreamHelpers.js +1 -0
  128. package/dist/open-sse/utils/sessionManager.js +49 -22
  129. package/dist/open-sse/utils/stream.js +54 -77
  130. package/dist/open-sse/utils/streamHandler.js +19 -15
  131. package/dist/open-sse/utils/streamHelpers.js +2 -17
  132. package/dist/open-sse/utils/usageTracking.js +103 -12
  133. package/dist/routes/headroom/extras/route.js +58 -0
  134. package/dist/routes/headroom/restart/route.js +33 -0
  135. package/open-sse/config/appConstants.js +23 -79
  136. package/open-sse/config/errorConfig.js +0 -11
  137. package/open-sse/config/grokCli.js +10 -0
  138. package/open-sse/config/kiroConstants.js +99 -46
  139. package/open-sse/config/runtimeConfig.js +2 -0
  140. package/open-sse/config/ttsModels.js +2 -0
  141. package/open-sse/executors/antigravity.js +250 -164
  142. package/open-sse/executors/base.js +16 -11
  143. package/open-sse/executors/codex.js +269 -1108
  144. package/open-sse/executors/commandcode.js +10 -4
  145. package/open-sse/executors/cursor.js +96 -203
  146. package/open-sse/executors/default.js +146 -244
  147. package/open-sse/executors/github.js +128 -73
  148. package/open-sse/executors/grok-cli.js +527 -94
  149. package/open-sse/executors/grok-web.js +5 -7
  150. package/open-sse/executors/index.js +12 -0
  151. package/open-sse/executors/kiro.js +150 -61
  152. package/open-sse/executors/opencode-go.js +12 -4
  153. package/open-sse/executors/opencode.js +1 -1
  154. package/open-sse/executors/perplexity-web.js +20 -96
  155. package/open-sse/executors/qoder.js +28 -18
  156. package/open-sse/executors/vertex.js +53 -7
  157. package/open-sse/executors/xiaomi-tokenplan.js +6 -5
  158. package/open-sse/handlers/chatCore/nonStreamingHandler.js +97 -85
  159. package/open-sse/handlers/chatCore/requestDetail.js +32 -8
  160. package/open-sse/handlers/chatCore/sseToJsonHandler.js +13 -7
  161. package/open-sse/handlers/chatCore/streamingHandler.js +74 -25
  162. package/open-sse/handlers/chatCore.js +35 -41
  163. package/open-sse/handlers/embeddingProviders/index.js +1 -0
  164. package/open-sse/handlers/embeddingProviders/openai.js +8 -16
  165. package/open-sse/handlers/imageProviders/blackForestLabs.js +2 -21
  166. package/open-sse/handlers/imageProviders/cloudflareAi.js +2 -30
  167. package/open-sse/handlers/imageProviders/codex.js +2 -20
  168. package/open-sse/handlers/imageProviders/comfyui.js +5 -18
  169. package/open-sse/handlers/imageProviders/falAi.js +2 -22
  170. package/open-sse/handlers/imageProviders/gemini.js +2 -16
  171. package/open-sse/handlers/imageProviders/huggingface.js +2 -17
  172. package/open-sse/handlers/imageProviders/index.js +3 -4
  173. package/open-sse/handlers/imageProviders/leonardo.js +1 -1
  174. package/open-sse/handlers/imageProviders/nanobanana.js +4 -23
  175. package/open-sse/handlers/imageProviders/openai.js +15 -43
  176. package/open-sse/handlers/imageProviders/runwayml.js +2 -26
  177. package/open-sse/handlers/imageProviders/sdwebui.js +4 -20
  178. package/open-sse/handlers/imageProviders/stabilityAi.js +2 -26
  179. package/open-sse/handlers/imageProviders/weavy.js +1 -1
  180. package/open-sse/handlers/search/chatSearch.js +60 -14
  181. package/open-sse/handlers/ttsProviders/gemini.js +14 -3
  182. package/open-sse/handlers/ttsProviders/index.js +4 -2
  183. package/open-sse/handlers/ttsProviders/openai.js +4 -1
  184. package/open-sse/handlers/ttsProviders/openrouter.js +7 -4
  185. package/open-sse/handlers/videoCore.js +166 -0
  186. package/open-sse/handlers/videoProviders/weavy.js +1 -1
  187. package/open-sse/mcp-server/audit.js +1 -1
  188. package/open-sse/mcp-server/catalog.js +2 -2
  189. package/open-sse/mcp-server/descriptionCompressor.js +1 -1
  190. package/open-sse/mcp-server/mcpCallerIdentity.js +1 -1
  191. package/open-sse/mcp-server/schemas/tools.js +1 -1
  192. package/open-sse/mcp-server/server.js +4 -4
  193. package/open-sse/mcp-server/tools/advancedTools.js +5 -5
  194. package/open-sse/mcp-server/tools/agentSkillTools.js +1 -1
  195. package/open-sse/mcp-server/tools/compressionTools.js +4 -4
  196. package/open-sse/mcp-server/tools/gamificationTools.js +10 -10
  197. package/open-sse/mcp-server/tools/githubSkillTools.js +1 -1
  198. package/open-sse/mcp-server/tools/memoryTools.js +3 -3
  199. package/open-sse/mcp-server/tools/notionTools.js +2 -2
  200. package/open-sse/mcp-server/tools/obsidianTools.js +2 -2
  201. package/open-sse/mcp-server/tools/pickFastestModel.js +3 -3
  202. package/open-sse/mcp-server/tools/pluginTools.js +4 -4
  203. package/open-sse/mcp-server/tools/skillTools.js +2 -2
  204. package/open-sse/providers/capabilities.js +24 -4
  205. package/open-sse/providers/registry/alicode-intl.js +1 -1
  206. package/open-sse/providers/registry/anthropic.js +1 -8
  207. package/open-sse/providers/registry/codex.js +0 -9
  208. package/open-sse/providers/registry/cohere.js +0 -2
  209. package/open-sse/providers/registry/gemini.js +0 -2
  210. package/open-sse/providers/registry/github.js +9 -6
  211. package/open-sse/providers/registry/grok-cli.js +28 -18
  212. package/open-sse/providers/registry/index.js +74 -80
  213. package/open-sse/providers/registry/kiro.js +12 -0
  214. package/open-sse/providers/registry/mistral.js +0 -3
  215. package/open-sse/providers/registry/openai.js +0 -3
  216. package/open-sse/providers/registry/perplexity.js +0 -2
  217. package/open-sse/providers/registry/xai.js +5 -3
  218. package/open-sse/rtk/autodetect.js +10 -2
  219. package/open-sse/rtk/caveman.js +2 -93
  220. package/open-sse/rtk/cavemanPrompts.js +34 -2
  221. package/open-sse/rtk/constants.js +7 -2
  222. package/open-sse/rtk/headroom.js +133 -0
  223. package/open-sse/rtk/ponytail.js +1 -1
  224. package/open-sse/rtk/registry.js +2 -0
  225. package/open-sse/services/accountFallback.js +0 -108
  226. package/open-sse/services/combo/quotaExhaustionCutoff.js +2 -2
  227. package/open-sse/services/combo/quotaShareStrategy.js +1 -1
  228. package/open-sse/services/combo/resolveAutoStrategy.js +1 -1
  229. package/open-sse/services/combo/sessionStickiness.js +1 -1
  230. package/open-sse/services/combo/shadowRouting.js +1 -1
  231. package/open-sse/services/combo/targetSorters.js +4 -4
  232. package/open-sse/services/combo/validateQuality.js +1 -1
  233. package/open-sse/services/evalRouting.js +1 -1
  234. package/open-sse/services/grokCliModels.js +127 -0
  235. package/open-sse/services/model.js +7 -1
  236. package/open-sse/services/modelCapabilities.js +1 -1
  237. package/open-sse/services/modelFamilyFallback.js +1 -1
  238. package/open-sse/services/provider.js +1 -1
  239. package/open-sse/services/providerCooldownTracker.js +1 -1
  240. package/open-sse/services/rateLimitManager.js +1 -1
  241. package/open-sse/services/tokenRefresh/providers.js +3 -3
  242. package/open-sse/services/usage/codex.js +148 -214
  243. package/open-sse/services/usage/grok-cli.js +61 -7
  244. package/open-sse/services/usage/misc.js +0 -19
  245. package/open-sse/services/usage.js +0 -2
  246. package/open-sse/translator/concerns/paramSupport.js +2 -2
  247. package/open-sse/translator/concerns/thinkingUnified.js +6 -0
  248. package/open-sse/translator/index.js +97 -59
  249. package/open-sse/translator/request/claude-to-kiro.js +67 -40
  250. package/open-sse/translator/request/openai-responses.js +1 -0
  251. package/open-sse/translator/request/openai-to-commandcode.js +0 -4
  252. package/open-sse/translator/request/openai-to-kiro.js +49 -20
  253. package/open-sse/translator/response/commandcode-to-openai.js +0 -4
  254. package/open-sse/utils/bypassHandler.js +18 -3
  255. package/open-sse/utils/claudeCloaking.js +15 -5
  256. package/open-sse/utils/error.js +0 -17
  257. package/open-sse/utils/kiroSessionReplay.js +125 -0
  258. package/open-sse/utils/logger.js +1 -1
  259. package/open-sse/utils/proxyFetch.js +0 -1
  260. package/open-sse/utils/reasoningContentInjector.js +4 -7
  261. package/open-sse/utils/responsesStreamHelpers.js +1 -0
  262. package/open-sse/utils/sessionManager.js +49 -22
  263. package/open-sse/utils/stream.js +54 -77
  264. package/open-sse/utils/streamHandler.js +19 -15
  265. package/open-sse/utils/streamHelpers.js +2 -17
  266. package/open-sse/utils/usageTracking.js +103 -12
  267. package/package.json +4 -7
  268. package/public/assets/EndpointPageClient.C2WMTYy0.js +6 -0
  269. package/public/assets/{Loading.Bj-WGl4k.js → Loading.BHPtQ9vj.js} +1 -1
  270. package/public/assets/{NoAuthProxyCard.qAv57b-0.js → NoAuthProxyCard.BDcXaWvM.js} +1 -1
  271. package/public/assets/index.Be3gbrBl.js +89 -0
  272. package/public/assets/index.COMgQZYj.css +1 -0
  273. package/public/assets/{page.CbkENBd5.js → page.-lpNgYAw.js} +1 -1
  274. package/public/assets/{page.CssmrzTT.js → page.11hpNKmq.js} +1 -1
  275. package/public/assets/{page.C72FTTJr.js → page.B-LxsnqU.js} +1 -1
  276. package/public/assets/{page.sOFOrxqq.js → page.B-dzeIUC.js} +1 -1
  277. package/public/assets/{page.CsxWmPoI.js → page.B-nBR75u.js} +1 -1
  278. package/public/assets/{page.Dx_GRRdT.js → page.B3QqvLep.js} +1 -1
  279. package/public/assets/{page.DPyOkPVo.js → page.B8xdkCWA.js} +1 -1
  280. package/public/assets/{page.DUI8kqOY.js → page.BFb7yUd8.js} +1 -1
  281. package/public/assets/page.BbPPdoas.js +1 -0
  282. package/public/assets/page.BdS20a1O.js +1 -0
  283. package/public/assets/{page.DibhF7f-.js → page.BfmI9KYe.js} +1 -1
  284. package/public/assets/{page.DX4Nno6M.js → page.BgGJovOg.js} +1 -1
  285. package/public/assets/{page.BnmTC5jG.js → page.C0gBvR4O.js} +1 -1
  286. package/public/assets/{page.D5gj98Oe.js → page.C6bYizL7.js} +1 -1
  287. package/public/assets/{page.vla5Mzki.js → page.C8sLEMa6.js} +1 -1
  288. package/public/assets/{page.CXd_R9yU.js → page.CCNsZBXp.js} +1 -1
  289. package/public/assets/{page.CQlVGoXg.js → page.CF_YSLwP.js} +1 -1
  290. package/public/assets/{page.BbO1pspY.js → page.CPTtRDxw.js} +1 -1
  291. package/public/assets/{page.D1oKew1j.js → page.CdMmlUEm.js} +1 -1
  292. package/public/assets/{page.DxMDTbSx.js → page.Cged1bOZ.js} +1 -1
  293. package/public/assets/{page.Cj5h09Zo.js → page.Ch647dVk.js} +1 -1
  294. package/public/assets/{page.DVIHRbxB.js → page.CpvXDkQF.js} +1 -1
  295. package/public/assets/{page.i4KDuWcM.js → page.CrBl7f8N.js} +1 -1
  296. package/public/assets/{page.BSLJ4tx5.js → page.CrP7niA2.js} +1 -1
  297. package/public/assets/{page.CnTop8Zt.js → page.CvUFZzXr.js} +1 -1
  298. package/public/assets/{page.O2ddJYoT.js → page.CyUqJPmx.js} +1 -1
  299. package/public/assets/{page.DBhu4Arl.js → page.D8Rp8fFR.js} +1 -1
  300. package/public/assets/{page.CPZav1_c.js → page.Df9qtrdG.js} +1 -1
  301. package/public/assets/{page.Qkkv8roc.js → page.DiL4Gwqe.js} +1 -1
  302. package/public/assets/{page.BdmJ3yY3.js → page.Dl1apZE2.js} +1 -1
  303. package/public/assets/{page.1qjqvrwX.js → page.HV0w1d5C.js} +1 -1
  304. package/public/assets/{page.ChX1NqmC.js → page.N1x4YL8_.js} +1 -1
  305. package/public/assets/{page.Dh5f0XJC.js → page.P2Ny5veR.js} +1 -1
  306. package/public/assets/{page.CSs3-gdt.js → page.fOOCr18J.js} +1 -1
  307. package/public/assets/{page.Ir7KvKcF.js → page.sUIPWIiF.js} +1 -1
  308. package/public/assets/{page.CzlQTyAL.js → page.tE7PpWYW.js} +1 -1
  309. package/public/assets/{page.DzZLqI5Q.js → page.uziaGZsT.js} +1 -1
  310. package/public/index.html +2 -2
  311. package/public/assets/EndpointPageClient.LyNNvZ4z.js +0 -6
  312. package/public/assets/index.BuPfZebu.css +0 -1
  313. package/public/assets/index.CShjRV_B.js +0 -89
  314. package/public/assets/page.DD_czjjP.js +0 -1
@@ -5,14 +5,16 @@
5
5
  import { register } from "../index.js";
6
6
  import { FORMATS } from "../formats.js";
7
7
  import { v4 as uuidv4 } from "uuid";
8
- import { resolveSessionId } from "../../utils/sessionManager.js";
8
+ import { applyKiroSessionReplay } from "../../utils/kiroSessionReplay.js";
9
+ import { resolveContinuationId, resolveSessionIdentity } from "../../utils/sessionManager.js";
9
10
  import {
10
11
  resolveKiroModel,
12
+ resolveKiroThinkingBudget,
11
13
  buildThinkingSystemPrefix,
12
14
  KIRO_AGENTIC_SYSTEM_PROMPT,
13
15
  resolveDefaultProfileArn,
16
+ buildKiroAdditionalModelRequestFieldsForModel
14
17
  } from "../../config/kiroConstants.js";
15
- import { resolveKiroThinkingBudget } from "../../services/thinkingBudget.js";
16
18
  import { parseDataUri } from "../concerns/image.js";
17
19
  import { DEFAULT_IMAGE_MIME } from "../schema/index.js";
18
20
  import { ROLE, OPENAI_BLOCK, CLAUDE_BLOCK } from "../schema/index.js";
@@ -546,47 +548,74 @@ export function openaiToKiroRequest(model, body, stream, credentials) {
546
548
  ? (credentials?.providerSpecificData?.profileArn || "")
547
549
  : (credentials?.providerSpecificData?.profileArn || resolveDefaultProfileArn(authMethod));
548
550
 
549
- let finalContent = currentMessage?.userInputMessage?.content || "";
550
-
551
551
  const timestamp = new Date().toISOString();
552
552
 
553
- // Build the system-prompt prefix that goes ABOVE the user message body.
554
- // Order: thinking_mode tag first (so Kiro sees it before any user text),
555
- // then context/timestamp marker, then optional agentic chunked-write prompt.
556
- const prefixParts = [];
553
+ // Kiro CLI/KAS sends these as top-level systemPrompt. Keep a content fallback
554
+ // too because the CodeWhisperer surface does not always enforce top-level
555
+ // systemPrompt for direct calls.
556
+ const systemPromptParts = [];
557
557
  if (thinkingBudget !== null) {
558
- prefixParts.push(buildThinkingSystemPrefix(thinkingBudget));
558
+ systemPromptParts.push(buildThinkingSystemPrefix(thinkingBudget));
559
559
  }
560
- prefixParts.push(`[Context: Current time is ${timestamp}]`);
561
560
  if (agentic) {
562
- prefixParts.push(KIRO_AGENTIC_SYSTEM_PROMPT);
561
+ systemPromptParts.push(KIRO_AGENTIC_SYSTEM_PROMPT);
563
562
  }
564
- finalContent = `${prefixParts.join("\n\n")}\n\n${finalContent}`;
563
+ const systemPrompt = systemPromptParts.filter(Boolean).join("\n\n");
564
+ const currentTimeContext = `[Context: Current time is ${timestamp}]`;
565
+ const contentPrefix = [systemPrompt, currentTimeContext].filter(Boolean).join("\n\n");
566
+
567
+ const sessionIdentity = resolveSessionIdentity({ headers: credentials?.rawHeaders, body, connectionId: credentials?.connectionId, scope: "kiro" });
568
+ const conversationId = sessionIdentity.sessionId;
569
+ const continuationId = resolveContinuationId({
570
+ sessionId: conversationId,
571
+ connectionId: credentials?.connectionId,
572
+ scope: "kiro",
573
+ ephemeral: sessionIdentity.ephemeral,
574
+ });
575
+ const replay = applyKiroSessionReplay({
576
+ conversationId,
577
+ connectionId: credentials?.connectionId,
578
+ modelId: upstreamModel,
579
+ systemPrompt,
580
+ contentPrefix,
581
+ currentContentPrefix: currentTimeContext,
582
+ history,
583
+ currentMessage,
584
+ });
585
+ const replayCurrent = replay.currentMessage?.userInputMessage || {};
565
586
 
566
587
  const payload = {
567
588
  conversationState: {
568
589
  chatTriggerType: "MANUAL",
569
- conversationId: resolveSessionId({ headers: credentials?.rawHeaders, body, connectionId: credentials?.connectionId, scope: "kiro" }),
590
+ conversationId,
591
+ agentContinuationId: continuationId,
592
+ agentTaskType: "vibe",
570
593
  currentMessage: {
571
594
  userInputMessage: {
572
- content: finalContent,
595
+ content: replayCurrent.content || "",
573
596
  modelId: upstreamModel,
574
597
  origin: "AI_EDITOR",
575
- ...(currentMessage?.userInputMessage?.images?.length > 0 && {
576
- images: currentMessage.userInputMessage.images
598
+ ...(replayCurrent.images?.length > 0 && {
599
+ images: replayCurrent.images
577
600
  }),
578
- ...(currentMessage?.userInputMessage?.userInputMessageContext && {
579
- userInputMessageContext: currentMessage.userInputMessage.userInputMessageContext
601
+ ...(replayCurrent.userInputMessageContext && {
602
+ userInputMessageContext: replayCurrent.userInputMessageContext
580
603
  })
581
604
  }
582
605
  },
583
- history: history
584
- }
606
+ history: replay.history
607
+ },
608
+ agentMode: "vibe",
585
609
  };
586
610
 
587
611
  if (profileArn) {
588
612
  payload.profileArn = profileArn;
589
613
  }
614
+ if (systemPrompt) payload.systemPrompt = systemPrompt;
615
+ const additionalModelRequestFields = buildKiroAdditionalModelRequestFieldsForModel(body, upstreamModel);
616
+ if (additionalModelRequestFields) {
617
+ payload.additionalModelRequestFields = additionalModelRequestFields;
618
+ }
590
619
 
591
620
  if (maxTokens || temperature !== undefined || topP !== undefined) {
592
621
  payload.inferenceConfig = {};
@@ -182,7 +182,3 @@ export function commandCodeToOpenAIResponse(chunk, state) {
182
182
  }
183
183
 
184
184
  register(FORMATS.COMMANDCODE, FORMATS.OPENAI, null, commandCodeToOpenAIResponse);
185
-
186
- // Backwards-compatible alias (executor expects this name)
187
- export const convertCommandCodeToOpenAI = commandCodeToOpenAIResponse;
188
-
@@ -247,9 +247,24 @@ function mergeChunksToResponse(chunks, sourceFormat) {
247
247
 
248
248
  if (messageStart?.message) {
249
249
  finalChunk = messageStart.message;
250
- // Merge usage if available
251
- if (messageDelta?.usage) {
252
- finalChunk.usage = messageDelta.usage;
250
+ // message_start.usage has input + cache; message_delta.usage has the
251
+ // final output_tokens. Merge so cache survives (delta omits it).
252
+ const startUsage = messageStart.message.usage;
253
+ const deltaUsage = messageDelta?.usage;
254
+ if (startUsage || deltaUsage) {
255
+ finalChunk.usage = {
256
+ ...(startUsage || {}),
257
+ ...(deltaUsage || {}),
258
+ ...(startUsage?.cache_read_input_tokens !== undefined
259
+ ? { cache_read_input_tokens: startUsage.cache_read_input_tokens }
260
+ : {}),
261
+ ...(startUsage?.cache_creation_input_tokens !== undefined
262
+ ? { cache_creation_input_tokens: startUsage.cache_creation_input_tokens }
263
+ : {}),
264
+ ...(startUsage?.input_tokens !== undefined
265
+ ? { input_tokens: startUsage.input_tokens }
266
+ : {})
267
+ };
253
268
  }
254
269
  }
255
270
  }
@@ -13,11 +13,18 @@ function generateBillingHeader(payload) {
13
13
  return `x-anthropic-billing-header: cc_version=${CLAUDE_VERSION}.${buildHash}; cc_entrypoint=${CC_ENTRYPOINT}; cch=${cch};`;
14
14
  }
15
15
 
16
+ // Derive a deterministic UUID-v4-shaped string from a seed (stable per account)
17
+ function deriveUuid(seed) {
18
+ const h = createHash("sha256").update(seed).digest("hex");
19
+ return `${h.slice(0, 8)}-${h.slice(8, 12)}-4${h.slice(13, 16)}-${((parseInt(h[16], 16) & 0x3) | 0x8).toString(16)}${h.slice(17, 20)}-${h.slice(20, 32)}`;
20
+ }
21
+
16
22
  // Generate fake user ID in Claude Code 2.1.92+ JSON format:
17
23
  // {"device_id":"<64hex>","account_uuid":"<uuid>","session_id":"<uuid>"}
18
- function generateFakeUserID(sessionId) {
19
- const deviceId = randomBytes(32).toString("hex");
20
- const accountUuid = randomUUID();
24
+ // device_id/account_uuid derive from apiKey (stable per account), session_id per-conversation
25
+ function generateFakeUserID(sessionId, apiKey) {
26
+ const deviceId = apiKey ? createHash("sha256").update(`device:${apiKey}`).digest("hex") : randomBytes(32).toString("hex");
27
+ const accountUuid = apiKey ? deriveUuid(`account:${apiKey}`) : randomUUID();
21
28
  const sessionUuid = sessionId || randomUUID();
22
29
  return `{"device_id":"${deviceId}","account_uuid":"${accountUuid}","session_id":"${sessionUuid}"}`;
23
30
  }
@@ -40,8 +47,11 @@ export function cloakClaudeTools(body) {
40
47
  const clientToolNames = new Set();
41
48
  const clientDeclarations = [];
42
49
 
43
- // All client tools get renamed with suffix
50
+ // All client tools get renamed with suffix.
51
+ // Built-in server tools (web_search_20250305, etc.) carry a `type` and require
52
+ // an exact reserved `name` — never suffix those or Claude rejects the request.
44
53
  for (const tool of tools) {
54
+ if (tool.type) { clientDeclarations.push(tool); continue; }
45
55
  const suffixed = suffix(tool.name);
46
56
  toolNameMap.set(suffixed, tool.name);
47
57
  clientToolNames.add(tool.name);
@@ -148,7 +158,7 @@ export function applyCloaking(body, apiKey, sessionId) {
148
158
  // Inject fake user ID into metadata (session_id must match X-Claude-Code-Session-Id)
149
159
  const existingUserId = result.metadata?.user_id;
150
160
  if (!existingUserId) {
151
- result.metadata = { ...result.metadata, user_id: generateFakeUserID(sessionId) };
161
+ result.metadata = { ...result.metadata, user_id: generateFakeUserID(sessionId, apiKey) };
152
162
  }
153
163
 
154
164
  return result;
@@ -145,20 +145,3 @@ export function formatProviderError(error, provider, model, statusCode) {
145
145
  const causeStr = causeCode || causeMsg ? ` (cause: ${[causeCode, causeMsg].filter(Boolean).join(": ")})` : "";
146
146
  return `[${code}]: ${message}${causeStr}`;
147
147
  }
148
-
149
-
150
- /**
151
- * Safely escape HTML characters from error strings to prevent XSS in clients that poorly render error JSON.
152
- * Note: Only intended for string values. Non-string inputs will be returned as-is or cast to strings based on usage.
153
- * @param {string} message The raw error message
154
- * @returns {string} The HTML-escaped error message
155
- */
156
- export function sanitizeErrorMessage(message) {
157
- if (typeof message !== 'string') return String(message);
158
- return message
159
- .replace(/&/g, '&amp;')
160
- .replace(/</g, '&lt;')
161
- .replace(/>/g, '&gt;')
162
- .replace(/"/g, '&quot;')
163
- .replace(/'/g, '&#39;');
164
- }
@@ -0,0 +1,125 @@
1
+ import { MEMORY_CONFIG } from "../config/runtimeConfig.js";
2
+
3
+ const sessionStartStore = new Map();
4
+ const MAX_SESSION_STARTS = 5000;
5
+
6
+ function clone(value) {
7
+ return value == null ? value : JSON.parse(JSON.stringify(value));
8
+ }
9
+
10
+ function sessionKey(connectionId, conversationId) {
11
+ return `${connectionId || ""}:${conversationId || ""}`;
12
+ }
13
+
14
+ function ensureUserMessageModelId(message, modelId) {
15
+ if (message?.userInputMessage && !message.userInputMessage.modelId && modelId) {
16
+ message.userInputMessage.modelId = modelId;
17
+ }
18
+ return message;
19
+ }
20
+
21
+ function ensureHistoryModelIds(history, modelId) {
22
+ for (const item of history || []) {
23
+ ensureUserMessageModelId(item, modelId);
24
+ }
25
+ return history;
26
+ }
27
+
28
+ function prefixUserMessage(message, contentPrefix, modelId) {
29
+ const out = clone(message) || { userInputMessage: { content: "" } };
30
+ if (!out.userInputMessage) out.userInputMessage = { content: "" };
31
+ ensureUserMessageModelId(out, modelId);
32
+ if (contentPrefix) {
33
+ const content = out.userInputMessage.content || "";
34
+ out.userInputMessage.content = content
35
+ ? `${contentPrefix}\n\n${content}`
36
+ : contentPrefix;
37
+ }
38
+ return out;
39
+ }
40
+
41
+ function findFirstUserIndex(history) {
42
+ return history.findIndex((item) => item?.userInputMessage);
43
+ }
44
+
45
+ function rememberSessionStart(key, entry) {
46
+ if (sessionStartStore.size >= MAX_SESSION_STARTS) {
47
+ sessionStartStore.delete(sessionStartStore.keys().next().value);
48
+ }
49
+ sessionStartStore.set(key, { ...entry, lastUsed: Date.now() });
50
+ }
51
+
52
+ /**
53
+ * Preserve Kiro cacheability by freezing the first user message (`msg0`) for a
54
+ * session, replaying that exact message as the first history user on later
55
+ * turns, and injecting volatile current-time context only into the current turn.
56
+ */
57
+ export function applyKiroSessionReplay({
58
+ conversationId,
59
+ connectionId,
60
+ modelId,
61
+ systemPrompt = "",
62
+ contentPrefix = "",
63
+ currentContentPrefix = "",
64
+ history = [],
65
+ currentMessage,
66
+ } = {}) {
67
+ const key = sessionKey(connectionId, conversationId);
68
+ const existing = conversationId ? sessionStartStore.get(key) : null;
69
+ const baseHistory = clone(history) || [];
70
+ const baseCurrent = clone(currentMessage) || { userInputMessage: { content: "" } };
71
+
72
+ if (existing && existing.modelId === modelId && existing.systemPrompt === systemPrompt) {
73
+ existing.lastUsed = Date.now();
74
+ const firstUserIndex = findFirstUserIndex(baseHistory);
75
+ const sessionStart = ensureUserMessageModelId(clone(existing.sessionStart), modelId);
76
+ if (firstUserIndex >= 0) {
77
+ baseHistory[firstUserIndex] = sessionStart;
78
+ } else {
79
+ baseHistory.unshift(sessionStart);
80
+ }
81
+ return {
82
+ history: ensureHistoryModelIds(baseHistory, modelId),
83
+ currentMessage: prefixUserMessage(baseCurrent, currentContentPrefix, modelId),
84
+ replayed: true,
85
+ };
86
+ }
87
+
88
+ const firstUserIndex = findFirstUserIndex(baseHistory);
89
+ let sessionStart;
90
+ let nextCurrent = ensureUserMessageModelId(baseCurrent, modelId);
91
+ if (firstUserIndex >= 0) {
92
+ sessionStart = prefixUserMessage(baseHistory[firstUserIndex], contentPrefix, modelId);
93
+ baseHistory[firstUserIndex] = clone(sessionStart);
94
+ nextCurrent = prefixUserMessage(baseCurrent, currentContentPrefix, modelId);
95
+ } else {
96
+ sessionStart = prefixUserMessage(baseCurrent, contentPrefix, modelId);
97
+ nextCurrent = clone(sessionStart);
98
+ }
99
+
100
+ if (conversationId) {
101
+ rememberSessionStart(key, {
102
+ sessionStart: clone(sessionStart),
103
+ modelId,
104
+ systemPrompt,
105
+ });
106
+ }
107
+
108
+ return {
109
+ history: ensureHistoryModelIds(baseHistory, modelId),
110
+ currentMessage: nextCurrent,
111
+ replayed: false,
112
+ };
113
+ }
114
+
115
+ export function clearKiroSessionReplayStore() {
116
+ sessionStartStore.clear();
117
+ }
118
+
119
+ const cleanup = setInterval(() => {
120
+ const now = Date.now();
121
+ for (const [key, entry] of sessionStartStore) {
122
+ if (now - entry.lastUsed > MEMORY_CONFIG.sessionTtlMs) sessionStartStore.delete(key);
123
+ }
124
+ }, MEMORY_CONFIG.sessionCleanupIntervalMs);
125
+ if (cleanup.unref) cleanup.unref();
@@ -1,4 +1,4 @@
1
- import { getAppLogFormat, getAppLogLevel } from "../../dist/lib/logEnv";
1
+ import { getAppLogFormat, getAppLogLevel } from "../../src/lib/logEnv";
2
2
  const LEVELS = { debug: 0, info: 1, warn: 2, error: 3 };
3
3
  function isLogLevel(value) {
4
4
  return Object.prototype.hasOwnProperty.call(LEVELS, value);
@@ -106,7 +106,6 @@ const MITM_BYPASS_HOSTS = [
106
106
  "q.us-east-1.amazonaws.com",
107
107
  "codewhisperer.us-east-1.amazonaws.com",
108
108
  "api2.cursor.sh",
109
- "leonardo.ai",
110
109
  ];
111
110
  const GOOGLE_DNS_SERVERS = ["8.8.8.8", "8.8.4.4"];
112
111
  const HTTPS_PORT = 443;
@@ -1,15 +1,12 @@
1
1
  // Some thinking-mode providers (DeepSeek, Kimi, MiniMax, ...) require reasoning_content
2
2
  // to be echoed back on assistant messages. Clients in OpenAI format don't send it,
3
3
  // so we inject a non-empty placeholder to satisfy upstream validation.
4
+ import { PROVIDERS } from "../config/providers.js";
4
5
 
5
6
  const PLACEHOLDER = " ";
6
7
 
7
- // Provider-level rules: keyed by executor.provider
8
- const PROVIDER_RULES = {
9
- deepseek: { scope: "all" },
10
- minimax: { scope: "all" },
11
- "minimax-cn": { scope: "all" }
12
- };
8
+ // Provider-level rules derive from registry transport.reasoningInject (single source)
9
+ const providerRuleFor = (provider) => PROVIDERS[provider]?.reasoningInject;
13
10
 
14
11
  // Model-level rules: matched by predicate against model id
15
12
  const MODEL_RULES = [
@@ -71,7 +68,7 @@ function applyDeepSeekV4ProAlias({ provider, model, body }) {
71
68
  }
72
69
 
73
70
  export function injectReasoningContent({ provider, model, body }) {
74
- const providerRule = PROVIDER_RULES[provider];
71
+ const providerRule = providerRuleFor(provider);
75
72
  const modelRule = MODEL_RULES.find(r => r.match(model));
76
73
  const rule = providerRule || modelRule;
77
74
  const nextBody = applyDeepSeekV4ProAlias({ provider, model, body });
@@ -5,6 +5,7 @@ import { formatSSE } from "./streamHelpers.js";
5
5
  // Responses API events that signal the stream has reached a terminal state
6
6
  const OPENAI_RESPONSES_TERMINAL_EVENTS = new Set([
7
7
  "response.completed",
8
+ "response.done",
8
9
  "response.failed",
9
10
  "error"
10
11
  ]);
@@ -13,6 +13,7 @@ import { MEMORY_CONFIG } from "../config/runtimeConfig.js";
13
13
 
14
14
  // Runtime storage: Key = connectionId, Value = { sessionId, lastUsed }
15
15
  const runtimeSessionStore = new Map();
16
+ const continuationStore = new Map();
16
17
 
17
18
  // Periodically evict entries that haven't been used within TTL
18
19
  const cleanupInterval = setInterval(() => {
@@ -80,6 +81,7 @@ export function generateBinaryStyleId() {
80
81
  export function clearSessionStore() {
81
82
  runtimeSessionStore.clear();
82
83
  assistantSessionStore.clear();
84
+ continuationStore.clear();
83
85
  }
84
86
 
85
87
  // Conversation-stable session store: Key = hash(scope+assistant text), Value = { sessionId, lastUsed }
@@ -87,9 +89,10 @@ const assistantSessionStore = new Map();
87
89
  const ASSISTANT_MIN_LEN = 50;
88
90
  const ASSISTANT_CAP_LEN = 50;
89
91
  const MAX_ASSISTANT_SESSIONS = 5000;
92
+ const MAX_CONTINUATION_SESSIONS = 5000;
90
93
 
91
94
  // Client headers/body fields that carry an upstream session id (priority order)
92
- const SESSION_HEADER_KEYS = ["x-session-id", "session-id", "session_id", "x-amp-thread-id", "x-client-request-id"];
95
+ const SESSION_HEADER_KEYS = ["x-session-id", "session-id", "session_id", "x-amp-thread-id"];
93
96
  const CLAUDE_CODE_SESSION_RE = /_session_([a-f0-9-]+)$/;
94
97
 
95
98
  function sha16(text) {
@@ -131,7 +134,7 @@ function extractAntigravitySession(body) {
131
134
  return m ? normalizeSessionId(m[1]) : null;
132
135
  }
133
136
 
134
- function extractClientSessionId(headers, body) {
137
+ function extractClientSessionId(headers, body, scope = "") {
135
138
  const claude = extractClaudeCodeSession(body?.metadata?.user_id);
136
139
  if (claude) return `claude:${claude}`;
137
140
  const antigravity = extractAntigravitySession(body);
@@ -140,18 +143,25 @@ function extractClientSessionId(headers, body) {
140
143
  const v = headerValue(headers, key);
141
144
  if (v) return v;
142
145
  }
146
+ const requestId = scope === "kiro" ? null : headerValue(headers, "x-client-request-id");
147
+ if (requestId) return requestId;
143
148
  const fromBody =
144
149
  normalizeSessionId(body?.prompt_cache_key) ||
145
150
  normalizeSessionId(body?.session_id) ||
146
151
  normalizeSessionId(body?.conversation_id) ||
147
- normalizeSessionId(body?.metadata?.user_id);
152
+ (scope === "kiro" ? null : normalizeSessionId(body?.metadata?.user_id));
148
153
  return fromBody || null;
149
154
  }
150
155
 
156
+ function requestMessages(body) {
157
+ if (Array.isArray(body?.messages)) return body.messages;
158
+ if (Array.isArray(body?.input)) return body.input;
159
+ return [];
160
+ }
161
+
151
162
  // Accumulate assistant text from OpenAI/Responses-style input/messages (cap-limited)
152
163
  function accumulateAssistantText(body) {
153
- const items = Array.isArray(body?.input) ? body.input
154
- : Array.isArray(body?.messages) ? body.messages : null;
164
+ const items = requestMessages(body);
155
165
  if (!items) return "";
156
166
  let text = "";
157
167
  for (const item of items) {
@@ -193,16 +203,39 @@ function assistantTextSessionId(scope, body) {
193
203
  * @param {string} [opts.connectionId] - Connection identifier (fallback scope)
194
204
  * @param {string} [opts.workspaceId] - Provider workspace id (account-wide fallback)
195
205
  * @param {string} [opts.scope] - Provider scope to isolate cache keys across providers
196
- * @returns {string} A stable session id
206
+ * @returns {{sessionId: string, ephemeral: boolean}} A session id plus whether it is one-shot
197
207
  */
198
- export function resolveSessionId({ headers, body, connectionId, workspaceId, scope = "" } = {}) {
199
- const client = extractClientSessionId(headers, body);
200
- if (client) return client;
201
- const fromAssistant = assistantTextSessionId(`${scope}:${connectionId || ""}`, body);
202
- if (fromAssistant) return fromAssistant;
208
+ export function resolveSessionIdentity({ headers, body, connectionId, workspaceId, scope = "" } = {}) {
209
+ const client = extractClientSessionId(headers, body, scope);
210
+ if (client) return { sessionId: client, ephemeral: false };
211
+ const fromAssistant = scope === "kiro" ? null : assistantTextSessionId(`${scope}:${connectionId || ""}`, body);
212
+ if (fromAssistant) return { sessionId: fromAssistant, ephemeral: false };
203
213
  const ws = normalizeSessionId(workspaceId);
204
- if (ws) return ws;
205
- return deriveSessionId(connectionId);
214
+ if (ws) return { sessionId: ws, ephemeral: false };
215
+ if (scope === "kiro") return { sessionId: generateBinaryStyleId(), ephemeral: true };
216
+ return { sessionId: deriveSessionId(connectionId), ephemeral: false };
217
+ }
218
+
219
+ export function resolveSessionId(opts = {}) {
220
+ return resolveSessionIdentity(opts).sessionId;
221
+ }
222
+
223
+ export function resolveContinuationId({ sessionId, connectionId, scope = "", ephemeral = false } = {}) {
224
+ if (ephemeral) return crypto.randomUUID();
225
+ const key = `${scope}:${connectionId || ""}:${sessionId || ""}`;
226
+ const existing = continuationStore.get(key);
227
+ if (existing) {
228
+ existing.lastUsed = Date.now();
229
+ continuationStore.delete(key);
230
+ continuationStore.set(key, existing);
231
+ return existing.continuationId;
232
+ }
233
+ const continuationId = crypto.randomUUID();
234
+ if (continuationStore.size >= MAX_CONTINUATION_SESSIONS) {
235
+ continuationStore.delete(continuationStore.keys().next().value);
236
+ }
237
+ continuationStore.set(key, { continuationId, lastUsed: Date.now() });
238
+ return continuationId;
206
239
  }
207
240
 
208
241
  // Capture session id from request body + credentials (envelope still intact here)
@@ -227,14 +260,8 @@ const assistantCleanup = setInterval(() => {
227
260
  for (const [key, entry] of assistantSessionStore) {
228
261
  if (now - entry.lastUsed > MEMORY_CONFIG.sessionTtlMs) assistantSessionStore.delete(key);
229
262
  }
263
+ for (const [key, entry] of continuationStore) {
264
+ if (now - entry.lastUsed > MEMORY_CONFIG.sessionTtlMs) continuationStore.delete(key);
265
+ }
230
266
  }, MEMORY_CONFIG.sessionCleanupIntervalMs);
231
267
  if (assistantCleanup.unref) assistantCleanup.unref();
232
-
233
- /**
234
- * Stub: get session info by session ID.
235
- * Returns session object if found, null otherwise.
236
- * TODO: Wire to actual session store when available.
237
- */
238
- export function getSessionInfo(sessionId) {
239
- return null;
240
- }