@armadra/agent 0.3.0 → 0.5.0

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 (527) hide show
  1. package/CHANGELOG.md +257 -0
  2. package/README.md +263 -95
  3. package/THIRD_PARTY_NOTICES.md +34 -0
  4. package/dist/acp.d.ts +18 -0
  5. package/dist/acp.js +19 -0
  6. package/dist/agent/limits.d.ts +38 -0
  7. package/dist/agent/limits.js +127 -0
  8. package/dist/agent/loop-guard.d.ts +38 -0
  9. package/dist/agent/loop-guard.js +95 -0
  10. package/dist/agent/loop.d.ts +4 -0
  11. package/dist/agent/loop.js +7 -0
  12. package/dist/agent/prompt-rules.d.ts +12 -0
  13. package/dist/agent/prompt-rules.js +18 -0
  14. package/dist/agent/reminders.d.ts +59 -0
  15. package/dist/agent/reminders.js +327 -0
  16. package/dist/agent/retry.d.ts +1 -1
  17. package/dist/agent/retry.js +2 -1
  18. package/dist/agent/session-cache.d.ts +5 -0
  19. package/dist/agent/session-cache.js +18 -2
  20. package/dist/agent/session-classifier.d.ts +18 -0
  21. package/dist/agent/session-classifier.js +105 -0
  22. package/dist/agent/session-compaction.d.ts +35 -6
  23. package/dist/agent/session-compaction.js +157 -31
  24. package/dist/agent/session-core.d.ts +40 -1
  25. package/dist/agent/session-extensions.d.ts +61 -0
  26. package/dist/agent/session-extensions.js +129 -0
  27. package/dist/agent/session-images.d.ts +23 -0
  28. package/dist/agent/session-images.js +97 -0
  29. package/dist/agent/session-plan.d.ts +21 -0
  30. package/dist/agent/session-plan.js +524 -0
  31. package/dist/agent/session-rewind.d.ts +81 -0
  32. package/dist/agent/session-rewind.js +354 -0
  33. package/dist/agent/session-run.d.ts +28 -1
  34. package/dist/agent/session-run.js +157 -6
  35. package/dist/agent/session-settings.d.ts +49 -0
  36. package/dist/agent/session-settings.js +95 -0
  37. package/dist/agent/session-subagent.d.ts +36 -24
  38. package/dist/agent/session-subagent.js +259 -129
  39. package/dist/agent/session-sync.d.ts +10 -3
  40. package/dist/agent/session-sync.js +37 -8
  41. package/dist/agent/session-telemetry.d.ts +39 -0
  42. package/dist/agent/session-telemetry.js +231 -0
  43. package/dist/agent/session-tools.js +63 -3
  44. package/dist/agent/session.d.ts +33 -29
  45. package/dist/agent/session.js +91 -126
  46. package/dist/agent/subagent-registry.d.ts +91 -0
  47. package/dist/agent/subagent-registry.js +494 -0
  48. package/dist/agent/system-prompt.d.ts +6 -3
  49. package/dist/agent/system-prompt.js +7 -2
  50. package/dist/agent/tool-runner.d.ts +8 -1
  51. package/dist/agent/tool-runner.js +72 -6
  52. package/dist/agent/types-w5.d.ts +192 -0
  53. package/dist/agent/types-w5.js +10 -0
  54. package/dist/agent/types.d.ts +55 -4
  55. package/dist/agent/types.js +2 -0
  56. package/dist/agent/worktree.d.ts +36 -0
  57. package/dist/agent/worktree.js +86 -0
  58. package/dist/agents/builtin.d.ts +14 -0
  59. package/dist/agents/builtin.js +39 -0
  60. package/dist/agents/catalog.d.ts +43 -0
  61. package/dist/agents/catalog.js +82 -0
  62. package/dist/agents/discover.d.ts +35 -0
  63. package/dist/agents/discover.js +83 -0
  64. package/dist/agents/external.d.ts +82 -0
  65. package/dist/agents/external.js +326 -0
  66. package/dist/agents/parse.d.ts +18 -0
  67. package/dist/agents/parse.js +116 -0
  68. package/dist/agents/result.d.ts +32 -0
  69. package/dist/agents/result.js +67 -0
  70. package/dist/agents/task-control.d.ts +17 -0
  71. package/dist/agents/task-control.js +17 -0
  72. package/dist/agents/task-record.d.ts +78 -0
  73. package/dist/agents/task-record.js +141 -0
  74. package/dist/agents/types.d.ts +46 -0
  75. package/dist/agents/types.js +8 -0
  76. package/dist/ai/apis/anthropic-compat.d.ts +36 -0
  77. package/dist/ai/apis/anthropic-compat.js +92 -0
  78. package/dist/ai/apis/anthropic-messages.js +3 -2
  79. package/dist/ai/apis/anthropic-request.d.ts +7 -6
  80. package/dist/ai/apis/anthropic-request.js +10 -28
  81. package/dist/ai/apis/cache-params.d.ts +11 -2
  82. package/dist/ai/apis/cache-params.js +25 -6
  83. package/dist/ai/apis/google-generative-ai.js +3 -2
  84. package/dist/ai/apis/openai-compat.d.ts +4 -1
  85. package/dist/ai/apis/openai-compat.js +8 -1
  86. package/dist/ai/apis/openai-completions.js +3 -2
  87. package/dist/ai/apis/openai-responses.js +3 -2
  88. package/dist/ai/http.d.ts +28 -6
  89. package/dist/ai/http.js +41 -8
  90. package/dist/ai/image-limits.d.ts +45 -0
  91. package/dist/ai/image-limits.js +68 -0
  92. package/dist/ai/providers/builtin.d.ts +18 -6
  93. package/dist/ai/providers/builtin.js +135 -6
  94. package/dist/ai/providers/catalog-data.js +17 -13
  95. package/dist/ai/providers/catalog.d.ts +60 -7
  96. package/dist/ai/providers/catalog.js +197 -38
  97. package/dist/ai/providers/channels.d.ts +33 -3
  98. package/dist/ai/providers/channels.js +108 -7
  99. package/dist/ai/providers/enrich.d.ts +6 -3
  100. package/dist/ai/providers/enrich.js +19 -4
  101. package/dist/ai/providers/models-dev-cache.d.ts +28 -24
  102. package/dist/ai/providers/models-dev-cache.js +92 -78
  103. package/dist/ai/providers/models-dev-data.d.ts +7 -0
  104. package/dist/ai/providers/models-dev-data.js +32 -0
  105. package/dist/ai/providers/models-dev-snapshot.d.ts +50 -0
  106. package/dist/ai/providers/models-dev-snapshot.js +137 -0
  107. package/dist/ai/providers/models-dev.d.ts +51 -10
  108. package/dist/ai/providers/models-dev.js +132 -39
  109. package/dist/ai/providers/registry.d.ts +28 -11
  110. package/dist/ai/providers/registry.js +112 -65
  111. package/dist/ai/providers/suggest.d.ts +18 -0
  112. package/dist/ai/providers/suggest.js +72 -0
  113. package/dist/ai/sse.d.ts +6 -2
  114. package/dist/ai/sse.js +22 -2
  115. package/dist/ai/types.d.ts +37 -4
  116. package/dist/ai/types.js +5 -0
  117. package/dist/bundle/ama.cjs +41979 -21147
  118. package/dist/checkpoints/backend.d.ts +61 -0
  119. package/dist/checkpoints/backend.js +135 -0
  120. package/dist/checkpoints/blobs.d.ts +60 -0
  121. package/dist/checkpoints/blobs.js +203 -0
  122. package/dist/checkpoints/gc.d.ts +47 -0
  123. package/dist/checkpoints/gc.js +144 -0
  124. package/dist/checkpoints/git-head.d.ts +15 -0
  125. package/dist/checkpoints/git-head.js +89 -0
  126. package/dist/checkpoints/index.d.ts +17 -0
  127. package/dist/checkpoints/index.js +17 -0
  128. package/dist/checkpoints/replay.d.ts +48 -0
  129. package/dist/checkpoints/replay.js +154 -0
  130. package/dist/checkpoints/restore.d.ts +86 -0
  131. package/dist/checkpoints/restore.js +263 -0
  132. package/dist/checkpoints/settings.d.ts +14 -0
  133. package/dist/checkpoints/settings.js +23 -0
  134. package/dist/checkpoints/shadow-git.d.ts +108 -0
  135. package/dist/checkpoints/shadow-git.js +491 -0
  136. package/dist/checkpoints/shadow-restore.d.ts +25 -0
  137. package/dist/checkpoints/shadow-restore.js +128 -0
  138. package/dist/checkpoints/tracker.d.ts +64 -0
  139. package/dist/checkpoints/tracker.js +192 -0
  140. package/dist/checkpoints/types.d.ts +99 -0
  141. package/dist/checkpoints/types.js +12 -0
  142. package/dist/cli/args.d.ts +26 -7
  143. package/dist/cli/args.js +75 -82
  144. package/dist/cli/bootstrap.js +40 -4
  145. package/dist/cli/codemode-notice.d.ts +21 -0
  146. package/dist/cli/codemode-notice.js +56 -0
  147. package/dist/cli/compose-agents.d.ts +27 -0
  148. package/dist/cli/compose-agents.js +111 -0
  149. package/dist/cli/compose-extensions.d.ts +29 -0
  150. package/dist/cli/compose-extensions.js +44 -0
  151. package/dist/cli/compose-session.d.ts +8 -0
  152. package/dist/cli/compose-session.js +76 -2
  153. package/dist/cli/compose-store.d.ts +1 -1
  154. package/dist/cli/compose-store.js +3 -1
  155. package/dist/cli/compose.d.ts +17 -4
  156. package/dist/cli/compose.js +60 -14
  157. package/dist/cli/default-model.d.ts +38 -1
  158. package/dist/cli/default-model.js +96 -9
  159. package/dist/cli/deps.d.ts +42 -0
  160. package/dist/cli/exit-codes.d.ts +12 -0
  161. package/dist/cli/exit-codes.js +15 -0
  162. package/dist/cli/fake-visibility.d.ts +13 -0
  163. package/dist/cli/fake-visibility.js +26 -0
  164. package/dist/cli/from-prompt.d.ts +18 -0
  165. package/dist/cli/from-prompt.js +49 -0
  166. package/dist/cli/help-text.d.ts +4 -0
  167. package/dist/cli/help-text.js +102 -0
  168. package/dist/cli/main.d.ts +9 -2
  169. package/dist/cli/main.js +77 -3
  170. package/dist/cli/proxy.d.ts +51 -0
  171. package/dist/cli/proxy.js +135 -0
  172. package/dist/cli/startup-screen.d.ts +29 -0
  173. package/dist/cli/startup-screen.js +51 -2
  174. package/dist/cli/startup-steps.d.ts +1 -1
  175. package/dist/cli/startup-steps.js +21 -13
  176. package/dist/cli/subcommands/config.d.ts +22 -3
  177. package/dist/cli/subcommands/config.js +119 -21
  178. package/dist/cli/subcommands/context.js +4 -1
  179. package/dist/cli/subcommands/doctor.js +33 -1
  180. package/dist/cli/subcommands/init.js +2 -1
  181. package/dist/cli/subcommands/models-discover.d.ts +15 -9
  182. package/dist/cli/subcommands/models-discover.js +58 -52
  183. package/dist/cli/subcommands/models.d.ts +2 -0
  184. package/dist/cli/subcommands/models.js +33 -14
  185. package/dist/cli/subcommands/probe-runner.d.ts +96 -0
  186. package/dist/cli/subcommands/probe-runner.js +264 -0
  187. package/dist/cli/subcommands/providers-probe.d.ts +34 -0
  188. package/dist/cli/subcommands/providers-probe.js +87 -0
  189. package/dist/cli/subcommands/providers.d.ts +3 -2
  190. package/dist/cli/subcommands/providers.js +53 -51
  191. package/dist/cli/subcommands/sessions-export.d.ts +10 -0
  192. package/dist/cli/subcommands/sessions-export.js +59 -0
  193. package/dist/cli/subcommands/sessions-search.d.ts +13 -0
  194. package/dist/cli/subcommands/sessions-search.js +103 -0
  195. package/dist/cli/subcommands/sessions.d.ts +6 -3
  196. package/dist/cli/subcommands/sessions.js +58 -3
  197. package/dist/cli/subcommands/stats.d.ts +17 -0
  198. package/dist/cli/subcommands/stats.js +198 -0
  199. package/dist/cli/system-prompt-arg.d.ts +11 -0
  200. package/dist/cli/system-prompt-arg.js +34 -0
  201. package/dist/codemode/capability.d.ts +24 -7
  202. package/dist/codemode/capability.js +38 -10
  203. package/dist/codemode/host-side.d.ts +14 -0
  204. package/dist/codemode/host-side.js +24 -1
  205. package/dist/codemode/modes.d.ts +4 -11
  206. package/dist/codemode/modes.js +5 -27
  207. package/dist/codemode/tool.d.ts +18 -14
  208. package/dist/codemode/tool.js +76 -31
  209. package/dist/compaction/breaker.d.ts +25 -9
  210. package/dist/compaction/breaker.js +47 -17
  211. package/dist/compaction/estimate.d.ts +11 -3
  212. package/dist/compaction/estimate.js +64 -22
  213. package/dist/compaction/image-budget.d.ts +45 -0
  214. package/dist/compaction/image-budget.js +115 -0
  215. package/dist/compaction/post-compact.d.ts +38 -0
  216. package/dist/compaction/post-compact.js +152 -0
  217. package/dist/compaction/protect.d.ts +27 -0
  218. package/dist/compaction/protect.js +56 -0
  219. package/dist/compaction/prune-tier.d.ts +58 -12
  220. package/dist/compaction/prune-tier.js +120 -54
  221. package/dist/compaction/summarize-tier.d.ts +23 -4
  222. package/dist/compaction/summarize-tier.js +100 -29
  223. package/dist/config/checker.d.ts +28 -0
  224. package/dist/config/checker.js +97 -0
  225. package/dist/config/init.d.ts +6 -2
  226. package/dist/config/init.js +12 -5
  227. package/dist/config/json-schema.d.ts +1 -0
  228. package/dist/config/json-schema.js +98 -4
  229. package/dist/config/key-docs.d.ts +22 -0
  230. package/dist/config/key-docs.js +174 -0
  231. package/dist/config/merge.d.ts +12 -9
  232. package/dist/config/merge.js +102 -13
  233. package/dist/config/profile.d.ts +2 -0
  234. package/dist/config/profile.js +2 -0
  235. package/dist/config/schema-w5.d.ts +18 -0
  236. package/dist/config/schema-w5.js +109 -0
  237. package/dist/config/schema.d.ts +5 -9
  238. package/dist/config/schema.js +91 -118
  239. package/dist/config/types-w5.d.ts +118 -0
  240. package/dist/config/types-w5.js +20 -0
  241. package/dist/config/types.d.ts +84 -7
  242. package/dist/config/types.js +29 -1
  243. package/dist/drivers/acp/client.d.ts +57 -0
  244. package/dist/drivers/acp/client.js +160 -0
  245. package/dist/drivers/acp/driver.d.ts +31 -0
  246. package/dist/drivers/acp/driver.js +274 -0
  247. package/dist/drivers/acp/testing/fake-agent-main.d.ts +5 -0
  248. package/dist/drivers/acp/testing/fake-agent-main.js +7 -0
  249. package/dist/drivers/acp/testing/fake-agent.d.ts +27 -0
  250. package/dist/drivers/acp/testing/fake-agent.js +211 -0
  251. package/dist/drivers/acp/types.d.ts +285 -0
  252. package/dist/drivers/acp/types.js +36 -0
  253. package/dist/drivers/agents.d.ts +58 -0
  254. package/dist/drivers/agents.js +142 -0
  255. package/dist/drivers/base.d.ts +35 -0
  256. package/dist/drivers/base.js +59 -0
  257. package/dist/drivers/catalog.d.ts +46 -0
  258. package/dist/drivers/catalog.js +167 -0
  259. package/dist/drivers/env.d.ts +20 -0
  260. package/dist/drivers/env.js +46 -0
  261. package/dist/drivers/host-runners.d.ts +18 -0
  262. package/dist/drivers/host-runners.js +45 -0
  263. package/dist/drivers/jsonrpc.d.ts +58 -0
  264. package/dist/drivers/jsonrpc.js +180 -0
  265. package/dist/drivers/native/claude-normalize.d.ts +46 -0
  266. package/dist/drivers/native/claude-normalize.js +106 -0
  267. package/dist/drivers/native/claude-stream.d.ts +29 -0
  268. package/dist/drivers/native/claude-stream.js +456 -0
  269. package/dist/drivers/native/codex-app-server.d.ts +26 -0
  270. package/dist/drivers/native/codex-app-server.js +407 -0
  271. package/dist/drivers/native/codex-normalize.d.ts +38 -0
  272. package/dist/drivers/native/codex-normalize.js +124 -0
  273. package/dist/drivers/native/oneshot.d.ts +28 -0
  274. package/dist/drivers/native/oneshot.js +312 -0
  275. package/dist/drivers/permissions.d.ts +40 -0
  276. package/dist/drivers/permissions.js +92 -0
  277. package/dist/drivers/pids.d.ts +32 -0
  278. package/dist/drivers/pids.js +93 -0
  279. package/dist/drivers/pool.d.ts +28 -0
  280. package/dist/drivers/pool.js +96 -0
  281. package/dist/drivers/probe.d.ts +47 -0
  282. package/dist/drivers/probe.js +172 -0
  283. package/dist/drivers/process.d.ts +48 -0
  284. package/dist/drivers/process.js +100 -0
  285. package/dist/drivers/runner.d.ts +61 -0
  286. package/dist/drivers/runner.js +388 -0
  287. package/dist/drivers/store.d.ts +49 -0
  288. package/dist/drivers/store.js +91 -0
  289. package/dist/drivers/turn.d.ts +41 -0
  290. package/dist/drivers/turn.js +99 -0
  291. package/dist/drivers/types.d.ts +122 -0
  292. package/dist/drivers/types.js +11 -0
  293. package/dist/git/info.d.ts +75 -0
  294. package/dist/git/info.js +191 -0
  295. package/dist/hooks/protocol.js +6 -1
  296. package/dist/hooks/types.d.ts +10 -1
  297. package/dist/hooks/types.js +2 -0
  298. package/dist/host/api-impl.d.ts +7 -0
  299. package/dist/host/api-impl.js +15 -0
  300. package/dist/host/types.d.ts +24 -2
  301. package/dist/host/types.js +4 -0
  302. package/dist/index.d.ts +3 -0
  303. package/dist/index.js +1 -0
  304. package/dist/modes/acp/acp-events.d.ts +46 -0
  305. package/dist/modes/acp/acp-events.js +233 -0
  306. package/dist/modes/acp/acp-mode.d.ts +17 -0
  307. package/dist/modes/acp/acp-mode.js +47 -0
  308. package/dist/modes/acp/acp-server.d.ts +79 -0
  309. package/dist/modes/acp/acp-server.js +315 -0
  310. package/dist/modes/commands-core.d.ts +7 -1
  311. package/dist/modes/commands-core.js +61 -5
  312. package/dist/modes/image-input.d.ts +12 -4
  313. package/dist/modes/image-input.js +22 -5
  314. package/dist/modes/interactive/agent-panels.d.ts +14 -0
  315. package/dist/modes/interactive/agent-panels.js +103 -0
  316. package/dist/modes/interactive/agent-ui.d.ts +73 -0
  317. package/dist/modes/interactive/agent-ui.js +234 -0
  318. package/dist/modes/interactive/approval-dialog.d.ts +40 -7
  319. package/dist/modes/interactive/approval-dialog.js +192 -35
  320. package/dist/modes/interactive/approval-merge.d.ts +41 -0
  321. package/dist/modes/interactive/approval-merge.js +89 -0
  322. package/dist/modes/interactive/clipboard-paste.d.ts +18 -0
  323. package/dist/modes/interactive/clipboard-paste.js +28 -0
  324. package/dist/modes/interactive/commands.d.ts +20 -3
  325. package/dist/modes/interactive/commands.js +75 -16
  326. package/dist/modes/interactive/double-esc.d.ts +20 -0
  327. package/dist/modes/interactive/double-esc.js +34 -0
  328. package/dist/modes/interactive/event-notices.d.ts +32 -0
  329. package/dist/modes/interactive/event-notices.js +79 -0
  330. package/dist/modes/interactive/external-editor.d.ts +16 -0
  331. package/dist/modes/interactive/external-editor.js +39 -0
  332. package/dist/modes/interactive/interactive-mode.d.ts +16 -2
  333. package/dist/modes/interactive/interactive-mode.js +184 -202
  334. package/dist/modes/interactive/key-dispatch.d.ts +18 -2
  335. package/dist/modes/interactive/key-dispatch.js +53 -6
  336. package/dist/modes/interactive/line/line-mode.d.ts +3 -1
  337. package/dist/modes/interactive/line/line-mode.js +28 -9
  338. package/dist/modes/interactive/line/line-render.d.ts +6 -1
  339. package/dist/modes/interactive/line/line-render.js +66 -8
  340. package/dist/modes/interactive/message-view.d.ts +49 -10
  341. package/dist/modes/interactive/message-view.js +262 -46
  342. package/dist/modes/interactive/panels.d.ts +35 -0
  343. package/dist/modes/interactive/panels.js +157 -0
  344. package/dist/modes/interactive/pickers.d.ts +23 -2
  345. package/dist/modes/interactive/pickers.js +48 -15
  346. package/dist/modes/interactive/plan-command.d.ts +40 -0
  347. package/dist/modes/interactive/plan-command.js +129 -0
  348. package/dist/modes/interactive/plan-dialog.d.ts +98 -0
  349. package/dist/modes/interactive/plan-dialog.js +290 -0
  350. package/dist/modes/interactive/plan-flow.d.ts +34 -0
  351. package/dist/modes/interactive/plan-flow.js +98 -0
  352. package/dist/modes/interactive/rewind-command.d.ts +31 -0
  353. package/dist/modes/interactive/rewind-command.js +106 -0
  354. package/dist/modes/interactive/rewind-flow.d.ts +37 -0
  355. package/dist/modes/interactive/rewind-flow.js +151 -0
  356. package/dist/modes/interactive/rewind-list.d.ts +36 -0
  357. package/dist/modes/interactive/rewind-list.js +123 -0
  358. package/dist/modes/interactive/rewind-panel.d.ts +77 -0
  359. package/dist/modes/interactive/rewind-panel.js +309 -0
  360. package/dist/modes/interactive/rewind-text.d.ts +40 -0
  361. package/dist/modes/interactive/rewind-text.js +139 -0
  362. package/dist/modes/interactive/run-indicator.d.ts +51 -0
  363. package/dist/modes/interactive/run-indicator.js +189 -0
  364. package/dist/modes/interactive/session-events.d.ts +24 -0
  365. package/dist/modes/interactive/session-events.js +96 -0
  366. package/dist/modes/interactive/startup-header.d.ts +40 -0
  367. package/dist/modes/interactive/startup-header.js +169 -0
  368. package/dist/modes/interactive/status-area.d.ts +73 -0
  369. package/dist/modes/interactive/status-area.js +190 -0
  370. package/dist/modes/interactive/status-bar.d.ts +107 -16
  371. package/dist/modes/interactive/status-bar.js +306 -81
  372. package/dist/modes/interactive/status-line.d.ts +33 -0
  373. package/dist/modes/interactive/status-line.js +113 -0
  374. package/dist/modes/interactive/subagent-view.d.ts +56 -0
  375. package/dist/modes/interactive/subagent-view.js +154 -0
  376. package/dist/modes/interactive/tasks-report.d.ts +27 -0
  377. package/dist/modes/interactive/tasks-report.js +114 -0
  378. package/dist/modes/interactive/tool-summary.d.ts +46 -0
  379. package/dist/modes/interactive/tool-summary.js +218 -0
  380. package/dist/modes/interactive/tool-view.d.ts +58 -15
  381. package/dist/modes/interactive/tool-view.js +233 -145
  382. package/dist/modes/print/print-mode.d.ts +40 -4
  383. package/dist/modes/print/print-mode.js +161 -8
  384. package/dist/modes/rpc/commands.d.ts +9 -0
  385. package/dist/modes/rpc/commands.js +49 -0
  386. package/dist/modes/rpc/rpc-mode.js +7 -1
  387. package/dist/modes/session-report.d.ts +11 -0
  388. package/dist/modes/session-report.js +48 -1
  389. package/dist/permissions/auto-safe.d.ts +65 -0
  390. package/dist/permissions/auto-safe.js +547 -0
  391. package/dist/permissions/classifier.d.ts +68 -0
  392. package/dist/permissions/classifier.js +186 -0
  393. package/dist/permissions/dangerous.d.ts +5 -0
  394. package/dist/permissions/dangerous.js +1 -1
  395. package/dist/permissions/modes.d.ts +30 -0
  396. package/dist/permissions/modes.js +78 -0
  397. package/dist/permissions/pipeline.d.ts +72 -6
  398. package/dist/permissions/pipeline.js +306 -11
  399. package/dist/permissions/protected.d.ts +19 -0
  400. package/dist/permissions/protected.js +74 -0
  401. package/dist/permissions/readonly-bash.d.ts +30 -0
  402. package/dist/permissions/readonly-bash.js +118 -0
  403. package/dist/permissions/rules.js +3 -0
  404. package/dist/permissions/types.d.ts +92 -3
  405. package/dist/permissions/types.js +3 -0
  406. package/dist/plan/compose.d.ts +9 -0
  407. package/dist/plan/compose.js +19 -0
  408. package/dist/plan/controller.d.ts +71 -0
  409. package/dist/plan/controller.js +27 -0
  410. package/dist/plan/done-markers.d.ts +17 -0
  411. package/dist/plan/done-markers.js +51 -0
  412. package/dist/plan/extract.d.ts +29 -0
  413. package/dist/plan/extract.js +160 -0
  414. package/dist/plan/prompts.d.ts +36 -0
  415. package/dist/plan/prompts.js +89 -0
  416. package/dist/plan/store.d.ts +37 -0
  417. package/dist/plan/store.js +90 -0
  418. package/dist/rpc.d.ts +58 -2
  419. package/dist/rpc.js +7 -0
  420. package/dist/sandbox/bash.d.ts +74 -0
  421. package/dist/sandbox/bash.js +126 -0
  422. package/dist/sandbox/detect.d.ts +48 -0
  423. package/dist/sandbox/detect.js +149 -0
  424. package/dist/sandbox/index.d.ts +5 -0
  425. package/dist/sandbox/index.js +5 -0
  426. package/dist/sandbox/profile.d.ts +33 -0
  427. package/dist/sandbox/profile.js +76 -0
  428. package/dist/sandbox/wrap.d.ts +29 -0
  429. package/dist/sandbox/wrap.js +117 -0
  430. package/dist/sdk.d.ts +42 -5
  431. package/dist/sdk.js +34 -4
  432. package/dist/session/export.d.ts +32 -0
  433. package/dist/session/export.js +187 -0
  434. package/dist/session/redact.d.ts +15 -0
  435. package/dist/session/redact.js +55 -0
  436. package/dist/session/reuse.d.ts +33 -0
  437. package/dist/session/reuse.js +86 -0
  438. package/dist/session/scan.d.ts +34 -0
  439. package/dist/session/scan.js +140 -0
  440. package/dist/session/search.d.ts +52 -0
  441. package/dist/session/search.js +211 -0
  442. package/dist/session/stats-aggregate.d.ts +63 -0
  443. package/dist/session/stats-aggregate.js +163 -0
  444. package/dist/session/stats-index.d.ts +26 -0
  445. package/dist/session/stats-index.js +91 -0
  446. package/dist/session/stats-scan.d.ts +54 -0
  447. package/dist/session/stats-scan.js +236 -0
  448. package/dist/session/types.d.ts +3 -1
  449. package/dist/session/types.js +1 -0
  450. package/dist/skills/builtin.d.ts +31 -0
  451. package/dist/skills/builtin.js +109 -0
  452. package/dist/skills/discover.d.ts +2 -1
  453. package/dist/skills/index-prompt.js +5 -8
  454. package/dist/tools/background-jobs.d.ts +71 -0
  455. package/dist/tools/background-jobs.js +198 -0
  456. package/dist/tools/bash.d.ts +53 -1
  457. package/dist/tools/bash.js +158 -7
  458. package/dist/tools/clipboard-image.d.ts +44 -0
  459. package/dist/tools/clipboard-image.js +148 -0
  460. package/dist/tools/edit.d.ts +2 -0
  461. package/dist/tools/edit.js +18 -3
  462. package/dist/tools/image-file.d.ts +38 -3
  463. package/dist/tools/image-file.js +81 -10
  464. package/dist/tools/image-resize.d.ts +58 -0
  465. package/dist/tools/image-resize.js +97 -0
  466. package/dist/tools/presets.d.ts +40 -8
  467. package/dist/tools/presets.js +65 -19
  468. package/dist/tools/read.d.ts +5 -2
  469. package/dist/tools/read.js +13 -10
  470. package/dist/tools/registry.d.ts +7 -1
  471. package/dist/tools/registry.js +27 -4
  472. package/dist/tools/task-ctl.d.ts +22 -0
  473. package/dist/tools/task-ctl.js +116 -0
  474. package/dist/tools/task.d.ts +22 -10
  475. package/dist/tools/task.js +66 -26
  476. package/dist/tools/todo.d.ts +22 -2
  477. package/dist/tools/todo.js +58 -14
  478. package/dist/tools/truncate.d.ts +15 -0
  479. package/dist/tools/truncate.js +25 -0
  480. package/dist/tools/types.d.ts +113 -0
  481. package/dist/tools/types.js +5 -0
  482. package/dist/tools/write.js +3 -0
  483. package/dist/tui/component.d.ts +8 -2
  484. package/dist/tui/component.js +3 -1
  485. package/dist/tui/components/box.d.ts +6 -1
  486. package/dist/tui/components/box.js +16 -6
  487. package/dist/tui/components/card.d.ts +23 -0
  488. package/dist/tui/components/card.js +37 -0
  489. package/dist/tui/components/editor-history.d.ts +6 -0
  490. package/dist/tui/components/editor-history.js +45 -0
  491. package/dist/tui/components/editor-paste.d.ts +1 -1
  492. package/dist/tui/components/editor-paste.js +4 -4
  493. package/dist/tui/components/editor.d.ts +11 -5
  494. package/dist/tui/components/editor.js +52 -58
  495. package/dist/tui/components/key-value.d.ts +3 -0
  496. package/dist/tui/components/key-value.js +16 -6
  497. package/dist/tui/components/loader.d.ts +37 -7
  498. package/dist/tui/components/loader.js +84 -21
  499. package/dist/tui/components/markdown.d.ts +5 -1
  500. package/dist/tui/components/markdown.js +45 -21
  501. package/dist/tui/components/meter.d.ts +3 -3
  502. package/dist/tui/components/meter.js +13 -11
  503. package/dist/tui/components/select-list.d.ts +23 -1
  504. package/dist/tui/components/select-list.js +76 -13
  505. package/dist/tui/glyphs.d.ts +72 -0
  506. package/dist/tui/glyphs.js +118 -0
  507. package/dist/tui/keybindings.d.ts +5 -0
  508. package/dist/tui/keybindings.js +5 -0
  509. package/dist/tui/theme.d.ts +30 -6
  510. package/dist/tui/theme.js +103 -17
  511. package/dist/tui.d.ts +4 -2
  512. package/dist/tui.js +3 -1
  513. package/docs/acp.md +78 -0
  514. package/docs/agents.md +250 -0
  515. package/docs/codemode.md +28 -10
  516. package/docs/hooks.md +36 -32
  517. package/docs/permissions.md +212 -0
  518. package/docs/plan.md +107 -0
  519. package/docs/providers.md +261 -62
  520. package/docs/rewind-plan.md +181 -0
  521. package/docs/rpc.md +127 -40
  522. package/docs/sandbox.md +215 -0
  523. package/docs/session-format.md +43 -22
  524. package/docs/sessions.md +174 -0
  525. package/docs/tui-design.md +751 -0
  526. package/docs/tui.md +260 -64
  527. package/package.json +15 -2
@@ -19,8 +19,14 @@
19
19
  * 重新物化(协议、地址、headers、compat 取渠道的,模型级 api / baseUrl 仍覆盖);渠道 key 经
20
20
  * `resolveApiKey(provider, channel)`。没有 `channels` 的供应商行为不变。
21
21
  *
22
+ * 内置渠道([W5-M2],builtin.ts):用户 `channels` 同名字段级覆盖、新名追加,`defaultChannel` 用户优先
23
+ * (也可只写 `defaultChannel`,或只写 `api` 选同协议的内置渠道);目录模型缺省挂全部渠道、缺省渠道在前。
24
+ * 用户(config / auth.json / `*_BASE_URL`)改了供应商级 baseUrl 而没写自己的 `channels` 时,内置渠道作废,
25
+ * 按单渠道回落(`api` 取用户写的或内置的回落协议)。
26
+ *
22
27
  * models.dev(enrich.ts):config 里缺元数据的自定义模型与合成模型,用传入的索引(只读缓存)补
23
- * contextWindow / maxTokens / input / reasoning / cost,来源记在 `modelMetadata()`;内置目录不补。
28
+ * contextWindow / maxTokens / input / reasoning / cost,来源记在 `modelMetadata()`;内置目录按同一索引
29
+ * (快照 ⊕ `ama models refresh` 的覆盖)在 catalog.ts 合并,缺字段的条目退回内置快照。
24
30
  */
25
31
  import { ApiRegistry, createDefaultApiRegistry } from "../apis/api.js";
26
32
  import { fakeProviderData } from "../fake/fake-provider.js";
@@ -28,33 +34,10 @@ import { mergeHeaders } from "../http.js";
28
34
  import { ApiKeyResolver } from "./auth.js";
29
35
  import { BUILTIN_PROVIDERS, fallbackEnvKey, isRelayedBaseUrl } from "./builtin.js";
30
36
  import { applyModelOverride, loadBuiltinCatalog, toModel, withCustomDefaults } from "./catalog.js";
31
- import { channelKeyId, modelChannels, parseChannels, splitChannelRef } from "./channels.js";
37
+ import { catalogChannels, channelKeyId, dropChannels, materializeModel, pickBuiltinChannel, modelChannels, parseChannels, splitChannelRef, } from "./channels.js";
32
38
  import { catalogMetadata, enrichEntry, lazyIndex, } from "./enrich.js";
33
- /**
34
- * 物化:模型补齐供应商级字段(不可变:返回新对象)。给了 `channel` 时协议与地址取渠道的(模型级
35
- * `explicit` 覆盖优先),headers / compat 按 供应商 ← 渠道 ← 模型 合并,并记下渠道名。
36
- */
37
- export function materializeModel(model, provider, channel, explicit) {
38
- const out = {
39
- ...model,
40
- provider: provider.id,
41
- baseUrl: model.baseUrl ?? provider.baseUrl,
42
- };
43
- if (channel !== undefined) {
44
- out.api = explicit?.api ?? channel.api;
45
- out.baseUrl = explicit?.baseUrl ?? channel.baseUrl;
46
- out.channel = channel.name;
47
- }
48
- if (provider.headers || channel?.headers || model.headers)
49
- out.headers = mergeHeaders(provider.headers, channel?.headers, model.headers);
50
- if (provider.compat || channel?.compat || model.compat)
51
- out.compat = { ...provider.compat, ...channel?.compat, ...model.compat };
52
- const authHeader = channel?.authHeader ?? provider.authHeader;
53
- if (authHeader !== undefined)
54
- out.authHeader = model.authHeader ?? authHeader;
55
- out.requiresApiKey = provider.requiresApiKey;
56
- return out;
57
- }
39
+ import { closest } from "./suggest.js";
40
+ export { materializeModel } from "./channels.js";
58
41
  function configKeysOf(config) {
59
42
  const keys = {};
60
43
  for (const [id, provider] of Object.entries(config?.providers ?? {})) {
@@ -74,6 +57,10 @@ export class ProviderRegistry {
74
57
  envBaseUrls = new Map();
75
58
  /** baseUrl 指向非官方主机的内置供应商:接受目录外的 model id。 */
76
59
  relayed = new Set();
60
+ /** config 里写了自己 `channels` 的供应商(内置渠道不因改 baseUrl 作废)。 */
61
+ userChannels = new Set();
62
+ /** config 里写了供应商级 `api` 的供应商(单渠道回落时目录模型跟它走)。 */
63
+ userApi = new Set();
77
64
  /** `provider/model` → 物化前的模型(多渠道供应商切换渠道时重新物化)。 */
78
65
  raw = new Map();
79
66
  /** `provider/model` → 元数据来源与 models.dev 匹配。 */
@@ -91,9 +78,9 @@ export class ProviderRegistry {
91
78
  configKeys: options.keys?.configKeys ?? configKeysOf(options.config),
92
79
  onWarning: (message) => this.warn(message),
93
80
  });
94
- const catalog = loadBuiltinCatalog();
81
+ const catalog = this.loadCatalog();
95
82
  const env = options.keys?.useEnv === false ? {} : (options.keys?.env ?? process.env);
96
- for (const { baseUrlEnv, ...base } of BUILTIN_PROVIDERS) {
83
+ for (const { baseUrlEnv, catalogApi: _catalogApi, ...base } of BUILTIN_PROVIDERS) {
97
84
  const models = (catalog.get(base.id) ?? []).map((entry) => {
98
85
  const api = entry.api ?? base.api;
99
86
  this.sources.set(`${base.id}/${entry.id}`, "builtin");
@@ -106,12 +93,12 @@ export class ProviderRegistry {
106
93
  const fromEnv = baseUrlEnv !== undefined ? env[baseUrlEnv]?.trim() : undefined;
107
94
  if (baseUrlEnv !== undefined && fromEnv)
108
95
  this.envBaseUrls.set(base.id, baseUrlEnv);
109
- this.providers.set(base.id, {
110
- ...base,
111
- ...(fromEnv ? { baseUrl: fromEnv } : {}),
112
- models,
113
- builtin: true,
114
- });
96
+ const provider = { ...structuredClone(base), models, builtin: true };
97
+ if (fromEnv) {
98
+ provider.baseUrl = fromEnv;
99
+ dropChannels(provider);
100
+ }
101
+ this.providers.set(base.id, provider);
115
102
  }
116
103
  for (const [id, config] of Object.entries(options.config?.providers ?? {})) {
117
104
  this.applyConfig(id, config);
@@ -121,6 +108,8 @@ export class ProviderRegistry {
121
108
  if (baseUrl) {
122
109
  provider.baseUrl = baseUrl;
123
110
  this.envBaseUrls.delete(provider.id);
111
+ if (provider.builtin && !this.userChannels.has(provider.id))
112
+ dropChannels(provider);
124
113
  }
125
114
  if (provider.builtin && isRelayedBaseUrl(provider.id, provider.baseUrl)) {
126
115
  this.relayed.add(provider.id);
@@ -135,9 +124,52 @@ export class ProviderRegistry {
135
124
  this.providers.set(fake.id, fake);
136
125
  }
137
126
  for (const provider of this.providers.values()) {
127
+ if (provider.builtin)
128
+ this.settleBuiltinChannels(provider);
138
129
  provider.models = provider.models.map((model) => this.materialize(provider, model));
139
130
  }
140
131
  }
132
+ /** 内置目录(快照 ⊕ 用户刷新);刷新数据出任何问题都退回内置快照,不让启动失败。 */
133
+ loadCatalog() {
134
+ try {
135
+ return loadBuiltinCatalog(this.modelsDev());
136
+ }
137
+ catch (error) {
138
+ this.warn(`models.dev refresh data ignored: ${error.message}`);
139
+ return loadBuiltinCatalog();
140
+ }
141
+ }
142
+ /**
143
+ * 内置供应商定渠道:供应商级 api / baseUrl 取缺省渠道的(discover 等单地址的用法看它);用户没指定渠道的
144
+ * 模型挂全部渠道(缺省在前)。渠道已作废的去掉模型上残留的 `channels`。
145
+ */
146
+ settleBuiltinChannels(provider) {
147
+ const channels = provider.channels;
148
+ if (channels === undefined || channels.length === 0) {
149
+ // 单渠道回落:没有模型级协议的目录模型走 catalogApi(用户改了 api 时走用户的)
150
+ const builtin = BUILTIN_PROVIDERS.find((p) => p.id === provider.id);
151
+ const api = builtin === undefined || this.userApi.has(provider.id)
152
+ ? provider.api
153
+ : (builtin.catalogApi ?? builtin.api);
154
+ for (const model of provider.models) {
155
+ delete model.channels;
156
+ const key = `${provider.id}/${model.id}`;
157
+ if (this.sources.get(key) === "builtin" && this.raw.get(key)?.explicit.api === undefined)
158
+ model.api = api;
159
+ }
160
+ return;
161
+ }
162
+ const first = channels.find((c) => c.name === provider.defaultChannel) ?? channels[0];
163
+ if (first === undefined)
164
+ return;
165
+ provider.defaultChannel = first.name;
166
+ provider.api = first.api;
167
+ provider.baseUrl = first.baseUrl;
168
+ for (const model of provider.models) {
169
+ if (this.sources.get(`${provider.id}/${model.id}`) === "builtin" || !model.channels)
170
+ model.channels = catalogChannels(model.channels, channels, first.name);
171
+ }
172
+ }
141
173
  warn(message) {
142
174
  this.warnings.push(message);
143
175
  this.onWarning?.(message);
@@ -159,7 +191,15 @@ export class ProviderRegistry {
159
191
  }
160
192
  applyConfig(id, config) {
161
193
  const existing = this.providers.get(id);
162
- const parsed = config.channels !== undefined ? parseChannels(id, config) : undefined;
194
+ const builtinChannels = existing?.builtin ? existing.channels : undefined;
195
+ const parsed = config.channels !== undefined
196
+ ? parseChannels(id, config, builtinChannels && {
197
+ channels: builtinChannels,
198
+ defaultChannel: existing?.defaultChannel,
199
+ })
200
+ : undefined;
201
+ if (config.channels !== undefined)
202
+ this.userChannels.add(id);
163
203
  for (const warning of parsed?.warnings ?? [])
164
204
  this.warn(warning);
165
205
  const first = parsed?.channels.find((c) => c.name === parsed.defaultChannel);
@@ -179,12 +219,16 @@ export class ProviderRegistry {
179
219
  };
180
220
  if (config.name !== undefined)
181
221
  provider.name = config.name;
182
- if (config.api !== undefined)
222
+ if (config.api !== undefined) {
183
223
  provider.api = config.api;
224
+ this.userApi.add(id);
225
+ }
184
226
  if (config.baseUrl !== undefined) {
185
227
  provider.baseUrl = config.baseUrl;
186
228
  this.envBaseUrls.delete(id);
187
229
  }
230
+ if (builtinChannels !== undefined && parsed === undefined)
231
+ pickBuiltinChannel(provider, config, (m) => this.warn(m));
188
232
  if (parsed !== undefined && first !== undefined) {
189
233
  // 有渠道时供应商级 api / baseUrl 取首选渠道的(discover 等单地址的用法看它)。
190
234
  provider.channels = parsed.channels;
@@ -214,7 +258,8 @@ export class ProviderRegistry {
214
258
  if (typeof entry.modelsDev === "string" && metadata.looked && metadata.match === undefined)
215
259
  this.warn(`modelsDev "${entry.modelsDev}" for "${id}/${entry.id}" not found`);
216
260
  const model = withCustomDefaults(filled, id, entry.api ?? provider.api);
217
- if (provider.channels !== undefined)
261
+ // 内置供应商上没写 channels 的模型:定渠道时挂全部渠道(settleBuiltinChannels)
262
+ if (provider.channels !== undefined && (entry.channels !== undefined || !provider.builtin))
218
263
  model.channels = channelsOf(entry.channels, entry.id);
219
264
  const index = provider.models.findIndex((m) => m.id === entry.id);
220
265
  if (index >= 0)
@@ -262,11 +307,6 @@ export class ProviderRegistry {
262
307
  if (fields[field] !== undefined)
263
308
  meta.sources[field] = "config";
264
309
  }
265
- if (provider.channels !== undefined) {
266
- // 目录模型(给内置供应商加了渠道时)挂到首选渠道。
267
- for (const model of provider.models)
268
- model.channels ??= [provider.defaultChannel ?? ""];
269
- }
270
310
  this.providers.set(id, provider);
271
311
  }
272
312
  /** baseUrl 来自哪个环境变量(未生效返回 undefined)。 */
@@ -326,36 +366,40 @@ export class ProviderRegistry {
326
366
  const channelData = provider.channels?.find((c) => c.name === (channel ?? model.channels?.[0]));
327
367
  return materializeModel(model, provider, channelData);
328
368
  }
329
- /** 按渠道取模型:渠道不在模型的 channels 里 → 列出可用渠道。 */
369
+ /** 按渠道取模型:渠道不在模型的 channels 里 → channel_not_found,列出可用渠道。 */
330
370
  withChannel(provider, model, channel) {
331
371
  const available = model.channels ?? [];
332
- if (!available.includes(channel)) {
372
+ if (!available.includes(channel) || !provider.channels?.some((c) => c.name === channel)) {
333
373
  return {
334
374
  ok: false,
335
- reason: "not_found",
336
- candidates: available.map((c) => `${provider.id}/${model.id}@${c}`),
375
+ reason: "channel_not_found",
376
+ candidates: available.filter(Boolean).map((c) => `${provider.id}/${model.id}@${c}`),
337
377
  };
338
378
  }
339
379
  if (channel === model.channel)
340
380
  return { ok: true, model, provider };
341
381
  return { ok: true, model: this.materialize(provider, model, channel), provider };
342
382
  }
383
+ /**
384
+ * `provider/model`、`provider/model@渠道` 或裸模型 id。`@` 先按渠道解析(id 里本来就带 `@` 且已登记的
385
+ * 模型除外),中转供应商的「未登记即合成」不会把 `@渠道` 吞进模型 id。失败的 reason:供应商不存在 →
386
+ * provider_not_found(候选是编辑距离最近的供应商);渠道不存在 → channel_not_found;模型不存在 →
387
+ * not_found(候选是最接近的模型)。
388
+ */
343
389
  findModel(ref) {
344
390
  const trimmed = ref.trim();
345
- const direct = this.findPlain(trimmed);
346
- if (direct.ok)
347
- return direct;
348
391
  const split = splitChannelRef(trimmed);
349
392
  if (split === undefined)
350
- return direct;
393
+ return this.findPlain(trimmed);
394
+ const exact = this.findPlain(trimmed, undefined, false);
395
+ if (exact.ok)
396
+ return exact;
351
397
  const base = this.findPlain(split.base, split.channel);
352
398
  if (!base.ok)
353
- return base.reason === "ambiguous" ? base : direct;
354
- if (!base.provider.channels?.some((c) => c.name === split.channel))
355
- return direct;
399
+ return base;
356
400
  return this.withChannel(base.provider, base.model, split.channel);
357
401
  }
358
- findPlain(trimmed, channel) {
402
+ findPlain(trimmed, channel, synthesize = true) {
359
403
  const slash = trimmed.indexOf("/");
360
404
  if (slash > 0) {
361
405
  const provider = this.providers.get(trimmed.slice(0, slash));
@@ -364,7 +408,8 @@ export class ProviderRegistry {
364
408
  const model = provider.models.find((m) => m.id === id);
365
409
  if (model)
366
410
  return { ok: true, model, provider };
367
- if ((provider.models.length === 0 || this.relayed.has(provider.id)) && id.length > 0) {
411
+ const relayed = provider.models.length === 0 || this.relayed.has(provider.id);
412
+ if (synthesize && relayed && id.length > 0) {
368
413
  const synthesized = this.synthesize(provider, id);
369
414
  if (channel !== undefined && provider.channels?.some((c) => c.name === channel))
370
415
  synthesized.channels = [...new Set([...(synthesized.channels ?? []), channel])];
@@ -374,6 +419,14 @@ export class ProviderRegistry {
374
419
  }
375
420
  }
376
421
  const matches = this.listModels().filter((entry) => entry.model.id === trimmed);
422
+ if (matches.length === 0 && slash > 0) {
423
+ const ids = [...this.providers.keys()];
424
+ return {
425
+ ok: false,
426
+ reason: "provider_not_found",
427
+ candidates: closest(trimmed.slice(0, slash), ids),
428
+ };
429
+ }
377
430
  if (matches.length === 1 && matches[0]) {
378
431
  return { ok: true, model: matches[0].model, provider: matches[0].provider };
379
432
  }
@@ -390,16 +443,10 @@ export class ProviderRegistry {
390
443
  candidates: (configured.length > 0 ? configured : matches).map((entry) => `${entry.provider.id}/${entry.model.id}`),
391
444
  };
392
445
  }
446
+ /** 最接近的模型(包含关系优先,其次编辑距离),`provider/id` 形式。 */
393
447
  similar(id, providerId) {
394
- const needle = id.toLowerCase();
395
- return this.listModels()
396
- .filter((entry) => providerId === undefined || entry.provider.id === providerId)
397
- .filter((entry) => {
398
- const candidate = entry.model.id.toLowerCase();
399
- return needle.length > 0 && (candidate.includes(needle) || needle.includes(candidate));
400
- })
401
- .slice(0, 10)
402
- .map((entry) => `${entry.provider.id}/${entry.model.id}`);
448
+ const entries = this.listModels().filter((entry) => providerId === undefined || entry.provider.id === providerId);
449
+ return closest(id, entries, 5, (entry) => entry.model.id).map((entry) => `${entry.provider.id}/${entry.model.id}`);
403
450
  }
404
451
  hasConfiguredKey(providerId) {
405
452
  const provider = this.providers.get(providerId);
@@ -0,0 +1,18 @@
1
+ /**
2
+ * 模型 / 供应商 / 渠道写错时的候选与报错文案(W4-C)。
3
+ *
4
+ * 候选排序:包含关系(`sonnet` ⊂ `claude-sonnet-5`)优先,其次按编辑距离;距离超过
5
+ * `max(2, ⌈长度 / 3⌉)` 的不算接近。只比较 id 本身(不含 `provider/` 前缀),大小写不敏感。
6
+ */
7
+ import type { ModelLookup } from "../types.js";
8
+ /** Levenshtein 距离(插入 / 删除 / 替换各计 1)。 */
9
+ export declare function editDistance(a: string, b: string): number;
10
+ /**
11
+ * 从 `candidates` 里挑与 `needle` 最接近的至多 `limit` 个。`key` 取参与比较的部分
12
+ * (缺省整串),返回原值。
13
+ */
14
+ export declare function closest<T>(needle: string, candidates: readonly T[], limit?: number, key?: (item: T) => string): T[];
15
+ /** 解析失败的一行说明(不含前缀标签):`渠道不存在:x;该模型可用渠道:…` 等。 */
16
+ export declare function describeLookupFailure(ref: string, failure: Extract<ModelLookup, {
17
+ ok: false;
18
+ }>): string;
@@ -0,0 +1,72 @@
1
+ /**
2
+ * 模型 / 供应商 / 渠道写错时的候选与报错文案(W4-C)。
3
+ *
4
+ * 候选排序:包含关系(`sonnet` ⊂ `claude-sonnet-5`)优先,其次按编辑距离;距离超过
5
+ * `max(2, ⌈长度 / 3⌉)` 的不算接近。只比较 id 本身(不含 `provider/` 前缀),大小写不敏感。
6
+ */
7
+ /** Levenshtein 距离(插入 / 删除 / 替换各计 1)。 */
8
+ export function editDistance(a, b) {
9
+ if (a === b)
10
+ return 0;
11
+ if (a.length === 0)
12
+ return b.length;
13
+ if (b.length === 0)
14
+ return a.length;
15
+ let prev = Array.from({ length: b.length + 1 }, (_, i) => i);
16
+ for (let i = 1; i <= a.length; i++) {
17
+ const row = [i];
18
+ for (let j = 1; j <= b.length; j++) {
19
+ const cost = a[i - 1] === b[j - 1] ? 0 : 1;
20
+ row[j] = Math.min((prev[j] ?? 0) + 1, (row[j - 1] ?? 0) + 1, (prev[j - 1] ?? 0) + cost);
21
+ }
22
+ prev = row;
23
+ }
24
+ return prev[b.length] ?? 0;
25
+ }
26
+ /**
27
+ * 从 `candidates` 里挑与 `needle` 最接近的至多 `limit` 个。`key` 取参与比较的部分
28
+ * (缺省整串),返回原值。
29
+ */
30
+ export function closest(needle, candidates, limit = 5, key = String) {
31
+ const target = needle.toLowerCase();
32
+ if (target === "")
33
+ return [];
34
+ const budget = Math.max(2, Math.ceil(target.length / 3));
35
+ const scored = [];
36
+ candidates.forEach((item, index) => {
37
+ const value = key(item).toLowerCase();
38
+ if (value === "")
39
+ return;
40
+ if (value.includes(target) || target.includes(value)) {
41
+ scored.push({ item, score: Math.abs(value.length - target.length) / 1000, index });
42
+ return;
43
+ }
44
+ const distance = editDistance(target, value);
45
+ if (distance <= budget)
46
+ scored.push({ item, score: distance, index });
47
+ });
48
+ return scored
49
+ .sort((a, b) => a.score - b.score || a.index - b.index)
50
+ .slice(0, limit)
51
+ .map((entry) => entry.item);
52
+ }
53
+ /** 解析失败的一行说明(不含前缀标签):`渠道不存在:x;该模型可用渠道:…` 等。 */
54
+ export function describeLookupFailure(ref, failure) {
55
+ const list = failure.candidates.slice(0, 20).join(", ");
56
+ switch (failure.reason) {
57
+ case "channel_not_found":
58
+ return failure.candidates.length > 0
59
+ ? `渠道不存在:${ref};该模型可用渠道:${list}`
60
+ : `渠道不存在:${ref};该模型没有可选渠道(去掉 @ 后缀)`;
61
+ case "provider_not_found":
62
+ return failure.candidates.length > 0
63
+ ? `供应商不存在:${ref};最接近的供应商:${list}`
64
+ : `供应商不存在:${ref}(ama providers list 查看已配置的供应商)`;
65
+ case "ambiguous":
66
+ return `模型名有歧义:${ref};候选:${list}`;
67
+ default:
68
+ return failure.candidates.length > 0
69
+ ? `模型不存在:${ref};最接近的模型:${list}`
70
+ : `模型不存在:${ref}(ama models list 查看可用模型)`;
71
+ }
72
+ }
package/dist/ai/sse.d.ts CHANGED
@@ -28,5 +28,9 @@ export declare class SseParser {
28
28
  private processLine;
29
29
  private dispatch;
30
30
  }
31
- /** 从字节流读 SSE 事件;`signal` 中止时停止读取(调用方据此产出 aborted)。 */
32
- export declare function readSseEvents(body: ReadableStream<Uint8Array>, signal?: AbortSignal): AsyncGenerator<SseEvent>;
31
+ /**
32
+ * 从字节流读 SSE 事件;`signal` 中止时停止读取(调用方据此产出 aborted)。
33
+ * `idleTimeoutMs`:等待下一块字节的上限,每收到一块即重新计时(消费者处理事件的时间不计);
34
+ * 超时取消底层流并抛 `IdleTimeoutError`(phase `stream`)。
35
+ */
36
+ export declare function readSseEvents(body: ReadableStream<Uint8Array>, signal?: AbortSignal, idleTimeoutMs?: number): AsyncGenerator<SseEvent>;
package/dist/ai/sse.js CHANGED
@@ -6,6 +6,7 @@
6
6
  * 第一个空格去掉;多条 data 以 LF 连接。为兼容不规范服务端,流结束时未以空行收尾的最后一个
7
7
  * 事件也会分派。
8
8
  */
9
+ import { IdleTimeoutError } from "./http.js";
9
10
  export class SseParser {
10
11
  buffer = "";
11
12
  event;
@@ -102,8 +103,12 @@ export class SseParser {
102
103
  return hadContent ? event : undefined;
103
104
  }
104
105
  }
105
- /** 从字节流读 SSE 事件;`signal` 中止时停止读取(调用方据此产出 aborted)。 */
106
- export async function* readSseEvents(body, signal) {
106
+ /**
107
+ * 从字节流读 SSE 事件;`signal` 中止时停止读取(调用方据此产出 aborted)。
108
+ * `idleTimeoutMs`:等待下一块字节的上限,每收到一块即重新计时(消费者处理事件的时间不计);
109
+ * 超时取消底层流并抛 `IdleTimeoutError`(phase `stream`)。
110
+ */
111
+ export async function* readSseEvents(body, signal, idleTimeoutMs) {
107
112
  const reader = body.getReader();
108
113
  const decoder = new TextDecoder("utf-8");
109
114
  const parser = new SseParser();
@@ -112,11 +117,25 @@ export async function* readSseEvents(body, signal) {
112
117
  };
113
118
  signal?.addEventListener("abort", onAbort, { once: true });
114
119
  let drained = false;
120
+ let idle;
121
+ let stalled = false;
122
+ const arm = () => {
123
+ if (idleTimeoutMs === undefined || idleTimeoutMs <= 0)
124
+ return;
125
+ idle = setTimeout(() => {
126
+ stalled = true;
127
+ reader.cancel().catch(() => undefined);
128
+ }, idleTimeoutMs);
129
+ };
115
130
  try {
116
131
  while (true) {
117
132
  if (signal?.aborted)
118
133
  return;
134
+ arm();
119
135
  const { value, done } = await reader.read();
136
+ clearTimeout(idle);
137
+ if (stalled && !signal?.aborted)
138
+ throw new IdleTimeoutError(idleTimeoutMs ?? 0, "stream");
120
139
  if (done)
121
140
  break;
122
141
  if (signal?.aborted)
@@ -131,6 +150,7 @@ export async function* readSseEvents(body, signal) {
131
150
  yield event;
132
151
  }
133
152
  finally {
153
+ clearTimeout(idle);
134
154
  signal?.removeEventListener("abort", onAbort);
135
155
  // 消费者提前退出(读到终止事件即 break)或中止:取消底层流,释放连接
136
156
  if (!drained)
@@ -15,6 +15,11 @@
15
15
  * - [W3-C0] 第三波 §1.3 的五个缓存兼容开关单列为 `PromptCacheCompat`(各协议共用),只并入
16
16
  * `ProviderCompat`(全部可选),不改各协议 compat 接口——`detectCompat` 的返回形状不变,
17
17
  * 缺省值由 C1a 在协议层按端点推断。
18
+ * - [W5-C0] 第五波(docs/wave5-plan.md §2.1、§3.1):`Model` 加 models.dev 元数据字段
19
+ * (`family / knowledge / releaseDate / inputLimit / status`);`AnthropicMessagesCompat` 加
20
+ * `sendInterleavedThinkingBeta / sendCacheControl`、`OpenAIResponsesCompat` 加
21
+ * `explicitCacheField`,全部可选(缺省由 W5-M2 的主机推断表给出);`ProviderData.channels /
22
+ * defaultChannel` 已有,内置供应商(`BuiltinProvider`)同样可带。
18
23
  */
19
24
  export type KnownApi = "anthropic-messages" | "openai-completions" | "openai-responses" | "google-generative-ai";
20
25
  export type Api = KnownApi | (string & {});
@@ -27,7 +32,8 @@ export type CacheRetention = "none" | "short" | "long";
27
32
  * 真实回合,`summary` 是压缩 / 分支摘要,`warm` 是缓存保温重放,`probe` 是 `models check` /
28
33
  * `cache-probe` 一类的探测。缺省视为 `turn`。协议层只透传,不改变请求体。
29
34
  */
30
- export type RequestPurpose = "turn" | "summary" | "warm" | "probe";
35
+ /** `classify`:auto 权限模式的分类请求(独立请求,不经会话层缓存观测、不触发保温)。 */
36
+ export type RequestPurpose = "turn" | "summary" | "warm" | "probe" | "classify";
31
37
  /** `provider/model-id` 拆开后的引用。 */
32
38
  export interface ModelRef {
33
39
  provider: string;
@@ -206,6 +212,12 @@ export interface AnthropicMessagesCompat {
206
212
  /** true:新模型用 `effort` 参数;false:老模型用 `budget_tokens`。 */
207
213
  adaptiveThinking: boolean;
208
214
  maxCacheBreakpoints: number;
215
+ /**
216
+ * [W5-C0] 发 `interleaved-thinking` beta 头;缺省(W5-M2 主机表):官方端点 true、其它主机 false。
217
+ */
218
+ sendInterleavedThinkingBeta?: boolean;
219
+ /** [W5-C0] 打 `cache_control`;缺省 true,忽略它的端点(DeepSeek 等)可关以减小请求体。 */
220
+ sendCacheControl?: boolean;
209
221
  }
210
222
  /** B8 补全。 */
211
223
  export interface GoogleCompat {
@@ -216,6 +228,8 @@ export interface GoogleCompat {
216
228
  export interface OpenAIResponsesCompat {
217
229
  supportsReasoningSummary: boolean;
218
230
  supportsStore: boolean;
231
+ /** [W5-C0] 端点私有的显式缓存字段:`volcengine` = 火山方舟 `caching: { type: "enabled" }`。 */
232
+ explicitCacheField?: "volcengine";
219
233
  }
220
234
  /**
221
235
  * [W3-C0] 供应商不报缓存时的处理(第三波 §1.6):`auto` 按响应自动判定三态;`silent` /
@@ -301,6 +315,16 @@ export interface Model {
301
315
  channel?: string;
302
316
  /** 该模型挂载的全部渠道,首个为首选(多渠道供应商才有)。 */
303
317
  channels?: string[];
318
+ /** 模型家族(如 `claude-sonnet`)。 */
319
+ family?: string;
320
+ /** 知识截止(`YYYY-MM` 或 `YYYY-MM-DD`)。 */
321
+ knowledge?: string;
322
+ /** 发布日期(`YYYY-MM-DD`)。 */
323
+ releaseDate?: string;
324
+ /** 输入上限(token),与 `contextWindow` 不同的模型才有。 */
325
+ inputLimit?: number;
326
+ /** 发布状态;正式版不填(deprecated 的模型在快照里已过滤)。 */
327
+ status?: "beta";
304
328
  }
305
329
  /** 物化后的渠道(docs/providers.md「渠道」);key 不在这里,经 `resolveApiKey(provider, channel)` 取。 */
306
330
  export interface ProviderChannel {
@@ -325,9 +349,12 @@ export interface ProviderData {
325
349
  /** 本地服务 false:无 key 也能用。 */
326
350
  requiresApiKey: boolean;
327
351
  builtin: boolean;
328
- /** 显式配置的渠道(没有 `channels` 的供应商不填,按单渠道处理)。 */
352
+ /**
353
+ * 渠道(没有 `channels` 的供应商不填,按单渠道处理)。[W5-C0] 内置供应商也可带内置渠道,
354
+ * 用户配置同名字段级覆盖、新名追加(物化归 W5-M2)。
355
+ */
329
356
  channels?: ProviderChannel[];
330
- /** 首选渠道名(有 `channels` 时)。 */
357
+ /** 首选渠道名(有 `channels` 时;用户配置优先)。 */
331
358
  defaultChannel?: string;
332
359
  }
333
360
  /** `catalog/*.json` 文件形状(§3.4)。 */
@@ -342,6 +369,11 @@ export interface StreamOptions {
342
369
  /** 值为 null 表示删除该头。 */
343
370
  headers?: Record<string, string | null>;
344
371
  timeoutMs?: number;
372
+ /**
373
+ * 空闲超时:等响应头、以及流中两块数据之间的最长间隔(每收到字节即重新计时)。缺省 300 000,
374
+ * 0 关闭。超时报 `idle timeout` 错误,会话层按可重试处理。
375
+ */
376
+ idleTimeoutMs?: number;
345
377
  maxTokens?: number;
346
378
  temperature?: number;
347
379
  thinkingLevel?: ModelThinkingLevel;
@@ -434,7 +466,8 @@ export type ModelLookup = {
434
466
  provider: ProviderData;
435
467
  } | {
436
468
  ok: false;
437
- reason: "not_found" | "ambiguous" | "provider_not_found";
469
+ /** `channel_not_found`:模型在,`@渠道` 不在(候选是该模型可用的 `provider/model@渠道`)。 */
470
+ reason: "not_found" | "ambiguous" | "provider_not_found" | "channel_not_found";
438
471
  candidates: string[];
439
472
  };
440
473
  export interface ProviderRegistryApi {
package/dist/ai/types.js CHANGED
@@ -15,5 +15,10 @@
15
15
  * - [W3-C0] 第三波 §1.3 的五个缓存兼容开关单列为 `PromptCacheCompat`(各协议共用),只并入
16
16
  * `ProviderCompat`(全部可选),不改各协议 compat 接口——`detectCompat` 的返回形状不变,
17
17
  * 缺省值由 C1a 在协议层按端点推断。
18
+ * - [W5-C0] 第五波(docs/wave5-plan.md §2.1、§3.1):`Model` 加 models.dev 元数据字段
19
+ * (`family / knowledge / releaseDate / inputLimit / status`);`AnthropicMessagesCompat` 加
20
+ * `sendInterleavedThinkingBeta / sendCacheControl`、`OpenAIResponsesCompat` 加
21
+ * `explicitCacheField`,全部可选(缺省由 W5-M2 的主机推断表给出);`ProviderData.channels /
22
+ * defaultChannel` 已有,内置供应商(`BuiltinProvider`)同样可带。
18
23
  */
19
24
  export {};