@poolzin/pool-bot 2026.2.23 → 2026.2.25

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 (235) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/dist/acp/client.js +207 -18
  3. package/dist/acp/secret-file.js +22 -0
  4. package/dist/agents/agent-scope.js +10 -0
  5. package/dist/agents/bash-process-registry.test-helpers.js +29 -0
  6. package/dist/agents/bash-tools.exec-approval-request.js +20 -0
  7. package/dist/agents/bash-tools.exec-host-gateway.js +230 -0
  8. package/dist/agents/bash-tools.exec-host-node.js +235 -0
  9. package/dist/agents/bash-tools.exec-types.js +1 -0
  10. package/dist/agents/bash-tools.process.js +224 -218
  11. package/dist/agents/content-blocks.js +16 -0
  12. package/dist/agents/model-fallback.js +96 -101
  13. package/dist/agents/models-config.providers.js +299 -182
  14. package/dist/agents/pi-embedded-payloads.js +1 -0
  15. package/dist/agents/pi-embedded-runner/run.overflow-compaction.fixture.js +34 -0
  16. package/dist/agents/skills.test-helpers.js +13 -0
  17. package/dist/agents/stable-stringify.js +12 -0
  18. package/dist/agents/subagent-registry.mocks.shared.js +12 -0
  19. package/dist/agents/test-helpers/assistant-message-fixtures.js +29 -0
  20. package/dist/agents/test-helpers/pi-tools-sandbox-context.js +27 -0
  21. package/dist/agents/tool-policy-shared.js +108 -0
  22. package/dist/agents/tools/browser-tool.js +160 -54
  23. package/dist/agents/tools/cron-tool.test-helpers.js +12 -0
  24. package/dist/agents/tools/discord-actions-moderation-shared.js +27 -0
  25. package/dist/agents/tools/image-tool.js +214 -99
  26. package/dist/agents/tools/sessions-history-tool.js +140 -108
  27. package/dist/agents/workspace.js +222 -46
  28. package/dist/auto-reply/commands-registry.js +15 -18
  29. package/dist/auto-reply/fallback-state.js +114 -0
  30. package/dist/auto-reply/model-runtime.js +68 -0
  31. package/dist/auto-reply/reply/agent-runner-execution.js +36 -4
  32. package/dist/auto-reply/reply/agent-runner.js +165 -39
  33. package/dist/auto-reply/reply/commands-setunset-standard.js +13 -0
  34. package/dist/browser/config.js +26 -0
  35. package/dist/browser/navigation-guard.js +31 -0
  36. package/dist/browser/routes/agent.act.js +431 -424
  37. package/dist/browser/routes/agent.shared.js +47 -3
  38. package/dist/browser/routes/agent.snapshot.js +122 -116
  39. package/dist/browser/routes/agent.storage.js +303 -297
  40. package/dist/browser/routes/tabs.js +154 -100
  41. package/dist/browser/server-lifecycle.js +37 -0
  42. package/dist/build-info.json +3 -3
  43. package/dist/channels/allow-from.js +25 -0
  44. package/dist/channels/plugins/account-action-gate.js +13 -0
  45. package/dist/channels/plugins/message-actions.js +10 -0
  46. package/dist/channels/telegram/api.js +18 -0
  47. package/dist/cli/argv.js +84 -21
  48. package/dist/cli/banner.js +2 -1
  49. package/dist/cli/exec-approvals-cli.js +92 -124
  50. package/dist/cli/memory-cli.js +158 -61
  51. package/dist/cli/nodes-cli/register.push.js +63 -0
  52. package/dist/cli/nodes-media-utils.js +21 -0
  53. package/dist/cli/plugins-cli.js +245 -61
  54. package/dist/cli/program/build-program.js +3 -1
  55. package/dist/cli/program/command-registry.js +223 -136
  56. package/dist/cli/program/help.js +43 -12
  57. package/dist/cli/route.js +1 -1
  58. package/dist/cli/test-runtime-capture.js +24 -0
  59. package/dist/commands/agent.js +163 -87
  60. package/dist/commands/channels.mock-harness.js +23 -0
  61. package/dist/commands/daemon-install-runtime-warning.js +11 -0
  62. package/dist/commands/onboard-helpers.js +4 -4
  63. package/dist/commands/sessions.test-helpers.js +61 -0
  64. package/dist/compat/legacy-names.js +2 -2
  65. package/dist/config/commands.js +3 -0
  66. package/dist/config/config.js +1 -1
  67. package/dist/config/env-substitution.js +62 -34
  68. package/dist/config/env-vars.js +9 -0
  69. package/dist/config/io.js +571 -171
  70. package/dist/config/merge-patch.js +50 -4
  71. package/dist/config/redact-snapshot.js +404 -76
  72. package/dist/config/schema.js +58 -570
  73. package/dist/config/validation.js +140 -85
  74. package/dist/config/zod-schema.hooks.js +40 -11
  75. package/dist/config/zod-schema.installs.js +20 -0
  76. package/dist/config/zod-schema.js +8 -7
  77. package/dist/control-ui/assets/{index-HRr1grwl.js → index-Dvkl4Xlx.js} +2 -1
  78. package/dist/control-ui/assets/{index-HRr1grwl.js.map → index-Dvkl4Xlx.js.map} +1 -1
  79. package/dist/control-ui/index.html +1 -1
  80. package/dist/daemon/cmd-argv.js +21 -0
  81. package/dist/daemon/cmd-set.js +58 -0
  82. package/dist/daemon/service-types.js +1 -0
  83. package/dist/discord/monitor/exec-approvals.js +357 -162
  84. package/dist/gateway/auth.js +38 -3
  85. package/dist/gateway/call.js +149 -68
  86. package/dist/gateway/canvas-capability.js +75 -0
  87. package/dist/gateway/control-plane-audit.js +28 -0
  88. package/dist/gateway/control-plane-rate-limit.js +53 -0
  89. package/dist/gateway/events.js +1 -0
  90. package/dist/gateway/hooks.js +109 -54
  91. package/dist/gateway/http-common.js +22 -0
  92. package/dist/gateway/method-scopes.js +169 -0
  93. package/dist/gateway/net.js +23 -0
  94. package/dist/gateway/openresponses-http.js +120 -110
  95. package/dist/gateway/probe-auth.js +2 -0
  96. package/dist/gateway/protocol/index.js +3 -2
  97. package/dist/gateway/protocol/schema/protocol-schemas.js +2 -0
  98. package/dist/gateway/protocol/schema/push.js +18 -0
  99. package/dist/gateway/protocol/schema.js +1 -0
  100. package/dist/gateway/server-http.js +236 -52
  101. package/dist/gateway/server-methods/agent.js +162 -24
  102. package/dist/gateway/server-methods/chat.js +461 -130
  103. package/dist/gateway/server-methods/config.js +193 -150
  104. package/dist/gateway/server-methods/nodes.helpers.js +12 -0
  105. package/dist/gateway/server-methods/nodes.js +251 -69
  106. package/dist/gateway/server-methods/push.js +53 -0
  107. package/dist/gateway/server-reload-handlers.js +2 -3
  108. package/dist/gateway/server-runtime-config.js +5 -0
  109. package/dist/gateway/server-runtime-state.js +2 -0
  110. package/dist/gateway/server-ws-runtime.js +1 -0
  111. package/dist/gateway/server.impl.js +296 -139
  112. package/dist/gateway/session-preview.test-helpers.js +11 -0
  113. package/dist/gateway/startup-auth.js +126 -0
  114. package/dist/gateway/test-helpers.agent-results.js +15 -0
  115. package/dist/gateway/test-helpers.mocks.js +37 -14
  116. package/dist/gateway/test-helpers.server.js +161 -77
  117. package/dist/hooks/bundled/session-memory/handler.js +165 -34
  118. package/dist/hooks/gmail-watcher-lifecycle.js +23 -0
  119. package/dist/infra/archive-path.js +49 -0
  120. package/dist/infra/device-pairing.js +148 -167
  121. package/dist/infra/exec-approvals-allowlist.js +19 -70
  122. package/dist/infra/exec-approvals-analysis.js +44 -17
  123. package/dist/infra/exec-safe-bin-policy.js +269 -0
  124. package/dist/infra/fixed-window-rate-limit.js +33 -0
  125. package/dist/infra/git-root.js +61 -0
  126. package/dist/infra/heartbeat-active-hours.js +2 -2
  127. package/dist/infra/heartbeat-reason.js +40 -0
  128. package/dist/infra/heartbeat-runner.js +72 -32
  129. package/dist/infra/install-source-utils.js +91 -7
  130. package/dist/infra/node-pairing.js +50 -105
  131. package/dist/infra/npm-integrity.js +45 -0
  132. package/dist/infra/npm-pack-install.js +40 -0
  133. package/dist/infra/outbound/channel-adapters.js +20 -7
  134. package/dist/infra/outbound/message-action-runner.js +107 -327
  135. package/dist/infra/outbound/message.js +59 -36
  136. package/dist/infra/outbound/outbound-policy.js +52 -25
  137. package/dist/infra/outbound/outbound-send-service.js +58 -71
  138. package/dist/infra/pairing-files.js +10 -0
  139. package/dist/infra/plain-object.js +9 -0
  140. package/dist/infra/push-apns.js +365 -0
  141. package/dist/infra/restart-sentinel.js +16 -1
  142. package/dist/infra/restart.js +229 -26
  143. package/dist/infra/scp-host.js +54 -0
  144. package/dist/infra/update-startup.js +86 -9
  145. package/dist/media/inbound-path-policy.js +114 -0
  146. package/dist/media/input-files.js +16 -0
  147. package/dist/memory/test-manager.js +8 -0
  148. package/dist/plugin-sdk/temp-path.js +47 -0
  149. package/dist/plugins/discovery.js +217 -23
  150. package/dist/plugins/hook-runner-global.js +16 -0
  151. package/dist/plugins/loader.js +192 -26
  152. package/dist/plugins/logger.js +8 -0
  153. package/dist/plugins/manifest-registry.js +3 -0
  154. package/dist/plugins/path-safety.js +34 -0
  155. package/dist/plugins/registry.js +5 -2
  156. package/dist/plugins/runtime/index.js +271 -206
  157. package/dist/providers/github-copilot-models.js +4 -1
  158. package/dist/security/audit-channel.js +8 -19
  159. package/dist/security/audit-extra.async.js +354 -182
  160. package/dist/security/audit-extra.js +11 -1
  161. package/dist/security/audit-extra.sync.js +340 -33
  162. package/dist/security/audit-fs.js +31 -13
  163. package/dist/security/audit.js +145 -371
  164. package/dist/security/dm-policy-shared.js +24 -0
  165. package/dist/security/external-content.js +20 -8
  166. package/dist/security/fix.js +49 -85
  167. package/dist/security/scan-paths.js +20 -0
  168. package/dist/security/secret-equal.js +3 -7
  169. package/dist/security/windows-acl.js +30 -15
  170. package/dist/shared/node-list-parse.js +13 -0
  171. package/dist/shared/operator-scope-compat.js +37 -0
  172. package/dist/shared/text-chunking.js +29 -0
  173. package/dist/slack/blocks.test-helpers.js +31 -0
  174. package/dist/slack/monitor/mrkdwn.js +8 -0
  175. package/dist/telegram/bot-message-dispatch.js +366 -164
  176. package/dist/telegram/draft-stream.js +30 -7
  177. package/dist/telegram/reasoning-lane-coordinator.js +128 -0
  178. package/dist/terminal/prompt-select-styled.js +9 -0
  179. package/dist/test-utils/command-runner.js +6 -0
  180. package/dist/test-utils/internal-hook-event-payload.js +10 -0
  181. package/dist/test-utils/model-auth-mock.js +12 -0
  182. package/dist/test-utils/provider-usage-fetch.js +14 -0
  183. package/dist/test-utils/temp-home.js +33 -0
  184. package/dist/tui/components/chat-log.js +9 -0
  185. package/dist/tui/tui-command-handlers.js +36 -27
  186. package/dist/tui/tui-event-handlers.js +122 -32
  187. package/dist/tui/tui.js +181 -45
  188. package/dist/utils/mask-api-key.js +10 -0
  189. package/dist/utils/run-with-concurrency.js +39 -0
  190. package/dist/web/media.js +4 -0
  191. package/docs/tools/slash-commands.md +5 -1
  192. package/extensions/bluebubbles/package.json +1 -1
  193. package/extensions/copilot-proxy/package.json +1 -1
  194. package/extensions/diagnostics-otel/package.json +1 -1
  195. package/extensions/discord/package.json +1 -1
  196. package/extensions/feishu/package.json +1 -1
  197. package/extensions/feishu/src/external-keys.ts +19 -0
  198. package/extensions/google-antigravity-auth/package.json +1 -1
  199. package/extensions/google-gemini-cli-auth/package.json +1 -1
  200. package/extensions/googlechat/package.json +1 -1
  201. package/extensions/imessage/package.json +1 -1
  202. package/extensions/irc/package.json +1 -1
  203. package/extensions/line/package.json +1 -1
  204. package/extensions/llm-task/package.json +1 -1
  205. package/extensions/lobster/package.json +1 -1
  206. package/extensions/lobster/src/windows-spawn.ts +193 -0
  207. package/extensions/matrix/CHANGELOG.md +5 -0
  208. package/extensions/matrix/package.json +1 -1
  209. package/extensions/matrix/src/matrix/actions/limits.ts +6 -0
  210. package/extensions/mattermost/package.json +1 -1
  211. package/extensions/mattermost/src/mattermost/reactions.test-helpers.ts +83 -0
  212. package/extensions/memory-core/package.json +1 -1
  213. package/extensions/memory-lancedb/package.json +1 -1
  214. package/extensions/minimax-portal-auth/package.json +1 -1
  215. package/extensions/msteams/CHANGELOG.md +5 -0
  216. package/extensions/msteams/package.json +1 -1
  217. package/extensions/nextcloud-talk/package.json +1 -1
  218. package/extensions/nostr/CHANGELOG.md +5 -0
  219. package/extensions/nostr/package.json +1 -1
  220. package/extensions/open-prose/package.json +1 -1
  221. package/extensions/openai-codex-auth/package.json +1 -1
  222. package/extensions/signal/package.json +1 -1
  223. package/extensions/slack/package.json +1 -1
  224. package/extensions/telegram/package.json +1 -1
  225. package/extensions/tlon/package.json +1 -1
  226. package/extensions/twitch/CHANGELOG.md +5 -0
  227. package/extensions/twitch/package.json +1 -1
  228. package/extensions/voice-call/CHANGELOG.md +5 -0
  229. package/extensions/voice-call/package.json +1 -1
  230. package/extensions/whatsapp/package.json +1 -1
  231. package/extensions/zalo/CHANGELOG.md +5 -0
  232. package/extensions/zalo/package.json +1 -1
  233. package/extensions/zalouser/CHANGELOG.md +5 -0
  234. package/extensions/zalouser/package.json +1 -1
  235. package/package.json +1 -1
@@ -1,13 +1,13 @@
1
1
  import { DEFAULT_COPILOT_API_BASE_URL, resolveCopilotApiToken, } from "../providers/github-copilot-token.js";
2
2
  import { ensureAuthProfileStore, listProfilesForProvider } from "./auth-profiles.js";
3
- import { resolveAwsSdkEnvVarName, resolveEnvApiKey } from "./model-auth.js";
4
3
  import { discoverBedrockModels } from "./bedrock-discovery.js";
5
4
  import { buildCloudflareAiGatewayModelDefinition, resolveCloudflareAiGatewayBaseUrl, } from "./cloudflare-ai-gateway.js";
5
+ import { discoverHuggingfaceModels, HUGGINGFACE_BASE_URL, HUGGINGFACE_MODEL_CATALOG, buildHuggingfaceModelDefinition, } from "./huggingface-models.js";
6
+ import { resolveAwsSdkEnvVarName, resolveEnvApiKey } from "./model-auth.js";
7
+ import { OLLAMA_NATIVE_BASE_URL } from "./ollama-stream.js";
6
8
  import { buildSyntheticModelDefinition, SYNTHETIC_BASE_URL, SYNTHETIC_MODEL_CATALOG, } from "./synthetic-models.js";
7
9
  import { TOGETHER_BASE_URL, TOGETHER_MODEL_CATALOG, buildTogetherModelDefinition, } from "./together-models.js";
8
- import { discoverNvidiaModels, NVIDIA_BASE_URL } from "./nvidia-models.js";
9
10
  import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
10
- const MINIMAX_API_BASE_URL = "https://api.minimax.chat/v1";
11
11
  const MINIMAX_PORTAL_BASE_URL = "https://api.minimax.io/anthropic";
12
12
  const MINIMAX_DEFAULT_MODEL_ID = "MiniMax-M2.1";
13
13
  const MINIMAX_DEFAULT_VISION_MODEL_ID = "MiniMax-VL-01";
@@ -21,43 +21,20 @@ const MINIMAX_API_COST = {
21
21
  cacheRead: 2,
22
22
  cacheWrite: 10,
23
23
  };
24
- const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1";
25
- const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5";
26
- const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000;
27
- const MOONSHOT_DEFAULT_MAX_TOKENS = 8192;
28
- const MOONSHOT_DEFAULT_COST = {
29
- input: 0,
30
- output: 0,
31
- cacheRead: 0,
32
- cacheWrite: 0,
33
- };
34
- // Z.AI (ZhipuAI / GLM) — OpenAI-compatible API
35
- // Docs: https://docs.z.ai/ | Base: https://open.bigmodel.cn/api/paas/v4/
36
- const ZAI_BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
37
- const ZAI_DEFAULT_MODEL_ID = "GLM-4.7-Flash";
38
- const ZAI_DEFAULT_CONTEXT_WINDOW = 128000;
39
- const ZAI_DEFAULT_MAX_TOKENS = 8192;
40
- // GLM-4.7-Flash and GLM-4.5-Flash are completely free
41
- const ZAI_FREE_COST = {
42
- input: 0,
43
- output: 0,
44
- cacheRead: 0,
45
- cacheWrite: 0,
46
- };
47
- // GLM-4.7-FlashX: $0.07/$0.4 per 1M tokens
48
- const ZAI_FLASHX_COST = {
49
- input: 0.07,
50
- output: 0.4,
51
- cacheRead: 0,
52
- cacheWrite: 0,
53
- };
54
- // GLM-4.7: $0.6/$2.2 per 1M tokens
55
- const ZAI_PREMIUM_COST = {
56
- input: 0.6,
57
- output: 2.2,
58
- cacheRead: 0,
59
- cacheWrite: 0,
60
- };
24
+ function buildMinimaxModel(params) {
25
+ return {
26
+ id: params.id,
27
+ name: params.name,
28
+ reasoning: params.reasoning,
29
+ input: params.input,
30
+ cost: MINIMAX_API_COST,
31
+ contextWindow: MINIMAX_DEFAULT_CONTEXT_WINDOW,
32
+ maxTokens: MINIMAX_DEFAULT_MAX_TOKENS,
33
+ };
34
+ }
35
+ function buildMinimaxTextModel(params) {
36
+ return buildMinimaxModel({ ...params, input: ["text"] });
37
+ }
61
38
  const XIAOMI_BASE_URL = "https://api.xiaomimimo.com/anthropic";
62
39
  export const XIAOMI_DEFAULT_MODEL_ID = "mimo-v2-flash";
63
40
  const XIAOMI_DEFAULT_CONTEXT_WINDOW = 262144;
@@ -68,6 +45,16 @@ const XIAOMI_DEFAULT_COST = {
68
45
  cacheRead: 0,
69
46
  cacheWrite: 0,
70
47
  };
48
+ const MOONSHOT_BASE_URL = "https://api.moonshot.ai/v1";
49
+ const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2.5";
50
+ const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000;
51
+ const MOONSHOT_DEFAULT_MAX_TOKENS = 8192;
52
+ const MOONSHOT_DEFAULT_COST = {
53
+ input: 0,
54
+ output: 0,
55
+ cacheRead: 0,
56
+ cacheWrite: 0,
57
+ };
71
58
  const QWEN_PORTAL_BASE_URL = "https://portal.qwen.ai/v1";
72
59
  const QWEN_PORTAL_OAUTH_PLACEHOLDER = "qwen-oauth";
73
60
  const QWEN_PORTAL_DEFAULT_CONTEXT_WINDOW = 128000;
@@ -78,8 +65,8 @@ const QWEN_PORTAL_DEFAULT_COST = {
78
65
  cacheRead: 0,
79
66
  cacheWrite: 0,
80
67
  };
81
- const OLLAMA_BASE_URL = "http://127.0.0.1:11434/v1";
82
- const OLLAMA_API_BASE_URL = "http://127.0.0.1:11434";
68
+ const OLLAMA_BASE_URL = OLLAMA_NATIVE_BASE_URL;
69
+ const OLLAMA_API_BASE_URL = OLLAMA_BASE_URL;
83
70
  const OLLAMA_DEFAULT_CONTEXT_WINDOW = 128000;
84
71
  const OLLAMA_DEFAULT_MAX_TOKENS = 8192;
85
72
  const OLLAMA_DEFAULT_COST = {
@@ -88,6 +75,15 @@ const OLLAMA_DEFAULT_COST = {
88
75
  cacheRead: 0,
89
76
  cacheWrite: 0,
90
77
  };
78
+ const VLLM_BASE_URL = "http://127.0.0.1:8000/v1";
79
+ const VLLM_DEFAULT_CONTEXT_WINDOW = 128000;
80
+ const VLLM_DEFAULT_MAX_TOKENS = 8192;
81
+ const VLLM_DEFAULT_COST = {
82
+ input: 0,
83
+ output: 0,
84
+ cacheRead: 0,
85
+ cacheWrite: 0,
86
+ };
91
87
  export const QIANFAN_BASE_URL = "https://qianfan.baidubce.com/v2";
92
88
  export const QIANFAN_DEFAULT_MODEL_ID = "deepseek-v3.2";
93
89
  const QIANFAN_DEFAULT_CONTEXT_WINDOW = 98304;
@@ -98,13 +94,40 @@ const QIANFAN_DEFAULT_COST = {
98
94
  cacheRead: 0,
99
95
  cacheWrite: 0,
100
96
  };
101
- async function discoverOllamaModels() {
97
+ const NVIDIA_BASE_URL = "https://integrate.api.nvidia.com/v1";
98
+ const NVIDIA_DEFAULT_MODEL_ID = "nvidia/llama-3.1-nemotron-70b-instruct";
99
+ const NVIDIA_DEFAULT_CONTEXT_WINDOW = 131072;
100
+ const NVIDIA_DEFAULT_MAX_TOKENS = 4096;
101
+ const NVIDIA_DEFAULT_COST = {
102
+ input: 0,
103
+ output: 0,
104
+ cacheRead: 0,
105
+ cacheWrite: 0,
106
+ };
107
+ /**
108
+ * Derive the Ollama native API base URL from a configured base URL.
109
+ *
110
+ * Users typically configure `baseUrl` with a `/v1` suffix (e.g.
111
+ * `http://192.168.20.14:11434/v1`) for the OpenAI-compatible endpoint.
112
+ * The native Ollama API lives at the root (e.g. `/api/tags`), so we
113
+ * strip the `/v1` suffix when present.
114
+ */
115
+ export function resolveOllamaApiBase(configuredBaseUrl) {
116
+ if (!configuredBaseUrl) {
117
+ return OLLAMA_API_BASE_URL;
118
+ }
119
+ // Strip trailing slash, then strip /v1 suffix if present
120
+ const trimmed = configuredBaseUrl.replace(/\/+$/, "");
121
+ return trimmed.replace(/\/v1$/i, "");
122
+ }
123
+ async function discoverOllamaModels(baseUrl) {
102
124
  // Skip Ollama discovery in test environments
103
125
  if (process.env.VITEST || process.env.NODE_ENV === "test") {
104
126
  return [];
105
127
  }
106
128
  try {
107
- const response = await fetch(`${OLLAMA_API_BASE_URL}/api/tags`, {
129
+ const apiBase = resolveOllamaApiBase(baseUrl);
130
+ const response = await fetch(`${apiBase}/api/tags`, {
108
131
  signal: AbortSignal.timeout(5000),
109
132
  });
110
133
  if (!response.ok) {
@@ -127,11 +150,6 @@ async function discoverOllamaModels() {
127
150
  cost: OLLAMA_DEFAULT_COST,
128
151
  contextWindow: OLLAMA_DEFAULT_CONTEXT_WINDOW,
129
152
  maxTokens: OLLAMA_DEFAULT_MAX_TOKENS,
130
- // Disable streaming by default for Ollama to avoid SDK issue #1205
131
- // See: https://github.com/badlogic/pi-mono/issues/1205
132
- params: {
133
- streaming: false,
134
- },
135
153
  };
136
154
  });
137
155
  }
@@ -140,6 +158,52 @@ async function discoverOllamaModels() {
140
158
  return [];
141
159
  }
142
160
  }
161
+ async function discoverVllmModels(baseUrl, apiKey) {
162
+ // Skip vLLM discovery in test environments
163
+ if (process.env.VITEST || process.env.NODE_ENV === "test") {
164
+ return [];
165
+ }
166
+ const trimmedBaseUrl = baseUrl.trim().replace(/\/+$/, "");
167
+ const url = `${trimmedBaseUrl}/models`;
168
+ try {
169
+ const trimmedApiKey = apiKey?.trim();
170
+ const response = await fetch(url, {
171
+ headers: trimmedApiKey ? { Authorization: `Bearer ${trimmedApiKey}` } : undefined,
172
+ signal: AbortSignal.timeout(5000),
173
+ });
174
+ if (!response.ok) {
175
+ console.warn(`Failed to discover vLLM models: ${response.status}`);
176
+ return [];
177
+ }
178
+ const data = (await response.json());
179
+ const models = data.data ?? [];
180
+ if (models.length === 0) {
181
+ console.warn("No vLLM models found on local instance");
182
+ return [];
183
+ }
184
+ return models
185
+ .map((m) => ({ id: typeof m.id === "string" ? m.id.trim() : "" }))
186
+ .filter((m) => Boolean(m.id))
187
+ .map((m) => {
188
+ const modelId = m.id;
189
+ const lower = modelId.toLowerCase();
190
+ const isReasoning = lower.includes("r1") || lower.includes("reasoning") || lower.includes("think");
191
+ return {
192
+ id: modelId,
193
+ name: modelId,
194
+ reasoning: isReasoning,
195
+ input: ["text"],
196
+ cost: VLLM_DEFAULT_COST,
197
+ contextWindow: VLLM_DEFAULT_CONTEXT_WINDOW,
198
+ maxTokens: VLLM_DEFAULT_MAX_TOKENS,
199
+ };
200
+ });
201
+ }
202
+ catch (error) {
203
+ console.warn(`Failed to discover vLLM models: ${String(error)}`);
204
+ return [];
205
+ }
206
+ }
143
207
  function normalizeApiKeyConfig(value) {
144
208
  const trimmed = value.trim();
145
209
  const match = /^\$\{([A-Z0-9_]+)\}$/.exec(trimmed);
@@ -147,8 +211,9 @@ function normalizeApiKeyConfig(value) {
147
211
  }
148
212
  function resolveEnvApiKeyVarName(provider) {
149
213
  const resolved = resolveEnvApiKey(provider);
150
- if (!resolved)
214
+ if (!resolved) {
151
215
  return undefined;
216
+ }
152
217
  const match = /^(?:env: |shell env: )([A-Z0-9_]+)$/.exec(resolved.source);
153
218
  return match ? match[1] : undefined;
154
219
  }
@@ -159,28 +224,34 @@ function resolveApiKeyFromProfiles(params) {
159
224
  const ids = listProfilesForProvider(params.store, params.provider);
160
225
  for (const id of ids) {
161
226
  const cred = params.store.profiles[id];
162
- if (!cred)
227
+ if (!cred) {
163
228
  continue;
164
- if (cred.type === "api_key")
229
+ }
230
+ if (cred.type === "api_key") {
165
231
  return cred.key;
166
- if (cred.type === "token")
232
+ }
233
+ if (cred.type === "token") {
167
234
  return cred.token;
235
+ }
168
236
  }
169
237
  return undefined;
170
238
  }
171
239
  export function normalizeGoogleModelId(id) {
172
- if (id === "gemini-3-pro")
240
+ if (id === "gemini-3-pro") {
173
241
  return "gemini-3-pro-preview";
174
- if (id === "gemini-3-flash")
242
+ }
243
+ if (id === "gemini-3-flash") {
175
244
  return "gemini-3-flash-preview";
245
+ }
176
246
  return id;
177
247
  }
178
248
  function normalizeGoogleProvider(provider) {
179
249
  let mutated = false;
180
250
  const models = provider.models.map((model) => {
181
251
  const nextId = normalizeGoogleModelId(model.id);
182
- if (nextId === model.id)
252
+ if (nextId === model.id) {
183
253
  return model;
254
+ }
184
255
  mutated = true;
185
256
  return { ...model, id: nextId };
186
257
  });
@@ -188,8 +259,9 @@ function normalizeGoogleProvider(provider) {
188
259
  }
189
260
  export function normalizeProviders(params) {
190
261
  const { providers } = params;
191
- if (!providers)
262
+ if (!providers) {
192
263
  return providers;
264
+ }
193
265
  const authStore = ensureAuthProfileStore(params.agentDir, {
194
266
  allowKeychainPrompt: false,
195
267
  });
@@ -232,8 +304,9 @@ export function normalizeProviders(params) {
232
304
  }
233
305
  if (normalizedKey === "google") {
234
306
  const googleNormalized = normalizeGoogleProvider(normalizedProvider);
235
- if (googleNormalized !== normalizedProvider)
307
+ if (googleNormalized !== normalizedProvider) {
236
308
  mutated = true;
309
+ }
237
310
  normalizedProvider = googleNormalized;
238
311
  }
239
312
  next[key] = normalizedProvider;
@@ -242,27 +315,53 @@ export function normalizeProviders(params) {
242
315
  }
243
316
  function buildMinimaxProvider() {
244
317
  return {
245
- baseUrl: MINIMAX_API_BASE_URL,
246
- api: "openai-completions",
318
+ baseUrl: MINIMAX_PORTAL_BASE_URL,
319
+ api: "anthropic-messages",
247
320
  models: [
248
- {
321
+ buildMinimaxTextModel({
249
322
  id: MINIMAX_DEFAULT_MODEL_ID,
250
323
  name: "MiniMax M2.1",
251
324
  reasoning: false,
252
- input: ["text"],
253
- cost: MINIMAX_API_COST,
254
- contextWindow: MINIMAX_DEFAULT_CONTEXT_WINDOW,
255
- maxTokens: MINIMAX_DEFAULT_MAX_TOKENS,
256
- },
257
- {
325
+ }),
326
+ buildMinimaxTextModel({
327
+ id: "MiniMax-M2.1-lightning",
328
+ name: "MiniMax M2.1 Lightning",
329
+ reasoning: false,
330
+ }),
331
+ buildMinimaxModel({
258
332
  id: MINIMAX_DEFAULT_VISION_MODEL_ID,
259
333
  name: "MiniMax VL 01",
260
334
  reasoning: false,
261
335
  input: ["text", "image"],
262
- cost: MINIMAX_API_COST,
263
- contextWindow: MINIMAX_DEFAULT_CONTEXT_WINDOW,
264
- maxTokens: MINIMAX_DEFAULT_MAX_TOKENS,
265
- },
336
+ }),
337
+ buildMinimaxTextModel({
338
+ id: "MiniMax-M2.5",
339
+ name: "MiniMax M2.5",
340
+ reasoning: true,
341
+ }),
342
+ buildMinimaxTextModel({
343
+ id: "MiniMax-M2.5-Lightning",
344
+ name: "MiniMax M2.5 Lightning",
345
+ reasoning: true,
346
+ }),
347
+ ],
348
+ };
349
+ }
350
+ function buildMinimaxPortalProvider() {
351
+ return {
352
+ baseUrl: MINIMAX_PORTAL_BASE_URL,
353
+ api: "anthropic-messages",
354
+ models: [
355
+ buildMinimaxTextModel({
356
+ id: MINIMAX_DEFAULT_MODEL_ID,
357
+ name: "MiniMax M2.1",
358
+ reasoning: false,
359
+ }),
360
+ buildMinimaxTextModel({
361
+ id: "MiniMax-M2.5",
362
+ name: "MiniMax M2.5",
363
+ reasoning: true,
364
+ }),
266
365
  ],
267
366
  };
268
367
  }
@@ -283,59 +382,6 @@ function buildMoonshotProvider() {
283
382
  ],
284
383
  };
285
384
  }
286
- function buildZaiProvider() {
287
- return {
288
- baseUrl: ZAI_BASE_URL,
289
- api: "openai-completions",
290
- models: [
291
- {
292
- id: ZAI_DEFAULT_MODEL_ID,
293
- name: "GLM 4.7 Flash",
294
- reasoning: false,
295
- input: ["text"],
296
- cost: ZAI_FREE_COST,
297
- contextWindow: ZAI_DEFAULT_CONTEXT_WINDOW,
298
- maxTokens: ZAI_DEFAULT_MAX_TOKENS,
299
- },
300
- {
301
- id: "GLM-4.5-Flash",
302
- name: "GLM 4.5 Flash",
303
- reasoning: false,
304
- input: ["text"],
305
- cost: ZAI_FREE_COST,
306
- contextWindow: ZAI_DEFAULT_CONTEXT_WINDOW,
307
- maxTokens: ZAI_DEFAULT_MAX_TOKENS,
308
- },
309
- {
310
- id: "GLM-4.6V-Flash",
311
- name: "GLM 4.6V Flash (Vision)",
312
- reasoning: false,
313
- input: ["text", "image"],
314
- cost: ZAI_FREE_COST,
315
- contextWindow: ZAI_DEFAULT_CONTEXT_WINDOW,
316
- maxTokens: ZAI_DEFAULT_MAX_TOKENS,
317
- },
318
- {
319
- id: "GLM-4.7-FlashX",
320
- name: "GLM 4.7 FlashX",
321
- reasoning: false,
322
- input: ["text"],
323
- cost: ZAI_FLASHX_COST,
324
- contextWindow: ZAI_DEFAULT_CONTEXT_WINDOW,
325
- maxTokens: ZAI_DEFAULT_MAX_TOKENS,
326
- },
327
- {
328
- id: "GLM-4.7",
329
- name: "GLM 4.7",
330
- reasoning: false,
331
- input: ["text"],
332
- cost: ZAI_PREMIUM_COST,
333
- contextWindow: ZAI_DEFAULT_CONTEXT_WINDOW,
334
- maxTokens: ZAI_DEFAULT_MAX_TOKENS,
335
- },
336
- ],
337
- };
338
- }
339
385
  function buildQwenPortalProvider() {
340
386
  return {
341
387
  baseUrl: QWEN_PORTAL_BASE_URL,
@@ -369,39 +415,6 @@ function buildSyntheticProvider() {
369
415
  models: SYNTHETIC_MODEL_CATALOG.map(buildSyntheticModelDefinition),
370
416
  };
371
417
  }
372
- async function buildVeniceProvider() {
373
- const models = await discoverVeniceModels();
374
- return {
375
- baseUrl: VENICE_BASE_URL,
376
- api: "openai-completions",
377
- models,
378
- };
379
- }
380
- async function buildOllamaProvider() {
381
- const models = await discoverOllamaModels();
382
- return {
383
- baseUrl: OLLAMA_BASE_URL,
384
- api: "openai-completions",
385
- models,
386
- };
387
- }
388
- function buildMinimaxPortalProvider() {
389
- return {
390
- baseUrl: MINIMAX_PORTAL_BASE_URL,
391
- api: "anthropic-messages",
392
- models: [
393
- {
394
- id: MINIMAX_DEFAULT_MODEL_ID,
395
- name: "MiniMax M2.1",
396
- reasoning: false,
397
- input: ["text"],
398
- cost: MINIMAX_API_COST,
399
- contextWindow: MINIMAX_DEFAULT_CONTEXT_WINDOW,
400
- maxTokens: MINIMAX_DEFAULT_MAX_TOKENS,
401
- },
402
- ],
403
- };
404
- }
405
418
  export function buildXiaomiProvider() {
406
419
  return {
407
420
  baseUrl: XIAOMI_BASE_URL,
@@ -419,6 +432,38 @@ export function buildXiaomiProvider() {
419
432
  ],
420
433
  };
421
434
  }
435
+ async function buildVeniceProvider() {
436
+ const models = await discoverVeniceModels();
437
+ return {
438
+ baseUrl: VENICE_BASE_URL,
439
+ api: "openai-completions",
440
+ models,
441
+ };
442
+ }
443
+ async function buildOllamaProvider(configuredBaseUrl) {
444
+ const models = await discoverOllamaModels(configuredBaseUrl);
445
+ return {
446
+ baseUrl: resolveOllamaApiBase(configuredBaseUrl),
447
+ api: "ollama",
448
+ models,
449
+ };
450
+ }
451
+ async function buildHuggingfaceProvider(apiKey) {
452
+ // Resolve env var name to value for discovery (GET /v1/models requires Bearer token).
453
+ const resolvedSecret = apiKey?.trim() !== ""
454
+ ? /^[A-Z][A-Z0-9_]*$/.test(apiKey.trim())
455
+ ? (process.env[apiKey.trim()] ?? "").trim()
456
+ : apiKey.trim()
457
+ : "";
458
+ const models = resolvedSecret !== ""
459
+ ? await discoverHuggingfaceModels(resolvedSecret)
460
+ : HUGGINGFACE_MODEL_CATALOG.map(buildHuggingfaceModelDefinition);
461
+ return {
462
+ baseUrl: HUGGINGFACE_BASE_URL,
463
+ api: "openai-completions",
464
+ models,
465
+ };
466
+ }
422
467
  function buildTogetherProvider() {
423
468
  return {
424
469
  baseUrl: TOGETHER_BASE_URL,
@@ -426,10 +471,11 @@ function buildTogetherProvider() {
426
471
  models: TOGETHER_MODEL_CATALOG.map(buildTogetherModelDefinition),
427
472
  };
428
473
  }
429
- async function buildNvidiaProvider(apiKey) {
430
- const models = await discoverNvidiaModels(apiKey);
474
+ async function buildVllmProvider(params) {
475
+ const baseUrl = (params?.baseUrl?.trim() || VLLM_BASE_URL).replace(/\/+$/, "");
476
+ const models = await discoverVllmModels(baseUrl, params?.apiKey);
431
477
  return {
432
- baseUrl: NVIDIA_BASE_URL,
478
+ baseUrl,
433
479
  api: "openai-completions",
434
480
  models,
435
481
  };
@@ -460,6 +506,41 @@ export function buildQianfanProvider() {
460
506
  ],
461
507
  };
462
508
  }
509
+ export function buildNvidiaProvider() {
510
+ return {
511
+ baseUrl: NVIDIA_BASE_URL,
512
+ api: "openai-completions",
513
+ models: [
514
+ {
515
+ id: NVIDIA_DEFAULT_MODEL_ID,
516
+ name: "NVIDIA Llama 3.1 Nemotron 70B Instruct",
517
+ reasoning: false,
518
+ input: ["text"],
519
+ cost: NVIDIA_DEFAULT_COST,
520
+ contextWindow: NVIDIA_DEFAULT_CONTEXT_WINDOW,
521
+ maxTokens: NVIDIA_DEFAULT_MAX_TOKENS,
522
+ },
523
+ {
524
+ id: "meta/llama-3.3-70b-instruct",
525
+ name: "Meta Llama 3.3 70B Instruct",
526
+ reasoning: false,
527
+ input: ["text"],
528
+ cost: NVIDIA_DEFAULT_COST,
529
+ contextWindow: 131072,
530
+ maxTokens: 4096,
531
+ },
532
+ {
533
+ id: "nvidia/mistral-nemo-minitron-8b-8k-instruct",
534
+ name: "NVIDIA Mistral NeMo Minitron 8B Instruct",
535
+ reasoning: false,
536
+ input: ["text"],
537
+ cost: NVIDIA_DEFAULT_COST,
538
+ contextWindow: 8192,
539
+ maxTokens: 2048,
540
+ },
541
+ ],
542
+ };
543
+ }
463
544
  export async function resolveImplicitProviders(params) {
464
545
  const providers = {};
465
546
  const authStore = ensureAuthProfileStore(params.agentDir, {
@@ -482,11 +563,6 @@ export async function resolveImplicitProviders(params) {
482
563
  if (moonshotKey) {
483
564
  providers.moonshot = { ...buildMoonshotProvider(), apiKey: moonshotKey };
484
565
  }
485
- const zaiKey = resolveEnvApiKeyVarName("zai") ??
486
- resolveApiKeyFromProfiles({ provider: "zai", store: authStore });
487
- if (zaiKey) {
488
- providers.zai = { ...buildZaiProvider(), apiKey: zaiKey };
489
- }
490
566
  const syntheticKey = resolveEnvApiKeyVarName("synthetic") ??
491
567
  resolveApiKeyFromProfiles({ provider: "synthetic", store: authStore });
492
568
  if (syntheticKey) {
@@ -512,18 +588,22 @@ export async function resolveImplicitProviders(params) {
512
588
  const cloudflareProfiles = listProfilesForProvider(authStore, "cloudflare-ai-gateway");
513
589
  for (const profileId of cloudflareProfiles) {
514
590
  const cred = authStore.profiles[profileId];
515
- if (cred?.type !== "api_key")
591
+ if (cred?.type !== "api_key") {
516
592
  continue;
593
+ }
517
594
  const accountId = cred.metadata?.accountId?.trim();
518
595
  const gatewayId = cred.metadata?.gatewayId?.trim();
519
- if (!accountId || !gatewayId)
596
+ if (!accountId || !gatewayId) {
520
597
  continue;
598
+ }
521
599
  const baseUrl = resolveCloudflareAiGatewayBaseUrl({ accountId, gatewayId });
522
- if (!baseUrl)
600
+ if (!baseUrl) {
523
601
  continue;
602
+ }
524
603
  const apiKey = resolveEnvApiKeyVarName("cloudflare-ai-gateway") ?? cred.key?.trim() ?? "";
525
- if (!apiKey)
604
+ if (!apiKey) {
526
605
  continue;
606
+ }
527
607
  providers["cloudflare-ai-gateway"] = {
528
608
  baseUrl,
529
609
  api: "anthropic-messages",
@@ -532,11 +612,30 @@ export async function resolveImplicitProviders(params) {
532
612
  };
533
613
  break;
534
614
  }
535
- // Ollama provider - only add if explicitly configured
615
+ // Ollama provider - only add if explicitly configured.
616
+ // Use the user's configured baseUrl (from explicit providers) for model
617
+ // discovery so that remote / non-default Ollama instances are reachable.
536
618
  const ollamaKey = resolveEnvApiKeyVarName("ollama") ??
537
619
  resolveApiKeyFromProfiles({ provider: "ollama", store: authStore });
538
620
  if (ollamaKey) {
539
- providers.ollama = { ...(await buildOllamaProvider()), apiKey: ollamaKey };
621
+ const ollamaBaseUrl = params.explicitProviders?.ollama?.baseUrl;
622
+ providers.ollama = { ...(await buildOllamaProvider(ollamaBaseUrl)), apiKey: ollamaKey };
623
+ }
624
+ // vLLM provider - OpenAI-compatible local server (opt-in via env/profile).
625
+ // If explicitly configured, keep user-defined models/settings as-is.
626
+ if (!params.explicitProviders?.vllm) {
627
+ const vllmEnvVar = resolveEnvApiKeyVarName("vllm");
628
+ const vllmProfileKey = resolveApiKeyFromProfiles({ provider: "vllm", store: authStore });
629
+ const vllmKey = vllmEnvVar ?? vllmProfileKey;
630
+ if (vllmKey) {
631
+ const discoveryApiKey = vllmEnvVar
632
+ ? (process.env[vllmEnvVar]?.trim() ?? "")
633
+ : (vllmProfileKey ?? "");
634
+ providers.vllm = {
635
+ ...(await buildVllmProvider({ apiKey: discoveryApiKey || undefined })),
636
+ apiKey: vllmKey,
637
+ };
638
+ }
540
639
  }
541
640
  const togetherKey = resolveEnvApiKeyVarName("together") ??
542
641
  resolveApiKeyFromProfiles({ provider: "together", store: authStore });
@@ -546,6 +645,15 @@ export async function resolveImplicitProviders(params) {
546
645
  apiKey: togetherKey,
547
646
  };
548
647
  }
648
+ const huggingfaceKey = resolveEnvApiKeyVarName("huggingface") ??
649
+ resolveApiKeyFromProfiles({ provider: "huggingface", store: authStore });
650
+ if (huggingfaceKey) {
651
+ const hfProvider = await buildHuggingfaceProvider(huggingfaceKey);
652
+ providers.huggingface = {
653
+ ...hfProvider,
654
+ apiKey: huggingfaceKey,
655
+ };
656
+ }
549
657
  const qianfanKey = resolveEnvApiKeyVarName("qianfan") ??
550
658
  resolveApiKeyFromProfiles({ provider: "qianfan", store: authStore });
551
659
  if (qianfanKey) {
@@ -554,18 +662,21 @@ export async function resolveImplicitProviders(params) {
554
662
  const nvidiaKey = resolveEnvApiKeyVarName("nvidia") ??
555
663
  resolveApiKeyFromProfiles({ provider: "nvidia", store: authStore });
556
664
  if (nvidiaKey) {
557
- providers.nvidia = { ...(await buildNvidiaProvider(nvidiaKey)), apiKey: nvidiaKey };
665
+ providers.nvidia = { ...buildNvidiaProvider(), apiKey: nvidiaKey };
558
666
  }
559
667
  return providers;
560
668
  }
561
669
  export async function resolveImplicitCopilotProvider(params) {
562
670
  const env = params.env ?? process.env;
563
- const authStore = ensureAuthProfileStore(params.agentDir, { allowKeychainPrompt: false });
671
+ const authStore = ensureAuthProfileStore(params.agentDir, {
672
+ allowKeychainPrompt: false,
673
+ });
564
674
  const hasProfile = listProfilesForProvider(authStore, "github-copilot").length > 0;
565
675
  const envToken = env.COPILOT_GITHUB_TOKEN ?? env.GH_TOKEN ?? env.GITHUB_TOKEN;
566
676
  const githubToken = (envToken ?? "").trim();
567
- if (!hasProfile && !githubToken)
677
+ if (!hasProfile && !githubToken) {
568
678
  return null;
679
+ }
569
680
  let selectedGithubToken = githubToken;
570
681
  if (!selectedGithubToken && hasProfile) {
571
682
  // Use the first available profile as a default for discovery (it will be
@@ -591,15 +702,15 @@ export async function resolveImplicitCopilotProvider(params) {
591
702
  }
592
703
  // pi-coding-agent's ModelRegistry marks a model "available" only if its
593
704
  // `AuthStorage` has auth configured for that provider (via auth.json/env/etc).
594
- // Our Copilot auth lives in Poolbot's auth-profiles store instead, so we also
705
+ // Our Copilot auth lives in Pool Bot's auth-profiles store instead, so we also
595
706
  // write a runtime-only auth.json entry for pi-coding-agent to pick up.
596
707
  //
597
- // This is safe because it's (1) within Poolbot's agent dir, (2) contains the
708
+ // This is safe because it's (1) within Pool Bot's agent dir, (2) contains the
598
709
  // GitHub token (not the exchanged Copilot token), and (3) matches existing
599
710
  // patterns for OAuth-like providers in pi-coding-agent.
600
711
  // Note: we deliberately do not write pi-coding-agent's `auth.json` here.
601
- // Poolbot uses its own auth store and exchanges tokens at runtime.
602
- // `models list` uses Poolbot's auth heuristics for availability.
712
+ // Pool Bot uses its own auth store and exchanges tokens at runtime.
713
+ // `models list` uses Pool Bot's auth heuristics for availability.
603
714
  // We intentionally do NOT define custom models for Copilot in models.json.
604
715
  // pi-coding-agent treats providers with models as replacements requiring apiKey.
605
716
  // We only override baseUrl; the model list comes from pi-ai built-ins.
@@ -613,14 +724,20 @@ export async function resolveImplicitBedrockProvider(params) {
613
724
  const discoveryConfig = params.config?.models?.bedrockDiscovery;
614
725
  const enabled = discoveryConfig?.enabled;
615
726
  const hasAwsCreds = resolveAwsSdkEnvVarName(env) !== undefined;
616
- if (enabled === false)
727
+ if (enabled === false) {
617
728
  return null;
618
- if (enabled !== true && !hasAwsCreds)
729
+ }
730
+ if (enabled !== true && !hasAwsCreds) {
619
731
  return null;
732
+ }
620
733
  const region = discoveryConfig?.region ?? env.AWS_REGION ?? env.AWS_DEFAULT_REGION ?? "us-east-1";
621
- const models = await discoverBedrockModels({ region, config: discoveryConfig });
622
- if (models.length === 0)
734
+ const models = await discoverBedrockModels({
735
+ region,
736
+ config: discoveryConfig,
737
+ });
738
+ if (models.length === 0) {
623
739
  return null;
740
+ }
624
741
  return {
625
742
  baseUrl: `https://bedrock-runtime.${region}.amazonaws.com`,
626
743
  api: "bedrock-converse-stream",