@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.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 (387) hide show
  1. package/README.md +13 -10
  2. package/dist/agent/agent-definition-registry.d.ts +3 -0
  3. package/dist/agent/agent-definition-registry.js +3 -1
  4. package/dist/agent/agent-definition.d.ts +15 -0
  5. package/dist/agent/agent-definition.js +27 -3
  6. package/dist/arena/context/context-tools.js +47 -4
  7. package/dist/arena/ledger.js +9 -1
  8. package/dist/arena/strategies/utils.d.ts +1 -4
  9. package/dist/arena/strategies/utils.js +7 -84
  10. package/dist/automation/cron-expr.d.ts +10 -0
  11. package/dist/automation/cron-expr.js +23 -5
  12. package/dist/automation/runner.d.ts +21 -4
  13. package/dist/automation/runner.js +48 -12
  14. package/dist/automation/scheduler.d.ts +38 -0
  15. package/dist/automation/scheduler.js +89 -12
  16. package/dist/automation/store.js +5 -2
  17. package/dist/capability-control/disabled-lists.d.ts +25 -0
  18. package/dist/capability-control/disabled-lists.js +57 -0
  19. package/dist/capability-control/overlay.d.ts +15 -0
  20. package/dist/capability-control/overlay.js +27 -0
  21. package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
  22. package/dist/cc-orchestrator/agent-adapter.js +133 -0
  23. package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
  24. package/dist/cc-orchestrator/cc-capability.js +53 -0
  25. package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
  26. package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
  27. package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
  28. package/dist/cc-orchestrator/codex-session-history.js +187 -0
  29. package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
  30. package/dist/cc-orchestrator/external-agent-changes.js +214 -0
  31. package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
  32. package/dist/cc-orchestrator/external-agent-driver.js +69 -0
  33. package/dist/cc-orchestrator/index.d.ts +8 -0
  34. package/dist/cc-orchestrator/index.js +8 -0
  35. package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
  36. package/dist/cc-orchestrator/relevance-judge.js +29 -0
  37. package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
  38. package/dist/cc-orchestrator/session-discovery.js +125 -0
  39. package/dist/cc-orchestrator/session-history.d.ts +19 -0
  40. package/dist/cc-orchestrator/session-history.js +67 -0
  41. package/dist/cli/agent-server-stdio.d.ts +15 -1
  42. package/dist/cli/agent-server-stdio.js +115 -17
  43. package/dist/cli/agent-server-tcp.js +40 -26
  44. package/dist/context/compaction.d.ts +56 -0
  45. package/dist/context/compaction.js +186 -0
  46. package/dist/context/manager.js +25 -4
  47. package/dist/cost-tracker.js +5 -61
  48. package/dist/credentials/cipher.d.ts +49 -0
  49. package/dist/credentials/cipher.js +45 -0
  50. package/dist/credentials/cookie-jar.d.ts +24 -0
  51. package/dist/credentials/cookie-jar.js +40 -0
  52. package/dist/credentials/index.d.ts +7 -0
  53. package/dist/credentials/index.js +5 -0
  54. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  55. package/dist/credentials/inject-credential-tool.js +130 -0
  56. package/dist/credentials/store.d.ts +72 -0
  57. package/dist/credentials/store.js +184 -0
  58. package/dist/credentials/types.d.ts +56 -0
  59. package/dist/credentials/use-credential-tool.d.ts +29 -0
  60. package/dist/credentials/use-credential-tool.js +205 -0
  61. package/dist/credentials/use-gate.d.ts +56 -0
  62. package/dist/credentials/use-gate.js +52 -0
  63. package/dist/data/model-metadata.d.ts +77 -0
  64. package/dist/data/model-metadata.js +56 -0
  65. package/dist/data/model-metadata.json +216 -0
  66. package/dist/data/openrouter-models.d.ts +18 -7
  67. package/dist/data/openrouter-models.js +35 -8
  68. package/dist/engine/aux-key.d.ts +10 -0
  69. package/dist/engine/aux-key.js +11 -0
  70. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  71. package/dist/engine/dynamic-tool-defs.js +36 -0
  72. package/dist/engine/engine.d.ts +267 -138
  73. package/dist/engine/engine.js +957 -191
  74. package/dist/engine/friendly-error.d.ts +18 -0
  75. package/dist/engine/friendly-error.js +63 -0
  76. package/dist/engine/goal.d.ts +145 -0
  77. package/dist/engine/goal.js +144 -0
  78. package/dist/engine/image-policy.d.ts +13 -0
  79. package/dist/engine/image-policy.js +24 -0
  80. package/dist/engine/model-connections-pool.d.ts +17 -0
  81. package/dist/engine/model-connections-pool.js +66 -0
  82. package/dist/engine/model-facade.d.ts +10 -0
  83. package/dist/engine/model-facade.js +25 -0
  84. package/dist/engine/patch-orphaned-tools.js +3 -0
  85. package/dist/engine/resolve-llm-config.d.ts +16 -0
  86. package/dist/engine/resolve-llm-config.js +44 -0
  87. package/dist/engine/runtime.js +2 -1
  88. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  89. package/dist/engine/sandbox-cache-key.js +9 -0
  90. package/dist/engine/sandbox-config.d.ts +31 -0
  91. package/dist/engine/sandbox-config.js +38 -0
  92. package/dist/engine/session-usage.d.ts +19 -0
  93. package/dist/engine/session-usage.js +25 -0
  94. package/dist/engine/steer-queue.d.ts +32 -0
  95. package/dist/engine/steer-queue.js +26 -0
  96. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  97. package/dist/engine/streaming-tool-queue.js +50 -10
  98. package/dist/engine/turn-loop.d.ts +67 -3
  99. package/dist/engine/turn-loop.js +292 -41
  100. package/dist/engine/types.d.ts +175 -0
  101. package/dist/engine/types.js +13 -0
  102. package/dist/external-agents/config.d.ts +2 -0
  103. package/dist/external-agents/config.js +15 -0
  104. package/dist/external-agents/types.d.ts +31 -0
  105. package/dist/external-agents/types.js +1 -0
  106. package/dist/git/utils.js +11 -6
  107. package/dist/git/worktree.d.ts +48 -0
  108. package/dist/git/worktree.js +86 -10
  109. package/dist/hooks/goal-stop-hook.d.ts +28 -0
  110. package/dist/hooks/goal-stop-hook.js +186 -9
  111. package/dist/hooks/registry.d.ts +8 -0
  112. package/dist/hooks/registry.js +19 -0
  113. package/dist/hooks/shell-runner.js +10 -21
  114. package/dist/index.d.ts +49 -6
  115. package/dist/index.js +60 -4
  116. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  117. package/dist/llm/capabilities/param-specs.js +62 -0
  118. package/dist/llm/capabilities/rules.js +4 -0
  119. package/dist/llm/capabilities/types.d.ts +10 -0
  120. package/dist/llm/client-base.d.ts +28 -1
  121. package/dist/llm/client-base.js +119 -13
  122. package/dist/llm/model-cache.js +4 -2
  123. package/dist/llm/model-pool.d.ts +14 -0
  124. package/dist/llm/model-pool.js +13 -0
  125. package/dist/llm/provider-auth.d.ts +41 -0
  126. package/dist/llm/provider-auth.js +76 -0
  127. package/dist/llm/provider-catalog.d.ts +4 -0
  128. package/dist/llm/providers/anthropic.js +64 -14
  129. package/dist/llm/providers/openai.d.ts +36 -0
  130. package/dist/llm/providers/openai.js +257 -51
  131. package/dist/llm/reasoning-setting.d.ts +3 -3
  132. package/dist/llm/reasoning-setting.js +9 -1
  133. package/dist/llm/stream-watchdog.js +5 -1
  134. package/dist/llm/token-counter.js +9 -2
  135. package/dist/llm/types.d.ts +4 -0
  136. package/dist/logging/sanitize-messages.js +22 -0
  137. package/dist/lsp/manager.d.ts +1 -1
  138. package/dist/lsp/manager.js +40 -10
  139. package/dist/model-catalog/builtin.d.ts +12 -0
  140. package/dist/model-catalog/builtin.js +407 -0
  141. package/dist/model-catalog/gen-connections.d.ts +20 -0
  142. package/dist/model-catalog/gen-connections.js +28 -0
  143. package/dist/model-catalog/index.d.ts +41 -0
  144. package/dist/model-catalog/index.js +90 -0
  145. package/dist/model-catalog/params.d.ts +20 -0
  146. package/dist/model-catalog/params.js +45 -0
  147. package/dist/model-catalog/resolve.d.ts +48 -0
  148. package/dist/model-catalog/resolve.js +33 -0
  149. package/dist/model-catalog/save-entry.d.ts +32 -0
  150. package/dist/model-catalog/save-entry.js +104 -0
  151. package/dist/model-catalog/types.d.ts +561 -0
  152. package/dist/model-catalog/types.js +93 -0
  153. package/dist/model-catalog/upsert.d.ts +9 -0
  154. package/dist/model-catalog/upsert.js +8 -0
  155. package/dist/onboarding.d.ts +12 -82
  156. package/dist/onboarding.js +61 -326
  157. package/dist/plugins/gitOps.d.ts +19 -0
  158. package/dist/plugins/gitOps.js +73 -4
  159. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  160. package/dist/plugins/installer/checkUpdate.js +32 -0
  161. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  162. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  163. package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
  164. package/dist/plugins/installer/codex/convertMcp.js +45 -5
  165. package/dist/plugins/installer/install.js +25 -1
  166. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  167. package/dist/plugins/installer/installFromArchive.js +134 -0
  168. package/dist/plugins/installer/installFromSource.js +8 -2
  169. package/dist/plugins/installer/loadPluginAgents.js +6 -2
  170. package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
  171. package/dist/plugins/installer/loadPluginMcp.js +35 -2
  172. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  173. package/dist/plugins/installer/pruneDisabled.js +73 -0
  174. package/dist/plugins/installer/types.d.ts +5 -2
  175. package/dist/plugins/installer/types.js +1 -0
  176. package/dist/plugins/installer/uninstall.js +4 -0
  177. package/dist/plugins/installer/unzip.d.ts +14 -0
  178. package/dist/plugins/installer/unzip.js +82 -0
  179. package/dist/plugins/installer/update.d.ts +14 -0
  180. package/dist/plugins/installer/update.js +53 -21
  181. package/dist/plugins/loadPluginHooks.d.ts +47 -1
  182. package/dist/plugins/loadPluginHooks.js +73 -1
  183. package/dist/plugins/marketplaceManager.d.ts +7 -0
  184. package/dist/plugins/marketplaceManager.js +20 -0
  185. package/dist/plugins/pluginCommandHook.js +4 -18
  186. package/dist/plugins/pluginContent.d.ts +30 -0
  187. package/dist/plugins/pluginContent.js +83 -0
  188. package/dist/plugins/pluginInstaller.d.ts +13 -0
  189. package/dist/plugins/pluginInstaller.js +42 -8
  190. package/dist/plugins/schemas.js +1 -0
  191. package/dist/plugins/types.d.ts +6 -0
  192. package/dist/preset/index.d.ts +7 -1
  193. package/dist/preset/index.js +96 -6
  194. package/dist/product/types.d.ts +1 -1
  195. package/dist/prompt/composer.d.ts +27 -0
  196. package/dist/prompt/composer.js +67 -21
  197. package/dist/prompt/instruction-scanner.js +5 -3
  198. package/dist/prompt/section-loader.js +1 -0
  199. package/dist/prompt/sections/base.md +1 -0
  200. package/dist/prompt/sections/browser.md +10 -0
  201. package/dist/prompt/sections/coding.md +4 -0
  202. package/dist/protocol/chat-session-manager.d.ts +8 -2
  203. package/dist/protocol/chat-session-manager.js +36 -0
  204. package/dist/protocol/chat-session.d.ts +65 -0
  205. package/dist/protocol/chat-session.js +94 -2
  206. package/dist/protocol/client.d.ts +27 -0
  207. package/dist/protocol/client.js +38 -0
  208. package/dist/protocol/server.d.ts +112 -0
  209. package/dist/protocol/server.js +586 -16
  210. package/dist/protocol/transport.js +3 -2
  211. package/dist/protocol/types.d.ts +46 -0
  212. package/dist/protocol/types.js +16 -0
  213. package/dist/quota/credentials.d.ts +3 -0
  214. package/dist/quota/credentials.js +80 -0
  215. package/dist/quota/index.d.ts +36 -0
  216. package/dist/quota/index.js +155 -0
  217. package/dist/quota/types.d.ts +48 -0
  218. package/dist/quota/types.js +13 -0
  219. package/dist/review/review-prompt.d.ts +28 -0
  220. package/dist/review/review-prompt.js +81 -0
  221. package/dist/run/FileRunStore.js +8 -3
  222. package/dist/run/RunApprovalBackend.js +25 -5
  223. package/dist/run/RunManager.d.ts +12 -0
  224. package/dist/run/RunManager.js +35 -0
  225. package/dist/run/factory.d.ts +1 -1
  226. package/dist/runtime/background-shell.d.ts +139 -0
  227. package/dist/runtime/background-shell.js +495 -0
  228. package/dist/runtime/output-clean.d.ts +24 -0
  229. package/dist/runtime/output-clean.js +41 -0
  230. package/dist/runtime/ring-file.d.ts +64 -0
  231. package/dist/runtime/ring-file.js +174 -0
  232. package/dist/runtime/safe-spawn.js +15 -34
  233. package/dist/runtime/spawn-common.d.ts +148 -0
  234. package/dist/runtime/spawn-common.js +303 -0
  235. package/dist/runtime/truncate-output.d.ts +22 -0
  236. package/dist/runtime/truncate-output.js +49 -0
  237. package/dist/runtime/utf8-cut.d.ts +11 -0
  238. package/dist/runtime/utf8-cut.js +23 -0
  239. package/dist/services/auto-dream.d.ts +4 -0
  240. package/dist/services/auto-dream.js +26 -26
  241. package/dist/services/diagnostics.d.ts +1 -2
  242. package/dist/services/diagnostics.js +12 -7
  243. package/dist/services/extract-memories.d.ts +14 -1
  244. package/dist/services/extract-memories.js +45 -6
  245. package/dist/services/memory-orchestrator.d.ts +21 -0
  246. package/dist/services/memory-orchestrator.js +125 -50
  247. package/dist/services/session-memory.js +24 -12
  248. package/dist/session/file-history.d.ts +124 -1
  249. package/dist/session/file-history.js +222 -6
  250. package/dist/session/memory.d.ts +116 -2
  251. package/dist/session/memory.js +250 -28
  252. package/dist/session/session-manager.d.ts +40 -0
  253. package/dist/session/session-manager.js +113 -3
  254. package/dist/session/simple-diff.d.ts +23 -0
  255. package/dist/session/simple-diff.js +84 -0
  256. package/dist/session/transcript.d.ts +25 -1
  257. package/dist/session/transcript.js +35 -2
  258. package/dist/session/undo-target.d.ts +67 -0
  259. package/dist/session/undo-target.js +144 -0
  260. package/dist/settings/disk-defaults.d.ts +9 -2
  261. package/dist/settings/disk-defaults.js +11 -2
  262. package/dist/settings/feature-flags.d.ts +64 -0
  263. package/dist/settings/feature-flags.js +61 -0
  264. package/dist/settings/manager.d.ts +68 -1
  265. package/dist/settings/manager.js +266 -29
  266. package/dist/settings/migrate-config.d.ts +45 -0
  267. package/dist/settings/migrate-config.js +125 -0
  268. package/dist/settings/schema-export.d.ts +25 -0
  269. package/dist/settings/schema-export.js +38 -0
  270. package/dist/settings/schema.d.ts +1186 -771
  271. package/dist/settings/schema.js +268 -97
  272. package/dist/skills/scanner.d.ts +9 -0
  273. package/dist/skills/scanner.js +30 -2
  274. package/dist/stt/resolve-transcribe.d.ts +31 -0
  275. package/dist/stt/resolve-transcribe.js +108 -0
  276. package/dist/stt/transcribe.d.ts +51 -0
  277. package/dist/stt/transcribe.js +65 -0
  278. package/dist/tool-system/browser-bridge.d.ts +226 -0
  279. package/dist/tool-system/browser-bridge.js +163 -0
  280. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  281. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  282. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  283. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  284. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  285. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  286. package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
  287. package/dist/tool-system/builtin/agent-registry.js +8 -0
  288. package/dist/tool-system/builtin/agent.d.ts +21 -1
  289. package/dist/tool-system/builtin/agent.js +489 -42
  290. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  291. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  292. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  293. package/dist/tool-system/builtin/apply-patch/index.js +0 -15
  294. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  295. package/dist/tool-system/builtin/background-jobs.js +124 -0
  296. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  297. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  298. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  299. package/dist/tool-system/builtin/background-work.js +86 -0
  300. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  301. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  302. package/dist/tool-system/builtin/bash.d.ts +5 -2
  303. package/dist/tool-system/builtin/bash.js +98 -62
  304. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  305. package/dist/tool-system/builtin/browser-tools.js +312 -0
  306. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  307. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  308. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  309. package/dist/tool-system/builtin/check-quota.js +34 -0
  310. package/dist/tool-system/builtin/config.js +7 -0
  311. package/dist/tool-system/builtin/cron.d.ts +7 -0
  312. package/dist/tool-system/builtin/cron.js +55 -3
  313. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  314. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  315. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  316. package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
  317. package/dist/tool-system/builtin/edit.js +20 -16
  318. package/dist/tool-system/builtin/eol.d.ts +29 -0
  319. package/dist/tool-system/builtin/eol.js +37 -0
  320. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  321. package/dist/tool-system/builtin/file-cache.js +8 -0
  322. package/dist/tool-system/builtin/generate-image.d.ts +35 -0
  323. package/dist/tool-system/builtin/generate-image.js +278 -50
  324. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  325. package/dist/tool-system/builtin/generate-video.js +361 -0
  326. package/dist/tool-system/builtin/glob.js +0 -7
  327. package/dist/tool-system/builtin/grep.js +6 -8
  328. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  329. package/dist/tool-system/builtin/image-providers.js +190 -0
  330. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  331. package/dist/tool-system/builtin/image-uploader.js +74 -0
  332. package/dist/tool-system/builtin/index.d.ts +7 -1
  333. package/dist/tool-system/builtin/index.js +249 -25
  334. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  335. package/dist/tool-system/builtin/memory.js +45 -7
  336. package/dist/tool-system/builtin/notebook-edit.js +0 -7
  337. package/dist/tool-system/builtin/powershell.js +4 -1
  338. package/dist/tool-system/builtin/read.js +10 -10
  339. package/dist/tool-system/builtin/repl.js +4 -1
  340. package/dist/tool-system/builtin/skill.js +9 -0
  341. package/dist/tool-system/builtin/sleep.js +3 -2
  342. package/dist/tool-system/builtin/tool-search.js +25 -7
  343. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  344. package/dist/tool-system/builtin/video-providers.js +235 -0
  345. package/dist/tool-system/builtin/web-fetch.js +12 -2
  346. package/dist/tool-system/builtin/web-search.js +21 -7
  347. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  348. package/dist/tool-system/builtin/worktree.js +31 -4
  349. package/dist/tool-system/builtin/write.js +0 -6
  350. package/dist/tool-system/context.d.ts +154 -6
  351. package/dist/tool-system/executor.d.ts +3 -1
  352. package/dist/tool-system/executor.js +172 -88
  353. package/dist/tool-system/investigation-guard.js +1 -1
  354. package/dist/tool-system/mcp-manager.d.ts +42 -4
  355. package/dist/tool-system/mcp-manager.js +186 -20
  356. package/dist/tool-system/path-policy.d.ts +5 -0
  357. package/dist/tool-system/path-policy.js +307 -8
  358. package/dist/tool-system/permission.d.ts +36 -1
  359. package/dist/tool-system/permission.js +281 -69
  360. package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
  361. package/dist/tool-system/plan-mode-allowlist.js +24 -2
  362. package/dist/tool-system/registry.d.ts +1 -0
  363. package/dist/tool-system/registry.js +16 -2
  364. package/dist/tool-system/sandbox/index.d.ts +8 -0
  365. package/dist/tool-system/sandbox/index.js +7 -2
  366. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  367. package/dist/tool-system/validate-tool-metadata.js +63 -0
  368. package/dist/types.d.ts +217 -6
  369. package/dist/updater.js +20 -9
  370. package/dist/utils/envUtils.d.ts +0 -9
  371. package/dist/utils/envUtils.js +3 -28
  372. package/dist/utils/exec.d.ts +40 -0
  373. package/dist/utils/exec.js +144 -0
  374. package/dist/utils/json.d.ts +12 -0
  375. package/dist/utils/json.js +92 -0
  376. package/dist/utils/theme.d.ts +1 -1
  377. package/dist/utils/theme.js +1 -1
  378. package/dist/utils/toolDisplay.js +0 -1
  379. package/package.json +13 -7
  380. package/dist/agent/coordinator.d.ts +0 -49
  381. package/dist/agent/coordinator.js +0 -77
  382. package/dist/settings/manager.test.js +0 -73
  383. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  384. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  385. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  386. package/dist/tool-system/builtin/send-message.js +0 -47
  387. /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
@@ -14,8 +14,33 @@ import { logger } from "../../logging/logger.js";
14
14
  import { countTokens } from "../token-counter.js";
15
15
  import { capabilitiesFor } from "../capabilities/index.js";
16
16
  import { clampMaxTokens } from "../clamp-max-tokens.js";
17
+ import { resolveApiKey, resolveHeaders } from "../provider-auth.js";
17
18
  import { stripVisionFromHistory } from "../strip-vision.js";
18
19
  import { STREAM_WATCHDOG_CONFIG, StreamIdleTimeoutError, } from "../stream-watchdog.js";
20
+ /**
21
+ * Extract prompt-cache counts from an OpenAI-compatible usage object.
22
+ *
23
+ * - Cache HITS live under `usage.prompt_tokens_details.cached_tokens` (NOT a
24
+ * top-level field). Both OpenAI and OpenRouter report this.
25
+ * - Cache WRITES (first-time prefix ingestion) are reported by OpenRouter as
26
+ * `prompt_tokens_details.cache_write_tokens` (verified live 2026-07-02).
27
+ * OpenAI's automatic caching has no separate write charge and omits it. We
28
+ * map it to `cacheCreationTokens` so the UI can show "writing cache" on the
29
+ * first turn, not just hits on later turns.
30
+ *
31
+ * Returns a spreadable partial so callers omit each key entirely when the API
32
+ * reports no value — keeping the field `undefined` rather than a misleading 0.
33
+ * See docs/todo/prompt-cache-optimization.md.
34
+ */
35
+ function cachedTokensOf(usage) {
36
+ const details = usage?.prompt_tokens_details;
37
+ const out = {};
38
+ if (typeof details?.cached_tokens === "number")
39
+ out.cacheReadTokens = details.cached_tokens;
40
+ if (typeof details?.cache_write_tokens === "number")
41
+ out.cacheCreationTokens = details.cache_write_tokens;
42
+ return out;
43
+ }
19
44
  /**
20
45
  * Consume an async iterable of stream chunks with an idle watchdog.
21
46
  * Returns the accumulated text — either from onChunk return values, or
@@ -28,7 +53,12 @@ import { STREAM_WATCHDOG_CONFIG, StreamIdleTimeoutError, } from "../stream-watch
28
53
  * the function rejects with StreamIdleTimeoutError.
29
54
  */
30
55
  export async function runStreamWithWatchdog(stream, opts = {}) {
31
- const watchdogActive = STREAM_WATCHDOG_CONFIG.enabled || opts.idleTimeoutMs !== undefined;
56
+ // An explicit idleTimeoutMs always activates the watchdog. Otherwise follow
57
+ // disableWatchdog (per-call override) if set, else the env default.
58
+ const watchdogActive = opts.idleTimeoutMs !== undefined ||
59
+ (opts.disableWatchdog === undefined
60
+ ? STREAM_WATCHDOG_CONFIG.enabled
61
+ : !opts.disableWatchdog);
32
62
  const idleTimeoutMs = opts.idleTimeoutMs ?? STREAM_WATCHDOG_CONFIG.idleTimeoutMs;
33
63
  let text = "";
34
64
  // Fast path: watchdog disabled AND caller did not override → no overhead.
@@ -137,9 +167,15 @@ export class OpenAIClient extends LLMClientBase {
137
167
  }
138
168
  get client() {
139
169
  if (!this._client) {
170
+ const headers = resolveHeaders(this.config.httpHeaders);
140
171
  this._client = new OpenAI({
141
- apiKey: this.config.apiKey ?? process.env.OPENAI_API_KEY,
172
+ // apiKey: explicit > authCommand stdout > OPENAI_API_KEY (TODO 7.2).
173
+ // OpenAI's SDK requires a non-empty string; fall back to a placeholder
174
+ // when a custom provider authenticates purely via httpHeaders.
175
+ apiKey: resolveApiKey(this.config, process.env.OPENAI_API_KEY) ??
176
+ (Object.keys(headers).length > 0 ? "x-headers-auth" : undefined),
142
177
  ...(this.config.baseUrl ? { baseURL: this.config.baseUrl } : {}),
178
+ ...(Object.keys(headers).length > 0 ? { defaultHeaders: headers } : {}),
143
179
  timeout: this.timeout,
144
180
  });
145
181
  }
@@ -160,8 +196,27 @@ export class OpenAIClient extends LLMClientBase {
160
196
  }
161
197
  return this._capability;
162
198
  }
199
+ /**
200
+ * True when this client routes an Anthropic-family model through OpenRouter's
201
+ * OpenAI-compatible endpoint. Anthropic caching is EXPLICIT — nothing is
202
+ * cached unless the request carries `cache_control` breakpoints (verified live
203
+ * 2026-07-02: plain requests to anthropic/claude-opus-4.7-fast via OpenRouter
204
+ * report cached_tokens 0 on every repeat; a single system-block breakpoint
205
+ * turns the whole stable prefix — tools + system — into a cache hit, ~89%
206
+ * cheaper on the follow-up). OpenAI and other OpenRouter models cache
207
+ * automatically, so they must NOT get breakpoints. The slug arrives resolved
208
+ * (e.g. "anthropic/claude-opus-4.7-fast") or as the router alias
209
+ * ("~anthropic/claude-opus-latest") — both start with an optional "~" then
210
+ * "anthropic/".
211
+ */
212
+ get isOpenRouterAnthropic() {
213
+ return this.config.providerKind === "openrouter" && /^~?anthropic\//.test(this.model);
214
+ }
163
215
  async createMessage(options) {
164
- return this.withRetry(async () => {
216
+ return this.withRetry(async (requestSignal) => {
217
+ // requestSignal = caller's cancel signal composed with a per-request
218
+ // hard deadline (withRetry). Hand it to the SDK so a wedged socket is
219
+ // torn down instead of hanging for tens of minutes.
165
220
  // Per-call reasoning wins; otherwise fall back to provider default
166
221
  // (settings.providers[].reasoning, threaded through LLMConfig).
167
222
  const reasoning = options.reasoning ?? this.config.reasoning;
@@ -177,8 +232,8 @@ export class OpenAIClient extends LLMClientBase {
177
232
  });
178
233
  try {
179
234
  const response = options.stream && options.onChunk
180
- ? await this.streamMessage(options, messages, tools, reasoning)
181
- : await this.nonStreamMessage(options, messages, tools, reasoning);
235
+ ? await this.streamMessage(options, messages, tools, reasoning, requestSignal)
236
+ : await this.nonStreamMessage(options, messages, tools, reasoning, requestSignal);
182
237
  span.end({
183
238
  stopReason: response.stopReason,
184
239
  promptTokens: response.usage?.promptTokens,
@@ -192,7 +247,7 @@ export class OpenAIClient extends LLMClientBase {
192
247
  span.fail(err);
193
248
  throw err;
194
249
  }
195
- });
250
+ }, { signal: options.signal });
196
251
  }
197
252
  /**
198
253
  * Build the request body honoring the model's capability descriptor.
@@ -216,11 +271,23 @@ export class OpenAIClient extends LLMClientBase {
216
271
  : useCompletion
217
272
  ? { max_completion_tokens: maxTokens }
218
273
  : { max_tokens: maxTokens };
219
- // Sampling params — only include if the model accepts them.
220
- const sampling = {};
274
+ // Sampling params — only include if the model accepts them. Split by
275
+ // precedence so the request body composes correctly against catalog
276
+ // extraBody (see the merge below):
277
+ // - samplingDefault: the connection's DEFAULT temperature (this.temperature).
278
+ // It's the BASE — a user's catalog `temperature` in extraBody should
279
+ // override the bare default.
280
+ // - samplingOverride: a PER-REQUEST temperature (options.temperature). It
281
+ // wins over both the default and the catalog value.
282
+ const samplingDefault = {};
283
+ const samplingOverride = {};
221
284
  if (!cap.rejectedParams.has("temperature")) {
222
- sampling.temperature =
223
- options.temperature !== undefined ? options.temperature : this.temperature;
285
+ if (options.temperature !== undefined) {
286
+ samplingOverride.temperature = options.temperature;
287
+ }
288
+ else {
289
+ samplingDefault.temperature = this.temperature;
290
+ }
224
291
  }
225
292
  // Reasoning shape — translate the user's ReasoningSetting to the wire
226
293
  // shape. Different vendors, different fields, never combine. We read the
@@ -228,6 +295,15 @@ export class OpenAIClient extends LLMClientBase {
228
295
  // when the setting says "thinking on" but carries no explicit effort
229
296
  // ({mode:"on"}).
230
297
  const reasoningBody = {};
298
+ // gpt-5.5+ 400s when `reasoning_effort` rides alongside `tools` on
299
+ // /v1/chat/completions. If the capability flags that combo AND this request
300
+ // carries tools, suppress the field up-front (same effect as the reactive
301
+ // _dropReasoningEffort sticky, but BEFORE the first failed request — so we
302
+ // never burn a 400 + 1s-backoff retry on every tool-using turn).
303
+ const suppressEffort = this._dropReasoningEffort ||
304
+ (cap.reasoning.kind === "openai-effort" &&
305
+ cap.reasoning.noEffortWithTools === true &&
306
+ !!tools?.length);
231
307
  if (reasoning && reasoning.mode !== "off") {
232
308
  switch (cap.reasoning.kind) {
233
309
  case "deepseek-thinking":
@@ -240,10 +316,11 @@ export class OpenAIClient extends LLMClientBase {
240
316
  // Mistral magistral, Groq reasoning models — `reasoning_effort`.
241
317
  // Send the user's real level; {mode:"on"} (no level) → "medium".
242
318
  //
243
- // Skip entirely once the endpoint has told us `reasoning_effort` is
244
- // incompatible with `tools` here (see _dropReasoningEffort) — sending
245
- // it again would just re-trigger the same 400.
246
- if (!this._dropReasoningEffort) {
319
+ // Skip when the endpoint has told us (reactive _dropReasoningEffort)
320
+ // OR the capability tells us up-front (noEffortWithTools) that
321
+ // `reasoning_effort` is incompatible with `tools` here sending it
322
+ // would just trigger the "use /v1/responses" 400.
323
+ if (!suppressEffort) {
247
324
  reasoningBody.reasoning_effort =
248
325
  reasoning.mode === "effort" ? reasoning.effort : "medium";
249
326
  }
@@ -269,8 +346,9 @@ export class OpenAIClient extends LLMClientBase {
269
346
  break;
270
347
  case "openai-effort":
271
348
  // The capability's `disabledEffort` (defaults "minimal"; xAI "low",
272
- // Mistral "none"). Skip if the endpoint already rejected the field.
273
- if (!this._dropReasoningEffort) {
349
+ // Mistral "none"). Skip if the endpoint already rejected the field
350
+ // OR the capability says it's incompatible with tools here.
351
+ if (!suppressEffort) {
274
352
  reasoningBody.reasoning_effort = cap.reasoning.disabledEffort ?? "minimal";
275
353
  }
276
354
  break;
@@ -281,19 +359,58 @@ export class OpenAIClient extends LLMClientBase {
281
359
  break;
282
360
  }
283
361
  }
362
+ // reasoning_summary (TODO 7.2): when the model uses the object-form
363
+ // reasoning shape (OpenRouter normalized / Responses-style), attach the
364
+ // requested summary level to that object. For the bare `reasoning_effort`
365
+ // shape there's no summary field on chat-completions, so we skip it rather
366
+ // than send an unknown top-level param.
367
+ if (this.config.reasoningSummary && reasoningBody.reasoning &&
368
+ typeof reasoningBody.reasoning === "object") {
369
+ reasoningBody.reasoning.summary =
370
+ this.config.reasoningSummary;
371
+ }
372
+ // Catalog-driven passthrough params (temperature/top_p/thinking etc, already
373
+ // wire-mapped from the connection's paramValues by applyParams). Filter each
374
+ // key by rejectedParams so we never send a field the model rejects (same
375
+ // contract as `sampling` above — e.g. temperature to gpt-5).
376
+ const extra = {};
377
+ const rejected = cap.rejectedParams;
378
+ for (const [k, v] of Object.entries(this.config.extraBody ?? {})) {
379
+ if (rejected.has(k))
380
+ continue;
381
+ extra[k] = v;
382
+ }
383
+ // Compose the param fragments with explicit precedence + deep merge:
384
+ // connection default sampling (base)
385
+ // ← static catalog extraBody
386
+ // ← per-request sampling override
387
+ // ← reasoning translation (wins)
388
+ // - A catalog `temperature` in extraBody overrides the bare connection
389
+ // default, but a PER-REQUEST temperature (options.temperature) overrides
390
+ // both — a plain `...sampling, ...extra` got this backwards. (review #4)
391
+ // - extra and reasoningBody can both carry nested objects under the SAME
392
+ // top-level key (a catalog param wired to `thinking.type`/`reasoning.effort`
393
+ // vs the reasoning translation's `thinking`/`reasoning`). A shallow spread
394
+ // would wholesale-replace one nested object; deepMergeInto merges them. (review #5)
395
+ const paramBody = {};
396
+ deepMergeInto(paramBody, samplingDefault);
397
+ deepMergeInto(paramBody, extra);
398
+ deepMergeInto(paramBody, samplingOverride);
399
+ deepMergeInto(paramBody, reasoningBody);
284
400
  return {
285
401
  model: this.model,
286
402
  messages,
287
403
  ...tokenLimit,
288
- ...sampling,
289
- ...reasoningBody,
404
+ ...paramBody,
405
+ // service_tier (TODO 7.2): passed through verbatim when configured.
406
+ ...(this.config.serviceTier ? { service_tier: this.config.serviceTier } : {}),
290
407
  ...(tools ? { tools } : {}),
291
408
  ...(stream ? { stream: true, stream_options: { include_usage: true } } : {}),
292
409
  };
293
410
  }
294
- async nonStreamMessage(options, messages, tools, reasoning) {
411
+ async nonStreamMessage(options, messages, tools, reasoning, requestSignal) {
295
412
  try {
296
- const response = await this.client.chat.completions.create(this.buildRequestBody(options, messages, tools, reasoning, false), { signal: options.signal });
413
+ const response = await this.client.chat.completions.create(this.buildRequestBody(options, messages, tools, reasoning, false), { signal: requestSignal ?? options.signal });
297
414
  const choice = response.choices[0];
298
415
  if (!choice)
299
416
  throw new LLMError("No response from OpenAI", "openai");
@@ -301,6 +418,9 @@ export class OpenAIClient extends LLMClientBase {
301
418
  promptTokens: response.usage?.prompt_tokens ?? 0,
302
419
  completionTokens: response.usage?.completion_tokens ?? 0,
303
420
  totalTokens: response.usage?.total_tokens ?? 0,
421
+ // OpenAI caching is automatic; hits land here, NOT in a top-level
422
+ // cacheReadTokens field. Reading the wrong field made hit-rate invisible.
423
+ ...cachedTokensOf(response.usage),
304
424
  };
305
425
  this.recordUsage(usage, options);
306
426
  return this.processChoice(choice, usage);
@@ -310,9 +430,10 @@ export class OpenAIClient extends LLMClientBase {
310
430
  throw err;
311
431
  }
312
432
  }
313
- async streamMessage(options, messages, tools, reasoning) {
433
+ async streamMessage(options, messages, tools, reasoning, requestSignal) {
434
+ const sdkSignal = requestSignal ?? options.signal;
314
435
  try {
315
- const stream = await this.client.chat.completions.create(this.buildRequestBody(options, messages, tools, reasoning, true), { signal: options.signal });
436
+ const stream = await this.client.chat.completions.create(this.buildRequestBody(options, messages, tools, reasoning, true), { signal: sdkSignal });
316
437
  let text = "";
317
438
  let reasoningContent = "";
318
439
  const toolCallsMap = new Map();
@@ -368,11 +489,18 @@ export class OpenAIClient extends LLMClientBase {
368
489
  for (const tc of delta.tool_calls) {
369
490
  const idx = tc.index;
370
491
  if (!toolCallsMap.has(idx)) {
371
- toolCallsMap.set(idx, { id: tc.id ?? "", name: tc.function?.name ?? "", args: "" });
372
- options.onChunk?.({
373
- type: "tool_use_start",
374
- toolCall: { id: tc.id, toolName: tc.function?.name },
375
- });
492
+ const id = tc.id ?? "";
493
+ const name = tc.function?.name ?? "";
494
+ toolCallsMap.set(idx, { id, name, args: "" });
495
+ // Only announce once we actually have an id+name; some providers
496
+ // stream them across deltas. Emitting undefined here violates the
497
+ // ToolCall contract and breaks downstream consumers.
498
+ if (id && name) {
499
+ options.onChunk?.({
500
+ type: "tool_use_start",
501
+ toolCall: { id, toolName: name },
502
+ });
503
+ }
376
504
  }
377
505
  const existing = toolCallsMap.get(idx);
378
506
  if (tc.id)
@@ -405,26 +533,42 @@ export class OpenAIClient extends LLMClientBase {
405
533
  return delta.content ?? "";
406
534
  };
407
535
  await runStreamWithWatchdog(stream, {
408
- idleTimeoutMs: STREAM_WATCHDOG_CONFIG.enabled
409
- ? STREAM_WATCHDOG_CONFIG.idleTimeoutMs
410
- : undefined,
536
+ // Idle watchdog is now ON by default (see STREAM_WATCHDOG_CONFIG) — it
537
+ // catches a stream that connects then stalls mid-generation; the
538
+ // per-request deadline (sdkSignal) catches connect/first-byte hangs.
539
+ idleTimeoutMs: STREAM_WATCHDOG_CONFIG.idleTimeoutMs,
411
540
  requestId,
412
541
  onChunk: handleChunk,
413
- signal: options.signal,
542
+ signal: sdkSignal,
414
543
  });
415
544
  const toolCalls = [];
416
545
  for (const [, tc] of toolCallsMap) {
546
+ // Drop incomplete tool calls: an empty id or name (the fallbacks set
547
+ // when a delta never delivered them) would become a malformed call
548
+ // that breaks transcript keying and tool dispatch downstream.
549
+ if (!tc.id || !tc.name) {
550
+ logger.warn("openai.incomplete_tool_call_dropped", {
551
+ id: tc.id || "(empty)",
552
+ name: tc.name || "(empty)",
553
+ });
554
+ continue;
555
+ }
417
556
  let args = {};
418
557
  try {
419
558
  args = JSON.parse(tc.args || "{}");
420
559
  }
421
- catch { }
560
+ catch {
561
+ /* intentional: model emitted malformed tool-call JSON — fall back to
562
+ empty args rather than crashing the stream; the tool layer reports
563
+ the resulting validation error back to the model. */
564
+ }
422
565
  toolCalls.push({ id: tc.id, toolName: tc.name, args });
423
566
  }
424
567
  const usage = {
425
568
  promptTokens: streamUsage?.prompt_tokens ?? 0,
426
569
  completionTokens: streamUsage?.completion_tokens ?? 0,
427
570
  totalTokens: streamUsage?.total_tokens ?? 0,
571
+ ...cachedTokensOf(streamUsage),
428
572
  };
429
573
  this.recordUsage(usage, options);
430
574
  return {
@@ -449,7 +593,11 @@ export class OpenAIClient extends LLMClientBase {
449
593
  try {
450
594
  args = JSON.parse(tc.function.arguments || "{}");
451
595
  }
452
- catch { }
596
+ catch {
597
+ /* intentional: model emitted malformed tool-call JSON — fall back to
598
+ empty args rather than crashing; the tool layer reports the
599
+ resulting validation error back to the model. */
600
+ }
453
601
  toolCalls.push({
454
602
  id: tc.id,
455
603
  toolName: tc.function.name,
@@ -674,20 +822,56 @@ export class OpenAIClient extends LLMClientBase {
674
822
  }
675
823
  }
676
824
  }
825
+ if (this.isOpenRouterAnthropic) {
826
+ this.applyAnthropicCacheBreakpoints(result);
827
+ }
677
828
  return result;
678
829
  }
830
+ /**
831
+ * In-place: add prompt-cache breakpoints for Anthropic-over-OpenRouter.
832
+ * Mirrors the native anthropic provider (≤4 breakpoints):
833
+ * 1. System block — the stable prefix. Anthropic sees tools BEFORE the
834
+ * system prompt, so one marker on the system block caches tools too
835
+ * (verified live: system-only marker cached 3511/3952 prompt tokens
836
+ * including tool defs).
837
+ * 2. Last message — one rolling breakpoint so the growing conversation
838
+ * history becomes a cached prefix. Not scrolled: as history grows the
839
+ * "last message" naturally advances and its tail is the next write.
840
+ * A string `content` is lifted to a single-element `[{type:"text",...}]`
841
+ * array so it can carry `cache_control`; OpenRouter accepts this OpenAI
842
+ * multimodal wire form for text.
843
+ */
844
+ applyAnthropicCacheBreakpoints(messages) {
845
+ const mark = (m) => {
846
+ if (!m)
847
+ return;
848
+ // Lift a plain-string content to a text-block array so it can carry the
849
+ // marker. Non-text content (tool messages, image arrays) already uses an
850
+ // array of parts — mark the last part instead.
851
+ if (typeof m.content === "string") {
852
+ m.content = [
853
+ { type: "text", text: m.content, cache_control: { type: "ephemeral" } },
854
+ ];
855
+ return;
856
+ }
857
+ if (Array.isArray(m.content) && m.content.length > 0) {
858
+ // cache_control is an Anthropic-via-OpenRouter extension field, not in
859
+ // the OpenAI content-part union — attach through `unknown`.
860
+ const last = m.content[m.content.length - 1];
861
+ last.cache_control = { type: "ephemeral" };
862
+ }
863
+ };
864
+ // 1. System block (always index 0 — buildMessages seeds it first).
865
+ const sys = messages[0];
866
+ if (sys && sys.role === "system")
867
+ mark(sys);
868
+ // 2. Rolling history breakpoint on the very last message. Skip if it IS the
869
+ // system message (no conversation yet) — one breakpoint already covers it.
870
+ const last = messages[messages.length - 1];
871
+ if (last && last !== sys)
872
+ mark(last);
873
+ }
679
874
  convertTools(tools) {
680
- // DEBUG: OpenAI rejects tool names that don't match ^[a-zA-Z0-9_-]+$.
681
- // Dump the full list with index + source so we can pin which tool
682
- // (e.g. tools[33]) carries the illegal name. Remove once diagnosed.
683
- const NAME_RE = /^[a-zA-Z0-9_-]+$/;
684
- logger.info("openai.convertTools.names", {
685
- count: tools.length,
686
- names: tools.map((t, i) => `[${i}] ${t.name}${NAME_RE.test(t.name) ? "" : " <-- ILLEGAL"} (src=${t.source ?? "?"})`),
687
- illegal: tools
688
- .map((t, i) => ({ i, name: t.name, source: t.source }))
689
- .filter((x) => !NAME_RE.test(x.name)),
690
- });
691
875
  return tools.map((t) => ({
692
876
  type: "function",
693
877
  function: {
@@ -773,6 +957,27 @@ export class OpenAIClient extends LLMClientBase {
773
957
  throw err;
774
958
  }
775
959
  }
960
+ /**
961
+ * Merge `src` into `dst` in place, recursing into plain-object values so a
962
+ * nested field (e.g. `thinking.type`) from one source doesn't wholesale-replace
963
+ * the nested object from another. Arrays and non-objects overwrite. `src` wins
964
+ * on leaf collisions. Used to compose the request body's param fragments
965
+ * (static extraBody base ← per-request sampling ← reasoning translation) so
966
+ * shared nested keys like `thinking`/`reasoning` merge instead of clobber.
967
+ */
968
+ function deepMergeInto(dst, src) {
969
+ for (const [k, v] of Object.entries(src)) {
970
+ const cur = dst[k];
971
+ if (v && typeof v === "object" && !Array.isArray(v) &&
972
+ cur && typeof cur === "object" && !Array.isArray(cur)) {
973
+ deepMergeInto(cur, v);
974
+ }
975
+ else {
976
+ dst[k] = v;
977
+ }
978
+ }
979
+ return dst;
980
+ }
776
981
  /**
777
982
  * Pull a non-empty reasoning payload out of a provider message.
778
983
  *
@@ -785,14 +990,15 @@ function extractReasoningContent(msg) {
785
990
  return typeof candidate === "string" && candidate.length > 0 ? candidate : undefined;
786
991
  }
787
992
  /**
788
- * Map our internal image-detail enum to the OpenAI wire enum.
993
+ * Map our internal image-clarity enum to the OpenAI wire enum.
994
+ *
995
+ * OpenAI accepts only `low` / `high` / `auto`. Our provider-agnostic
996
+ * levels are low / standard / high — the real token saving happens in
997
+ * the renderer downscale (long-edge cap) before send, so on the wire
998
+ * we only need the coarse low/high distinction: low→low, while both
999
+ * standard and high collapse to high (OpenAI's full-tile rendering).
789
1000
  *
790
- * OpenAI accepts only `low` / `high` / `auto`. We carry an extra
791
- * `original` value through settings/config to match the Codex
792
- * concept (preserve client-side dimensions, most expensive), but on
793
- * the wire it has to collapse to `high` — OpenAI's server scales
794
- * 2048+ images down regardless, so this is the closest faithful
795
- * mapping.
1001
+ * Legacy "original" (from older settings) is treated as high.
796
1002
  *
797
1003
  * Returns undefined when the caller didn't set a detail at all, so
798
1004
  * the OpenAI client uses its own default ("auto", equivalent to
@@ -27,13 +27,13 @@ export declare const ReasoningSettingSchema: z.ZodDiscriminatedUnion<"mode", [z.
27
27
  mode: "on";
28
28
  }>, z.ZodObject<{
29
29
  mode: z.ZodLiteral<"effort">;
30
- effort: z.ZodEnum<["minimal", "low", "medium", "high", "xhigh"]>;
30
+ effort: z.ZodString;
31
31
  }, "strip", z.ZodTypeAny, {
32
32
  mode: "effort";
33
- effort: "minimal" | "low" | "medium" | "high" | "xhigh";
33
+ effort: string;
34
34
  }, {
35
35
  mode: "effort";
36
- effort: "minimal" | "low" | "medium" | "high" | "xhigh";
36
+ effort: string;
37
37
  }>, z.ZodObject<{
38
38
  mode: z.ZodLiteral<"budget">;
39
39
  budgetTokens: z.ZodNumber;
@@ -11,11 +11,19 @@
11
11
  * lingering caller/config still works (mapped to on/off).
12
12
  */
13
13
  import { z } from "zod";
14
+ // Recommended effort levels — used to render UI dropdowns and as capability
15
+ // hints. NOT a hard schema constraint: effort is a free-form, catalog-driven
16
+ // param (a model's real ladder is declared by its catalog ParamSpec, and models
17
+ // gain/rename levels over time — e.g. gpt-5.5 added "xhigh", some models accept
18
+ // "max"). The settings schema validates the *shape* (mode/field names), not the
19
+ // *value*; pinning effort to a closed enum here made one unknown level
20
+ // (a connection's paramValues.reasoning flowing through the legacy models[]
21
+ // bridge) throw in validateSettings and take the whole app down on boot.
14
22
  export const REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
15
23
  export const ReasoningSettingSchema = z.discriminatedUnion("mode", [
16
24
  z.object({ mode: z.literal("off") }),
17
25
  z.object({ mode: z.literal("on") }),
18
- z.object({ mode: z.literal("effort"), effort: z.enum(REASONING_EFFORTS) }),
26
+ z.object({ mode: z.literal("effort"), effort: z.string().min(1) }),
19
27
  z.object({ mode: z.literal("budget"), budgetTokens: z.number().int().positive() }),
20
28
  ]);
21
29
  /** Coerce legacy "enabled"/"disabled" or an object into a ReasoningSetting. */
@@ -64,7 +64,11 @@ export function createStreamWatchdog(opts) {
64
64
  }
65
65
  /** Environment-driven defaults. Read once at import time is fine — these never change inside a process. */
66
66
  export const STREAM_WATCHDOG_CONFIG = {
67
- enabled: process.env.CODESHELL_ENABLE_STREAM_WATCHDOG === "1",
67
+ // ON by default — a streamed response that connects then stalls mid-flight
68
+ // would otherwise hang until the SDK's (unreliable-for-half-dead-sockets)
69
+ // timeout, which we observed take 15–33 min in practice. Opt OUT with
70
+ // CODESHELL_ENABLE_STREAM_WATCHDOG=0 (rollback knob).
71
+ enabled: process.env.CODESHELL_ENABLE_STREAM_WATCHDOG !== "0",
68
72
  idleTimeoutMs: parseInt(process.env.CODESHELL_STREAM_IDLE_TIMEOUT_MS || "", 10) || 90_000,
69
73
  retries: parseInt(process.env.CODESHELL_STREAM_WATCHDOG_RETRIES || "", 10) || 2,
70
74
  };
@@ -18,9 +18,16 @@ async function getEncoder() {
18
18
  }
19
19
  let encoderSync = null;
20
20
  // Kick off the import so synchronous callers can use it on the next tick.
21
- // First call still falls back to a length estimate.
22
- void getEncoder().then((fn) => {
21
+ // First call still falls back to a length estimate. The .catch keeps a failed
22
+ // import (corrupt node_modules / packaging error) from becoming an unhandled
23
+ // rejection — the chars/4 fallback below IS the intended degradation, so a
24
+ // load failure should stay silent, not surface as a process-level warning/crash.
25
+ void getEncoder()
26
+ .then((fn) => {
23
27
  encoderSync = fn;
28
+ })
29
+ .catch(() => {
30
+ /* encoder unavailable — count() falls back to the length estimate */
24
31
  });
25
32
  /**
26
33
  * Count tokens in `text`. Synchronous. If the encoder isn't loaded yet,
@@ -32,5 +32,9 @@ export interface LLMUsageTracker {
32
32
  totalPromptTokens: number;
33
33
  totalCompletionTokens: number;
34
34
  totalTokens: number;
35
+ /** Sum of cache-read tokens across responses (0 when no provider reported any). */
36
+ totalCacheReadTokens: number;
37
+ /** Sum of cache-creation tokens across responses. */
38
+ totalCacheCreationTokens: number;
35
39
  requestCount: number;
36
40
  }
@@ -139,6 +139,23 @@ export function sanitizeMessages(messages) {
139
139
  // These walkers redact secrets *in place on a deep clone* so the caller
140
140
  // can still log "useful shape, scrubbed values".
141
141
  const SECRET_KEY_RE = /(^|[._-])(api[_-]?key|authorization|x[_-]api[_-]key|bearer[_-]?token|access[_-]?token|refresh[_-]?token|session[_-]?token|token|secret|password|client[_-]?secret|cookie)($|[._-])/i;
142
+ // Header containers whose VALUES are all header values — any of them can carry
143
+ // a bespoke auth token under a non-secret-looking key name (e.g.
144
+ // `x-custom-auth`), which SECRET_KEY_RE alone would miss. Treat the whole
145
+ // container as sensitive: every non-empty value inside is redacted.
146
+ const HEADERS_CONTAINER_RE = /^(httpHeaders|headers|defaultHeaders|envHeaders)$/;
147
+ /** Redact all non-empty string/scalar values of a headers container object. */
148
+ function redactHeaderValues(headers) {
149
+ const out = {};
150
+ for (const [hName, hVal] of Object.entries(headers)) {
151
+ // Preserve present-vs-absent for empty/null, redact everything else.
152
+ if (hVal === null || hVal === undefined || hVal === "")
153
+ out[hName] = hVal;
154
+ else
155
+ out[hName] = REDACTED;
156
+ }
157
+ return out;
158
+ }
142
159
  const BEARER_RE = /\bBearer\s+[A-Za-z0-9._\-+/=~]{8,}/g;
143
160
  // URL query parameters that look like credentials. Conservative — only
144
161
  // trigger on a small named set so a normal `?id=…&q=…` URL passes through.
@@ -211,6 +228,11 @@ export function redactSecrets(value, depth = 0) {
211
228
  else
212
229
  out[k] = REDACTED;
213
230
  }
231
+ else if (HEADERS_CONTAINER_RE.test(k) && v && typeof v === "object" && !Array.isArray(v)) {
232
+ // Blanket-redact header values regardless of the inner header name, so a
233
+ // custom `x-custom-auth` doesn't leak in cleartext.
234
+ out[k] = redactHeaderValues(v);
235
+ }
214
236
  else {
215
237
  out[k] = redactSecrets(v, depth + 1);
216
238
  }
@@ -33,8 +33,8 @@ export declare class LSPServerManager {
33
33
  * Shutdown all servers.
34
34
  */
35
35
  shutdownAll(): Promise<void>;
36
- private isCommandAvailable;
37
36
  }
37
+ export declare function isCommandAvailable(command: string, env?: NodeJS.ProcessEnv): boolean;
38
38
  export declare function initializeLSPManager(cwd: string): LSPServerManager;
39
39
  export declare function getLSPManager(): LSPServerManager | undefined;
40
40
  export {};