@armadra/agent 0.0.0-stage → 0.2.1

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 (407) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/LICENSE +21 -0
  3. package/README.md +426 -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 +511 -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 +118 -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 +104 -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 +484 -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 +303 -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 +102 -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/registry.d.ts +83 -0
  101. package/dist/ai/providers/registry.js +305 -0
  102. package/dist/ai/sse.d.ts +32 -0
  103. package/dist/ai/sse.js +140 -0
  104. package/dist/ai/thinking.d.ts +42 -0
  105. package/dist/ai/thinking.js +101 -0
  106. package/dist/ai/types.d.ts +428 -0
  107. package/dist/ai/types.js +19 -0
  108. package/dist/bundle/ama-sandbox.cjs +324 -0
  109. package/dist/bundle/ama.cjs +25770 -0
  110. package/dist/bundle.d.ts +9 -0
  111. package/dist/bundle.js +15 -0
  112. package/dist/cli/args.d.ts +82 -0
  113. package/dist/cli/args.js +381 -0
  114. package/dist/cli/bootstrap.d.ts +18 -0
  115. package/dist/cli/bootstrap.js +398 -0
  116. package/dist/cli/compose-providers.d.ts +37 -0
  117. package/dist/cli/compose-providers.js +104 -0
  118. package/dist/cli/compose-session.d.ts +69 -0
  119. package/dist/cli/compose-session.js +370 -0
  120. package/dist/cli/compose-store.d.ts +24 -0
  121. package/dist/cli/compose-store.js +125 -0
  122. package/dist/cli/compose.d.ts +106 -0
  123. package/dist/cli/compose.js +206 -0
  124. package/dist/cli/default-model.d.ts +16 -0
  125. package/dist/cli/default-model.js +24 -0
  126. package/dist/cli/deps.d.ts +205 -0
  127. package/dist/cli/deps.js +12 -0
  128. package/dist/cli/exit-codes.d.ts +29 -0
  129. package/dist/cli/exit-codes.js +40 -0
  130. package/dist/cli/main.d.ts +26 -0
  131. package/dist/cli/main.js +165 -0
  132. package/dist/cli/runtime.d.ts +90 -0
  133. package/dist/cli/runtime.js +8 -0
  134. package/dist/cli/startup-screen.d.ts +15 -0
  135. package/dist/cli/startup-screen.js +56 -0
  136. package/dist/cli/startup-steps.d.ts +35 -0
  137. package/dist/cli/startup-steps.js +197 -0
  138. package/dist/cli/subcommands/auth.d.ts +12 -0
  139. package/dist/cli/subcommands/auth.js +91 -0
  140. package/dist/cli/subcommands/config.d.ts +44 -0
  141. package/dist/cli/subcommands/config.js +201 -0
  142. package/dist/cli/subcommands/context.d.ts +21 -0
  143. package/dist/cli/subcommands/context.js +41 -0
  144. package/dist/cli/subcommands/doctor.d.ts +11 -0
  145. package/dist/cli/subcommands/doctor.js +246 -0
  146. package/dist/cli/subcommands/models-cache-probe.d.ts +34 -0
  147. package/dist/cli/subcommands/models-cache-probe.js +190 -0
  148. package/dist/cli/subcommands/models-discover.d.ts +40 -0
  149. package/dist/cli/subcommands/models-discover.js +204 -0
  150. package/dist/cli/subcommands/models.d.ts +40 -0
  151. package/dist/cli/subcommands/models.js +144 -0
  152. package/dist/cli/subcommands/sessions.d.ts +11 -0
  153. package/dist/cli/subcommands/sessions.js +100 -0
  154. package/dist/codemode/capability.d.ts +37 -0
  155. package/dist/codemode/capability.js +55 -0
  156. package/dist/codemode/declarations.d.ts +44 -0
  157. package/dist/codemode/declarations.js +111 -0
  158. package/dist/codemode/host-side.d.ts +59 -0
  159. package/dist/codemode/host-side.js +253 -0
  160. package/dist/codemode/modes.d.ts +23 -0
  161. package/dist/codemode/modes.js +40 -0
  162. package/dist/codemode/protocol.d.ts +91 -0
  163. package/dist/codemode/protocol.js +114 -0
  164. package/dist/codemode/sandbox-entry.d.ts +25 -0
  165. package/dist/codemode/sandbox-entry.js +323 -0
  166. package/dist/codemode/store.d.ts +26 -0
  167. package/dist/codemode/store.js +53 -0
  168. package/dist/codemode/tool.d.ts +105 -0
  169. package/dist/codemode/tool.js +283 -0
  170. package/dist/compaction/branch-summary.d.ts +30 -0
  171. package/dist/compaction/branch-summary.js +79 -0
  172. package/dist/compaction/breaker.d.ts +32 -0
  173. package/dist/compaction/breaker.js +65 -0
  174. package/dist/compaction/cut-point.d.ts +23 -0
  175. package/dist/compaction/cut-point.js +70 -0
  176. package/dist/compaction/estimate.d.ts +30 -0
  177. package/dist/compaction/estimate.js +114 -0
  178. package/dist/compaction/prune-tier.d.ts +31 -0
  179. package/dist/compaction/prune-tier.js +83 -0
  180. package/dist/compaction/serialize.d.ts +20 -0
  181. package/dist/compaction/serialize.js +115 -0
  182. package/dist/compaction/summarize-tier.d.ts +111 -0
  183. package/dist/compaction/summarize-tier.js +305 -0
  184. package/dist/config/auth-file.d.ts +39 -0
  185. package/dist/config/auth-file.js +92 -0
  186. package/dist/config/context-files.d.ts +30 -0
  187. package/dist/config/context-files.js +77 -0
  188. package/dist/config/load.d.ts +45 -0
  189. package/dist/config/load.js +97 -0
  190. package/dist/config/merge.d.ts +73 -0
  191. package/dist/config/merge.js +248 -0
  192. package/dist/config/paths.d.ts +38 -0
  193. package/dist/config/paths.js +108 -0
  194. package/dist/config/profile.d.ts +27 -0
  195. package/dist/config/profile.js +65 -0
  196. package/dist/config/schema.d.ts +34 -0
  197. package/dist/config/schema.js +413 -0
  198. package/dist/config/trust.d.ts +42 -0
  199. package/dist/config/trust.js +122 -0
  200. package/dist/config/types.d.ts +172 -0
  201. package/dist/config/types.js +27 -0
  202. package/dist/config/write.d.ts +10 -0
  203. package/dist/config/write.js +25 -0
  204. package/dist/errors.d.ts +28 -0
  205. package/dist/errors.js +30 -0
  206. package/dist/hooks/config.d.ts +49 -0
  207. package/dist/hooks/config.js +102 -0
  208. package/dist/hooks/dispatcher.d.ts +41 -0
  209. package/dist/hooks/dispatcher.js +104 -0
  210. package/dist/hooks/matcher.d.ts +22 -0
  211. package/dist/hooks/matcher.js +108 -0
  212. package/dist/hooks/protocol.d.ts +33 -0
  213. package/dist/hooks/protocol.js +240 -0
  214. package/dist/hooks/runner.d.ts +30 -0
  215. package/dist/hooks/runner.js +143 -0
  216. package/dist/hooks/types.d.ts +147 -0
  217. package/dist/hooks/types.js +20 -0
  218. package/dist/host/api-impl.d.ts +75 -0
  219. package/dist/host/api-impl.js +173 -0
  220. package/dist/host/loader.d.ts +31 -0
  221. package/dist/host/loader.js +147 -0
  222. package/dist/host/types.d.ts +169 -0
  223. package/dist/host/types.js +14 -0
  224. package/dist/host.d.ts +5 -0
  225. package/dist/host.js +4 -0
  226. package/dist/index.d.ts +41 -0
  227. package/dist/index.js +28 -0
  228. package/dist/modes/commands-core.d.ts +44 -0
  229. package/dist/modes/commands-core.js +171 -0
  230. package/dist/modes/interactive/approval-dialog.d.ts +48 -0
  231. package/dist/modes/interactive/approval-dialog.js +202 -0
  232. package/dist/modes/interactive/commands.d.ts +41 -0
  233. package/dist/modes/interactive/commands.js +202 -0
  234. package/dist/modes/interactive/completion.d.ts +53 -0
  235. package/dist/modes/interactive/completion.js +157 -0
  236. package/dist/modes/interactive/interactive-mode.d.ts +46 -0
  237. package/dist/modes/interactive/interactive-mode.js +487 -0
  238. package/dist/modes/interactive/key-dispatch.d.ts +29 -0
  239. package/dist/modes/interactive/key-dispatch.js +107 -0
  240. package/dist/modes/interactive/line/line-editor.d.ts +50 -0
  241. package/dist/modes/interactive/line/line-editor.js +232 -0
  242. package/dist/modes/interactive/line/line-mode.d.ts +20 -0
  243. package/dist/modes/interactive/line/line-mode.js +216 -0
  244. package/dist/modes/interactive/line/line-render.d.ts +35 -0
  245. package/dist/modes/interactive/line/line-render.js +171 -0
  246. package/dist/modes/interactive/line/paste-state.d.ts +26 -0
  247. package/dist/modes/interactive/line/paste-state.js +72 -0
  248. package/dist/modes/interactive/message-view.d.ts +77 -0
  249. package/dist/modes/interactive/message-view.js +269 -0
  250. package/dist/modes/interactive/pickers.d.ts +42 -0
  251. package/dist/modes/interactive/pickers.js +115 -0
  252. package/dist/modes/interactive/startup-ui.d.ts +28 -0
  253. package/dist/modes/interactive/startup-ui.js +238 -0
  254. package/dist/modes/interactive/status-bar.d.ts +48 -0
  255. package/dist/modes/interactive/status-bar.js +139 -0
  256. package/dist/modes/interactive/tool-view.d.ts +95 -0
  257. package/dist/modes/interactive/tool-view.js +344 -0
  258. package/dist/modes/print/json-event.d.ts +15 -0
  259. package/dist/modes/print/json-event.js +39 -0
  260. package/dist/modes/print/print-mode.d.ts +15 -0
  261. package/dist/modes/print/print-mode.js +96 -0
  262. package/dist/modes/rpc/commands.d.ts +40 -0
  263. package/dist/modes/rpc/commands.js +258 -0
  264. package/dist/modes/rpc/jsonl.d.ts +16 -0
  265. package/dist/modes/rpc/jsonl.js +55 -0
  266. package/dist/modes/rpc/rpc-mode.d.ts +22 -0
  267. package/dist/modes/rpc/rpc-mode.js +153 -0
  268. package/dist/modes/session-report.d.ts +55 -0
  269. package/dist/modes/session-report.js +278 -0
  270. package/dist/modes/shared.d.ts +13 -0
  271. package/dist/modes/shared.js +52 -0
  272. package/dist/modes/startup-ui-text.d.ts +16 -0
  273. package/dist/modes/startup-ui-text.js +103 -0
  274. package/dist/permissions/broker.d.ts +47 -0
  275. package/dist/permissions/broker.js +107 -0
  276. package/dist/permissions/dangerous.d.ts +47 -0
  277. package/dist/permissions/dangerous.js +370 -0
  278. package/dist/permissions/pipeline.d.ts +51 -0
  279. package/dist/permissions/pipeline.js +181 -0
  280. package/dist/permissions/preview.d.ts +43 -0
  281. package/dist/permissions/preview.js +463 -0
  282. package/dist/permissions/rules.d.ts +58 -0
  283. package/dist/permissions/rules.js +249 -0
  284. package/dist/permissions/types.d.ts +100 -0
  285. package/dist/permissions/types.js +18 -0
  286. package/dist/rpc.d.ts +171 -0
  287. package/dist/rpc.js +13 -0
  288. package/dist/sdk.d.ts +98 -0
  289. package/dist/sdk.js +195 -0
  290. package/dist/session/manager.d.ts +70 -0
  291. package/dist/session/manager.js +278 -0
  292. package/dist/session/migrate.d.ts +19 -0
  293. package/dist/session/migrate.js +53 -0
  294. package/dist/session/projection.d.ts +50 -0
  295. package/dist/session/projection.js +180 -0
  296. package/dist/session/store.d.ts +47 -0
  297. package/dist/session/store.js +210 -0
  298. package/dist/session/tree.d.ts +21 -0
  299. package/dist/session/tree.js +88 -0
  300. package/dist/session/types.d.ts +199 -0
  301. package/dist/session/types.js +18 -0
  302. package/dist/skills/discover.d.ts +60 -0
  303. package/dist/skills/discover.js +160 -0
  304. package/dist/skills/expand.d.ts +35 -0
  305. package/dist/skills/expand.js +46 -0
  306. package/dist/skills/frontmatter.d.ts +27 -0
  307. package/dist/skills/frontmatter.js +157 -0
  308. package/dist/skills/index-prompt.d.ts +13 -0
  309. package/dist/skills/index-prompt.js +42 -0
  310. package/dist/skills/templates.d.ts +52 -0
  311. package/dist/skills/templates.js +177 -0
  312. package/dist/tools/bash.d.ts +49 -0
  313. package/dist/tools/bash.js +222 -0
  314. package/dist/tools/edit-fuzzy.d.ts +36 -0
  315. package/dist/tools/edit-fuzzy.js +129 -0
  316. package/dist/tools/edit.d.ts +38 -0
  317. package/dist/tools/edit.js +241 -0
  318. package/dist/tools/file-mutex.d.ts +8 -0
  319. package/dist/tools/file-mutex.js +29 -0
  320. package/dist/tools/glob.d.ts +44 -0
  321. package/dist/tools/glob.js +217 -0
  322. package/dist/tools/grep.d.ts +39 -0
  323. package/dist/tools/grep.js +179 -0
  324. package/dist/tools/ignore.d.ts +40 -0
  325. package/dist/tools/ignore.js +174 -0
  326. package/dist/tools/ls.d.ts +21 -0
  327. package/dist/tools/ls.js +96 -0
  328. package/dist/tools/output-accumulator.d.ts +48 -0
  329. package/dist/tools/output-accumulator.js +106 -0
  330. package/dist/tools/paths.d.ts +20 -0
  331. package/dist/tools/paths.js +58 -0
  332. package/dist/tools/presets.d.ts +71 -0
  333. package/dist/tools/presets.js +128 -0
  334. package/dist/tools/process-tree.d.ts +35 -0
  335. package/dist/tools/process-tree.js +125 -0
  336. package/dist/tools/read.d.ts +28 -0
  337. package/dist/tools/read.js +181 -0
  338. package/dist/tools/registry.d.ts +43 -0
  339. package/dist/tools/registry.js +106 -0
  340. package/dist/tools/shell.d.ts +38 -0
  341. package/dist/tools/shell.js +91 -0
  342. package/dist/tools/task.d.ts +29 -0
  343. package/dist/tools/task.js +107 -0
  344. package/dist/tools/todo.d.ts +28 -0
  345. package/dist/tools/todo.js +107 -0
  346. package/dist/tools/truncate.d.ts +44 -0
  347. package/dist/tools/truncate.js +175 -0
  348. package/dist/tools/types.d.ts +135 -0
  349. package/dist/tools/types.js +19 -0
  350. package/dist/tools/write.d.ts +20 -0
  351. package/dist/tools/write.js +84 -0
  352. package/dist/tui/ansi.d.ts +29 -0
  353. package/dist/tui/ansi.js +420 -0
  354. package/dist/tui/component.d.ts +38 -0
  355. package/dist/tui/component.js +13 -0
  356. package/dist/tui/components/box.d.ts +26 -0
  357. package/dist/tui/components/box.js +65 -0
  358. package/dist/tui/components/container.d.ts +14 -0
  359. package/dist/tui/components/container.js +39 -0
  360. package/dist/tui/components/editor-buffer.d.ts +67 -0
  361. package/dist/tui/components/editor-buffer.js +300 -0
  362. package/dist/tui/components/editor-paste.d.ts +29 -0
  363. package/dist/tui/components/editor-paste.js +64 -0
  364. package/dist/tui/components/editor.d.ts +114 -0
  365. package/dist/tui/components/editor.js +530 -0
  366. package/dist/tui/components/key-value.d.ts +29 -0
  367. package/dist/tui/components/key-value.js +48 -0
  368. package/dist/tui/components/loader.d.ts +35 -0
  369. package/dist/tui/components/loader.js +71 -0
  370. package/dist/tui/components/markdown.d.ts +90 -0
  371. package/dist/tui/components/markdown.js +462 -0
  372. package/dist/tui/components/meter.d.ts +29 -0
  373. package/dist/tui/components/meter.js +47 -0
  374. package/dist/tui/components/overlay.d.ts +24 -0
  375. package/dist/tui/components/overlay.js +52 -0
  376. package/dist/tui/components/select-list.d.ts +57 -0
  377. package/dist/tui/components/select-list.js +179 -0
  378. package/dist/tui/components/spacer.d.ts +11 -0
  379. package/dist/tui/components/spacer.js +16 -0
  380. package/dist/tui/components/text.d.ts +30 -0
  381. package/dist/tui/components/text.js +65 -0
  382. package/dist/tui/keybindings.d.ts +66 -0
  383. package/dist/tui/keybindings.js +120 -0
  384. package/dist/tui/keys.d.ts +38 -0
  385. package/dist/tui/keys.js +275 -0
  386. package/dist/tui/stdin-buffer.d.ts +41 -0
  387. package/dist/tui/stdin-buffer.js +206 -0
  388. package/dist/tui/terminal.d.ts +79 -0
  389. package/dist/tui/terminal.js +153 -0
  390. package/dist/tui/theme.d.ts +31 -0
  391. package/dist/tui/theme.js +199 -0
  392. package/dist/tui/tui.d.ts +103 -0
  393. package/dist/tui/tui.js +363 -0
  394. package/dist/tui/vt-screen.d.ts +46 -0
  395. package/dist/tui/vt-screen.js +251 -0
  396. package/dist/tui.d.ts +30 -0
  397. package/dist/tui.js +31 -0
  398. package/dist/version.d.ts +8 -0
  399. package/dist/version.js +24 -0
  400. package/docs/codemode.md +102 -0
  401. package/docs/hooks.md +196 -0
  402. package/docs/host-api.md +161 -0
  403. package/docs/providers.md +316 -0
  404. package/docs/rpc.md +253 -0
  405. package/docs/session-format.md +119 -0
  406. package/docs/tui.md +168 -0
  407. package/package.json +101 -4
@@ -0,0 +1,303 @@
1
+ /**
2
+ * openai-completions 请求体(设计 §3.1、§3.3):消息转换、compat 开关、思考字段、缓存。
3
+ *
4
+ * compat 开关在这里生效的位置:
5
+ * - maxTokensField / supportsDeveloperRole / supportsUsageInStreaming(stream_options)/
6
+ * supportsStore(store:false)/ supportsStrictTools(strict:true,仅对严格兼容的 schema);
7
+ * - thinkingFormat:openai → reasoning_effort;openrouter → reasoning.effort;deepseek →
8
+ * thinking.type(+ reasoning_effort);zai → thinking.type(+ reasoning_effort);qwen →
9
+ * enable_thinking(+ thinkingTokenBudgetField 预算);none → 不发;
10
+ * - requiresReasoningContentOnAssistantMessages:推理模型的助手消息一律带 reasoning_content;
11
+ * - requiresToolResultName / requiresAssistantAfterToolResult / supportsMidConvoSystemMessages;
12
+ * - cacheControlFormat "anthropic":system 末、最后一个工具、最后一条 user / tool 消息打
13
+ * cache_control(OpenRouter 上的 anthropic/* 模型)。
14
+ * 缓存(第三波 §1.3):`prompt_cache_key = sessionId` 只在 `sendPromptCacheKey`(官方端点缺省开)时发;
15
+ * `long` 在 `supportsLongCacheRetention` 时发 `prompt_cache_retention: "24h"`,否则降为 short;
16
+ * 保留层级未指定时读 `AMA_CACHE_RETENTION`。`toolChoice: "none"`(有工具时)→ `tool_choice: "none"`。
17
+ */
18
+ import { contentText, normalizeContext, normalizeContextInline, sanitizeText, } from "../context.js";
19
+ import { DEFAULT_THINKING_BUDGETS, clampBudgetToAnswerRoom, clampThinkingLevel, mappedThinkingValue, } from "../thinking.js";
20
+ import { cacheControlFor } from "./anthropic-request.js";
21
+ import { effectiveRetention, resolveCacheRetention, resolvePromptCacheCompat, } from "./cache-params.js";
22
+ import { detectCompat } from "./openai-compat.js";
23
+ /** 思考文本回放用的字段名;thinkingSignature 记录来源字段,回放时原样放回。 */
24
+ export const REASONING_FIELDS = ["reasoning_content", "reasoning", "reasoning_text"];
25
+ export const ASSISTANT_BRIDGE_TEXT = "Tool results received.";
26
+ function imagePart(block) {
27
+ return { type: "image_url", image_url: { url: `data:${block.mimeType};base64,${block.data}` } };
28
+ }
29
+ function convertUser(message) {
30
+ if (typeof message.content === "string") {
31
+ return { role: "user", content: sanitizeText(message.content) };
32
+ }
33
+ const parts = [];
34
+ for (const block of message.content) {
35
+ if (block.type === "image")
36
+ parts.push(imagePart(block));
37
+ else if (block.text.length > 0)
38
+ parts.push({ type: "text", text: sanitizeText(block.text) });
39
+ }
40
+ return parts.length > 0 ? { role: "user", content: parts } : undefined;
41
+ }
42
+ function normalizeCallId(model, id) {
43
+ const base = id.includes("|") ? (id.split("|")[0] ?? id) : id;
44
+ return model.provider === "openai" && base.length > 40 ? base.slice(0, 40) : base;
45
+ }
46
+ function convertAssistant(model, message, compat) {
47
+ const text = message.content
48
+ .filter((b) => b.type === "text")
49
+ .map((b) => b.text)
50
+ .filter((t) => t.trim().length > 0)
51
+ .join("");
52
+ const thinking = message.content.filter((b) => b.type === "thinking" && !b.redacted);
53
+ const calls = message.content.filter((b) => b.type === "toolCall");
54
+ const out = { role: "assistant", content: text.length > 0 ? sanitizeText(text) : null };
55
+ const thinkingText = thinking
56
+ .map((b) => b.thinking)
57
+ .filter((t) => t.trim().length > 0)
58
+ .join("\n");
59
+ const field = thinking.find((b) => REASONING_FIELDS.includes(b.thinkingSignature ?? ""))?.thinkingSignature;
60
+ if (compat.requiresReasoningContentOnAssistantMessages && model.reasoning) {
61
+ out["reasoning_content"] = thinkingText;
62
+ }
63
+ else if (field && thinkingText.length > 0) {
64
+ out[field] = thinkingText;
65
+ }
66
+ if (calls.length > 0) {
67
+ out["tool_calls"] = calls.map((call) => ({
68
+ id: normalizeCallId(model, call.id),
69
+ type: "function",
70
+ function: { name: call.name, arguments: JSON.stringify(call.arguments) },
71
+ }));
72
+ }
73
+ if (out["content"] === null && calls.length === 0)
74
+ return undefined;
75
+ return out;
76
+ }
77
+ function convertToolResults(model, results, compat) {
78
+ const messages = [];
79
+ const images = [];
80
+ for (const result of results) {
81
+ const text = contentText(result.content);
82
+ const blocks = typeof result.content === "string" ? [] : result.content;
83
+ const hasImages = blocks.some((b) => b.type === "image");
84
+ const message = {
85
+ role: "tool",
86
+ tool_call_id: normalizeCallId(model, result.toolCallId),
87
+ content: sanitizeText(text.length > 0 ? text : hasImages ? "(see attached image)" : "(no output)"),
88
+ };
89
+ if (compat.requiresToolResultName)
90
+ message["name"] = result.toolName;
91
+ messages.push(message);
92
+ if (hasImages && model.input.includes("image")) {
93
+ for (const block of blocks)
94
+ if (block.type === "image")
95
+ images.push(imagePart(block));
96
+ }
97
+ }
98
+ return { messages, images };
99
+ }
100
+ export function convertMessages(model, messages, compat, instructionRole, updates = []) {
101
+ const out = [];
102
+ let afterToolResult = false;
103
+ const flushUpdates = (index) => {
104
+ for (const update of updates) {
105
+ if (update.beforeIndex === index)
106
+ out.push({ role: instructionRole, content: update.text });
107
+ }
108
+ };
109
+ for (let i = 0; i < messages.length; i++) {
110
+ flushUpdates(i);
111
+ const message = messages[i];
112
+ if (!message)
113
+ continue;
114
+ if (message.role === "toolResult") {
115
+ const batch = [];
116
+ while (messages[i]?.role === "toolResult")
117
+ batch.push(messages[i++]);
118
+ i--;
119
+ const converted = convertToolResults(model, batch, compat);
120
+ out.push(...converted.messages);
121
+ afterToolResult = true;
122
+ if (converted.images.length > 0) {
123
+ if (compat.requiresAssistantAfterToolResult) {
124
+ out.push({ role: "assistant", content: ASSISTANT_BRIDGE_TEXT });
125
+ }
126
+ out.push({
127
+ role: "user",
128
+ content: [{ type: "text", text: "Images from the tool results:" }, ...converted.images],
129
+ });
130
+ afterToolResult = false;
131
+ }
132
+ continue;
133
+ }
134
+ if (message.role === "user") {
135
+ const converted = convertUser(message);
136
+ if (!converted)
137
+ continue;
138
+ if (afterToolResult && compat.requiresAssistantAfterToolResult) {
139
+ out.push({ role: "assistant", content: ASSISTANT_BRIDGE_TEXT });
140
+ }
141
+ out.push(converted);
142
+ }
143
+ else {
144
+ const converted = convertAssistant(model, message, compat);
145
+ if (converted)
146
+ out.push(converted);
147
+ }
148
+ afterToolResult = false;
149
+ }
150
+ flushUpdates(messages.length);
151
+ return out;
152
+ }
153
+ /** strict 模式要求:object 关闭 additionalProperties 且全部属性必填(递归)。 */
154
+ export function isStrictCompatible(schema) {
155
+ if (schema.type === "object" || schema.properties) {
156
+ if (schema.additionalProperties !== false)
157
+ return false;
158
+ const keys = Object.keys(schema.properties ?? {});
159
+ const required = new Set(schema.required ?? []);
160
+ if (!keys.every((key) => required.has(key)))
161
+ return false;
162
+ return Object.values(schema.properties ?? {}).every(isStrictCompatible);
163
+ }
164
+ if (schema.type === "array" && schema.items)
165
+ return isStrictCompatible(schema.items);
166
+ return true;
167
+ }
168
+ function convertTools(tools, compat) {
169
+ return tools.map((tool) => {
170
+ const parameters = { ...tool.parameters, type: "object" };
171
+ const fn = { name: tool.name, description: tool.description, parameters };
172
+ if (compat.supportsStrictTools && isStrictCompatible(parameters))
173
+ fn["strict"] = true;
174
+ return { type: "function", function: fn };
175
+ });
176
+ }
177
+ function addCacheControlToText(message, cacheControl) {
178
+ const content = message["content"];
179
+ if (typeof content === "string" && content.length > 0) {
180
+ message["content"] = [{ type: "text", text: content, cache_control: cacheControl }];
181
+ return true;
182
+ }
183
+ if (!Array.isArray(content))
184
+ return false;
185
+ for (let i = content.length - 1; i >= 0; i--) {
186
+ const part = content[i];
187
+ if (part["type"] === "text") {
188
+ part["cache_control"] = cacheControl;
189
+ return true;
190
+ }
191
+ }
192
+ return false;
193
+ }
194
+ function applyAnthropicCache(messages, tools, cacheControl) {
195
+ const system = messages.find((m) => m["role"] === "system" || m["role"] === "developer");
196
+ if (system)
197
+ addCacheControlToText(system, cacheControl);
198
+ const lastTool = tools?.[tools.length - 1];
199
+ if (lastTool)
200
+ lastTool["cache_control"] = cacheControl;
201
+ for (let i = messages.length - 1; i >= 0; i--) {
202
+ const message = messages[i];
203
+ if (message && (message["role"] === "user" || message["role"] === "tool")) {
204
+ if (addCacheControlToText(message, cacheControl))
205
+ return;
206
+ }
207
+ }
208
+ }
209
+ /** 写思考相关字段;返回实际发出的级别值(effort 字串或预算)。 */
210
+ function applyThinking(body, model, compat, level, maxTokens) {
211
+ if (!model.reasoning || compat.thinkingFormat === "none")
212
+ return undefined;
213
+ const on = level !== "off";
214
+ const mapped = mappedThinkingValue(model, level);
215
+ const effort = on ? (typeof mapped === "string" ? mapped : level) : undefined;
216
+ const offValue = model.thinkingLevelMap?.off;
217
+ let sent;
218
+ switch (compat.thinkingFormat) {
219
+ case "openai":
220
+ if (compat.supportsReasoningEffort && effort)
221
+ sent = effort;
222
+ else if (compat.supportsReasoningEffort && !on && typeof offValue === "string")
223
+ sent = offValue;
224
+ if (sent !== undefined)
225
+ body["reasoning_effort"] = sent;
226
+ break;
227
+ case "openrouter":
228
+ if (effort)
229
+ sent = effort;
230
+ else if (offValue !== null)
231
+ sent = typeof offValue === "string" ? offValue : "none";
232
+ if (sent !== undefined)
233
+ body["reasoning"] = { effort: sent };
234
+ break;
235
+ case "deepseek":
236
+ case "zai":
237
+ if (on || offValue !== null)
238
+ body["thinking"] = { type: on ? "enabled" : "disabled" };
239
+ if (on && compat.supportsReasoningEffort && effort) {
240
+ body["reasoning_effort"] = effort;
241
+ sent = effort;
242
+ }
243
+ break;
244
+ case "qwen":
245
+ body["enable_thinking"] = on;
246
+ if (on && compat.supportsReasoningEffort && effort) {
247
+ body["reasoning_effort"] = effort;
248
+ sent = effort;
249
+ }
250
+ break;
251
+ }
252
+ if (compat.thinkingTokenBudgetField && level !== "off") {
253
+ const budget = clampBudgetToAnswerRoom(typeof mapped === "number" ? mapped : DEFAULT_THINKING_BUDGETS[level], maxTokens);
254
+ if (budget > 0) {
255
+ body[compat.thinkingTokenBudgetField] = budget;
256
+ sent ??= String(budget);
257
+ }
258
+ }
259
+ return sent;
260
+ }
261
+ export function buildOpenAIRequest(model, context, options) {
262
+ const compat = detectCompat(model);
263
+ const normalized = compat.supportsMidConvoSystemMessages
264
+ ? normalizeContextInline(context, { model })
265
+ : { ...normalizeContext(context, { model }), systemUpdates: [] };
266
+ const role = model.reasoning && compat.supportsDeveloperRole ? "developer" : "system";
267
+ const messages = [];
268
+ if (normalized.systemPrompt.length > 0) {
269
+ messages.push({ role, content: sanitizeText(normalized.systemPrompt) });
270
+ }
271
+ messages.push(...convertMessages(model, normalized.messages, compat, role, normalized.systemUpdates));
272
+ const maxTokens = options.maxTokens ?? model.maxTokens;
273
+ const level = clampThinkingLevel(model, options.thinkingLevel ?? "off");
274
+ const body = { model: model.id, messages, stream: true };
275
+ if (compat.supportsUsageInStreaming)
276
+ body["stream_options"] = { include_usage: true };
277
+ if (compat.supportsStore)
278
+ body["store"] = false;
279
+ body[compat.maxTokensField] = maxTokens;
280
+ if (options.temperature !== undefined)
281
+ body["temperature"] = options.temperature;
282
+ const tools = normalized.tools.length > 0 ? convertTools(normalized.tools, compat) : undefined;
283
+ if (tools)
284
+ body["tools"] = tools;
285
+ if (tools && options.toolChoice === "none")
286
+ body["tool_choice"] = "none";
287
+ const cacheCompat = resolvePromptCacheCompat(model, "openai-completions");
288
+ const retention = effectiveRetention(resolveCacheRetention(options.cacheRetention), cacheCompat);
289
+ if (options.sessionId && retention !== "none" && cacheCompat.sendPromptCacheKey) {
290
+ body["prompt_cache_key"] = options.sessionId.slice(0, 64);
291
+ }
292
+ if (retention === "long" && compat.cacheControlFormat !== "anthropic") {
293
+ body["prompt_cache_retention"] = "24h";
294
+ }
295
+ const cacheControl = cacheControlFor(retention);
296
+ if (compat.cacheControlFormat === "anthropic" && cacheControl) {
297
+ applyAnthropicCache(messages, tools, cacheControl);
298
+ }
299
+ const providerLevel = applyThinking(body, model, compat, level, maxTokens);
300
+ if (model.samplingParams)
301
+ Object.assign(body, model.samplingParams);
302
+ return { body, compat, thinkingLevel: level, providerThinkingLevel: providerLevel };
303
+ }
@@ -0,0 +1,52 @@
1
+ /**
2
+ * openai-responses 请求体(设计 §3.1、§3.3、§3.6):input items、instructions、工具、reasoning、
3
+ * 缓存键、无状态回放。
4
+ *
5
+ * - 系统提示折叠后放 `instructions`(不进 input,前缀稳定利于缓存);
6
+ * - 助手消息拆成 items:思考块的 `thinkingSignature` 是完整的 reasoning item(JSON,含
7
+ * `encrypted_content`),只回放给同 provider / 同模型 / 同协议;文本块的 `textSignature` 记
8
+ * message item 的 id(与 phase),同模型时以带 id 的 message item 回放,否则退回
9
+ * `{role:"assistant", content}`;工具调用 `id` 是 `call_id`,`thoughtSignature` 记 function_call
10
+ * item 的 `fc_…` id(同模型才带回,跨模型由 transform.ts 去掉);
11
+ * - `supportsStore`:发 `store: false`,推理模型同时要 `include: ["reasoning.encrypted_content"]`
12
+ * (不落服务端也能多轮回放推理);
13
+ * - reasoning:`{effort, summary:"auto"}`(summary 需 `supportsReasoningSummary`);off 只在映射表
14
+ * 给了 off 的字串时发(例如 "none"),否则不发(服务端缺省);
15
+ * - 工具 `strict` 显式给出:Responses 缺省按严格模式校验 schema,非严格兼容的 schema 必须发 false;
16
+ * - 缓存(第三波 §1.3):`prompt_cache_key = sessionId` 只在 `sendPromptCacheKey`(官方端点缺省开)
17
+ * 时发,`cacheRetention: "none"` 不发;`long` 在 `supportsExplicitPromptCacheMode` 时发
18
+ * `prompt_cache_options: {ttl:"30m"}`,否则在 `supportsLongCacheRetention` 时发
19
+ * `prompt_cache_retention: "24h"`,两者都不支持按 short;
20
+ * - `toolChoice: "none"`(有工具时)→ `tool_choice: "none"`。
21
+ */
22
+ import type { AssistantMessage, Model, ModelThinkingLevel, OpenAIResponsesCompat, ProviderData, StreamOptions, ToolResultMessage, TranscriptContext, UserMessage } from "../types.js";
23
+ type Json = Record<string, unknown>;
24
+ type Conversation = UserMessage | AssistantMessage | ToolResultMessage;
25
+ export declare const RESPONSES_API = "openai-responses";
26
+ /** 缺省(未知的 Responses 兼容服务):不要 summary、不发 store。 */
27
+ export declare const CONSERVATIVE_RESPONSES_COMPAT: Readonly<OpenAIResponsesCompat>;
28
+ /** 推断表:先 provider id,后 baseUrl 子串。 */
29
+ export declare const RESPONSES_INFERENCE_RULES: readonly {
30
+ provider: string;
31
+ baseUrl: string;
32
+ patch: Partial<OpenAIResponsesCompat>;
33
+ }[];
34
+ /** compat:保守缺省 ← 推断表 ← provider.compat ← model.compat。 */
35
+ export declare function detectResponsesCompat(model: Model, provider?: ProviderData): OpenAIResponsesCompat;
36
+ export interface MessageSignature {
37
+ id: string;
38
+ phase?: string;
39
+ }
40
+ export declare function encodeMessageSignature(id: string, phase?: string): string;
41
+ export declare function parseMessageSignature(signature: string | undefined): MessageSignature | undefined;
42
+ /** thinkingSignature → reasoning item(不是 reasoning item 的 JSON 返回 undefined)。 */
43
+ export declare function parseReasoningItem(signature: string | undefined): Json | undefined;
44
+ export declare function convertResponsesInput(model: Model, messages: readonly Conversation[]): Json[];
45
+ export interface ResponsesRequest {
46
+ body: Json;
47
+ compat: OpenAIResponsesCompat;
48
+ thinkingLevel: ModelThinkingLevel;
49
+ providerThinkingLevel: string | undefined;
50
+ }
51
+ export declare function buildResponsesRequest(model: Model, context: TranscriptContext, options: StreamOptions): ResponsesRequest;
52
+ export {};
@@ -0,0 +1,266 @@
1
+ /**
2
+ * openai-responses 请求体(设计 §3.1、§3.3、§3.6):input items、instructions、工具、reasoning、
3
+ * 缓存键、无状态回放。
4
+ *
5
+ * - 系统提示折叠后放 `instructions`(不进 input,前缀稳定利于缓存);
6
+ * - 助手消息拆成 items:思考块的 `thinkingSignature` 是完整的 reasoning item(JSON,含
7
+ * `encrypted_content`),只回放给同 provider / 同模型 / 同协议;文本块的 `textSignature` 记
8
+ * message item 的 id(与 phase),同模型时以带 id 的 message item 回放,否则退回
9
+ * `{role:"assistant", content}`;工具调用 `id` 是 `call_id`,`thoughtSignature` 记 function_call
10
+ * item 的 `fc_…` id(同模型才带回,跨模型由 transform.ts 去掉);
11
+ * - `supportsStore`:发 `store: false`,推理模型同时要 `include: ["reasoning.encrypted_content"]`
12
+ * (不落服务端也能多轮回放推理);
13
+ * - reasoning:`{effort, summary:"auto"}`(summary 需 `supportsReasoningSummary`);off 只在映射表
14
+ * 给了 off 的字串时发(例如 "none"),否则不发(服务端缺省);
15
+ * - 工具 `strict` 显式给出:Responses 缺省按严格模式校验 schema,非严格兼容的 schema 必须发 false;
16
+ * - 缓存(第三波 §1.3):`prompt_cache_key = sessionId` 只在 `sendPromptCacheKey`(官方端点缺省开)
17
+ * 时发,`cacheRetention: "none"` 不发;`long` 在 `supportsExplicitPromptCacheMode` 时发
18
+ * `prompt_cache_options: {ttl:"30m"}`,否则在 `supportsLongCacheRetention` 时发
19
+ * `prompt_cache_retention: "24h"`,两者都不支持按 short;
20
+ * - `toolChoice: "none"`(有工具时)→ `tool_choice: "none"`。
21
+ */
22
+ import { contentText, normalizeContext, sanitizeText } from "../context.js";
23
+ import { clampThinkingLevel, mappedThinkingValue } from "../thinking.js";
24
+ import { resolveCacheRetention, resolvePromptCacheCompat } from "./cache-params.js";
25
+ import { isStrictCompatible } from "./openai-request.js";
26
+ export const RESPONSES_API = "openai-responses";
27
+ const RESPONSES_COMPAT_KEYS = [
28
+ "supportsReasoningSummary",
29
+ "supportsStore",
30
+ ];
31
+ /** 缺省(未知的 Responses 兼容服务):不要 summary、不发 store。 */
32
+ export const CONSERVATIVE_RESPONSES_COMPAT = {
33
+ supportsReasoningSummary: false,
34
+ supportsStore: false,
35
+ };
36
+ /** 推断表:先 provider id,后 baseUrl 子串。 */
37
+ export const RESPONSES_INFERENCE_RULES = [
38
+ {
39
+ provider: "openai",
40
+ baseUrl: "api.openai.com",
41
+ patch: { supportsReasoningSummary: true, supportsStore: true },
42
+ },
43
+ // xAI:store 与 encrypted_content 可用;未验证 reasoning summary,不发
44
+ { provider: "xai", baseUrl: "api.x.ai", patch: { supportsStore: true } },
45
+ ];
46
+ function pick(compat) {
47
+ const out = {};
48
+ for (const key of RESPONSES_COMPAT_KEYS) {
49
+ const value = compat?.[key];
50
+ if (value !== undefined)
51
+ out[key] = value;
52
+ }
53
+ return out;
54
+ }
55
+ /** compat:保守缺省 ← 推断表 ← provider.compat ← model.compat。 */
56
+ export function detectResponsesCompat(model, provider) {
57
+ const providerId = provider?.id ?? model.provider;
58
+ const baseUrl = (model.baseUrl ?? provider?.baseUrl ?? "").toLowerCase();
59
+ const rule = RESPONSES_INFERENCE_RULES.find((r) => r.provider === providerId) ??
60
+ RESPONSES_INFERENCE_RULES.find((r) => baseUrl.includes(r.baseUrl));
61
+ return {
62
+ ...CONSERVATIVE_RESPONSES_COMPAT,
63
+ ...rule?.patch,
64
+ ...pick(provider?.compat),
65
+ ...pick(model.compat),
66
+ };
67
+ }
68
+ export function encodeMessageSignature(id, phase) {
69
+ return JSON.stringify(phase ? { v: 1, id, phase } : { v: 1, id });
70
+ }
71
+ export function parseMessageSignature(signature) {
72
+ if (!signature?.startsWith("{"))
73
+ return undefined;
74
+ try {
75
+ const parsed = JSON.parse(signature);
76
+ if (parsed["v"] !== 1 || typeof parsed["id"] !== "string")
77
+ return undefined;
78
+ return typeof parsed["phase"] === "string"
79
+ ? { id: parsed["id"], phase: parsed["phase"] }
80
+ : { id: parsed["id"] };
81
+ }
82
+ catch {
83
+ return undefined;
84
+ }
85
+ }
86
+ /** thinkingSignature → reasoning item(不是 reasoning item 的 JSON 返回 undefined)。 */
87
+ export function parseReasoningItem(signature) {
88
+ if (!signature?.startsWith("{"))
89
+ return undefined;
90
+ try {
91
+ const parsed = JSON.parse(signature);
92
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
93
+ return undefined;
94
+ const item = parsed;
95
+ return item["type"] === "reasoning" && typeof item["id"] === "string" ? item : undefined;
96
+ }
97
+ catch {
98
+ return undefined;
99
+ }
100
+ }
101
+ // ---------------------------------------------------------------------------
102
+ // input items
103
+ // ---------------------------------------------------------------------------
104
+ function imagePart(block) {
105
+ return {
106
+ type: "input_image",
107
+ detail: "auto",
108
+ image_url: `data:${block.mimeType};base64,${block.data}`,
109
+ };
110
+ }
111
+ function convertUser(message) {
112
+ const blocks = typeof message.content === "string"
113
+ ? [{ type: "text", text: message.content }]
114
+ : message.content;
115
+ const content = [];
116
+ for (const block of blocks) {
117
+ if (block.type === "image")
118
+ content.push(imagePart(block));
119
+ else if (block.text.length > 0) {
120
+ content.push({ type: "input_text", text: sanitizeText(block.text) });
121
+ }
122
+ }
123
+ return content.length > 0 ? { role: "user", content } : undefined;
124
+ }
125
+ function convertAssistant(model, message) {
126
+ const sameModel = message.provider === model.provider &&
127
+ message.model === model.id &&
128
+ message.api === RESPONSES_API;
129
+ const items = [];
130
+ for (const block of message.content) {
131
+ if (block.type === "thinking") {
132
+ // 推理只能以 reasoning item 回放;没有可用 item 的(别家 / 中止)不发
133
+ const item = sameModel ? parseReasoningItem(block.thinkingSignature) : undefined;
134
+ if (item)
135
+ items.push(item);
136
+ }
137
+ else if (block.type === "text") {
138
+ const signature = sameModel ? parseMessageSignature(block.textSignature) : undefined;
139
+ if (signature) {
140
+ items.push({
141
+ type: "message",
142
+ role: "assistant",
143
+ id: signature.id,
144
+ status: "completed",
145
+ content: [{ type: "output_text", text: sanitizeText(block.text), annotations: [] }],
146
+ ...(signature.phase ? { phase: signature.phase } : {}),
147
+ });
148
+ }
149
+ else if (block.text.trim().length > 0) {
150
+ items.push({ role: "assistant", content: sanitizeText(block.text) });
151
+ }
152
+ }
153
+ else {
154
+ const itemId = block.thoughtSignature;
155
+ items.push({
156
+ type: "function_call",
157
+ ...(sameModel && itemId?.startsWith("fc") ? { id: itemId } : {}),
158
+ call_id: block.id,
159
+ name: block.name,
160
+ arguments: JSON.stringify(block.arguments),
161
+ });
162
+ }
163
+ }
164
+ return items;
165
+ }
166
+ function convertToolResult(model, message) {
167
+ const text = contentText(message.content);
168
+ const images = typeof message.content === "string" || !model.input.includes("image")
169
+ ? []
170
+ : message.content.filter((b) => b.type === "image");
171
+ let output;
172
+ if (images.length === 0) {
173
+ const hadImages = typeof message.content !== "string" && message.content.length > 0;
174
+ output = sanitizeText(text.length > 0 ? text : hadImages ? "(see attached image)" : "(no output)");
175
+ }
176
+ else {
177
+ output = [
178
+ ...(text.length > 0 ? [{ type: "input_text", text: sanitizeText(text) }] : []),
179
+ ...images.map(imagePart),
180
+ ];
181
+ }
182
+ return { type: "function_call_output", call_id: message.toolCallId, output };
183
+ }
184
+ export function convertResponsesInput(model, messages) {
185
+ const input = [];
186
+ for (const message of messages) {
187
+ if (message.role === "user") {
188
+ const converted = convertUser(message);
189
+ if (converted)
190
+ input.push(converted);
191
+ }
192
+ else if (message.role === "assistant") {
193
+ input.push(...convertAssistant(model, message));
194
+ }
195
+ else {
196
+ input.push(convertToolResult(model, message));
197
+ }
198
+ }
199
+ return input;
200
+ }
201
+ function convertTools(tools) {
202
+ return tools.map((tool) => {
203
+ const parameters = { ...tool.parameters, type: "object" };
204
+ return {
205
+ type: "function",
206
+ name: tool.name,
207
+ description: tool.description,
208
+ parameters,
209
+ strict: isStrictCompatible(parameters),
210
+ };
211
+ });
212
+ }
213
+ /** 写 reasoning;返回实际发出的 effort。 */
214
+ function applyReasoning(body, model, compat, level) {
215
+ if (!model.reasoning)
216
+ return undefined;
217
+ if (level === "off") {
218
+ const off = model.thinkingLevelMap?.off;
219
+ if (typeof off !== "string")
220
+ return undefined;
221
+ body["reasoning"] = { effort: off };
222
+ return off;
223
+ }
224
+ const mapped = mappedThinkingValue(model, level);
225
+ const effort = typeof mapped === "string" ? mapped : level;
226
+ body["reasoning"] = compat.supportsReasoningSummary ? { effort, summary: "auto" } : { effort };
227
+ return effort;
228
+ }
229
+ export function buildResponsesRequest(model, context, options) {
230
+ const compat = detectResponsesCompat(model);
231
+ const normalized = normalizeContext(context, { model });
232
+ const level = clampThinkingLevel(model, options.thinkingLevel ?? "off");
233
+ const body = { model: model.id, stream: true };
234
+ if (normalized.systemPrompt.length > 0) {
235
+ body["instructions"] = sanitizeText(normalized.systemPrompt);
236
+ }
237
+ body["input"] = convertResponsesInput(model, normalized.messages);
238
+ body["max_output_tokens"] = options.maxTokens ?? model.maxTokens;
239
+ if (compat.supportsStore) {
240
+ body["store"] = false;
241
+ if (model.reasoning)
242
+ body["include"] = ["reasoning.encrypted_content"];
243
+ }
244
+ if (normalized.tools.length > 0) {
245
+ body["tools"] = convertTools(normalized.tools);
246
+ if (options.toolChoice === "none")
247
+ body["tool_choice"] = "none";
248
+ }
249
+ if (options.temperature !== undefined)
250
+ body["temperature"] = options.temperature;
251
+ const cacheCompat = resolvePromptCacheCompat(model, RESPONSES_API);
252
+ const retention = resolveCacheRetention(options.cacheRetention);
253
+ if (options.sessionId && retention !== "none" && cacheCompat.sendPromptCacheKey) {
254
+ body["prompt_cache_key"] = options.sessionId.slice(0, 64);
255
+ }
256
+ if (retention === "long" && cacheCompat.supportsExplicitPromptCacheMode) {
257
+ body["prompt_cache_options"] = { ttl: "30m" };
258
+ }
259
+ else if (retention === "long" && cacheCompat.supportsLongCacheRetention) {
260
+ body["prompt_cache_retention"] = "24h";
261
+ }
262
+ const providerLevel = applyReasoning(body, model, compat, level);
263
+ if (model.samplingParams)
264
+ Object.assign(body, model.samplingParams);
265
+ return { body, compat, thinkingLevel: level, providerThinkingLevel: providerLevel };
266
+ }
@@ -0,0 +1,28 @@
1
+ /**
2
+ * openai-responses 协议(设计 §3.1):POST `{baseUrl}/responses`(stream),`event: response.*` →
3
+ * 事件;没有 `[DONE]`,以 `response.completed / incomplete / failed` 结束。
4
+ *
5
+ * - 每个 output item 一个内容块(按 `output_index` 对应,缺省时按 item id):reasoning → 思考、
6
+ * message → 文本、function_call → 工具调用;`output_item.done` 关块并记签名:reasoning 记完整
7
+ * item(含 `encrypted_content`,供无状态回放),message 记 id / phase,function_call 记 `fc_` id;
8
+ * - 思考文本来自 `reasoning_summary_text.delta`(多段 summary 之间空一行)或
9
+ * `reasoning_text.delta`;增量缺失而 done 里有全文时补齐;
10
+ * - `function_call_arguments.done` 与已拼接的增量不一致时以前缀补齐;
11
+ * - 停止:completed → stop(有工具调用则 toolUse);incomplete + max_output_tokens → length,其它
12
+ * incomplete 原因 → error;failed / `error` 事件 → error(`code: message`);无终止事件 → 断流;
13
+ * - usage:input = input_tokens − input_tokens_details.cached_tokens,reasoning =
14
+ * output_tokens_details.reasoning_tokens(已含在 output_tokens 里);cached_tokens 出现(含 0)即
15
+ * `cacheReported: true`。
16
+ */
17
+ import type { ApiImplementation, OpenAIResponsesCompat, Usage } from "../types.js";
18
+ type Json = Record<string, unknown>;
19
+ export declare function parseResponsesUsage(raw: Json): Usage;
20
+ type MappedStop = {
21
+ reason: "stop" | "length";
22
+ } | {
23
+ reason: "error";
24
+ message: string;
25
+ };
26
+ export declare function mapResponsesStatus(status: string | undefined, incomplete?: string): MappedStop;
27
+ export declare const openAIResponsesApi: ApiImplementation<OpenAIResponsesCompat>;
28
+ export {};