@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,249 @@
1
+ /**
2
+ * google-generative-ai 协议(设计 §3.1):POST `{baseUrl}/models/{id}:streamGenerateContent?alt=sse`,
3
+ * 每个 `data:` 是一个完整的 GenerateContentResponse(没有 `[DONE]`)。
4
+ *
5
+ * - `candidates[0].content.parts`:`text`(`thought: true` 为思考)→ 文本 / 思考块,相邻同类 part
6
+ * 并入同一块;`functionCall` 整块到达 → toolcall_start / delta(整段 JSON)/ end;
7
+ * - `thoughtSignature` 可挂在任何 part 上:思考 → `thinkingSignature`,文本 → `textSignature`,
8
+ * 工具调用 → `thoughtSignature`;同一块后到的空签名不覆盖先到的(签名常在末尾的空文本 part 上);
9
+ * - 工具调用缺 id(Gemini 2.5 起常见)时按 responseId + 内容下标生成确定的 id;
10
+ * - `finishReason`:STOP → stop(有工具调用则 toolUse)、MAX_TOKENS → length,其余(SAFETY、
11
+ * RECITATION、MALFORMED_FUNCTION_CALL…)→ error;`promptFeedback.blockReason` → error;
12
+ * 流里没出现过 finishReason → 断流错误;
13
+ * - `usageMetadata`(每块累计,取最后一次):input = promptTokenCount − cachedContentTokenCount,
14
+ * output = candidatesTokenCount + thoughtsTokenCount(思考按输出计费),reasoning = thoughts;
15
+ * cachedContentTokenCount 出现(含 0)即 `cacheReported: true`(隐式缓存未命中时常常不给该字段);
16
+ * - 错误体 `{error:{code,status,message}}` 重排为 `429 RESOURCE_EXHAUSTED: …`。
17
+ */
18
+ import { AssistantEventStreamImpl } from "../event-stream.js";
19
+ import { HttpError, USER_AGENT, authHeaders, joinUrl, mergeHeaders, postJson } from "../http.js";
20
+ import { readSseEvents } from "../sse.js";
21
+ import { GOOGLE_BASE_URL, buildGoogleRequest, detectGoogleCompat } from "./google-request.js";
22
+ import { BlockTracker, ProviderStopError, STREAM_ENDED_MESSAGE, createOutput, finishDone, finishError, requireApiKey, } from "./shared.js";
23
+ function num(value) {
24
+ return typeof value === "number" && Number.isFinite(value) ? value : undefined;
25
+ }
26
+ function obj(value) {
27
+ return typeof value === "object" && value !== null && !Array.isArray(value)
28
+ ? value
29
+ : undefined;
30
+ }
31
+ function str(value) {
32
+ return typeof value === "string" ? value : undefined;
33
+ }
34
+ export function parseGoogleUsage(raw) {
35
+ const prompt = num(raw["promptTokenCount"]) ?? 0;
36
+ const reported = num(raw["cachedContentTokenCount"]);
37
+ const cached = reported ?? 0;
38
+ const thoughts = num(raw["thoughtsTokenCount"]) ?? 0;
39
+ const usage = {
40
+ input: Math.max(0, prompt - cached),
41
+ output: (num(raw["candidatesTokenCount"]) ?? 0) + thoughts,
42
+ cacheRead: cached,
43
+ cacheWrite: 0,
44
+ totalTokens: 0,
45
+ cacheReported: reported !== undefined,
46
+ };
47
+ if (raw["thoughtsTokenCount"] !== undefined)
48
+ usage.reasoning = thoughts;
49
+ return usage;
50
+ }
51
+ export function mapGoogleFinishReason(raw) {
52
+ if (raw === "STOP")
53
+ return { reason: "stop" };
54
+ if (raw === "MAX_TOKENS")
55
+ return { reason: "length" };
56
+ return { reason: "error", message: `Provider finish reason: ${raw}` };
57
+ }
58
+ /** Google 错误体 `{error:{code,status,message}}` → `status: message`;其它形状返回 undefined。 */
59
+ export function describeGoogleError(value) {
60
+ const error = obj(obj(value)?.["error"]);
61
+ if (!error)
62
+ return undefined;
63
+ const message = str(error["message"]) ?? JSON.stringify(error);
64
+ const status = str(error["status"]);
65
+ return status && !message.startsWith(status) ? `${status}: ${message}` : message;
66
+ }
67
+ function rewriteHttpError(error) {
68
+ if (!(error instanceof HttpError))
69
+ return error;
70
+ let detail;
71
+ try {
72
+ detail = describeGoogleError(JSON.parse(error.body));
73
+ }
74
+ catch {
75
+ detail = undefined;
76
+ }
77
+ if (!detail)
78
+ return error;
79
+ return new HttpError(error.status, `${error.status} ${detail}`, error.body, error.retryAfterMs);
80
+ }
81
+ function closeProse(state, tracker) {
82
+ if (state.prose)
83
+ tracker.end(state.prose.index);
84
+ state.prose = undefined;
85
+ }
86
+ function setSignature(tracker, index, signature) {
87
+ const block = tracker.output.content[index];
88
+ if (block?.type === "thinking")
89
+ block.thinkingSignature = signature;
90
+ else if (block?.type === "text")
91
+ block.textSignature = signature;
92
+ }
93
+ function toolCallId(state, tracker, provided) {
94
+ const taken = (id) => tracker.output.content.some((b) => b.type === "toolCall" && b.id === id);
95
+ if (provided && !taken(provided))
96
+ return provided;
97
+ const seed = state.idSeed.replace(/[^A-Za-z0-9_-]/g, "").slice(0, 40) || "gemini";
98
+ let id = `call_${seed}_${tracker.output.content.length}`;
99
+ for (let n = 1; taken(id); n++)
100
+ id = `call_${seed}_${tracker.output.content.length}_${n}`;
101
+ return id;
102
+ }
103
+ function handlePart(part, state, tracker) {
104
+ const signature = str(part["thoughtSignature"]) || undefined;
105
+ const call = obj(part["functionCall"]);
106
+ if (call) {
107
+ closeProse(state, tracker);
108
+ const name = str(call["name"]) ?? "";
109
+ const index = tracker.startToolCall(toolCallId(state, tracker, str(call["id"])), name);
110
+ const block = tracker.toolCallBlock(index);
111
+ if (block && signature)
112
+ block.thoughtSignature = signature;
113
+ tracker.appendToolArgs(index, JSON.stringify(obj(call["args"]) ?? {}));
114
+ tracker.end(index);
115
+ return;
116
+ }
117
+ const text = str(part["text"]);
118
+ if (text === undefined)
119
+ return;
120
+ const kind = part["thought"] === true ? "thinking" : "text";
121
+ if (state.prose?.kind !== kind) {
122
+ closeProse(state, tracker);
123
+ // 空 part 不单独开块;只带签名的挂到前一个同类块上
124
+ if (text.length === 0) {
125
+ const last = tracker.output.content.length - 1;
126
+ if (signature && tracker.output.content[last]?.type === kind) {
127
+ setSignature(tracker, last, signature);
128
+ }
129
+ return;
130
+ }
131
+ const index = kind === "thinking" ? tracker.startThinking() : tracker.startText();
132
+ state.prose = { index, kind };
133
+ }
134
+ const index = state.prose.index;
135
+ if (kind === "thinking")
136
+ tracker.appendThinking(index, text);
137
+ else
138
+ tracker.appendText(index, text);
139
+ if (signature)
140
+ setSignature(tracker, index, signature);
141
+ }
142
+ function handleChunk(chunk, state, tracker) {
143
+ if (chunk["error"] !== undefined) {
144
+ throw new Error(describeGoogleError(chunk) ?? JSON.stringify(chunk["error"]));
145
+ }
146
+ const output = tracker.output;
147
+ const responseId = str(chunk["responseId"]);
148
+ if (responseId && !output.responseId) {
149
+ output.responseId = responseId;
150
+ state.idSeed = responseId;
151
+ }
152
+ const usage = obj(chunk["usageMetadata"]);
153
+ if (usage)
154
+ output.usage = parseGoogleUsage(usage);
155
+ const blocked = str(obj(chunk["promptFeedback"])?.["blockReason"]);
156
+ const candidates = Array.isArray(chunk["candidates"]) ? chunk["candidates"] : [];
157
+ const candidate = obj(candidates[0]);
158
+ if (!candidate && blocked) {
159
+ output.rawStopReason = blocked;
160
+ throw new ProviderStopError(`Prompt blocked: ${blocked}`);
161
+ }
162
+ const parts = obj(candidate?.["content"])?.["parts"];
163
+ if (Array.isArray(parts)) {
164
+ for (const part of parts) {
165
+ const value = obj(part);
166
+ if (value)
167
+ handlePart(value, state, tracker);
168
+ }
169
+ }
170
+ const finish = str(candidate?.["finishReason"]);
171
+ if (finish) {
172
+ state.finish = finish;
173
+ output.rawStopReason = finish;
174
+ }
175
+ }
176
+ function buildHeaders(model, options) {
177
+ return mergeHeaders({ "content-type": "application/json", accept: "text/event-stream", "user-agent": USER_AGENT }, authHeaders(options.apiKey, model.authHeader, "x-goog-api-key"), model.headers, options.headers);
178
+ }
179
+ export function googleStreamUrl(model) {
180
+ const id = model.id.replace(/^models\//, "");
181
+ return joinUrl(model.baseUrl ?? GOOGLE_BASE_URL, `/models/${encodeURIComponent(id)}:streamGenerateContent?alt=sse`);
182
+ }
183
+ async function run(stream, model, context, options) {
184
+ const tracker = new BlockTracker(stream, createOutput(model));
185
+ try {
186
+ const request = buildGoogleRequest(model, context, options);
187
+ tracker.output.thinkingLevel = request.thinkingLevel;
188
+ if (request.providerThinkingLevel !== undefined) {
189
+ tracker.output.providerThinkingLevel = request.providerThinkingLevel;
190
+ }
191
+ const replaced = options.onPayload?.(request.body);
192
+ let response;
193
+ try {
194
+ response = await postJson(googleStreamUrl(model), {
195
+ headers: buildHeaders(model, options),
196
+ body: replaced === undefined ? request.body : replaced,
197
+ signal: options.signal,
198
+ timeoutMs: options.timeoutMs,
199
+ onResponse: options.onResponse,
200
+ });
201
+ }
202
+ catch (error) {
203
+ throw rewriteHttpError(error);
204
+ }
205
+ stream.push({ type: "start", partial: tracker.output });
206
+ const state = {
207
+ prose: undefined,
208
+ finish: undefined,
209
+ idSeed: Date.now().toString(36),
210
+ };
211
+ const body = response.body;
212
+ for await (const sse of readSseEvents(body, options.signal)) {
213
+ const data = sse.data.trim();
214
+ if (data === "" || data === "[DONE]")
215
+ continue;
216
+ let chunk;
217
+ try {
218
+ chunk = obj(JSON.parse(data)) ?? {};
219
+ }
220
+ catch {
221
+ throw new Error(`Malformed SSE data: ${data.slice(0, 200)}`);
222
+ }
223
+ handleChunk(chunk, state, tracker);
224
+ }
225
+ if (options.signal.aborted)
226
+ throw new Error("aborted");
227
+ if (state.finish === undefined)
228
+ throw new Error(STREAM_ENDED_MESSAGE);
229
+ const mapped = mapGoogleFinishReason(state.finish);
230
+ if (mapped.reason === "error")
231
+ throw new ProviderStopError(mapped.message);
232
+ const reason = mapped.reason === "stop" && tracker.hasToolCalls ? "toolUse" : mapped.reason;
233
+ finishDone(stream, tracker, model, reason);
234
+ }
235
+ catch (error) {
236
+ finishError(stream, tracker, model, error, options.signal);
237
+ }
238
+ }
239
+ function stream(model, context, options) {
240
+ requireApiKey(model, options);
241
+ const events = new AssistantEventStreamImpl();
242
+ void run(events, model, context, options).finally(() => events.end());
243
+ return events;
244
+ }
245
+ export const googleGenerativeAiApi = {
246
+ id: "google-generative-ai",
247
+ stream,
248
+ detectCompat: detectGoogleCompat,
249
+ };
@@ -0,0 +1,40 @@
1
+ /**
2
+ * google-generative-ai 请求体(设计 §3.1、§3.3、§3.6):contents 转换、thoughtSignature 回放、
3
+ * 工具声明、thinkingConfig。
4
+ *
5
+ * - 角色:user / model;工具结果是 user 回合里的 `functionResponse` part,连续多条合进同一回合;
6
+ * - thoughtSignature:只回放同 provider / 同模型、且是合法 base64 的签名(Gemini 要求 bytes);
7
+ * 签名可能挂在空文本 part 上,此时空 part 也要原样送回;跨模型的思考由 transform.ts 降级为文本;
8
+ * - Gemini 3 起 functionCall / functionResponse 带 `id`,并支持把工具结果图片放进
9
+ * `functionResponse.parts`(`supportsFunctionResponseParts`);更早的模型图片另起一个 user 回合;
10
+ * - thinkingConfig:级别映射到字串(或模型属于 Gemini 3 族且映射缺省)→ 离散 `thinkingLevel`;
11
+ * 映射到数字或其它模型 → `thinkingBudget`(不超过回答上限留白);off → `thinkingBudget: 0`;
12
+ * - 缓存:Gemini 的隐式缓存自动生效,请求里没有可设的字段;`cacheRetention` 不影响请求体;
13
+ * - `toolChoice: "none"`(有工具时)→ `toolConfig.functionCallingConfig.mode: "NONE"`。
14
+ */
15
+ import type { AssistantMessage, GoogleCompat, JsonSchema, Model, ModelThinkingLevel, ProviderData, StreamOptions, ToolResultMessage, TranscriptContext, UserMessage } from "../types.js";
16
+ type Json = Record<string, unknown>;
17
+ type Conversation = UserMessage | AssistantMessage | ToolResultMessage;
18
+ export declare const GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
19
+ /** `gemini-3.1-pro-preview` → 3;不是 Gemini 版本号命名返回 undefined。 */
20
+ export declare function geminiMajorVersion(modelId: string): number | undefined;
21
+ /** Gemini 3 起 functionCall / functionResponse 要带 id。 */
22
+ export declare function requiresToolCallId(modelId: string): boolean;
23
+ /** 缺省按模型族推断离散级别:Gemini 3 Pro / Flash 及 `gemini-flash(-lite)-latest`。 */
24
+ export declare function usesDiscreteThinkingLevel(modelId: string): boolean;
25
+ /**
26
+ * compat:推断 ← provider.compat ← model.compat。原生协议的实现都认 thoughtSignature,缺省开;
27
+ * 工具结果内嵌图片只有 Gemini 3 起支持,非 Gemini 命名的模型保守关。
28
+ */
29
+ export declare function detectGoogleCompat(model: Model, provider?: ProviderData): GoogleCompat;
30
+ export declare function convertGoogleContents(model: Model, messages: readonly Conversation[], compat: GoogleCompat): Json[];
31
+ /** Gemini 的 schema 是 OpenAPI 子集:去掉它不认的 `additionalProperties`。 */
32
+ export declare function toGoogleSchema(schema: JsonSchema): Json;
33
+ export interface GoogleRequest {
34
+ body: Json;
35
+ compat: GoogleCompat;
36
+ thinkingLevel: ModelThinkingLevel;
37
+ providerThinkingLevel: string | undefined;
38
+ }
39
+ export declare function buildGoogleRequest(model: Model, context: TranscriptContext, options: StreamOptions): GoogleRequest;
40
+ export {};
@@ -0,0 +1,255 @@
1
+ /**
2
+ * google-generative-ai 请求体(设计 §3.1、§3.3、§3.6):contents 转换、thoughtSignature 回放、
3
+ * 工具声明、thinkingConfig。
4
+ *
5
+ * - 角色:user / model;工具结果是 user 回合里的 `functionResponse` part,连续多条合进同一回合;
6
+ * - thoughtSignature:只回放同 provider / 同模型、且是合法 base64 的签名(Gemini 要求 bytes);
7
+ * 签名可能挂在空文本 part 上,此时空 part 也要原样送回;跨模型的思考由 transform.ts 降级为文本;
8
+ * - Gemini 3 起 functionCall / functionResponse 带 `id`,并支持把工具结果图片放进
9
+ * `functionResponse.parts`(`supportsFunctionResponseParts`);更早的模型图片另起一个 user 回合;
10
+ * - thinkingConfig:级别映射到字串(或模型属于 Gemini 3 族且映射缺省)→ 离散 `thinkingLevel`;
11
+ * 映射到数字或其它模型 → `thinkingBudget`(不超过回答上限留白);off → `thinkingBudget: 0`;
12
+ * - 缓存:Gemini 的隐式缓存自动生效,请求里没有可设的字段;`cacheRetention` 不影响请求体;
13
+ * - `toolChoice: "none"`(有工具时)→ `toolConfig.functionCallingConfig.mode: "NONE"`。
14
+ */
15
+ import { contentText, normalizeContext, sanitizeText } from "../context.js";
16
+ import { DEFAULT_THINKING_BUDGETS, clampBudgetToAnswerRoom, clampThinkingLevel, discreteThinkingLevel, } from "../thinking.js";
17
+ export const GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
18
+ const GOOGLE_COMPAT_KEYS = [
19
+ "supportsThoughtSignature",
20
+ "supportsFunctionResponseParts",
21
+ ];
22
+ /** `gemini-3.1-pro-preview` → 3;不是 Gemini 版本号命名返回 undefined。 */
23
+ export function geminiMajorVersion(modelId) {
24
+ const match = /^(?:models\/)?gemini(?:-live)?-(\d+)/.exec(modelId.toLowerCase());
25
+ return match?.[1] !== undefined ? Number.parseInt(match[1], 10) : undefined;
26
+ }
27
+ /** Gemini 3 起 functionCall / functionResponse 要带 id。 */
28
+ export function requiresToolCallId(modelId) {
29
+ return (geminiMajorVersion(modelId) ?? 0) >= 3;
30
+ }
31
+ /** 缺省按模型族推断离散级别:Gemini 3 Pro / Flash 及 `gemini-flash(-lite)-latest`。 */
32
+ export function usesDiscreteThinkingLevel(modelId) {
33
+ const id = modelId.toLowerCase();
34
+ return /gemini-3(?:\.\d+)?-(?:pro|flash)/.test(id) || /^gemini-flash(?:-lite)?-latest$/.test(id);
35
+ }
36
+ function pick(compat) {
37
+ const out = {};
38
+ for (const key of GOOGLE_COMPAT_KEYS) {
39
+ const value = compat?.[key];
40
+ if (value !== undefined)
41
+ out[key] = value;
42
+ }
43
+ return out;
44
+ }
45
+ /**
46
+ * compat:推断 ← provider.compat ← model.compat。原生协议的实现都认 thoughtSignature,缺省开;
47
+ * 工具结果内嵌图片只有 Gemini 3 起支持,非 Gemini 命名的模型保守关。
48
+ */
49
+ export function detectGoogleCompat(model, provider) {
50
+ const major = geminiMajorVersion(model.id);
51
+ return {
52
+ supportsThoughtSignature: true,
53
+ supportsFunctionResponseParts: major !== undefined && major >= 3,
54
+ ...pick(provider?.compat),
55
+ ...pick(model.compat),
56
+ };
57
+ }
58
+ const BASE64 = /^[A-Za-z0-9+/]+={0,2}$/;
59
+ function validSignature(signature) {
60
+ return (signature !== undefined &&
61
+ signature.length > 0 &&
62
+ signature.length % 4 === 0 &&
63
+ BASE64.test(signature));
64
+ }
65
+ function inlineData(block) {
66
+ return { inlineData: { mimeType: block.mimeType, data: block.data } };
67
+ }
68
+ function convertUser(message) {
69
+ if (typeof message.content === "string") {
70
+ return message.content.length > 0
71
+ ? { role: "user", parts: [{ text: sanitizeText(message.content) }] }
72
+ : undefined;
73
+ }
74
+ const parts = [];
75
+ for (const block of message.content) {
76
+ if (block.type === "image")
77
+ parts.push(inlineData(block));
78
+ else if (block.text.length > 0)
79
+ parts.push({ text: sanitizeText(block.text) });
80
+ }
81
+ return parts.length > 0 ? { role: "user", parts } : undefined;
82
+ }
83
+ function convertAssistant(model, message, compat) {
84
+ const sameModel = message.provider === model.provider && message.model === model.id;
85
+ const signatureOf = (value) => sameModel && compat.supportsThoughtSignature && validSignature(value) ? value : undefined;
86
+ const parts = [];
87
+ for (const block of message.content) {
88
+ if (block.type === "text") {
89
+ const signature = signatureOf(block.textSignature);
90
+ if (block.text.trim().length === 0 && !signature)
91
+ continue;
92
+ parts.push({
93
+ text: sanitizeText(block.text),
94
+ ...(signature ? { thoughtSignature: signature } : {}),
95
+ });
96
+ }
97
+ else if (block.type === "thinking") {
98
+ if (block.redacted)
99
+ continue;
100
+ const signature = signatureOf(block.thinkingSignature);
101
+ if (sameModel) {
102
+ if (block.thinking.trim().length === 0 && !signature)
103
+ continue;
104
+ parts.push({
105
+ thought: true,
106
+ text: sanitizeText(block.thinking),
107
+ ...(signature ? { thoughtSignature: signature } : {}),
108
+ });
109
+ }
110
+ else if (block.thinking.trim().length > 0) {
111
+ parts.push({ text: sanitizeText(block.thinking) });
112
+ }
113
+ }
114
+ else {
115
+ const signature = signatureOf(block.thoughtSignature);
116
+ parts.push({
117
+ functionCall: {
118
+ name: block.name,
119
+ args: block.arguments,
120
+ ...(requiresToolCallId(model.id) ? { id: block.id } : {}),
121
+ },
122
+ ...(signature ? { thoughtSignature: signature } : {}),
123
+ });
124
+ }
125
+ }
126
+ return parts.length > 0 ? { role: "model", parts } : undefined;
127
+ }
128
+ function convertToolResult(model, message, compat) {
129
+ const text = contentText(message.content);
130
+ const images = typeof message.content === "string" || !model.input.includes("image")
131
+ ? []
132
+ : message.content.filter((b) => b.type === "image");
133
+ const value = sanitizeText(text.length > 0 ? text : images.length > 0 ? "(see attached image)" : "(no output)");
134
+ const nested = images.length > 0 && compat.supportsFunctionResponseParts;
135
+ const part = {
136
+ functionResponse: {
137
+ name: message.toolName,
138
+ response: message.isError ? { error: value } : { output: value },
139
+ ...(nested ? { parts: images.map(inlineData) } : {}),
140
+ ...(requiresToolCallId(model.id) ? { id: message.toolCallId } : {}),
141
+ },
142
+ };
143
+ const extra = images.length > 0 && !nested
144
+ ? { role: "user", parts: [{ text: "Tool result images:" }, ...images.map(inlineData)] }
145
+ : undefined;
146
+ return { part, extra };
147
+ }
148
+ export function convertGoogleContents(model, messages, compat) {
149
+ const contents = [];
150
+ for (let i = 0; i < messages.length; i++) {
151
+ const message = messages[i];
152
+ if (!message)
153
+ continue;
154
+ if (message.role === "toolResult") {
155
+ const parts = [];
156
+ const extras = [];
157
+ while (messages[i]?.role === "toolResult") {
158
+ const converted = convertToolResult(model, messages[i], compat);
159
+ parts.push(converted.part);
160
+ if (converted.extra)
161
+ extras.push(converted.extra);
162
+ i++;
163
+ }
164
+ i--;
165
+ contents.push({ role: "user", parts }, ...extras);
166
+ continue;
167
+ }
168
+ const converted = message.role === "user" ? convertUser(message) : convertAssistant(model, message, compat);
169
+ if (converted)
170
+ contents.push(converted);
171
+ }
172
+ return contents;
173
+ }
174
+ /** Gemini 的 schema 是 OpenAPI 子集:去掉它不认的 `additionalProperties`。 */
175
+ export function toGoogleSchema(schema) {
176
+ const out = {};
177
+ for (const [key, value] of Object.entries(schema)) {
178
+ if (key === "additionalProperties")
179
+ continue;
180
+ if (key === "properties" && value && typeof value === "object") {
181
+ const props = {};
182
+ for (const [name, sub] of Object.entries(value)) {
183
+ props[name] = toGoogleSchema(sub);
184
+ }
185
+ out[key] = props;
186
+ }
187
+ else if (key === "items" && value && typeof value === "object") {
188
+ out[key] = toGoogleSchema(value);
189
+ }
190
+ else {
191
+ out[key] = value;
192
+ }
193
+ }
194
+ return out;
195
+ }
196
+ function convertTools(tools) {
197
+ return [
198
+ {
199
+ functionDeclarations: tools.map((tool) => ({
200
+ name: tool.name,
201
+ description: tool.description,
202
+ parameters: toGoogleSchema({ ...tool.parameters, type: "object" }),
203
+ })),
204
+ },
205
+ ];
206
+ }
207
+ /** 写 thinkingConfig;返回实际发出的值(离散级别名或预算)。 */
208
+ function applyThinking(config, model, level, maxTokens) {
209
+ if (!model.reasoning)
210
+ return undefined;
211
+ if (level === "off") {
212
+ const off = model.thinkingLevelMap?.off;
213
+ const discrete = typeof off === "string" ? off.toUpperCase() : undefined;
214
+ config["thinkingConfig"] = discrete ? { thinkingLevel: discrete } : { thinkingBudget: 0 };
215
+ return discrete ?? "0";
216
+ }
217
+ const mapped = model.thinkingLevelMap?.[level];
218
+ const discrete = typeof mapped === "string" || (mapped === undefined && usesDiscreteThinkingLevel(model.id))
219
+ ? discreteThinkingLevel(model, level)
220
+ : undefined;
221
+ if (discrete) {
222
+ const value = discrete.toUpperCase();
223
+ config["thinkingConfig"] = { includeThoughts: true, thinkingLevel: value };
224
+ return value;
225
+ }
226
+ const requested = typeof mapped === "number" ? mapped : DEFAULT_THINKING_BUDGETS[level];
227
+ // -1 = 动态预算(Gemini 自行决定),不参与留白钳位
228
+ const budget = requested < 0 ? -1 : clampBudgetToAnswerRoom(requested, maxTokens);
229
+ config["thinkingConfig"] = { includeThoughts: true, thinkingBudget: budget };
230
+ return String(budget);
231
+ }
232
+ export function buildGoogleRequest(model, context, options) {
233
+ const compat = detectGoogleCompat(model);
234
+ const normalized = normalizeContext(context, { model });
235
+ const maxTokens = options.maxTokens ?? model.maxTokens;
236
+ const level = clampThinkingLevel(model, options.thinkingLevel ?? "off");
237
+ const body = { contents: convertGoogleContents(model, normalized.messages, compat) };
238
+ if (normalized.systemPrompt.length > 0) {
239
+ body["systemInstruction"] = { parts: [{ text: sanitizeText(normalized.systemPrompt) }] };
240
+ }
241
+ if (normalized.tools.length > 0) {
242
+ body["tools"] = convertTools(normalized.tools);
243
+ if (options.toolChoice === "none") {
244
+ body["toolConfig"] = { functionCallingConfig: { mode: "NONE" } };
245
+ }
246
+ }
247
+ const config = { maxOutputTokens: maxTokens };
248
+ if (options.temperature !== undefined)
249
+ config["temperature"] = options.temperature;
250
+ const providerLevel = applyThinking(config, model, level, maxTokens);
251
+ if (model.samplingParams)
252
+ Object.assign(config, model.samplingParams);
253
+ body["generationConfig"] = config;
254
+ return { body, compat, thinkingLevel: level, providerThinkingLevel: providerLevel };
255
+ }
@@ -0,0 +1,35 @@
1
+ /**
2
+ * OpenAI 兼容线的 compat 推断(设计 §3.3)。
3
+ *
4
+ * 顺序:保守缺省 ← 推断表(先按 provider id,再按 baseUrl 子串)← `provider.compat` ←
5
+ * `model.compat`(字段级覆盖,undefined 不覆盖)。显式配置永远胜过推断。
6
+ *
7
+ * 缺省是「最保守的 OpenAI 兼容服务」:`max_tokens`、`system` 角色、不发 `store` /
8
+ * `reasoning_effort` / `strict`。只有 OpenAI 官方端点打开 OpenAI 专有开关。
9
+ * 表里每一项都应对应一个已验证的差异(文档或真实样本);没验证过的不要加。
10
+ */
11
+ import type { Model, OpenAICompletionsCompat, ProviderCompat, ProviderData } from "../types.js";
12
+ export declare const OPENAI_COMPAT_KEYS: readonly ["maxTokensField", "supportsDeveloperRole", "supportsUsageInStreaming", "supportsFinishReason", "supportsReasoningEffort", "thinkingFormat", "thinkingTokenBudgetField", "requiresReasoningContentOnAssistantMessages", "requiresToolResultName", "requiresAssistantAfterToolResult", "supportsMidConvoSystemMessages", "cacheControlFormat", "supportsStrictTools", "supportsStore"];
13
+ export declare const CONSERVATIVE_COMPAT: Readonly<OpenAICompletionsCompat>;
14
+ type Patch = Partial<OpenAICompletionsCompat>;
15
+ interface InferenceRule {
16
+ /** 供应商 id(内置 id)。 */
17
+ provider: string;
18
+ /** baseUrl 子串(自定义供应商指向同一服务时命中)。 */
19
+ baseUrl: string;
20
+ patch: (modelId: string) => Patch;
21
+ }
22
+ /** 推断表:13 家内置里走 OpenAI 兼容线的 11 家(anthropic / google 不走本协议)。 */
23
+ export declare const INFERENCE_RULES: readonly InferenceRule[];
24
+ /** 命中的推断规则(先 provider id,后 baseUrl 子串)。 */
25
+ export declare function findInferenceRule(providerId: string, baseUrl: string): InferenceRule | undefined;
26
+ /** 从 ProviderCompat 里挑出本协议的字段(undefined 跳过)。 */
27
+ export declare function pickOpenAICompat(compat: ProviderCompat | undefined): Patch;
28
+ /** 推断(不含显式配置)。 */
29
+ export declare function inferOpenAICompat(providerId: string, baseUrl: string, modelId: string): OpenAICompletionsCompat;
30
+ /**
31
+ * 完整 compat:推断 ← provider.compat ← model.compat。`provider` 缺省时只用 model
32
+ * 自带信息(registry 物化后的模型已把 provider.compat 合进 model.compat)。
33
+ */
34
+ export declare function detectCompat(model: Model, provider?: ProviderData): OpenAICompletionsCompat;
35
+ export {};