@poolzin/pool-bot 2026.2.20 → 2026.2.22

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 (388) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/agents/api-key-rotation.js +47 -0
  3. package/dist/agents/apply-patch-update.js +19 -9
  4. package/dist/agents/apply-patch.js +72 -47
  5. package/dist/agents/bash-tools.exec.js +141 -559
  6. package/dist/agents/cli-backends.js +49 -6
  7. package/dist/agents/cli-runner/helpers.js +69 -152
  8. package/dist/agents/cli-runner.js +70 -19
  9. package/dist/agents/identity.js +20 -1
  10. package/dist/agents/image-sanitization.js +9 -0
  11. package/dist/agents/live-auth-keys.js +123 -26
  12. package/dist/agents/live-model-filter.js +13 -4
  13. package/dist/agents/model-auth.js +12 -0
  14. package/dist/agents/model-catalog.js +40 -9
  15. package/dist/agents/model-fallback.js +24 -0
  16. package/dist/agents/model-forward-compat.js +60 -23
  17. package/dist/agents/model-selection.js +134 -41
  18. package/dist/agents/pi-auth-json.js +2 -2
  19. package/dist/agents/pi-embedded-helpers/bootstrap.js +65 -15
  20. package/dist/agents/pi-embedded-helpers/errors.js +140 -15
  21. package/dist/agents/pi-embedded-helpers/images.js +22 -12
  22. package/dist/agents/pi-embedded-helpers.js +2 -2
  23. package/dist/agents/pi-embedded-runner/abort.js +10 -3
  24. package/dist/agents/pi-embedded-runner/compact.js +230 -32
  25. package/dist/agents/pi-embedded-runner/extra-params.js +203 -12
  26. package/dist/agents/pi-embedded-runner/google.js +109 -19
  27. package/dist/agents/pi-embedded-runner/history.js +35 -17
  28. package/dist/agents/pi-embedded-runner/run/attempt.js +386 -80
  29. package/dist/agents/pi-embedded-runner/run/images.js +81 -55
  30. package/dist/agents/pi-embedded-runner/run/payloads.js +89 -39
  31. package/dist/agents/pi-embedded-runner/run.js +193 -25
  32. package/dist/agents/pi-embedded-runner/run.overflow-compaction.mocks.shared.js +2 -2
  33. package/dist/agents/pi-embedded-runner/runs.js +17 -8
  34. package/dist/agents/pi-embedded-runner/tool-result-context-guard.js +262 -0
  35. package/dist/agents/pi-embedded-runner.js +1 -1
  36. package/dist/agents/pi-embedded-subscribe.handlers.tools.js +180 -10
  37. package/dist/agents/pi-embedded-subscribe.js +37 -0
  38. package/dist/agents/pi-embedded-subscribe.tools.js +127 -30
  39. package/dist/agents/pi-model-discovery.js +9 -2
  40. package/dist/agents/pi-tool-definition-adapter.js +60 -8
  41. package/dist/agents/pi-tools.before-tool-call.js +1 -1
  42. package/dist/agents/pi-tools.js +113 -94
  43. package/dist/agents/pi-tools.read.js +337 -38
  44. package/dist/agents/poolbot-tools.js +14 -5
  45. package/dist/agents/provider/config-loader.js +76 -0
  46. package/dist/agents/provider/index.js +15 -0
  47. package/dist/agents/provider/integration.js +136 -0
  48. package/dist/agents/provider/models-dev.js +129 -0
  49. package/dist/agents/provider/rate-limits.js +458 -0
  50. package/dist/agents/provider/request-monitor.js +449 -0
  51. package/dist/agents/provider/session-binding.js +376 -0
  52. package/dist/agents/provider/token-pool.js +541 -0
  53. package/dist/agents/sandbox/docker.js +10 -5
  54. package/dist/agents/sandbox/registry.js +96 -46
  55. package/dist/agents/sandbox/sanitize-env-vars.js +82 -0
  56. package/dist/agents/sandbox-paths.js +43 -10
  57. package/dist/agents/session-tool-result-guard-wrapper.js +23 -11
  58. package/dist/agents/session-tool-result-guard.js +39 -39
  59. package/dist/agents/session-transcript-repair.js +36 -33
  60. package/dist/agents/session-write-lock.js +62 -44
  61. package/dist/agents/skills/frontmatter.js +49 -88
  62. package/dist/agents/skills/workspace.js +335 -28
  63. package/dist/agents/subagent-announce.js +508 -174
  64. package/dist/agents/subagent-registry.js +45 -4
  65. package/dist/agents/subagent-spawn.js +16 -33
  66. package/dist/agents/system-prompt-report.js +27 -10
  67. package/dist/agents/system-prompt.js +26 -32
  68. package/dist/agents/tool-call-id.js +69 -17
  69. package/dist/agents/tool-display-common.js +1 -1
  70. package/dist/agents/tool-images.js +64 -31
  71. package/dist/agents/tools/canvas-tool.js +17 -11
  72. package/dist/agents/tools/common.js +37 -19
  73. package/dist/agents/tools/cron-tool.js +40 -38
  74. package/dist/agents/tools/gateway.js +70 -2
  75. package/dist/agents/tools/message-tool.js +181 -40
  76. package/dist/agents/tools/nodes-tool.js +128 -36
  77. package/dist/agents/tools/nodes-utils.js +12 -38
  78. package/dist/agents/tools/session-status-tool.js +24 -71
  79. package/dist/agents/tools/sessions-helpers.js +38 -210
  80. package/dist/agents/tools/sessions-spawn-tool.js +28 -198
  81. package/dist/agents/tools/telegram-actions.js +58 -7
  82. package/dist/agents/tools/web-fetch-utils.js +112 -7
  83. package/dist/agents/tools/web-fetch.js +279 -175
  84. package/dist/agents/tools/web-shared.js +71 -8
  85. package/dist/agents/usage.js +25 -16
  86. package/dist/auto-reply/commands-registry.data.js +85 -11
  87. package/dist/auto-reply/dispatch.js +40 -21
  88. package/dist/auto-reply/reply/abort.js +102 -33
  89. package/dist/auto-reply/reply/commands-core.js +82 -33
  90. package/dist/auto-reply/reply/commands-export-session.js +1 -1
  91. package/dist/auto-reply/reply/commands-info.js +41 -12
  92. package/dist/auto-reply/reply/commands-subagents.js +352 -100
  93. package/dist/auto-reply/reply/commands-system-prompt.js +2 -2
  94. package/dist/auto-reply/reply/dispatch-from-config.js +100 -29
  95. package/dist/auto-reply/reply/elevated-unavailable.js +1 -1
  96. package/dist/auto-reply/reply/inbound-meta.js +12 -1
  97. package/dist/auto-reply/reply/mentions.js +18 -11
  98. package/dist/auto-reply/reply/normalize-reply.js +17 -8
  99. package/dist/auto-reply/reply/reply-dispatcher.js +62 -10
  100. package/dist/auto-reply/reply/session.js +102 -21
  101. package/dist/auto-reply/reply/streaming-directives.js +16 -5
  102. package/dist/auto-reply/status.js +73 -50
  103. package/dist/browser/extension-relay.js +3 -3
  104. package/dist/browser/http-auth.js +1 -1
  105. package/dist/browser/paths.js +2 -2
  106. package/dist/build-info.json +3 -3
  107. package/dist/channels/allowlist-match.js +20 -0
  108. package/dist/channels/allowlists/resolve-utils.js +65 -2
  109. package/dist/channels/chat-type.js +8 -4
  110. package/dist/channels/dock.js +127 -35
  111. package/dist/channels/draft-stream-loop.js +6 -2
  112. package/dist/channels/plugins/actions/telegram.js +42 -18
  113. package/dist/channels/plugins/allowlist-match.js +1 -1
  114. package/dist/channels/plugins/group-mentions.js +51 -41
  115. package/dist/channels/plugins/message-action-names.js +2 -0
  116. package/dist/channels/plugins/message-actions.js +24 -5
  117. package/dist/channels/plugins/normalize/discord.js +26 -4
  118. package/dist/channels/plugins/normalize/signal.js +35 -22
  119. package/dist/channels/plugins/onboarding/helpers.js +8 -26
  120. package/dist/channels/plugins/outbound/imessage.js +15 -14
  121. package/dist/channels/registry.js +20 -7
  122. package/dist/cli/acp-cli.js +7 -5
  123. package/dist/cli/browser-cli-extension.js +25 -12
  124. package/dist/cli/browser-cli-state.cookies-storage.js +25 -6
  125. package/dist/cli/browser-cli-state.js +101 -145
  126. package/dist/cli/command-options.js +28 -0
  127. package/dist/cli/completion-cli.js +6 -6
  128. package/dist/cli/cron-cli/register.cron-add.js +25 -1
  129. package/dist/cli/cron-cli/register.cron-edit.js +44 -0
  130. package/dist/cli/cron-cli/shared.js +7 -1
  131. package/dist/cli/daemon-cli/lifecycle-core.js +23 -21
  132. package/dist/cli/daemon-cli/lifecycle.js +23 -247
  133. package/dist/cli/daemon-cli/register-service-commands.js +25 -4
  134. package/dist/cli/daemon-cli.js +1 -0
  135. package/dist/cli/devices-cli.js +33 -20
  136. package/dist/cli/gateway-cli/register.js +37 -105
  137. package/dist/cli/gateway-cli/run.js +49 -11
  138. package/dist/cli/nodes-camera.js +59 -4
  139. package/dist/cli/nodes-cli/register.camera.js +27 -24
  140. package/dist/cli/nodes-cli/rpc.js +21 -38
  141. package/dist/cli/qr-cli.js +2 -2
  142. package/dist/cli/skills-cli.format.js +2 -2
  143. package/dist/cli/update-cli/progress.js +2 -2
  144. package/dist/cli/update-cli/restart-helper.js +28 -7
  145. package/dist/cli/update-cli/shared.js +7 -7
  146. package/dist/cli/update-cli/status.js +1 -1
  147. package/dist/cli/update-cli/update-command.js +14 -8
  148. package/dist/cli/update-cli/wizard.js +2 -2
  149. package/dist/cli/update-cli.js +21 -1027
  150. package/dist/commands/auth-choice.apply.anthropic.js +10 -2
  151. package/dist/commands/channels/add-mutators.js +3 -35
  152. package/dist/commands/channels/add.js +39 -51
  153. package/dist/commands/config-validation.js +1 -1
  154. package/dist/commands/configure.gateway-auth.js +52 -15
  155. package/dist/commands/configure.gateway.js +84 -40
  156. package/dist/commands/doctor-completion.js +3 -3
  157. package/dist/commands/doctor-config-flow.js +536 -16
  158. package/dist/commands/doctor-gateway-services.js +103 -79
  159. package/dist/commands/doctor-memory-search.js +9 -9
  160. package/dist/commands/doctor-platform-notes.js +57 -30
  161. package/dist/commands/doctor-prompter.js +26 -15
  162. package/dist/commands/doctor-session-locks.js +1 -1
  163. package/dist/commands/doctor.js +21 -9
  164. package/dist/commands/model-picker.js +120 -95
  165. package/dist/commands/models/set.js +2 -21
  166. package/dist/commands/models/shared.js +65 -37
  167. package/dist/commands/onboard-helpers.js +81 -39
  168. package/dist/commands/openai-codex-oauth.js +1 -1
  169. package/dist/commands/sessions.js +52 -53
  170. package/dist/commands/status.summary.js +52 -34
  171. package/dist/commands/test-wizard-helpers.js +2 -2
  172. package/dist/config/defaults.js +79 -42
  173. package/dist/config/group-policy.js +50 -18
  174. package/dist/config/includes.js +37 -10
  175. package/dist/config/schema.help.js +5 -4
  176. package/dist/config/schema.hints.js +2 -2
  177. package/dist/config/schema.labels.js +1 -0
  178. package/dist/config/sessions/group.js +12 -11
  179. package/dist/config/sessions/paths.js +137 -11
  180. package/dist/config/sessions/store.js +185 -65
  181. package/dist/config/sessions/types.js +15 -1
  182. package/dist/config/sessions.js +1 -0
  183. package/dist/config/telegram-custom-commands.js +3 -2
  184. package/dist/config/types.js +2 -0
  185. package/dist/config/zod-schema.agent-defaults.js +6 -27
  186. package/dist/config/zod-schema.agent-runtime.js +171 -79
  187. package/dist/config/zod-schema.providers-core.js +138 -65
  188. package/dist/config/zod-schema.session.js +49 -22
  189. package/dist/control-ui/assets/index-HRr1grwl.js.map +1 -1
  190. package/dist/cron/isolated-agent/run.js +224 -57
  191. package/dist/cron/normalize.js +48 -45
  192. package/dist/cron/run-log.js +14 -0
  193. package/dist/cron/service/jobs.js +190 -28
  194. package/dist/cron/service/normalize.js +29 -11
  195. package/dist/cron/service/store.js +30 -44
  196. package/dist/cron/service/timer.js +182 -96
  197. package/dist/cron/service.js +3 -0
  198. package/dist/cron/stagger.js +37 -0
  199. package/dist/daemon/inspect.js +132 -92
  200. package/dist/daemon/runtime-paths.js +25 -4
  201. package/dist/daemon/service-audit.js +47 -16
  202. package/dist/discord/accounts.js +23 -20
  203. package/dist/discord/monitor/agent-components.js +1115 -219
  204. package/dist/discord/monitor/allow-list.js +114 -34
  205. package/dist/discord/monitor/listeners.js +204 -97
  206. package/dist/discord/monitor/message-handler.js +21 -10
  207. package/dist/discord/monitor/message-handler.preflight.js +195 -101
  208. package/dist/discord/monitor/message-handler.process.js +384 -123
  209. package/dist/discord/monitor/message-utils.js +86 -23
  210. package/dist/discord/monitor/native-command.js +77 -57
  211. package/dist/discord/monitor/provider.js +122 -117
  212. package/dist/discord/monitor/reply-context.js +20 -16
  213. package/dist/discord/monitor/reply-delivery.js +40 -8
  214. package/dist/discord/monitor/rest-fetch.js +22 -0
  215. package/dist/discord/monitor/threading.js +117 -24
  216. package/dist/discord/send.js +2 -1
  217. package/dist/discord/send.outbound.js +124 -11
  218. package/dist/discord/send.shared.js +112 -72
  219. package/dist/discord/voice-message.js +3 -3
  220. package/dist/gateway/auth.js +119 -44
  221. package/dist/gateway/call.js +76 -34
  222. package/dist/gateway/channel-health-monitor.js +57 -50
  223. package/dist/gateway/client.js +63 -29
  224. package/dist/gateway/control-ui-contract.js +1 -1
  225. package/dist/gateway/gateway-config-prompts.shared.js +2 -2
  226. package/dist/gateway/net.js +109 -1
  227. package/dist/gateway/protocol/index.js +5 -8
  228. package/dist/gateway/protocol/schema/agent.js +19 -1
  229. package/dist/gateway/protocol/schema/channels.js +21 -0
  230. package/dist/gateway/protocol/schema/cron.js +43 -30
  231. package/dist/gateway/protocol/schema/protocol-schemas.js +6 -11
  232. package/dist/gateway/protocol/schema/sessions.js +5 -1
  233. package/dist/gateway/protocol/schema.js +0 -1
  234. package/dist/gateway/server/presence-events.js +12 -0
  235. package/dist/gateway/server/ws-connection/message-handler.js +203 -212
  236. package/dist/gateway/server/ws-connection.js +58 -21
  237. package/dist/gateway/server-broadcast.js +18 -13
  238. package/dist/gateway/server-cron.js +177 -10
  239. package/dist/gateway/server-methods/agent-job.js +131 -38
  240. package/dist/gateway/server-methods/send.js +60 -14
  241. package/dist/gateway/server-methods/sessions.js +160 -96
  242. package/dist/gateway/server-methods/system.js +5 -7
  243. package/dist/gateway/server-methods-list.js +8 -0
  244. package/dist/gateway/server-methods.js +24 -8
  245. package/dist/gateway/server-node-events.js +278 -68
  246. package/dist/gateway/session-utils.fs.js +316 -75
  247. package/dist/gateway/session-utils.js +224 -70
  248. package/dist/gateway/sessions-patch.js +63 -20
  249. package/dist/gateway/test-temp-config.js +1 -1
  250. package/dist/gateway/tools-invoke-http.js +118 -70
  251. package/dist/gateway/ws-log.js +135 -107
  252. package/dist/hooks/frontmatter.js +36 -82
  253. package/dist/hooks/install.js +149 -139
  254. package/dist/hooks/internal-hooks.js +29 -4
  255. package/dist/hooks/plugin-hooks.js +2 -1
  256. package/dist/imessage/monitor/deliver.js +10 -4
  257. package/dist/imessage/monitor/monitor-provider.js +138 -375
  258. package/dist/imessage/monitor/runtime.js +4 -8
  259. package/dist/imessage/send.js +65 -19
  260. package/dist/infra/exec-approvals-allowlist.js +7 -0
  261. package/dist/infra/exec-approvals.js +35 -920
  262. package/dist/infra/exec-safe-bin-trust.js +64 -0
  263. package/dist/infra/heartbeat-runner.js +207 -134
  264. package/dist/infra/heartbeat-wake.js +183 -22
  265. package/dist/infra/install-source-utils.js +47 -0
  266. package/dist/infra/net/ssrf.js +170 -36
  267. package/dist/infra/outbound/deliver.js +224 -58
  268. package/dist/infra/outbound/message-action-spec.js +12 -5
  269. package/dist/infra/outbound/outbound-session.js +27 -25
  270. package/dist/infra/poolbot-root.js +32 -22
  271. package/dist/infra/ports.js +14 -11
  272. package/dist/infra/skills-remote.js +48 -37
  273. package/dist/infra/system-events.js +25 -11
  274. package/dist/infra/system-presence.js +26 -33
  275. package/dist/infra/tmp-poolbot-dir.js +81 -2
  276. package/dist/infra/wsl.js +37 -1
  277. package/dist/line/bot-message-context.js +163 -191
  278. package/dist/logging/subsystem.js +59 -22
  279. package/dist/markdown/ir.js +124 -50
  280. package/dist/media/store.js +1 -1
  281. package/dist/media-understanding/runner.entries.js +42 -25
  282. package/dist/media-understanding/runner.js +53 -488
  283. package/dist/memory/embeddings-gemini.js +53 -38
  284. package/dist/memory/manager-embedding-ops.js +48 -69
  285. package/dist/pairing/pairing-store.js +178 -119
  286. package/dist/plugin-sdk/index.js +34 -6
  287. package/dist/plugins/hooks.js +135 -14
  288. package/dist/plugins/install.js +190 -152
  289. package/dist/polls.js +11 -0
  290. package/dist/routing/resolve-route.js +190 -56
  291. package/dist/routing/session-key.js +38 -22
  292. package/dist/runtime.js +35 -9
  293. package/dist/security/audit-channel.js +1 -1
  294. package/dist/sessions/session-key-utils.js +29 -11
  295. package/dist/shared/frontmatter.js +5 -5
  296. package/dist/shared/node-list-types.js +1 -0
  297. package/dist/shared/string-normalization.js +15 -0
  298. package/dist/signal/monitor/event-handler.js +68 -36
  299. package/dist/signal/send.js +29 -37
  300. package/dist/slack/monitor/allow-list.js +10 -11
  301. package/dist/slack/monitor/commands.js +14 -3
  302. package/dist/slack/monitor/events/interactions.js +4 -4
  303. package/dist/slack/monitor/media.js +224 -16
  304. package/dist/slack/monitor/message-handler/dispatch.js +247 -13
  305. package/dist/slack/monitor/message-handler/prepare.js +128 -45
  306. package/dist/slack/monitor/slash.js +357 -144
  307. package/dist/slack/streaming.js +77 -0
  308. package/dist/telegram/accounts.js +40 -13
  309. package/dist/telegram/allowed-updates.js +3 -0
  310. package/dist/telegram/bot/delivery.js +129 -66
  311. package/dist/telegram/bot/helpers.js +136 -122
  312. package/dist/telegram/bot-handlers.js +600 -339
  313. package/dist/telegram/bot-message-context.js +115 -73
  314. package/dist/telegram/bot-message-dispatch.js +235 -104
  315. package/dist/telegram/bot-native-command-menu.js +3 -1
  316. package/dist/telegram/bot-native-commands.js +213 -193
  317. package/dist/telegram/bot.js +24 -132
  318. package/dist/telegram/draft-stream.js +84 -75
  319. package/dist/telegram/format.js +150 -6
  320. package/dist/telegram/send.js +415 -255
  321. package/dist/telegram/targets.js +21 -2
  322. package/dist/telegram/update-offset-store.js +19 -3
  323. package/dist/terminal/restore.js +5 -2
  324. package/dist/test-utils/fetch-mock.js +5 -0
  325. package/dist/version.js +18 -5
  326. package/dist/web/auto-reply/monitor/broadcast.js +7 -3
  327. package/dist/web/auto-reply/monitor/on-message.js +6 -3
  328. package/dist/web/inbound/media.js +34 -8
  329. package/dist/web/inbound/monitor.js +34 -17
  330. package/dist/web/inbound/send-api.js +18 -17
  331. package/dist/web/outbound.js +12 -5
  332. package/dist/wizard/clack-prompter.js +40 -7
  333. package/extensions/bluebubbles/package.json +1 -1
  334. package/extensions/copilot-proxy/package.json +1 -1
  335. package/extensions/diagnostics-otel/package.json +1 -1
  336. package/extensions/discord/package.json +1 -1
  337. package/extensions/feishu/package.json +1 -1
  338. package/extensions/google-antigravity-auth/package.json +1 -1
  339. package/extensions/google-gemini-cli-auth/package.json +1 -1
  340. package/extensions/googlechat/package.json +1 -1
  341. package/extensions/imessage/package.json +1 -1
  342. package/extensions/irc/package.json +1 -1
  343. package/extensions/line/package.json +1 -1
  344. package/extensions/llm-task/package.json +1 -1
  345. package/extensions/lobster/package.json +1 -1
  346. package/extensions/matrix/CHANGELOG.md +5 -0
  347. package/extensions/matrix/package.json +1 -1
  348. package/extensions/mattermost/package.json +1 -1
  349. package/extensions/memory-core/package.json +1 -1
  350. package/extensions/memory-lancedb/package.json +1 -1
  351. package/extensions/minimax-portal-auth/package.json +1 -1
  352. package/extensions/msteams/CHANGELOG.md +5 -0
  353. package/extensions/msteams/package.json +1 -1
  354. package/extensions/nextcloud-talk/package.json +1 -1
  355. package/extensions/nostr/CHANGELOG.md +5 -0
  356. package/extensions/nostr/package.json +1 -1
  357. package/extensions/open-prose/package.json +1 -1
  358. package/extensions/openai-codex-auth/package.json +1 -1
  359. package/extensions/signal/package.json +1 -1
  360. package/extensions/slack/package.json +1 -1
  361. package/extensions/telegram/package.json +1 -1
  362. package/extensions/tlon/package.json +1 -1
  363. package/extensions/twitch/CHANGELOG.md +5 -0
  364. package/extensions/twitch/package.json +1 -1
  365. package/extensions/voice-call/CHANGELOG.md +5 -0
  366. package/extensions/voice-call/package.json +1 -1
  367. package/extensions/whatsapp/package.json +1 -1
  368. package/extensions/zalo/CHANGELOG.md +5 -0
  369. package/extensions/zalo/package.json +1 -1
  370. package/extensions/zalouser/CHANGELOG.md +5 -0
  371. package/extensions/zalouser/package.json +1 -1
  372. package/package.json +1 -1
  373. package/skills/apple-reminders/SKILL.md +100 -49
  374. package/skills/coding-agent/SKILL.md +34 -28
  375. package/skills/github/SKILL.md +131 -16
  376. package/skills/imsg/SKILL.md +112 -15
  377. package/skills/openhue/SKILL.md +101 -19
  378. package/skills/plcode-controller/SKILL.md +156 -0
  379. package/skills/plcode-controller/assets/operator-prompts.md +65 -0
  380. package/skills/plcode-controller/references/command-cheatsheet.md +53 -0
  381. package/skills/plcode-controller/references/failure-handling.md +60 -0
  382. package/skills/plcode-controller/references/model-selection.md +57 -0
  383. package/skills/plcode-controller/references/plan-vs-build.md +52 -0
  384. package/skills/plcode-controller/references/question-handling.md +40 -0
  385. package/skills/plcode-controller/references/session-management.md +63 -0
  386. package/skills/plcode-controller/references/workflow.md +35 -0
  387. package/skills/tmux/SKILL.md +111 -79
  388. package/skills/weather/SKILL.md +88 -25
@@ -1,7 +1,40 @@
1
+ import { normalizeProviderId } from "./model-selection.js";
1
2
  const KEY_SPLIT_RE = /[\s,;]+/g;
3
+ const GOOGLE_LIVE_SINGLE_KEY = "POOLBOT_LIVE_GEMINI_KEY";
4
+ const PROVIDER_PREFIX_OVERRIDES = {
5
+ google: "GEMINI",
6
+ "google-vertex": "GEMINI",
7
+ };
8
+ const PROVIDER_API_KEY_CONFIG = {
9
+ anthropic: {
10
+ liveSingle: "POOLBOT_LIVE_ANTHROPIC_KEY",
11
+ listVar: "POOLBOT_LIVE_ANTHROPIC_KEYS",
12
+ primaryVar: "ANTHROPIC_API_KEY",
13
+ prefixedVar: "ANTHROPIC_API_KEY_",
14
+ },
15
+ google: {
16
+ liveSingle: GOOGLE_LIVE_SINGLE_KEY,
17
+ listVar: "GEMINI_API_KEYS",
18
+ primaryVar: "GEMINI_API_KEY",
19
+ prefixedVar: "GEMINI_API_KEY_",
20
+ },
21
+ "google-vertex": {
22
+ liveSingle: GOOGLE_LIVE_SINGLE_KEY,
23
+ listVar: "GEMINI_API_KEYS",
24
+ primaryVar: "GEMINI_API_KEY",
25
+ prefixedVar: "GEMINI_API_KEY_",
26
+ },
27
+ openai: {
28
+ liveSingle: "POOLBOT_LIVE_OPENAI_KEY",
29
+ listVar: "OPENAI_API_KEYS",
30
+ primaryVar: "OPENAI_API_KEY",
31
+ prefixedVar: "OPENAI_API_KEY_",
32
+ },
33
+ };
2
34
  function parseKeyList(raw) {
3
- if (!raw)
35
+ if (!raw) {
4
36
  return [];
37
+ }
5
38
  return raw
6
39
  .split(KEY_SPLIT_RE)
7
40
  .map((value) => value.trim())
@@ -10,62 +43,126 @@ function parseKeyList(raw) {
10
43
  function collectEnvPrefixedKeys(prefix) {
11
44
  const keys = [];
12
45
  for (const [name, value] of Object.entries(process.env)) {
13
- if (!name.startsWith(prefix))
46
+ if (!name.startsWith(prefix)) {
14
47
  continue;
48
+ }
15
49
  const trimmed = value?.trim();
16
- if (!trimmed)
50
+ if (!trimmed) {
17
51
  continue;
52
+ }
18
53
  keys.push(trimmed);
19
54
  }
20
55
  return keys;
21
56
  }
22
- export function collectAnthropicApiKeys() {
23
- const forcedSingle = process.env.POOLBOT_LIVE_ANTHROPIC_KEY?.trim() ||
24
- process.env.CLAWDBOT_LIVE_ANTHROPIC_KEY?.trim();
25
- if (forcedSingle)
57
+ function resolveProviderApiKeyConfig(provider) {
58
+ const normalized = normalizeProviderId(provider);
59
+ const custom = PROVIDER_API_KEY_CONFIG[normalized];
60
+ const base = PROVIDER_PREFIX_OVERRIDES[normalized] ?? normalized.toUpperCase().replace(/-/g, "_");
61
+ const liveSingle = custom?.liveSingle ?? `POOLBOT_LIVE_${base}_KEY`;
62
+ const listVar = custom?.listVar ?? `${base}_API_KEYS`;
63
+ const primaryVar = custom?.primaryVar ?? `${base}_API_KEY`;
64
+ const prefixedVar = custom?.prefixedVar ?? `${base}_API_KEY_`;
65
+ if (normalized === "google" || normalized === "google-vertex") {
66
+ return {
67
+ liveSingle,
68
+ listVar,
69
+ primaryVar,
70
+ prefixedVar,
71
+ fallbackVars: ["GOOGLE_API_KEY"],
72
+ };
73
+ }
74
+ return {
75
+ liveSingle,
76
+ listVar,
77
+ primaryVar,
78
+ prefixedVar,
79
+ fallbackVars: [],
80
+ };
81
+ }
82
+ export function collectProviderApiKeys(provider) {
83
+ const config = resolveProviderApiKeyConfig(provider);
84
+ const forcedSingle = config.liveSingle ? process.env[config.liveSingle]?.trim() : undefined;
85
+ if (forcedSingle) {
26
86
  return [forcedSingle];
27
- const fromList = parseKeyList(process.env.POOLBOT_LIVE_ANTHROPIC_KEYS || process.env.CLAWDBOT_LIVE_ANTHROPIC_KEYS);
28
- const fromEnv = collectEnvPrefixedKeys("ANTHROPIC_API_KEY");
29
- const primary = process.env.ANTHROPIC_API_KEY?.trim();
87
+ }
88
+ const fromList = parseKeyList(config.listVar ? process.env[config.listVar] : undefined);
89
+ const primary = config.primaryVar ? process.env[config.primaryVar]?.trim() : undefined;
90
+ const fromPrefixed = config.prefixedVar ? collectEnvPrefixedKeys(config.prefixedVar) : [];
91
+ const fallback = config.fallbackVars
92
+ .map((envVar) => process.env[envVar]?.trim())
93
+ .filter(Boolean);
30
94
  const seen = new Set();
31
95
  const add = (value) => {
32
- if (!value)
96
+ if (!value) {
33
97
  return;
34
- if (seen.has(value))
98
+ }
99
+ if (seen.has(value)) {
35
100
  return;
101
+ }
36
102
  seen.add(value);
37
103
  };
38
- for (const value of fromList)
104
+ for (const value of fromList) {
105
+ add(value);
106
+ }
107
+ add(primary);
108
+ for (const value of fromPrefixed) {
39
109
  add(value);
40
- if (primary)
41
- add(primary);
42
- for (const value of fromEnv)
110
+ }
111
+ for (const value of fallback) {
43
112
  add(value);
113
+ }
44
114
  return Array.from(seen);
45
115
  }
46
- export function isAnthropicRateLimitError(message) {
116
+ export function collectAnthropicApiKeys() {
117
+ return collectProviderApiKeys("anthropic");
118
+ }
119
+ export function collectGeminiApiKeys() {
120
+ return collectProviderApiKeys("google");
121
+ }
122
+ export function isApiKeyRateLimitError(message) {
47
123
  const lower = message.toLowerCase();
48
- if (lower.includes("rate_limit"))
124
+ if (lower.includes("rate_limit")) {
125
+ return true;
126
+ }
127
+ if (lower.includes("rate limit")) {
128
+ return true;
129
+ }
130
+ if (lower.includes("429")) {
131
+ return true;
132
+ }
133
+ if (lower.includes("quota exceeded") || lower.includes("quota_exceeded")) {
49
134
  return true;
50
- if (lower.includes("rate limit"))
135
+ }
136
+ if (lower.includes("resource exhausted") || lower.includes("resource_exhausted")) {
51
137
  return true;
52
- if (lower.includes("429"))
138
+ }
139
+ if (lower.includes("too many requests")) {
53
140
  return true;
141
+ }
54
142
  return false;
55
143
  }
144
+ export function isAnthropicRateLimitError(message) {
145
+ return isApiKeyRateLimitError(message);
146
+ }
56
147
  export function isAnthropicBillingError(message) {
57
148
  const lower = message.toLowerCase();
58
- if (lower.includes("credit balance"))
149
+ if (lower.includes("credit balance")) {
59
150
  return true;
60
- if (lower.includes("insufficient credit"))
151
+ }
152
+ if (lower.includes("insufficient credit")) {
61
153
  return true;
62
- if (lower.includes("insufficient credits"))
154
+ }
155
+ if (lower.includes("insufficient credits")) {
63
156
  return true;
64
- if (lower.includes("payment required"))
157
+ }
158
+ if (lower.includes("payment required")) {
65
159
  return true;
66
- if (lower.includes("billing") && lower.includes("disabled"))
160
+ }
161
+ if (lower.includes("billing") && lower.includes("disabled")) {
67
162
  return true;
68
- if (lower.includes("402"))
163
+ }
164
+ if (/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\spayment/i.test(lower)) {
69
165
  return true;
166
+ }
70
167
  return false;
71
168
  }
@@ -1,15 +1,23 @@
1
- const ANTHROPIC_PREFIXES = ["claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5"];
1
+ const ANTHROPIC_PREFIXES = [
2
+ "claude-opus-4-6",
3
+ "claude-sonnet-4-6",
4
+ "claude-opus-4-5",
5
+ "claude-sonnet-4-5",
6
+ "claude-haiku-4-5",
7
+ ];
2
8
  const OPENAI_MODELS = ["gpt-5.2", "gpt-5.0"];
3
9
  const CODEX_MODELS = [
4
10
  "gpt-5.2",
5
11
  "gpt-5.2-codex",
12
+ "gpt-5.3-codex",
13
+ "gpt-5.3-codex-spark",
6
14
  "gpt-5.1-codex",
7
15
  "gpt-5.1-codex-mini",
8
16
  "gpt-5.1-codex-max",
9
17
  ];
10
18
  const GOOGLE_PREFIXES = ["gemini-3"];
11
- const ZAI_PREFIXES = ["glm-4.7"];
12
- const MINIMAX_PREFIXES = ["minimax-m2.1"];
19
+ const ZAI_PREFIXES = ["glm-5", "glm-4.7", "glm-4.7-flash", "glm-4.7-flashx"];
20
+ const MINIMAX_PREFIXES = ["minimax-m2.1", "minimax-m2.5"];
13
21
  const XAI_PREFIXES = ["grok-4"];
14
22
  function matchesPrefix(id, prefixes) {
15
23
  return prefixes.some((prefix) => id.startsWith(prefix));
@@ -23,8 +31,9 @@ function matchesAny(id, values) {
23
31
  export function isModernModelRef(ref) {
24
32
  const provider = ref.provider?.trim().toLowerCase() ?? "";
25
33
  const id = ref.id?.trim().toLowerCase() ?? "";
26
- if (!provider || !id)
34
+ if (!provider || !id) {
27
35
  return false;
36
+ }
28
37
  if (provider === "anthropic") {
29
38
  return matchesPrefix(id, ANTHROPIC_PREFIXES);
30
39
  }
@@ -4,6 +4,7 @@ import { getShellEnvAppliedKeys } from "../infra/shell-env.js";
4
4
  import { formatCliCommand } from "../cli/command-format.js";
5
5
  import { ensureAuthProfileStore, listProfilesForProvider, resolveApiKeyForProfile, resolveAuthProfileOrder, resolveAuthStorePathForDisplay, } from "./auth-profiles.js";
6
6
  import { normalizeProviderId } from "./model-selection.js";
7
+ import { resolveTokenFromPool } from "./provider/integration.js";
7
8
  export { ensureAuthProfileStore, resolveAuthProfileOrder } from "./auth-profiles.js";
8
9
  const AWS_BEARER_ENV = "AWS_BEARER_TOKEN_BEDROCK";
9
10
  const AWS_ACCESS_KEY_ENV = "AWS_ACCESS_KEY_ID";
@@ -135,6 +136,17 @@ export async function resolveApiKeyForProvider(params) {
135
136
  }
136
137
  catch { }
137
138
  }
139
+ // Token pool rotation: if a pool is configured for this provider,
140
+ // try to get a key from the pool (with rate-limit-aware scheduling).
141
+ // Falls through to existing env/config resolution if no pool or no tokens.
142
+ const poolResult = await resolveTokenFromPool(provider);
143
+ if (poolResult) {
144
+ return {
145
+ apiKey: poolResult.apiKey,
146
+ source: poolResult.source,
147
+ mode: "api-key",
148
+ };
149
+ }
138
150
  const envResolved = resolveEnvApiKey(provider);
139
151
  if (envResolved) {
140
152
  return {
@@ -5,6 +5,25 @@ let modelCatalogPromise = null;
5
5
  let hasLoggedModelCatalogError = false;
6
6
  const defaultImportPiSdk = () => import("./pi-model-discovery.js");
7
7
  let importPiSdk = defaultImportPiSdk;
8
+ const CODEX_PROVIDER = "openai-codex";
9
+ const OPENAI_CODEX_GPT53_MODEL_ID = "gpt-5.3-codex";
10
+ const OPENAI_CODEX_GPT53_SPARK_MODEL_ID = "gpt-5.3-codex-spark";
11
+ function applyOpenAICodexSparkFallback(models) {
12
+ const hasSpark = models.some((entry) => entry.provider === CODEX_PROVIDER &&
13
+ entry.id.toLowerCase() === OPENAI_CODEX_GPT53_SPARK_MODEL_ID);
14
+ if (hasSpark) {
15
+ return;
16
+ }
17
+ const baseModel = models.find((entry) => entry.provider === CODEX_PROVIDER && entry.id.toLowerCase() === OPENAI_CODEX_GPT53_MODEL_ID);
18
+ if (!baseModel) {
19
+ return;
20
+ }
21
+ models.push({
22
+ ...baseModel,
23
+ id: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
24
+ name: OPENAI_CODEX_GPT53_SPARK_MODEL_ID,
25
+ });
26
+ }
8
27
  export function resetModelCatalogCacheForTest() {
9
28
  modelCatalogPromise = null;
10
29
  hasLoggedModelCatalogError = false;
@@ -14,49 +33,61 @@ export function resetModelCatalogCacheForTest() {
14
33
  export function __setModelCatalogImportForTest(loader) {
15
34
  importPiSdk = loader ?? defaultImportPiSdk;
16
35
  }
36
+ function createAuthStorage(AuthStorageLike, path) {
37
+ const withFactory = AuthStorageLike;
38
+ if (typeof withFactory.create === "function") {
39
+ return withFactory.create(path);
40
+ }
41
+ return new AuthStorageLike(path);
42
+ }
17
43
  export async function loadModelCatalog(params) {
18
44
  if (params?.useCache === false) {
19
45
  modelCatalogPromise = null;
20
46
  }
21
- if (modelCatalogPromise)
47
+ if (modelCatalogPromise) {
22
48
  return modelCatalogPromise;
49
+ }
23
50
  modelCatalogPromise = (async () => {
24
51
  const models = [];
25
52
  const sortModels = (entries) => entries.sort((a, b) => {
26
53
  const p = a.provider.localeCompare(b.provider);
27
- if (p !== 0)
54
+ if (p !== 0) {
28
55
  return p;
56
+ }
29
57
  return a.name.localeCompare(b.name);
30
58
  });
31
59
  try {
32
60
  const cfg = params?.config ?? loadConfig();
33
61
  await ensurePoolbotModelsJson(cfg);
62
+ await (await import("./pi-auth-json.js")).ensurePiAuthJsonFromAuthProfiles(resolvePoolbotAgentDir());
34
63
  // IMPORTANT: keep the dynamic import *inside* the try/catch.
35
64
  // If this fails once (e.g. during a pnpm install that temporarily swaps node_modules),
36
65
  // we must not poison the cache with a rejected promise (otherwise all channel handlers
37
66
  // will keep failing until restart).
38
67
  const piSdk = await importPiSdk();
39
68
  const agentDir = resolvePoolbotAgentDir();
40
- const authStorage = piSdk.discoverAuthStorage(agentDir);
41
- const registry = piSdk.discoverModels(authStorage, agentDir);
69
+ const { join } = await import("node:path");
70
+ const authStorage = createAuthStorage(piSdk.AuthStorage, join(agentDir, "auth.json"));
71
+ const registry = new piSdk.ModelRegistry(authStorage, join(agentDir, "models.json"));
42
72
  const entries = Array.isArray(registry) ? registry : registry.getAll();
43
73
  for (const entry of entries) {
44
74
  const id = String(entry?.id ?? "").trim();
45
- if (!id)
75
+ if (!id) {
46
76
  continue;
77
+ }
47
78
  const provider = String(entry?.provider ?? "").trim();
48
- if (!provider)
79
+ if (!provider) {
49
80
  continue;
81
+ }
50
82
  const name = String(entry?.name ?? id).trim() || id;
51
83
  const contextWindow = typeof entry?.contextWindow === "number" && entry.contextWindow > 0
52
84
  ? entry.contextWindow
53
85
  : undefined;
54
86
  const reasoning = typeof entry?.reasoning === "boolean" ? entry.reasoning : undefined;
55
- const input = Array.isArray(entry?.input)
56
- ? entry.input
57
- : undefined;
87
+ const input = Array.isArray(entry?.input) ? entry.input : undefined;
58
88
  models.push({ id, name, provider, contextWindow, reasoning, input });
59
89
  }
90
+ applyOpenAICodexSparkFallback(models);
60
91
  if (models.length === 0) {
61
92
  // If we found nothing, don't cache this result so we can try again.
62
93
  modelCatalogPromise = null;
@@ -2,6 +2,7 @@ import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "./defaults.js";
2
2
  import { coerceToFailoverError, describeFailoverError, isFailoverError, isTimeoutError, } from "./failover-error.js";
3
3
  import { buildModelAliasIndex, modelKey, parseModelRef, resolveConfiguredModelRef, resolveModelRefFromString, } from "./model-selection.js";
4
4
  import { ensureAuthProfileStore, getSoonestCooldownExpiry, isProfileInCooldown, resolveAuthProfileOrder, } from "./auth-profiles.js";
5
+ import { isProviderRateLimited, recordFallbackError } from "./provider/integration.js";
5
6
  function isAbortError(err) {
6
7
  if (!err || typeof err !== "object")
7
8
  return false;
@@ -218,6 +219,21 @@ export async function runWithModelFallback(params) {
218
219
  lastProbeAttempt.set(probeThrottleKey, now);
219
220
  }
220
221
  }
222
+ // Provider-level rate limit check (from token pool / rate limit tracking).
223
+ // Complements the per-profile cooldown above — skips candidates when all
224
+ // API keys in the pool are known to be rate-limited.
225
+ const poolLimit = isProviderRateLimited(candidate.provider);
226
+ if (poolLimit.isLimited && hasFallbackCandidates && i > 0) {
227
+ // Skip non-primary candidates that are pool-rate-limited.
228
+ // Primary (i === 0) is never skipped here — it gets a chance to probe.
229
+ attempts.push({
230
+ provider: candidate.provider,
231
+ model: candidate.model,
232
+ error: `Provider ${candidate.provider} pool is rate-limited (wait ${poolLimit.waitTimeMs}ms)`,
233
+ reason: "rate_limit",
234
+ });
235
+ continue;
236
+ }
221
237
  try {
222
238
  const result = await params.run(candidate.provider, candidate.model);
223
239
  return {
@@ -246,6 +262,14 @@ export async function runWithModelFallback(params) {
246
262
  status: described.status,
247
263
  code: described.code,
248
264
  });
265
+ // Feed error into provider infrastructure (rate limits + monitoring)
266
+ recordFallbackError({
267
+ provider: candidate.provider,
268
+ model: candidate.model,
269
+ status: described.status,
270
+ reason: described.reason,
271
+ error: described.message,
272
+ });
249
273
  await params.onError?.({
250
274
  provider: candidate.provider,
251
275
  model: candidate.model,
@@ -6,6 +6,9 @@ const OPENAI_CODEX_TEMPLATE_MODEL_IDS = ["gpt-5.2-codex"];
6
6
  const ANTHROPIC_OPUS_46_MODEL_ID = "claude-opus-4-6";
7
7
  const ANTHROPIC_OPUS_46_DOT_MODEL_ID = "claude-opus-4.6";
8
8
  const ANTHROPIC_OPUS_TEMPLATE_MODEL_IDS = ["claude-opus-4-5", "claude-opus-4.5"];
9
+ const ANTHROPIC_SONNET_46_MODEL_ID = "claude-sonnet-4-6";
10
+ const ANTHROPIC_SONNET_46_DOT_MODEL_ID = "claude-sonnet-4.6";
11
+ const ANTHROPIC_SONNET_TEMPLATE_MODEL_IDS = ["claude-sonnet-4-5", "claude-sonnet-4.5"];
9
12
  const ZAI_GLM5_MODEL_ID = "glm-5";
10
13
  const ZAI_GLM5_TEMPLATE_MODEL_IDS = ["glm-4.7"];
11
14
  const ANTIGRAVITY_OPUS_46_MODEL_ID = "claude-opus-4-6";
@@ -30,6 +33,22 @@ export const ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES = [
30
33
  templatePrefixes: ["google-antigravity/claude-opus-4-5", "google-antigravity/claude-opus-4.5"],
31
34
  },
32
35
  ];
36
+ function cloneFirstTemplateModel(params) {
37
+ const { normalizedProvider, trimmedModelId, templateIds, modelRegistry } = params;
38
+ for (const templateId of [...new Set(templateIds)].filter(Boolean)) {
39
+ const template = modelRegistry.find(normalizedProvider, templateId);
40
+ if (!template) {
41
+ continue;
42
+ }
43
+ return normalizeModelCompat({
44
+ ...template,
45
+ id: trimmedModelId,
46
+ name: trimmedModelId,
47
+ ...params.patch,
48
+ });
49
+ }
50
+ return undefined;
51
+ }
33
52
  function resolveOpenAICodexGpt53FallbackModel(provider, modelId, modelRegistry) {
34
53
  const normalizedProvider = normalizeProviderId(provider);
35
54
  const trimmedModelId = modelId.trim();
@@ -85,18 +104,41 @@ function resolveAnthropicOpus46ForwardCompatModel(provider, modelId, modelRegist
85
104
  templateIds.push(lower.replace(ANTHROPIC_OPUS_46_DOT_MODEL_ID, "claude-opus-4.5"));
86
105
  }
87
106
  templateIds.push(...ANTHROPIC_OPUS_TEMPLATE_MODEL_IDS);
88
- for (const templateId of [...new Set(templateIds)].filter(Boolean)) {
89
- const template = modelRegistry.find(normalizedProvider, templateId);
90
- if (!template) {
91
- continue;
92
- }
93
- return normalizeModelCompat({
94
- ...template,
95
- id: trimmedModelId,
96
- name: trimmedModelId,
97
- });
107
+ return cloneFirstTemplateModel({
108
+ normalizedProvider,
109
+ trimmedModelId,
110
+ templateIds,
111
+ modelRegistry,
112
+ });
113
+ }
114
+ function resolveAnthropicSonnet46ForwardCompatModel(provider, modelId, modelRegistry) {
115
+ const normalizedProvider = normalizeProviderId(provider);
116
+ if (normalizedProvider !== "anthropic") {
117
+ return undefined;
98
118
  }
99
- return undefined;
119
+ const trimmedModelId = modelId.trim();
120
+ const lower = trimmedModelId.toLowerCase();
121
+ const isSonnet46 = lower === ANTHROPIC_SONNET_46_MODEL_ID ||
122
+ lower === ANTHROPIC_SONNET_46_DOT_MODEL_ID ||
123
+ lower.startsWith(`${ANTHROPIC_SONNET_46_MODEL_ID}-`) ||
124
+ lower.startsWith(`${ANTHROPIC_SONNET_46_DOT_MODEL_ID}-`);
125
+ if (!isSonnet46) {
126
+ return undefined;
127
+ }
128
+ const templateIds = [];
129
+ if (lower.startsWith(ANTHROPIC_SONNET_46_MODEL_ID)) {
130
+ templateIds.push(lower.replace(ANTHROPIC_SONNET_46_MODEL_ID, "claude-sonnet-4-5"));
131
+ }
132
+ if (lower.startsWith(ANTHROPIC_SONNET_46_DOT_MODEL_ID)) {
133
+ templateIds.push(lower.replace(ANTHROPIC_SONNET_46_DOT_MODEL_ID, "claude-sonnet-4.5"));
134
+ }
135
+ templateIds.push(...ANTHROPIC_SONNET_TEMPLATE_MODEL_IDS);
136
+ return cloneFirstTemplateModel({
137
+ normalizedProvider,
138
+ trimmedModelId,
139
+ templateIds,
140
+ modelRegistry,
141
+ });
100
142
  }
101
143
  // Z.ai's GLM-5 may not be present in pi-ai's built-in model catalog yet.
102
144
  // When a user configures zai/glm-5 without a models.json entry, clone glm-4.7 as a forward-compat fallback.
@@ -166,22 +208,17 @@ function resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegi
166
208
  }
167
209
  templateIds.push(...ANTIGRAVITY_OPUS_TEMPLATE_MODEL_IDS);
168
210
  templateIds.push(...ANTIGRAVITY_OPUS_THINKING_TEMPLATE_MODEL_IDS);
169
- for (const templateId of [...new Set(templateIds)].filter(Boolean)) {
170
- const template = modelRegistry.find(normalizedProvider, templateId);
171
- if (!template) {
172
- continue;
173
- }
174
- return normalizeModelCompat({
175
- ...template,
176
- id: trimmedModelId,
177
- name: trimmedModelId,
178
- });
179
- }
180
- return undefined;
211
+ return cloneFirstTemplateModel({
212
+ normalizedProvider,
213
+ trimmedModelId,
214
+ templateIds,
215
+ modelRegistry,
216
+ });
181
217
  }
182
218
  export function resolveForwardCompatModel(provider, modelId, modelRegistry) {
183
219
  return (resolveOpenAICodexGpt53FallbackModel(provider, modelId, modelRegistry) ??
184
220
  resolveAnthropicOpus46ForwardCompatModel(provider, modelId, modelRegistry) ??
221
+ resolveAnthropicSonnet46ForwardCompatModel(provider, modelId, modelRegistry) ??
185
222
  resolveZaiGlm5ForwardCompatModel(provider, modelId, modelRegistry) ??
186
223
  resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegistry));
187
224
  }