@armadra/agent 0.0.0-stage → 0.3.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 (433) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +470 -2
  4. package/dist/agent/agent.d.ts +56 -0
  5. package/dist/agent/agent.js +129 -0
  6. package/dist/agent/loop.d.ts +51 -0
  7. package/dist/agent/loop.js +158 -0
  8. package/dist/agent/queue.d.ts +25 -0
  9. package/dist/agent/queue.js +55 -0
  10. package/dist/agent/retry.d.ts +22 -0
  11. package/dist/agent/retry.js +92 -0
  12. package/dist/agent/schema.d.ts +27 -0
  13. package/dist/agent/schema.js +186 -0
  14. package/dist/agent/session-cache.d.ts +100 -0
  15. package/dist/agent/session-cache.js +514 -0
  16. package/dist/agent/session-compaction.d.ts +49 -0
  17. package/dist/agent/session-compaction.js +251 -0
  18. package/dist/agent/session-core.d.ts +103 -0
  19. package/dist/agent/session-core.js +7 -0
  20. package/dist/agent/session-run.d.ts +55 -0
  21. package/dist/agent/session-run.js +246 -0
  22. package/dist/agent/session-state.d.ts +39 -0
  23. package/dist/agent/session-state.js +119 -0
  24. package/dist/agent/session-subagent.d.ts +54 -0
  25. package/dist/agent/session-subagent.js +157 -0
  26. package/dist/agent/session-sync.d.ts +20 -0
  27. package/dist/agent/session-sync.js +111 -0
  28. package/dist/agent/session-tools.d.ts +24 -0
  29. package/dist/agent/session-tools.js +277 -0
  30. package/dist/agent/session.d.ts +117 -0
  31. package/dist/agent/session.js +485 -0
  32. package/dist/agent/system-prompt.d.ts +49 -0
  33. package/dist/agent/system-prompt.js +121 -0
  34. package/dist/agent/tool-runner.d.ts +64 -0
  35. package/dist/agent/tool-runner.js +309 -0
  36. package/dist/agent/transform.d.ts +26 -0
  37. package/dist/agent/transform.js +171 -0
  38. package/dist/agent/types.d.ts +378 -0
  39. package/dist/agent/types.js +21 -0
  40. package/dist/ai/apis/anthropic-messages.d.ts +26 -0
  41. package/dist/ai/apis/anthropic-messages.js +214 -0
  42. package/dist/ai/apis/anthropic-request.d.ts +42 -0
  43. package/dist/ai/apis/anthropic-request.js +282 -0
  44. package/dist/ai/apis/api.d.ts +28 -0
  45. package/dist/ai/apis/api.js +102 -0
  46. package/dist/ai/apis/cache-params.d.ts +48 -0
  47. package/dist/ai/apis/cache-params.js +163 -0
  48. package/dist/ai/apis/google-generative-ai.d.ts +32 -0
  49. package/dist/ai/apis/google-generative-ai.js +249 -0
  50. package/dist/ai/apis/google-request.d.ts +40 -0
  51. package/dist/ai/apis/google-request.js +255 -0
  52. package/dist/ai/apis/openai-compat.d.ts +35 -0
  53. package/dist/ai/apis/openai-compat.js +142 -0
  54. package/dist/ai/apis/openai-completions.d.ts +28 -0
  55. package/dist/ai/apis/openai-completions.js +246 -0
  56. package/dist/ai/apis/openai-request.d.ts +35 -0
  57. package/dist/ai/apis/openai-request.js +303 -0
  58. package/dist/ai/apis/openai-responses-request.d.ts +52 -0
  59. package/dist/ai/apis/openai-responses-request.js +266 -0
  60. package/dist/ai/apis/openai-responses.d.ts +28 -0
  61. package/dist/ai/apis/openai-responses.js +304 -0
  62. package/dist/ai/apis/shared.d.ts +56 -0
  63. package/dist/ai/apis/shared.js +179 -0
  64. package/dist/ai/cache/economics.d.ts +24 -0
  65. package/dist/ai/cache/economics.js +69 -0
  66. package/dist/ai/cache/fingerprint.d.ts +17 -0
  67. package/dist/ai/cache/fingerprint.js +39 -0
  68. package/dist/ai/cache/miss.d.ts +49 -0
  69. package/dist/ai/cache/miss.js +96 -0
  70. package/dist/ai/cache/reporting.d.ts +39 -0
  71. package/dist/ai/cache/reporting.js +103 -0
  72. package/dist/ai/cache/types.d.ts +94 -0
  73. package/dist/ai/cache/types.js +19 -0
  74. package/dist/ai/cache/warmer.d.ts +94 -0
  75. package/dist/ai/cache/warmer.js +224 -0
  76. package/dist/ai/context.d.ts +35 -0
  77. package/dist/ai/context.js +114 -0
  78. package/dist/ai/cost.d.ts +21 -0
  79. package/dist/ai/cost.js +60 -0
  80. package/dist/ai/event-stream.d.ts +33 -0
  81. package/dist/ai/event-stream.js +101 -0
  82. package/dist/ai/fake/fake-provider.d.ts +68 -0
  83. package/dist/ai/fake/fake-provider.js +278 -0
  84. package/dist/ai/fake/fake-script.d.ts +69 -0
  85. package/dist/ai/fake/fake-script.js +142 -0
  86. package/dist/ai/http.d.ts +54 -0
  87. package/dist/ai/http.js +212 -0
  88. package/dist/ai/json-partial.d.ts +17 -0
  89. package/dist/ai/json-partial.js +243 -0
  90. package/dist/ai/overflow.d.ts +22 -0
  91. package/dist/ai/overflow.js +61 -0
  92. package/dist/ai/providers/auth.d.ts +71 -0
  93. package/dist/ai/providers/auth.js +202 -0
  94. package/dist/ai/providers/builtin.d.ts +23 -0
  95. package/dist/ai/providers/builtin.js +148 -0
  96. package/dist/ai/providers/catalog-data.d.ts +5 -0
  97. package/dist/ai/providers/catalog-data.js +19 -0
  98. package/dist/ai/providers/catalog.d.ts +28 -0
  99. package/dist/ai/providers/catalog.js +166 -0
  100. package/dist/ai/providers/channels.d.ts +51 -0
  101. package/dist/ai/providers/channels.js +96 -0
  102. package/dist/ai/providers/enrich.d.ts +34 -0
  103. package/dist/ai/providers/enrich.js +86 -0
  104. package/dist/ai/providers/models-dev-cache.d.ts +53 -0
  105. package/dist/ai/providers/models-dev-cache.js +147 -0
  106. package/dist/ai/providers/models-dev.d.ts +99 -0
  107. package/dist/ai/providers/models-dev.js +315 -0
  108. package/dist/ai/providers/registry.d.ts +114 -0
  109. package/dist/ai/providers/registry.js +458 -0
  110. package/dist/ai/sse.d.ts +32 -0
  111. package/dist/ai/sse.js +140 -0
  112. package/dist/ai/thinking.d.ts +42 -0
  113. package/dist/ai/thinking.js +101 -0
  114. package/dist/ai/types.d.ts +448 -0
  115. package/dist/ai/types.js +19 -0
  116. package/dist/bundle/ama-sandbox.cjs +324 -0
  117. package/dist/bundle/ama.cjs +27837 -0
  118. package/dist/bundle.d.ts +9 -0
  119. package/dist/bundle.js +15 -0
  120. package/dist/cli/args.d.ts +85 -0
  121. package/dist/cli/args.js +408 -0
  122. package/dist/cli/bootstrap.d.ts +18 -0
  123. package/dist/cli/bootstrap.js +399 -0
  124. package/dist/cli/compose-providers.d.ts +37 -0
  125. package/dist/cli/compose-providers.js +107 -0
  126. package/dist/cli/compose-session.d.ts +72 -0
  127. package/dist/cli/compose-session.js +370 -0
  128. package/dist/cli/compose-store.d.ts +24 -0
  129. package/dist/cli/compose-store.js +125 -0
  130. package/dist/cli/compose.d.ts +108 -0
  131. package/dist/cli/compose.js +221 -0
  132. package/dist/cli/default-model.d.ts +16 -0
  133. package/dist/cli/default-model.js +24 -0
  134. package/dist/cli/deps.d.ts +207 -0
  135. package/dist/cli/deps.js +12 -0
  136. package/dist/cli/exit-codes.d.ts +29 -0
  137. package/dist/cli/exit-codes.js +40 -0
  138. package/dist/cli/main.d.ts +27 -0
  139. package/dist/cli/main.js +177 -0
  140. package/dist/cli/runtime.d.ts +90 -0
  141. package/dist/cli/runtime.js +8 -0
  142. package/dist/cli/startup-screen.d.ts +15 -0
  143. package/dist/cli/startup-screen.js +56 -0
  144. package/dist/cli/startup-steps.d.ts +35 -0
  145. package/dist/cli/startup-steps.js +202 -0
  146. package/dist/cli/subcommands/auth.d.ts +12 -0
  147. package/dist/cli/subcommands/auth.js +91 -0
  148. package/dist/cli/subcommands/config.d.ts +53 -0
  149. package/dist/cli/subcommands/config.js +277 -0
  150. package/dist/cli/subcommands/context.d.ts +21 -0
  151. package/dist/cli/subcommands/context.js +42 -0
  152. package/dist/cli/subcommands/doctor.d.ts +11 -0
  153. package/dist/cli/subcommands/doctor.js +246 -0
  154. package/dist/cli/subcommands/init.d.ts +6 -0
  155. package/dist/cli/subcommands/init.js +22 -0
  156. package/dist/cli/subcommands/model-meta.d.ts +16 -0
  157. package/dist/cli/subcommands/model-meta.js +54 -0
  158. package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
  159. package/dist/cli/subcommands/models-cache-probe.js +190 -0
  160. package/dist/cli/subcommands/models-discover.d.ts +46 -0
  161. package/dist/cli/subcommands/models-discover.js +232 -0
  162. package/dist/cli/subcommands/models.d.ts +40 -0
  163. package/dist/cli/subcommands/models.js +152 -0
  164. package/dist/cli/subcommands/providers-list.d.ts +8 -0
  165. package/dist/cli/subcommands/providers-list.js +97 -0
  166. package/dist/cli/subcommands/providers-plan.d.ts +79 -0
  167. package/dist/cli/subcommands/providers-plan.js +215 -0
  168. package/dist/cli/subcommands/providers.d.ts +27 -0
  169. package/dist/cli/subcommands/providers.js +433 -0
  170. package/dist/cli/subcommands/sessions.d.ts +11 -0
  171. package/dist/cli/subcommands/sessions.js +100 -0
  172. package/dist/codemode/capability.d.ts +37 -0
  173. package/dist/codemode/capability.js +55 -0
  174. package/dist/codemode/declarations.d.ts +44 -0
  175. package/dist/codemode/declarations.js +111 -0
  176. package/dist/codemode/host-side.d.ts +59 -0
  177. package/dist/codemode/host-side.js +253 -0
  178. package/dist/codemode/modes.d.ts +23 -0
  179. package/dist/codemode/modes.js +40 -0
  180. package/dist/codemode/protocol.d.ts +91 -0
  181. package/dist/codemode/protocol.js +114 -0
  182. package/dist/codemode/sandbox-entry.d.ts +25 -0
  183. package/dist/codemode/sandbox-entry.js +323 -0
  184. package/dist/codemode/store.d.ts +26 -0
  185. package/dist/codemode/store.js +53 -0
  186. package/dist/codemode/tool.d.ts +105 -0
  187. package/dist/codemode/tool.js +283 -0
  188. package/dist/compaction/branch-summary.d.ts +30 -0
  189. package/dist/compaction/branch-summary.js +79 -0
  190. package/dist/compaction/breaker.d.ts +32 -0
  191. package/dist/compaction/breaker.js +65 -0
  192. package/dist/compaction/cut-point.d.ts +23 -0
  193. package/dist/compaction/cut-point.js +70 -0
  194. package/dist/compaction/estimate.d.ts +30 -0
  195. package/dist/compaction/estimate.js +114 -0
  196. package/dist/compaction/prune-tier.d.ts +31 -0
  197. package/dist/compaction/prune-tier.js +83 -0
  198. package/dist/compaction/serialize.d.ts +20 -0
  199. package/dist/compaction/serialize.js +115 -0
  200. package/dist/compaction/summarize-tier.d.ts +111 -0
  201. package/dist/compaction/summarize-tier.js +305 -0
  202. package/dist/config/auth-file.d.ts +39 -0
  203. package/dist/config/auth-file.js +92 -0
  204. package/dist/config/context-files.d.ts +30 -0
  205. package/dist/config/context-files.js +77 -0
  206. package/dist/config/init.d.ts +30 -0
  207. package/dist/config/init.js +92 -0
  208. package/dist/config/json-schema.d.ts +14 -0
  209. package/dist/config/json-schema.js +182 -0
  210. package/dist/config/load.d.ts +45 -0
  211. package/dist/config/load.js +97 -0
  212. package/dist/config/merge.d.ts +73 -0
  213. package/dist/config/merge.js +248 -0
  214. package/dist/config/paths.d.ts +38 -0
  215. package/dist/config/paths.js +108 -0
  216. package/dist/config/profile.d.ts +27 -0
  217. package/dist/config/profile.js +65 -0
  218. package/dist/config/schema.d.ts +34 -0
  219. package/dist/config/schema.js +476 -0
  220. package/dist/config/trust.d.ts +42 -0
  221. package/dist/config/trust.js +122 -0
  222. package/dist/config/types.d.ts +190 -0
  223. package/dist/config/types.js +29 -0
  224. package/dist/config/write.d.ts +10 -0
  225. package/dist/config/write.js +25 -0
  226. package/dist/errors.d.ts +28 -0
  227. package/dist/errors.js +30 -0
  228. package/dist/hooks/config.d.ts +49 -0
  229. package/dist/hooks/config.js +102 -0
  230. package/dist/hooks/dispatcher.d.ts +41 -0
  231. package/dist/hooks/dispatcher.js +104 -0
  232. package/dist/hooks/matcher.d.ts +22 -0
  233. package/dist/hooks/matcher.js +108 -0
  234. package/dist/hooks/protocol.d.ts +33 -0
  235. package/dist/hooks/protocol.js +240 -0
  236. package/dist/hooks/runner.d.ts +30 -0
  237. package/dist/hooks/runner.js +143 -0
  238. package/dist/hooks/types.d.ts +147 -0
  239. package/dist/hooks/types.js +20 -0
  240. package/dist/host/api-impl.d.ts +75 -0
  241. package/dist/host/api-impl.js +173 -0
  242. package/dist/host/loader.d.ts +31 -0
  243. package/dist/host/loader.js +147 -0
  244. package/dist/host/types.d.ts +169 -0
  245. package/dist/host/types.js +14 -0
  246. package/dist/host.d.ts +5 -0
  247. package/dist/host.js +4 -0
  248. package/dist/index.d.ts +41 -0
  249. package/dist/index.js +28 -0
  250. package/dist/modes/commands-core.d.ts +44 -0
  251. package/dist/modes/commands-core.js +171 -0
  252. package/dist/modes/image-input.d.ts +27 -0
  253. package/dist/modes/image-input.js +78 -0
  254. package/dist/modes/interactive/approval-dialog.d.ts +48 -0
  255. package/dist/modes/interactive/approval-dialog.js +202 -0
  256. package/dist/modes/interactive/commands.d.ts +41 -0
  257. package/dist/modes/interactive/commands.js +201 -0
  258. package/dist/modes/interactive/completion.d.ts +53 -0
  259. package/dist/modes/interactive/completion.js +157 -0
  260. package/dist/modes/interactive/interactive-mode.d.ts +46 -0
  261. package/dist/modes/interactive/interactive-mode.js +491 -0
  262. package/dist/modes/interactive/key-dispatch.d.ts +29 -0
  263. package/dist/modes/interactive/key-dispatch.js +107 -0
  264. package/dist/modes/interactive/line/line-editor.d.ts +50 -0
  265. package/dist/modes/interactive/line/line-editor.js +232 -0
  266. package/dist/modes/interactive/line/line-mode.d.ts +20 -0
  267. package/dist/modes/interactive/line/line-mode.js +218 -0
  268. package/dist/modes/interactive/line/line-render.d.ts +35 -0
  269. package/dist/modes/interactive/line/line-render.js +171 -0
  270. package/dist/modes/interactive/line/paste-state.d.ts +26 -0
  271. package/dist/modes/interactive/line/paste-state.js +72 -0
  272. package/dist/modes/interactive/message-view.d.ts +77 -0
  273. package/dist/modes/interactive/message-view.js +269 -0
  274. package/dist/modes/interactive/pickers.d.ts +42 -0
  275. package/dist/modes/interactive/pickers.js +115 -0
  276. package/dist/modes/interactive/startup-ui.d.ts +33 -0
  277. package/dist/modes/interactive/startup-ui.js +268 -0
  278. package/dist/modes/interactive/status-bar.d.ts +48 -0
  279. package/dist/modes/interactive/status-bar.js +139 -0
  280. package/dist/modes/interactive/tool-view.d.ts +95 -0
  281. package/dist/modes/interactive/tool-view.js +344 -0
  282. package/dist/modes/print/json-event.d.ts +15 -0
  283. package/dist/modes/print/json-event.js +39 -0
  284. package/dist/modes/print/print-mode.d.ts +17 -0
  285. package/dist/modes/print/print-mode.js +107 -0
  286. package/dist/modes/rpc/commands.d.ts +40 -0
  287. package/dist/modes/rpc/commands.js +263 -0
  288. package/dist/modes/rpc/jsonl.d.ts +16 -0
  289. package/dist/modes/rpc/jsonl.js +55 -0
  290. package/dist/modes/rpc/rpc-mode.d.ts +22 -0
  291. package/dist/modes/rpc/rpc-mode.js +153 -0
  292. package/dist/modes/session-report.d.ts +55 -0
  293. package/dist/modes/session-report.js +278 -0
  294. package/dist/modes/shared.d.ts +13 -0
  295. package/dist/modes/shared.js +52 -0
  296. package/dist/modes/startup-ui-text.d.ts +16 -0
  297. package/dist/modes/startup-ui-text.js +103 -0
  298. package/dist/permissions/broker.d.ts +47 -0
  299. package/dist/permissions/broker.js +107 -0
  300. package/dist/permissions/dangerous.d.ts +47 -0
  301. package/dist/permissions/dangerous.js +370 -0
  302. package/dist/permissions/pipeline.d.ts +51 -0
  303. package/dist/permissions/pipeline.js +181 -0
  304. package/dist/permissions/preview.d.ts +43 -0
  305. package/dist/permissions/preview.js +463 -0
  306. package/dist/permissions/rules.d.ts +58 -0
  307. package/dist/permissions/rules.js +249 -0
  308. package/dist/permissions/types.d.ts +100 -0
  309. package/dist/permissions/types.js +18 -0
  310. package/dist/rpc.d.ts +173 -0
  311. package/dist/rpc.js +13 -0
  312. package/dist/sdk.d.ts +98 -0
  313. package/dist/sdk.js +195 -0
  314. package/dist/session/manager.d.ts +70 -0
  315. package/dist/session/manager.js +278 -0
  316. package/dist/session/migrate.d.ts +19 -0
  317. package/dist/session/migrate.js +53 -0
  318. package/dist/session/projection.d.ts +50 -0
  319. package/dist/session/projection.js +184 -0
  320. package/dist/session/store.d.ts +47 -0
  321. package/dist/session/store.js +210 -0
  322. package/dist/session/tree.d.ts +21 -0
  323. package/dist/session/tree.js +88 -0
  324. package/dist/session/types.d.ts +201 -0
  325. package/dist/session/types.js +18 -0
  326. package/dist/skills/discover.d.ts +60 -0
  327. package/dist/skills/discover.js +160 -0
  328. package/dist/skills/expand.d.ts +35 -0
  329. package/dist/skills/expand.js +46 -0
  330. package/dist/skills/frontmatter.d.ts +27 -0
  331. package/dist/skills/frontmatter.js +157 -0
  332. package/dist/skills/index-prompt.d.ts +13 -0
  333. package/dist/skills/index-prompt.js +42 -0
  334. package/dist/skills/templates.d.ts +52 -0
  335. package/dist/skills/templates.js +177 -0
  336. package/dist/tools/bash.d.ts +49 -0
  337. package/dist/tools/bash.js +222 -0
  338. package/dist/tools/edit-fuzzy.d.ts +36 -0
  339. package/dist/tools/edit-fuzzy.js +129 -0
  340. package/dist/tools/edit.d.ts +38 -0
  341. package/dist/tools/edit.js +241 -0
  342. package/dist/tools/file-mutex.d.ts +8 -0
  343. package/dist/tools/file-mutex.js +29 -0
  344. package/dist/tools/glob.d.ts +44 -0
  345. package/dist/tools/glob.js +217 -0
  346. package/dist/tools/grep.d.ts +39 -0
  347. package/dist/tools/grep.js +179 -0
  348. package/dist/tools/ignore.d.ts +40 -0
  349. package/dist/tools/ignore.js +174 -0
  350. package/dist/tools/image-file.d.ts +31 -0
  351. package/dist/tools/image-file.js +114 -0
  352. package/dist/tools/ls.d.ts +21 -0
  353. package/dist/tools/ls.js +96 -0
  354. package/dist/tools/output-accumulator.d.ts +48 -0
  355. package/dist/tools/output-accumulator.js +106 -0
  356. package/dist/tools/paths.d.ts +20 -0
  357. package/dist/tools/paths.js +58 -0
  358. package/dist/tools/presets.d.ts +71 -0
  359. package/dist/tools/presets.js +128 -0
  360. package/dist/tools/process-tree.d.ts +35 -0
  361. package/dist/tools/process-tree.js +125 -0
  362. package/dist/tools/read.d.ts +24 -0
  363. package/dist/tools/read.js +132 -0
  364. package/dist/tools/registry.d.ts +43 -0
  365. package/dist/tools/registry.js +106 -0
  366. package/dist/tools/shell.d.ts +38 -0
  367. package/dist/tools/shell.js +91 -0
  368. package/dist/tools/task.d.ts +29 -0
  369. package/dist/tools/task.js +107 -0
  370. package/dist/tools/todo.d.ts +28 -0
  371. package/dist/tools/todo.js +107 -0
  372. package/dist/tools/truncate.d.ts +44 -0
  373. package/dist/tools/truncate.js +175 -0
  374. package/dist/tools/types.d.ts +135 -0
  375. package/dist/tools/types.js +19 -0
  376. package/dist/tools/write.d.ts +20 -0
  377. package/dist/tools/write.js +84 -0
  378. package/dist/tui/ansi.d.ts +29 -0
  379. package/dist/tui/ansi.js +420 -0
  380. package/dist/tui/component.d.ts +38 -0
  381. package/dist/tui/component.js +13 -0
  382. package/dist/tui/components/box.d.ts +26 -0
  383. package/dist/tui/components/box.js +65 -0
  384. package/dist/tui/components/container.d.ts +14 -0
  385. package/dist/tui/components/container.js +39 -0
  386. package/dist/tui/components/editor-buffer.d.ts +67 -0
  387. package/dist/tui/components/editor-buffer.js +300 -0
  388. package/dist/tui/components/editor-paste.d.ts +29 -0
  389. package/dist/tui/components/editor-paste.js +64 -0
  390. package/dist/tui/components/editor.d.ts +114 -0
  391. package/dist/tui/components/editor.js +530 -0
  392. package/dist/tui/components/key-value.d.ts +29 -0
  393. package/dist/tui/components/key-value.js +48 -0
  394. package/dist/tui/components/loader.d.ts +35 -0
  395. package/dist/tui/components/loader.js +71 -0
  396. package/dist/tui/components/markdown.d.ts +90 -0
  397. package/dist/tui/components/markdown.js +462 -0
  398. package/dist/tui/components/meter.d.ts +29 -0
  399. package/dist/tui/components/meter.js +47 -0
  400. package/dist/tui/components/overlay.d.ts +24 -0
  401. package/dist/tui/components/overlay.js +52 -0
  402. package/dist/tui/components/select-list.d.ts +57 -0
  403. package/dist/tui/components/select-list.js +179 -0
  404. package/dist/tui/components/spacer.d.ts +11 -0
  405. package/dist/tui/components/spacer.js +16 -0
  406. package/dist/tui/components/text.d.ts +30 -0
  407. package/dist/tui/components/text.js +65 -0
  408. package/dist/tui/keybindings.d.ts +66 -0
  409. package/dist/tui/keybindings.js +120 -0
  410. package/dist/tui/keys.d.ts +38 -0
  411. package/dist/tui/keys.js +275 -0
  412. package/dist/tui/stdin-buffer.d.ts +41 -0
  413. package/dist/tui/stdin-buffer.js +206 -0
  414. package/dist/tui/terminal.d.ts +79 -0
  415. package/dist/tui/terminal.js +153 -0
  416. package/dist/tui/theme.d.ts +31 -0
  417. package/dist/tui/theme.js +199 -0
  418. package/dist/tui/tui.d.ts +103 -0
  419. package/dist/tui/tui.js +363 -0
  420. package/dist/tui/vt-screen.d.ts +46 -0
  421. package/dist/tui/vt-screen.js +251 -0
  422. package/dist/tui.d.ts +30 -0
  423. package/dist/tui.js +31 -0
  424. package/dist/version.d.ts +8 -0
  425. package/dist/version.js +24 -0
  426. package/docs/codemode.md +102 -0
  427. package/docs/hooks.md +196 -0
  428. package/docs/host-api.md +161 -0
  429. package/docs/providers.md +531 -0
  430. package/docs/rpc.md +253 -0
  431. package/docs/session-format.md +119 -0
  432. package/docs/tui.md +170 -0
  433. package/package.json +101 -4
@@ -0,0 +1,531 @@
1
+ # 供应商与模型
2
+
3
+ 内置供应商、模型引用、API Key、自定义供应商与中转站、各协议的 compat 开关,以及缓存。设计依据见 [design.md](design.md) §3、§9.1。
4
+
5
+ ## 配置目录
6
+
7
+ 缺省 `~/.config/ama/`(Windows `%APPDATA%\ama\`;`AMA_CONFIG_DIR` 优先,其次 `XDG_CONFIG_HOME/ama`)。数据
8
+ (会话、models.dev 缓存)在另一个目录:`~/.local/share/ama/`(`AMA_DATA_DIR` / `XDG_DATA_HOME`)。
9
+
10
+ ```
11
+ ~/.config/ama/ 0700
12
+ ├── config.json 用户级配置:供应商、渠道、模型、权限、工具、缓存……(直接编辑)
13
+ ├── config.schema.json config.json 的 JSON Schema(编辑器补全与校验;由 ama 生成,会被重写)
14
+ ├── auth.json API key(0600;只在 ama auth set / ama providers add 时创建)
15
+ ├── config.json.bak ama 改写 config.json 前的备份
16
+ ├── hooks.json / trust.json / keybindings.json (按需)
17
+ └── skills/ prompts/ (按需)
18
+ ~/.local/share/ama/
19
+ ├── sessions/ 会话
20
+ └── models-dev.json models.dev 元数据缓存
21
+ ```
22
+
23
+ - `ama init`:建目录(0700)并补齐缺失的 `config.json` 与 `config.schema.json`,逐个打印「已创建」或
24
+ 「已存在,未改动」;已存在的 `config.json` 一律不覆盖(`--force` 也不),`config.schema.json` 不是用户文件,
25
+ 每次 `init` 都重写为当前版本;不创建空的 `auth.json`。
26
+ - **首次运行自动初始化**:CLI 启动时若配置目录不存在,静默建目录并写最小 `config.json` 与 schema
27
+ (`AMA_NO_INIT=1` 关闭;SDK 与测试不触发)。
28
+ - 最小 `config.json`:
29
+
30
+ ```json
31
+ {
32
+ "$schema": "./config.schema.json",
33
+ "version": 1,
34
+ "thinkingLevel": "medium",
35
+ "permission": { "mode": "default" },
36
+ "tools": { "preset": "default" },
37
+ "providers": {}
38
+ }
39
+ ```
40
+
41
+ 不写 `defaultModel`(零配置按「第一个有 key / 本地可达的供应商」挑选)。
42
+
43
+ - `ama config path`:打印配置目录、数据目录与各文件路径(标出是否存在);`ama config edit`:用
44
+ `$VISUAL` / `$EDITOR` 打开 `config.json`(不存在先 `init`),没有编辑器时打印路径。
45
+
46
+ 示例:一个三渠道中转 + 一个图像模型 + 内置供应商的覆盖。
47
+
48
+ ```json
49
+ {
50
+ "$schema": "./config.schema.json",
51
+ "version": 1,
52
+ "defaultModel": "packy/kimi-k2.5",
53
+ "providers": {
54
+ "packy": {
55
+ "apiKey": "$PACKY_API_KEY",
56
+ "channels": {
57
+ "chat": { "api": "openai-completions", "baseUrl": "https://www.packyapi.com/v1" },
58
+ "responses": { "api": "openai-responses", "baseUrl": "https://www.packyapi.com/v1" },
59
+ "messages": { "api": "anthropic-messages", "baseUrl": "https://www.packyapi.com" }
60
+ },
61
+ "models": [
62
+ { "id": "kimi-k2.5", "channels": ["chat", "messages"] },
63
+ { "id": "grok-4.7", "channels": ["responses"] },
64
+ {
65
+ "id": "qwen3-vl-flash",
66
+ "input": ["text", "image"],
67
+ "modelsDev": "llmgateway/qwen3-vl-flash"
68
+ }
69
+ ]
70
+ },
71
+ "deepseek": { "modelOverrides": [{ "id": "deepseek-flash", "contextWindow": 131072 }] }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ## 内置供应商
77
+
78
+ | id | 协议 | baseUrl | API Key 环境变量(顺序) |
79
+ | ------------ | ----------------------------------------------- | --------------------------------------------------- | ------------------------------------------------------------ |
80
+ | `anthropic` | anthropic-messages | `https://api.anthropic.com` | `ANTHROPIC_API_KEY`、`AMA_API_KEY_ANTHROPIC` |
81
+ | `openai` | openai-completions(推理模型 openai-responses) | `https://api.openai.com/v1` | `OPENAI_API_KEY`、`AMA_API_KEY_OPENAI` |
82
+ | `google` | google-generative-ai | `https://generativelanguage.googleapis.com/v1beta` | `GEMINI_API_KEY`、`GOOGLE_API_KEY`、`AMA_API_KEY_GOOGLE` |
83
+ | `deepseek` | openai-completions | `https://api.deepseek.com` | `DEEPSEEK_API_KEY`、`AMA_API_KEY_DEEPSEEK` |
84
+ | `moonshot` | openai-completions | `https://api.moonshot.cn/v1` | `MOONSHOT_API_KEY`、`KIMI_API_KEY`、`AMA_API_KEY_MOONSHOT` |
85
+ | `zhipu` | openai-completions | `https://open.bigmodel.cn/api/paas/v4` | `ZHIPU_API_KEY`、`ZAI_API_KEY`、`AMA_API_KEY_ZHIPU` |
86
+ | `dashscope` | openai-completions | `https://dashscope.aliyuncs.com/compatible-mode/v1` | `DASHSCOPE_API_KEY`、`QWEN_API_KEY`、`AMA_API_KEY_DASHSCOPE` |
87
+ | `openrouter` | openai-completions | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY`、`AMA_API_KEY_OPENROUTER` |
88
+ | `groq` | openai-completions | `https://api.groq.com/openai/v1` | `GROQ_API_KEY`、`AMA_API_KEY_GROQ` |
89
+ | `xai` | openai-completions(目录模型 openai-responses) | `https://api.x.ai/v1` | `XAI_API_KEY`、`AMA_API_KEY_XAI` |
90
+ | `mistral` | openai-completions | `https://api.mistral.ai/v1` | `MISTRAL_API_KEY`、`AMA_API_KEY_MISTRAL` |
91
+ | `ollama` | openai-completions | `http://127.0.0.1:11434/v1` | 可无(`OLLAMA_API_KEY`) |
92
+ | `lmstudio` | openai-completions | `http://127.0.0.1:1234/v1` | 可无 |
93
+
94
+ 另有测试用供应商 `fake`(模型 `fake/echo`、`fake/reasoning`),见下文。
95
+
96
+ 协议列是供应商级缺省;目录条目可以用 `api` 覆盖(openai 的推理模型与 xai 的目录模型走
97
+ `openai-responses`,非推理的 `gpt-4.1`、`gpt-4o*` 仍走 Completions)。
98
+
99
+ ## 模型引用
100
+
101
+ `provider/model-id`,例如 `deepseek/deepseek-v4-pro`、`openrouter/anthropic/claude-sonnet-5.5`。
102
+ 不带供应商前缀时在全部目录里唯一匹配;多家同名时只看已配置 key 的供应商,仍不唯一则报错并列出
103
+ 候选。模型表为空的供应商(ollama、lmstudio、没写 `models` 的自定义供应商)与 baseUrl 指向非官方
104
+ 主机的内置供应商(见「接入中转站」)接受任意 model id。
105
+
106
+ ## API Key 发现顺序
107
+
108
+ 1. `--api-key`(只对 `--model` 指定的供应商)
109
+ 2. `--auth-file` / profile 的 `authFile`
110
+ 3. `~/.config/ama/auth.json`(权限不是 0600 时警告但照用)
111
+ 4. `config.json` 的 `providers.<id>.apiKey`:支持 `$ENV`、`${ENV}`、`!command`,`$$` 表示字面 `$`
112
+ 5. 环境变量(上表顺序;profile `authEnv: false` 时跳过)
113
+ 6. 本地服务(`requiresApiKey: false`)无 key 也能用
114
+
115
+ `auth.json` 的 `apiKey` 以 `!` 开头表示执行命令取值(10 秒超时;空输出或非零退出视为未配置)。
116
+
117
+ ## 自定义供应商
118
+
119
+ ```json
120
+ {
121
+ "providers": {
122
+ "my-proxy": {
123
+ "baseUrl": "https://proxy.example/v1",
124
+ "apiKey": "$MY_PROXY_KEY",
125
+ "models": [{ "id": "gpt-x", "contextWindow": 128000, "maxTokens": 16384, "reasoning": true }],
126
+ "compat": { "maxTokensField": "max_tokens" }
127
+ },
128
+ "deepseek": { "modelOverrides": [{ "id": "deepseek-flash", "contextWindow": 131072 }] }
129
+ }
130
+ }
131
+ ```
132
+
133
+ - `api` 缺省 `openai-completions`;自定义模型缺省 `maxTokens: 8192`、`reasoning: false`、
134
+ `input: ["text"]`;不猜 `contextWindow`(缺省关自动压缩)。
135
+ - `models[]` 同 id 整条替换、新 id 追加;`modelOverrides[]` 只改已有模型的元数据。
136
+
137
+ ## 接入中转站
138
+
139
+ 同一个中转站下,不同模型支持的协议常常不同(有的三种都行,有的只有 Chat 与 Messages,有的只有
140
+ Responses)。一个供应商就够:协议写在模型上。
141
+
142
+ ```sh
143
+ export PACKY_API_KEY=sk-...
144
+ ```
145
+
146
+ ```json
147
+ {
148
+ "providers": {
149
+ "packy": {
150
+ "baseUrl": "https://proxy.example/v1",
151
+ "apiKey": "$PACKY_API_KEY",
152
+ "models": [
153
+ { "id": "deepseek-v4-flash" },
154
+ { "id": "grok-4.7", "api": "openai-responses" },
155
+ { "id": "MiniMax-M2.7", "api": "anthropic-messages" }
156
+ ]
157
+ }
158
+ }
159
+ }
160
+ ```
161
+
162
+ - 模型的 `api` 缺省沿用供应商的(这里是 `openai-completions`);`modelOverrides[]` 也可以改 `api`。
163
+ - 三种协议共用一个 `baseUrl`:Completions / Responses 拼 `/chat/completions`、`/responses`;
164
+ Messages 在 baseUrl 以 `/v1` 结尾时拼 `/messages`,否则 `/v1/messages`。
165
+ - 不想手写 `models`:`ama models discover packy` 列出中转站的模型(`GET {baseUrl}/models`);
166
+ `--probe` 对每个模型依次试供应商协议、completions、responses、messages 的最小请求,记第一个成功
167
+ 的(每模型最多 3 次,`--limit` 限制探测的模型数,缺省 30,执行前打印预估,401 / 403 / 429 即停);
168
+ `--write` 把结果合并进用户级 `config.json`(已有同 id 不覆盖,只写 `id` 与和供应商不同的 `api`,
169
+ 原文件备份为 `config.json.bak`)。上下文等元数据在运行时从 models.dev 缓存补(见下文「模型元数据」),
170
+ 匹配不到的条目没有 `contextWindow`,自动压缩随之关闭,需要时手动补。
171
+
172
+ ```sh
173
+ ama models discover packy --probe --write --limit 8
174
+ ama -p "hi" --model packy/grok-4.7
175
+ ```
176
+
177
+ 零配置:内置 `openai` / `anthropic` 识别 `OPENAI_BASE_URL` / `ANTHROPIC_BASE_URL`(OpenAI SDK 与
178
+ Claude Code 的通行约定),优先级低于 config 与 auth.json 的 `baseUrl`,profile `authEnv: false` 时
179
+ 不读。baseUrl 不在官方主机时,目录外的 model id 也接受,compat 按保守缺省(不发
180
+ `prompt_cache_key`)。`ama config show` 的「供应商」节与 `ama doctor` 标出 baseUrl 来自哪个变量;
181
+ 零配置挑的缺省模型来自官方目录,中转站未必有,用 `--model` 或 `defaultModel` 指定。
182
+
183
+ ```sh
184
+ OPENAI_BASE_URL=https://proxy.example/v1 OPENAI_API_KEY=$PACKY_API_KEY ama -p "hi" --model openai/qwen3.8-flash
185
+ ```
186
+
187
+ ### 渠道(channels):一个供应商、多种接口
188
+
189
+ 同一个中转常常同时开放 Chat Completions(`/v1/chat/completions`)、Responses(`/v1/responses`)与
190
+ Anthropic Messages(`/v1/messages`),且每个模型只在其中一部分接口上可用。**渠道**是「协议 + 地址(+ 可选
191
+ 的 key / headers / compat)」,一个供应商可以有多个渠道,模型声明自己挂在哪些渠道上:
192
+
193
+ ```json
194
+ {
195
+ "providers": {
196
+ "packy": {
197
+ "name": "Packy",
198
+ "apiKey": "$PACKY_API_KEY",
199
+ "channels": {
200
+ "chat": { "api": "openai-completions", "baseUrl": "https://www.packyapi.com/v1" },
201
+ "responses": { "api": "openai-responses", "baseUrl": "https://www.packyapi.com/v1" },
202
+ "messages": { "api": "anthropic-messages", "baseUrl": "https://www.packyapi.com" }
203
+ },
204
+ "defaultChannel": "chat",
205
+ "models": [
206
+ { "id": "kimi-k2.5", "channels": ["chat", "messages"] },
207
+ { "id": "grok-4.7", "channels": ["responses"] },
208
+ { "id": "deepseek-v4-flash", "channels": ["chat", "responses", "messages"] },
209
+ { "id": "glm-5" }
210
+ ]
211
+ }
212
+ }
213
+ }
214
+ ```
215
+
216
+ - **渠道字段**:`api`、`baseUrl` 必填;`apiKey`(同供应商级写法,`$ENV` / `!command` / 字面量;auth.json 里
217
+ `"<provider>@<channel>"` 条目同样生效)、`headers`、`compat`、`authHeader` 可选,缺省继承供应商级。渠道名
218
+ `[A-Za-z0-9][A-Za-z0-9_-]*`,不含 `/` 与 `@`。
219
+ - **模型挂载**:`models[].channels` 列出可用渠道,第一个是首选;不写 → `defaultChannel`(缺省为 `channels`
220
+ 的第一个键)。引用了不存在的渠道 → 配置校验报带路径的错误。
221
+ - **模型引用**:`provider/model` 走首选渠道;`provider/model@channel` 显式指定(`--model`、`defaultModel`、
222
+ `/model`、SDK、RPC `set_model` 一致)。指定的渠道不在该模型的 `channels` 里 → 报错并列出可用的
223
+ `provider/model@channel`。`@` 之后不是该供应商的渠道名时整串仍按模型 id 处理(兼容 id 里本来带 `@` 的模型)。
224
+ - **向后兼容**:没有 `channels` 的供应商(含全部内置供应商)按单渠道处理——供应商级 `api` + `baseUrl`
225
+ 就是隐式的 `default` 渠道;模型级 `api` / `baseUrl` 仍然有效,覆盖在所选渠道之上(等价于一个匿名渠道)。
226
+ 已有配置不用改。写了 `channels` 时供应商级 `api` / `baseUrl` 不再单独成渠道。
227
+ - **运行时**:选中的模型带上该渠道的协议、地址、key、headers 与 compat;会话记录(`model_change`)与
228
+ `ModelRef` 带上 `channel`;缓存的端点键(三态、未命中、粒度推断)是 `供应商|主机|模型@渠道`,同一模型的
229
+ 不同渠道分开统计。价格与 models.dev 元数据按模型共享。
230
+
231
+ ### 一键接入:`ama providers`
232
+
233
+ 只有 baseUrl 与 key 时,一条命令建好供应商、列出模型、补齐元数据:
234
+
235
+ ```sh
236
+ ama providers add packy --base-url https://www.packyapi.com/v1 --key-env PACKY_API_KEY --probe --limit 8 --yes
237
+ ```
238
+
239
+ ```
240
+ ama providers add <id> --base-url <url> [--channel <name>=<api>@<baseUrl> …] [--api <api>|auto]
241
+ [--key-env <VAR>] [--probe] [--limit N] [--probe-models a,b,…]
242
+ [--max-requests N] [--prefer chat,responses,messages] [--include-no-tools] [--yes]
243
+ ama providers list
244
+ ama providers channels <id>
245
+ ama providers remove <id>
246
+ ama providers refresh <id> [--probe …]
247
+ ```
248
+
249
+ - **key**:缺省从 stdin 读(终端下不回显,不进命令行与 shell 历史),存 `auth.json`(0600);给
250
+ `--key-env VAR` 时不读 stdin,`config.json` 里写 `"apiKey": "$VAR"`。供应商已有 key 时不再询问。
251
+ - **候选渠道**:给了 `--channel`(可重复)就只用这些;否则从 `--base-url` 推出三个——`chat`
252
+ (openai-completions,baseUrl 原样)、`responses`(openai-responses,同上)、`messages`
253
+ (anthropic-messages,去掉末尾 `/v1` 的主机根);`--api <api>` 只留对应的一个。
254
+ - **模型列表**:`GET {baseUrl}/models`(第一个 OpenAI 系渠道的地址;只有 Messages 渠道时是 `/v1/models`,先带
255
+ `Authorization: Bearer`,401 / 403 再试 `x-api-key`——实测中转只认前者)。new-api 一类中转在条目上给
256
+ `supported_endpoint_types`(`openai` / `openai-response` / `anthropic`),据此把模型挂到对应渠道;没有提示
257
+ 时挂到全部候选渠道里的第一个;有提示但候选渠道都不支持(如只配了 messages 渠道时的 grok)→ 不写入。
258
+ - **`--probe`**:对选中的模型(`--probe-models` 列出的,缺省按 id 字母序不分大小写取前 `--limit` 个,缺省 30)
259
+ 逐个渠道发一次最小请求(有提示时只试提示里的渠道),**探测成功的渠道全部写进模型的 `channels`**,顺序按
260
+ `--prefer`(缺省 chat、responses、messages);全部失败的模型不写入;未探测的按提示写入并在表格里标「未探测」。
261
+ 执行前打印请求数预估,超过 `--max-requests`(缺省 60)时截断模型数;401 / 403 / 429 立即停止。
262
+ - **渠道收敛**:写入前删掉没有任何模型挂载的候选渠道;`defaultChannel` 取剩下的第一个(按 `--prefer`)。
263
+ - **写入**:用户级 `config.json` 的 `providers.<id>`(先备份为 `config.json.bak`)。模型条目只写 `id` 与
264
+ `channels`;上下文、输出、图像、推理、价格**不写进配置**,运行时从 models.dev 缓存补(见下节),所以
265
+ `refresh` 不会覆盖手改的字段,手写的值永远优先。models.dev 标明不支持工具调用的模型缺省不写入(Agent
266
+ 离不开工具调用),`--include-no-tools` 照写。对已存在的供应商再执行 `add`:只追加新渠道与新模型,已有
267
+ 渠道定义与模型条目一字不改。
268
+ - **确认**:写配置前打印摘要,终端里问一次 y/N;非 TTY 必须带 `--yes`(否则退出 2)。
269
+ - 打印表格:id、渠道、上下文、输出、图像、推理、工具调用、价格(models.dev 的原厂价,$/M 输入 / 输出,
270
+ 中转实际价格可能不同)、匹配方式。
271
+ - `list`:全部供应商(config.json 里的与有 key 的内置供应商)→ 渠道(协议、地址、key 来源:auth.json /
272
+ `$VAR` / 字面量 / 无,从不显示 key)→ 模型数。`channels <id>`:每个渠道的协议、地址与挂载的模型数。
273
+ `remove`:删 `providers.<id>`(备份)与 auth.json 里该供应商的条目。`refresh`:重拉 `/models` 与
274
+ models.dev,只追加新模型(带 `--probe` 时同 add 的探测),已有条目不改;上游已下架的 id 只提示、不删。
275
+
276
+ 实测(2026-10-02,一家同时提供三种接口的中转,22 个模型,共 29 次请求):
277
+
278
+ - `providers add --probe --probe-models kimi-k2.5,grok-4.7,deepseek-v4-flash` 共 8 次请求(1 次列表 + 7 次探测):
279
+ kimi-k2.5 → chat、messages(Responses 不通);grok-4.7 → responses;deepseek-v4-flash 在 Responses 上回
280
+ `incomplete_details.reason: "length"`(中转转发 DeepSeek 时不写 `max_output_tokens`),已按输出截断处理,三种接口都通。
281
+ - models.dev 匹配 22 / 22:原厂条目 19 个(其中 `qwen3.8-max-0902` 去日期后缀匹配到 `alibaba/qwen3.8-max`),多数一致 2 个
282
+ (kimi-k2.5:原厂 `moonshotai/kimi-k2.5` 不在库里,同 canonical 的 11 条取多数 262k / 图像;qwen3-coder-next),
283
+ 唯一条目 1 个(qwen3-vl-flash)。
284
+ - `-p` 经 chat 与 `@messages` 两条渠道都正常;`--image` 四色方块图在 kimi-k2.5(chat、messages)与 qwen3-vl-flash 上都答对
285
+ 红 / 绿 / 蓝 / 黄;对 glm-5(models.dev 标纯文本)直接退出 2、不发请求。
286
+ - 第二个供应商只配 messages 渠道:19 个模型挂上,3 个只支持 Responses 的 grok 不写入;同名模型不加前缀时报歧义并列出两家。
287
+
288
+ ### 模型元数据:models.dev
289
+
290
+ [models.dev](https://models.dev) 汇总了两百多家供应商的模型参数(`https://models.dev/api.json`,约 5 MB)。
291
+ ama 用它给**没写元数据**的自定义模型补上下文、输出上限、输入模态、推理、价格与工具调用能力。
292
+
293
+ - **何时联网**:只有 `ama providers add|refresh`、`ama models discover`、`ama models refresh-catalog`
294
+ 会拉取;**启动不联网**,只读缓存。缓存在数据目录 `models-dev.json`(缺省 `~/.local/share/ama/`,只留用到的
295
+ 字段,约 2.3 MB),记获取时间与 ETag,24 小时内不重拉(`refresh-catalog` 强制,带 `If-None-Match`)。离线或
296
+ 失败时用旧缓存并 warning。`AMA_MODELS_DEV_URL` 换数据源(镜像或本地文件服务)。
297
+ - **优先级**:用户配置(`models[]` / `modelOverrides[]` 里写了的字段)> 内置目录 > models.dev > 自定义缺省
298
+ (`maxTokens: 8192`、`input: ["text"]`、`reasoning: false`、不猜 `contextWindow`)。`ama models list` 与
299
+ `ama config show` 标出每个字段来自哪里(`config` / `目录` / `models.dev` / `缺省`)。
300
+ - **字段映射**:`contextWindow = limit.context`;`maxTokens = min(limit.output, 65536, contextWindow)`——
301
+ `maxTokens` 每次请求都作为 `max_tokens` 发出,models.dev 给的是原厂上限(不少模型写的是与上下文相同的
302
+ 1M),中转换了上游后常拒收超大值,Anthropic 协议的思考预算也从它推导,64k 对编码 Agent 的单轮输出足够,
303
+ 需要更大时在配置里写;`input` 由 `modalities.input` 含不含 `image` 定为 `["text","image"]` 或 `["text"]`;
304
+ `reasoning`;`cost` 取 `input` / `output` / `cache_read` / `cache_write`($/M),缺缓存价时按输入价算
305
+ (不假设有折扣,保温的经济性判断因此偏保守)。
306
+ - **匹配规则**(同一个 id 常在几十家转售商下重复出现,取值不一):
307
+ 1. 模型上写了 `"modelsDev": "provider/model"` → 直接用该条目(写 `false` 关闭补全);
308
+ 2. id 形如 `vendor/model` 且 models.dev 正好有这个 `provider/model` → 用它;
309
+ 3. 按 id 不分大小写找全部同名条目;有 `canonical_model_id` 的,取指向与 id 同名的那个(否则取票数最多的),
310
+ 它若能在原厂供应商下找到 → 用原厂条目;
311
+ 4. 否则在(同一 canonical 的)条目里优先原厂供应商:anthropic、openai、google、deepseek、moonshotai(-cn)、
312
+ zhipuai、zai、alibaba(-cn)、xai、mistral、minimax(-cn)、llama(Meta)、cohere、xiaomi、stepfun 等
313
+ (models.dev 里没有 `qwen` / `meta` 这样的供应商 id,通义在 `alibaba`,Llama 在 `llama`);
314
+ 5. 仍有多条 → 按 (上下文, 输出, 图像) 取多数,取值不一时记 warning;只有一条就用它;
315
+ 6. 同名找不到时依次试归一化后的 id:去 `vendor/` 前缀、去 `:free` 一类后缀、去 `-latest`、去日期后缀
316
+ (`-0902`、`-20250514`、`-2025-05-14`);
317
+ 7. 都没有 → 「未匹配」,保持自定义缺省(不猜 `contextWindow`,自动压缩关闭)。
318
+
319
+ ### 图像输入
320
+
321
+ - 四条协议都把图片放进用户消息:Chat Completions `image_url`(data URL)、Responses `input_image`、
322
+ Anthropic `image`(base64 source)、Gemini `inlineData`;工具结果里的图片同样映射。
323
+ - 入口:`ama -p "描述这张图" --image a.png --image b.jpg`;交互界面与行式界面里写 `@图片路径`,或粘贴 /
324
+ 拖入一个图片文件路径(整段输入里以 `.png` / `.jpg` / `.jpeg` / `.gif` / `.webp` 结尾且文件存在的词)。
325
+ - 与 `read` 工具共用 MIME 检测(按文件头识别 PNG / JPEG / GIF / WebP,扩展名不符时以文件头为准)与大小上限
326
+ (单张 5 MB,取各家上限中最小的 Anthropic)。
327
+ - 模型 `input` 不含 `image` 时直接拒绝并提示换模型(`-p` 退出 2,界面里给错误提示,不发请求);`read`
328
+ 工具读图时只返回路径、尺寸与「当前模型不接受图片」。
329
+
330
+ 接好之后:`ama models check packy/<id>` 发一次最小请求确认连通;`ama models cache-probe packy/<id>` 看这个端点报不报缓存(见下节「缓存」),中转上不报缓存的模型按建议设 `compat.cacheReporting: "silent"`,状态栏就显示「未报告」而不是 0%。
331
+
332
+ ## OpenAI 兼容线的 compat
333
+
334
+ 推断顺序:保守缺省 ← 推断表(provider id,其次 baseUrl 子串)← `provider.compat` ← `model.compat`。
335
+
336
+ | 开关 | 作用 |
337
+ | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
338
+ | `maxTokensField` | `max_tokens` 或 `max_completion_tokens` |
339
+ | `supportsDeveloperRole` | 推理模型的系统提示用 `developer` 角色 |
340
+ | `supportsUsageInStreaming` | 发 `stream_options.include_usage` |
341
+ | `supportsFinishReason` | false 时忽略 finish_reason,按内容推断停止原因 |
342
+ | `supportsReasoningEffort` | 发 `reasoning_effort` |
343
+ | `thinkingFormat` | `openai` / `openrouter`(`reasoning.effort`)/ `deepseek`、`zai`(`thinking.type`)/ `qwen`(`enable_thinking`)/ `none` |
344
+ | `thinkingTokenBudgetField` | 预算字段名(DashScope:`thinking_budget`) |
345
+ | `requiresReasoningContentOnAssistantMessages` | 推理模型的历史助手消息带 `reasoning_content`(DeepSeek) |
346
+ | `requiresToolResultName` | 工具结果消息带 `name`(Mistral) |
347
+ | `requiresAssistantAfterToolResult` | 工具结果后紧跟用户消息时插入一条助手消息 |
348
+ | `supportsMidConvoSystemMessages` | 后续系统提示补丁按位置作为 system 消息插回 |
349
+ | `cacheControlFormat` | `anthropic`:在 system、最后一个工具、最后一条 user/tool 消息上打 `cache_control` |
350
+ | `supportsStrictTools` | 对严格兼容的工具 schema 发 `strict: true` |
351
+ | `supportsStore` | 发 `store: false` |
352
+
353
+ compat 只记录**已验证**的差异;新增条目请附文档链接或真实样本。
354
+
355
+ ## Responses 与 Gemini 的 compat
356
+
357
+ | 协议 | 开关 | 作用 | 缺省 |
358
+ | ---------------------- | ------------------------------- | --------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
359
+ | `openai-responses` | `supportsReasoningSummary` | `reasoning.summary: "auto"`(思考块有文字) | OpenAI 官方开;xAI 与其它关 |
360
+ | `openai-responses` | `supportsStore` | 发 `store: false`;推理模型同时要 `include: ["reasoning.encrypted_content"]`,多轮回放加密 reasoning item | OpenAI 官方、xAI 开;其它关 |
361
+ | `google-generative-ai` | `supportsThoughtSignature` | 同模型回放 `thoughtSignature`(思考、文本、functionCall part) | 开 |
362
+ | `google-generative-ai` | `supportsFunctionResponseParts` | 工具结果图片放进 `functionResponse.parts`;关时另起一个 user 回合 | Gemini 3 起开;Gemini 2.x 与非 Gemini 命名关 |
363
+
364
+ - Responses:系统提示放 `instructions`;缓存字段见下节「缓存」;思考 off 只在映射表给了 off 的字串(如 `"none"`)时发
365
+ `reasoning.effort`,否则交给服务端缺省。
366
+ - Gemini:映射值是字串(或 Gemini 3 族且未映射)→ 离散 `thinkingLevel`(`LOW` / `HIGH`…);映射值是
367
+ 数字或其它模型 → `thinkingBudget`(`-1` 动态);off → `thinkingBudget: 0`。隐式缓存自动生效,
368
+ `cachedContentTokenCount` 计入 `cacheRead`。
369
+
370
+ ## 缓存
371
+
372
+ 长任务的主要用量是缓存读取:前缀一旦变化,此后每次请求都要按全价重读。ama 分三层处理缓存:**协议层**按各家写法打断点、发缓存键与保留层级,并标记响应里有没有缓存字段;**会话层**记录每次请求的前缀指纹,检测未命中、判定端点报不报缓存、在长工具运行期间保温;**展示层**是状态栏、`/session`、RPC 统计与 `ama models cache-probe`(界面怎么读见 [tui.md](tui.md)「缓存与上下文」)。
373
+
374
+ 前缀稳定由组装保证:系统提示节顺序固定、不含时间戳,工具按名排序,会话中途的变化只以 system 补丁追加在末尾([session-format.md](session-format.md)「消息」)。
375
+
376
+ ### 请求字段
377
+
378
+ | 协议 | 字段 | 条件 |
379
+ | ---------------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
380
+ | `anthropic-messages` | 三断点 `cache_control`(最后一条 user、system 末、最后一个工具) | `cacheRetention` 不是 `none` |
381
+ | `anthropic-messages` | `ttl: "1h"` | `long` 且 `supportsLongCacheRetention`;否则按 5m |
382
+ | `openai-completions` | `prompt_cache_key = sessionId`(截 64 字符) | `sendPromptCacheKey` 且不是 `none` |
383
+ | `openai-completions` | `prompt_cache_retention: "24h"` | `long` 且 `supportsLongCacheRetention` |
384
+ | `openai-completions`(`anthropic/*` 等) | `cache_control`(`cacheControlFormat: "anthropic"`),`long` 时带 `ttl: "1h"` | 同 Anthropic |
385
+ | `openai-responses` | `prompt_cache_key` | 同 Completions |
386
+ | `openai-responses` | `prompt_cache_options: { ttl: "30m" }`,否则 `prompt_cache_retention: "24h"` | `long` 且 `supportsExplicitPromptCacheMode`;否则 `long` 且 `supportsLongCacheRetention` |
387
+ | OpenAI 两条 | 亲和头 `x-session-affinity` + 每请求 `x-client-request-id`(OpenRouter:`x-session-id`) | `sendSessionAffinityHeaders` 且有 sessionId |
388
+ | `google-generative-ai` | 无(隐式缓存) | — |
389
+ | 全部 | `toolChoice: "none"` → 各家的「禁止调用工具」写法 | 请求带工具时(摘要续写**不用**,见「压缩摘要续写」) |
390
+
391
+ 保留层级:`StreamOptions.cacheRetention` 优先;未指定时读 `AMA_CACHE_RETENTION=none|short|long`;都没有为
392
+ `short`。Anthropic 请求体最后做 TTL 顺序校验(tools → system → messages 里 5m 之后出现 1h 则全部降为 5m)。
393
+ Anthropic 的 `baseUrl` 以 `/v1` 结尾时请求 `{baseUrl}/messages`,不会拼成 `/v1/v1/messages`。
394
+
395
+ ### 兼容开关(`providers.<id>.compat` 或模型级 `compat`)
396
+
397
+ | 开关 | 作用 | 缺省 |
398
+ | --------------------------------- | ------------------------------------------------------- | ----------------------------------------- |
399
+ | `sendPromptCacheKey` | 发 `prompt_cache_key` | 请求主机是 `api.openai.com` 时开,其余关 |
400
+ | `sendSessionAffinityHeaders` | 发亲和头 | 关(含 OpenRouter,未实测) |
401
+ | `supportsLongCacheRetention` | `long` 可用(Anthropic 1h、OpenAI 24h);否则降为 short | `api.openai.com` / `api.anthropic.com` 开 |
402
+ | `supportsExplicitPromptCacheMode` | Responses 的 `prompt_cache_options`(30m) | 关 |
403
+ | `cacheReporting` | `auto` / `silent` / `reported`:强制「是否报缓存」三态 | `auto` |
404
+
405
+ 推断只看最终请求的主机名,不看 provider id:用 `OPENAI_BASE_URL` 或自定义 `baseUrl` 把 `openai` 指到中转时
406
+ 按中转处理。缺省只对官方端点开,是因为中转上实测「接受但未见收益」或「收下但不生效」(下表)。
407
+
408
+ **400 自动剥离**:端点以 400 拒收并在错误体里点名 `prompt_cache_key` / `prompt_cache_retention` /
409
+ `prompt_cache_options` / `cache_control` 时,ama 把 `provider/model` 记入进程内的剥离表,去掉这些字段重发一次
410
+ (仍只有一个终止事件),提示一次建议写哪个开关;同一进程里之后的请求直接不带。
411
+
412
+ ### usage 与 `cacheReported`
413
+
414
+ 原始 usage 里出现任一缓存字段(即使为 0)→ `Usage.cacheReported = true`,都没有 → `false`:Completions 认
415
+ `prompt_tokens_details.cached_tokens` / `cache_write_tokens`、`prompt_cache_hit_tokens` / `prompt_cache_miss_tokens`、
416
+ 顶层 `cached_tokens`;Responses 认 `input_tokens_details.cached_tokens`;Anthropic 认
417
+ `cache_read_input_tokens` / `cache_creation_input_tokens`;Google 认 `cachedContentTokenCount`(隐式缓存未命中时
418
+ 常常不给)。字段存在但一直为 0 的端点由会话层按连续 3 次判 `silent`。
419
+
420
+ ### 模型目录 `promptCache`
421
+
422
+ 只写有公开依据的值(秒 / token):Anthropic 全部 `short 300 / long 3600`,`minTokens` 按模型 512–4096;OpenAI
423
+ 全部 `short 300 / long 86400 / minTokens 1024`;Kimi 全部 `short 300`。DeepSeek、智谱、通义、Groq、xAI、Mistral、
424
+ OpenRouter、Google 没有承诺的 TTL,留空(不保温,归因按隐式缓存 10 分钟估)。可在 `models[]` /
425
+ `modelOverrides[]` 里自填。
426
+
427
+ ### 会话层:指纹、未命中与三态
428
+
429
+ 每次真实请求在内存里记一条记录:前缀指纹(system 与工具表各取 sha256 前 16 位 hex,加 `provider/model`)、`promptTokens`(input + cacheRead + cacheWrite)、用量与发出时刻。下一次请求与上一条比对:
430
+
431
+ - **未命中**:`missed = min(上次前缀, 本次前缀) − 本次 cacheRead`,低于噪声下限(`max(1024, promptCache.minTokens, 端点缓存粒度)`)不计——有的端点按块报缓存读(DeepSeek 经中转是 2048 一块),粒度取同一端点(供应商 + 主机 + 模型)观察到的非零 cacheRead 的最大公约数,至少 2 个样本且在 128–8192 之间才采信,只在内存、进程内跨会话复用;相对比例超过随规模自适应的门槛(约 `0.10 × √(100k / 前缀)`,夹在 2%–30%),或绝对值 ≥ 20 000 才记一次。重计费金额按本条实付单价与读价之差估算,模型无价格时只有 token。
432
+ - **原因**(按顺序判定):system / 工具表指纹变了 → `prefix_changed`(`detail` 说明哪段,多半是宿主中途注册工具或 Hook 上下文变化);模型变了 → `model_changed`;间隔超过 TTL → `idle`(目录没有 TTL 的隐式缓存按 10 分钟估);两次请求之间 `task` 子任务占了间隔的 80% 以上 → `subtask`;其余 → `evicted`(服务端淘汰)。
433
+ - **不算未命中**:压缩、分支摘要、档一裁剪之后的首个请求(上下文合法地变了);前缀低于最小可缓存长度。切换模型**不**豁免。
434
+ - **三态**:按 `(provider, baseUrl 主机名, model)` 在进程内维护。`unknown`:还没有足够长的可比请求;`reported`:出现过 cacheRead 或 cacheWrite > 0;`silent`:连续 3 个可比请求(前缀 ≥ minTokens、指纹未变、间隔 < TTL)读写都是 0,或 `compat.cacheReporting: "silent"`。只有 `reported` 时显示命中率、检测未命中并保温;`unknown` / `silent` 的请求不进命中率分母,界面显示 `—` / `未报告` 而不是 0%。
435
+
436
+ `task` 子会话有自己的记录链与统计,`/session` 的「子任务」行汇总;fork 出的会话沿用根会话 id 作 `prompt_cache_key`(只是路由提示)。
437
+
438
+ ### 保温
439
+
440
+ 工具长时间运行(长测试、`task` 子任务、codemode 脚本)时,前缀可能在下一次请求前过期。保温在 TTL 到期前重放上一次真实请求(同模型、同上下文,`maxTokens: 1`),只买一次读价,把缓存续上。
441
+
442
+ | 项 | 规则 |
443
+ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
444
+ | 模式 | `off`;`streaming`(缺省,只在运行中、也就是工具执行期间);`idle`(运行结束后的空闲期也保温,适合贵模型) |
445
+ | 前提 | 端点为 `reported`;模型目录有 `promptCache.short`(TTL > 10 秒);请求的 `cacheRetention` 不是 `none`;请求体没被 `onPayload` 替换;Anthropic 开思考且思考预算随 `max_tokens` 推导的不保温 |
446
+ | 时机 | 从上一次请求**发出**时刻起算,`max(1s, min(0.9·TTL, TTL − 10s))` 后发;计时器迟到超过截止(睡眠、事件循环阻塞)直接停 |
447
+ | 经济性 | `p · missCost − warmCost ≥ cache.minSavingsUsd`(缺省 $0.05)才发,`p` 在 streaming 为 1、idle 为 0.15;缺价格不发 |
448
+ | 上限 | streaming 60 分钟、idle 30 分钟;连续 2 次保温零命中即停 |
449
+ | 取消 | 换模型、换思考级别、压缩、`/tree`、退出时取消,下一次真实请求再开始 |
450
+ | 记账 | 成功的保温追加 `usage{kind:"cache_warm"}` 条目(不进上下文),计入 `/session` 费用与 RPC 统计;事件 `cache_warm{scheduled|sent|stopped}` |
451
+
452
+ 宿主可以经 `api.cache.onWarmingDecision` 否决或强制每一次保温([host-api.md](host-api.md)「缓存保温」)。子会话缺省不保温(`cache.warmSubagents: true` 打开)。按目录价格估算,长工具运行期间几乎总是划算;空闲保温只对贵模型、长前缀划算。
453
+
454
+ ### 压缩摘要续写
455
+
456
+ 档二压缩的摘要请求不再另起一段新对话,而是在与上一次真实请求逐字节相同的前缀后面追加一条摘要指令(`cacheRetention: "short"`),所以整段历史按读价计费。续写请求**不发 `tool_choice`**:实测中转与 Kimi 在 `tool_choice: "none"` 时渲染的提示不带工具定义,前缀在工具段断开、读不到缓存;Anthropic 也写明改动 tool_choice 会让消息缓存失效。工具表照常发,「不要调用工具、只输出摘要」写在末尾指令里。响应为空、被截断、含工具调用或请求出错时,回落为独立的摘要请求(`cacheRetention: "none"`)并记 warning。
457
+
458
+ ### 配置
459
+
460
+ ```json
461
+ {
462
+ "cache": {
463
+ "warming": "streaming",
464
+ "retention": "short",
465
+ "minSavingsUsd": 0.05,
466
+ "missNotices": true,
467
+ "warmSubagents": false
468
+ }
469
+ }
470
+ ```
471
+
472
+ | 键 | 缺省 | 说明 |
473
+ | --------------- | ----------- | --------------------------------------------------------------------------------------------- |
474
+ | `warming` | `streaming` | `off` / `streaming` / `idle`;环境变量 `AMA_CACHE_WARMING` 覆盖;`/cache warm …` 本会话内切换 |
475
+ | `retention` | `short` | `none` / `short` / `long`;环境变量 `AMA_CACHE_RETENTION` 覆盖 |
476
+ | `minSavingsUsd` | `0.05` | 保温的最低期望节省(美元) |
477
+ | `missNotices` | `true` | 消息区的未命中与上下文余量提示(统计不受影响) |
478
+ | `warmSubagents` | `false` | `task` 子会话也保温 |
479
+
480
+ 整段只认用户级与 profile 的 `config.json`,项目级忽略并 warning。供应商级开关在 `providers.<id>.compat`(上文「兼容开关」),TTL 在模型的 `promptCache`。
481
+
482
+ ### `ama models cache-probe`
483
+
484
+ ```sh
485
+ ama models cache-probe <provider/id> [--tokens 2048] [--gap-ms 3000] [--json] [--yes]
486
+ ```
487
+
488
+ 用一个确定性的固定前缀(约 `--tokens` token)+ `Reply with: ok`,`maxTokens: 16`,相隔 `--gap-ms` 发两次,判定:
489
+
490
+ - `reported`:第二次 cacheRead ≥ 前缀的 50%;目录没有 `promptCache` 时建议自填 `promptCache.short` 以启用保温;
491
+ - `silent`:两次读写都是 0;建议设 `compat.cacheReporting: "silent"`。响应里有缓存字段但恒为 0 时另提示可能是写入延迟(同一中转的 kimi-k2.5 间隔 3 秒两次都是 0、间隔 8 秒第二次读满前缀),可加大 `--gap-ms` 重试;
492
+ - `inconclusive`:读到一点或只有写入,多半是缓存粒度或 TTL 问题。
493
+
494
+ 输出两次请求的 input / cacheRead / cacheWrite 与该协议读取的 usage 字段名。这是计费动作:执行前打印预估(无价格显示 `$?`),交互终端问一次 y/N,非交互环境必须带 `--yes`(否则退出 2);`--json` 时预估写 stderr,stdout 只有结果对象。
495
+
496
+ ### 中转实测(2026-10-02)
497
+
498
+ 一家同时提供 Chat / Responses / Messages 三种接口的测试中转,固定前缀约 8.6k–10.9k token,同一前缀相隔 2–3 秒
499
+ 发两次(共 38 次请求)。
500
+
501
+ | 接口 / 模型 | 发送的缓存参数 | 结果 | 第二次 cacheRead / 前缀 | usage 里的缓存字段(原始形状) |
502
+ | ------------------------------------------------- | ------------------------------------------------- | ----------------------- | -------------------------- | ----------------------------------------------------------------------------- |
503
+ | Chat · kimi-k2.5 | 无 | 200 | 8576 / 8597 | `prompt_tokens_details.cached_tokens`(首个请求为 0) |
504
+ | Chat · kimi-k2.5 | `prompt_cache_key`;再加亲和头 | 200,接受 | 8576 / 8597(无提升) | 同上 |
505
+ | Chat · deepseek-v4-flash | `prompt_cache_key` + `x-session-affinity` | 200,接受 | 9472 / 9767 | `prompt_tokens_details.cached_tokens` |
506
+ | Chat · qwen3.8-flash | 同上 | 200,接受 | 10240 / 10400 | 同上 |
507
+ | Chat · glm-5 | 同上 | 200,接受 | 8704 / 9040 | 同上 |
508
+ | Chat · MiniMax-M2.7 | 同上 | 200,接受 | 9389 / 9700 | 同上 |
509
+ | Responses · qwen3.8-flash | `prompt_cache_key` + `prompt_cache_retention` | 200,接受 | 10240 / 10432 | `input_tokens_details.cached_tokens` |
510
+ | Responses · qwen3.8-flash | `prompt_cache_options: {ttl:"30m"}` | 200,接受 | 同上 | 同上 |
511
+ | Responses · grok-4.7 | 同上两组 | 200,接受 | 1152 / 10929 | 同上 |
512
+ | Responses · deepseek-v4-flash | `prompt_cache_retention` / `prompt_cache_options` | **400** `unknown field` | — | 去掉后 200;`input_tokens_details.cached_tokens` |
513
+ | Messages · kimi-k2.5、qwen3.8-flash | `cache_control` + `ttl:"1h"` | 200,接受 | 9464 / 9476、10385 / 10400 | `cache_creation.ephemeral_5m_input_tokens` 有值、无 1h 字段:**1h 被当作 5m** |
514
+ | Messages · MiniMax-M2.7、deepseek-v4-flash、glm-5 | 同上 | 200,接受 | 9403、8192、8704 | `cache_creation_input_tokens` 恒 0,读命中照常(端点自管的隐式缓存) |
515
+
516
+ 结论与缺省值:
517
+
518
+ - `prompt_cache_key`、亲和头在中转上都被接受,但未见命中提升 → `sendPromptCacheKey`、
519
+ `sendSessionAffinityHeaders` 对非官方端点缺省关;需要时自行打开(400 剥离兜底)。
520
+ - 1h 保留在中转的 Messages 接口上被收下但按 5m 写入,Responses 的长保留字段在部分上游 400 →
521
+ `supportsLongCacheRetention` 只对官方端点缺省开,`supportsExplicitPromptCacheMode` 缺省关。
522
+ - 实测的五家在 Chat 接口上都报缓存字段(前一版调研里 DeepSeek / GLM 报 0 的现象本次未复现),它们首个
523
+ 请求的 `cached_tokens: 0` 正是「字段存在但为 0」,`cacheReported` 为 true。
524
+ - `/v1` 去重与 `toolChoice: "none"` 经 ama 协议层实发验证:Messages 请求落在 `/v1/messages`,三种接口都接受
525
+ `tool_choice: none` 且未产生工具调用。
526
+
527
+ ## 测试用 fake 供应商
528
+
529
+ `--provider fake --model fake/echo`:回显最后一条用户消息。设 `AMA_FAKE_SCRIPT=<file.json>` 后
530
+ 按脚本第 n 次调用产出文本、思考、工具调用、429、溢出、断流、延迟,脚本格式见
531
+ `src/ai/fake/fake-script.ts`,示例在 `test/fixtures/scripts/`。