@poolzin/pool-bot 2026.2.3 → 2026.2.5

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 (81) hide show
  1. package/dist/agents/agent-paths.js +3 -1
  2. package/dist/agents/anthropic-payload-log.js +2 -1
  3. package/dist/agents/bash-tools.exec.js +2 -1
  4. package/dist/agents/cache-trace.js +8 -4
  5. package/dist/agents/live-auth-keys.js +2 -1
  6. package/dist/agents/model-auth.js +1 -0
  7. package/dist/agents/model-forward-compat.js +187 -0
  8. package/dist/agents/pi-embedded-runner/model.js +10 -56
  9. package/dist/agents/pi-embedded-runner/session-manager-cache.js +2 -1
  10. package/dist/agents/pi-embedded-subscribe.raw-stream.js +2 -1
  11. package/dist/agents/skills/bundled-dir.js +2 -1
  12. package/dist/browser/constants.js +1 -1
  13. package/dist/browser/profiles.js +1 -1
  14. package/dist/build-info.json +3 -3
  15. package/dist/channels/plugins/catalog.js +6 -1
  16. package/dist/cli/daemon-cli/install.js +4 -1
  17. package/dist/cli/daemon-cli/status.gather.js +4 -2
  18. package/dist/cli/memory-cli.js +9 -3
  19. package/dist/cli/profile.js +6 -2
  20. package/dist/cli/program/register.onboard.js +10 -0
  21. package/dist/commands/auth-choice-options.js +11 -0
  22. package/dist/commands/auth-choice.apply.api-providers.js +55 -1
  23. package/dist/commands/auth-choice.apply.plugin-provider.js +1 -56
  24. package/dist/commands/auth-choice.preferred-provider.js +1 -0
  25. package/dist/commands/configure.wizard.js +29 -10
  26. package/dist/commands/dashboard.js +4 -1
  27. package/dist/commands/doctor-gateway-daemon-flow.js +8 -2
  28. package/dist/commands/doctor-gateway-services.js +6 -2
  29. package/dist/commands/doctor-platform-notes.js +3 -1
  30. package/dist/commands/gateway-status/helpers.js +3 -1
  31. package/dist/commands/models/auth.js +1 -58
  32. package/dist/commands/models/list.errors.js +14 -0
  33. package/dist/commands/models/list.list-command.js +32 -21
  34. package/dist/commands/models/list.registry.js +120 -28
  35. package/dist/commands/models/list.status-command.js +1 -0
  36. package/dist/commands/models/shared.js +14 -0
  37. package/dist/commands/onboard-auth.config-core.js +60 -2
  38. package/dist/commands/onboard-auth.credentials.js +12 -1
  39. package/dist/commands/onboard-auth.js +3 -3
  40. package/dist/commands/onboard-auth.models.js +22 -0
  41. package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +1 -0
  42. package/dist/commands/onboard-non-interactive/local/auth-choice.js +21 -1
  43. package/dist/commands/provider-auth-helpers.js +61 -0
  44. package/dist/commands/status-all.js +4 -2
  45. package/dist/commands/status.gateway-probe.js +4 -2
  46. package/dist/commands/status.scan.js +2 -1
  47. package/dist/config/paths.js +18 -6
  48. package/dist/daemon/launchd.js +4 -1
  49. package/dist/daemon/schtasks.js +4 -1
  50. package/dist/daemon/systemd.js +4 -1
  51. package/dist/entry.js +4 -2
  52. package/dist/gateway/auth.js +4 -1
  53. package/dist/gateway/call.js +4 -2
  54. package/dist/gateway/server/ws-connection/message-handler.js +4 -1
  55. package/dist/gateway/server-browser.js +4 -2
  56. package/dist/gateway/server-constants.js +5 -2
  57. package/dist/gateway/server-cron.js +3 -1
  58. package/dist/gateway/server-discovery-runtime.js +5 -2
  59. package/dist/infra/restart.js +2 -1
  60. package/dist/infra/shell-env.js +3 -2
  61. package/dist/infra/state-migrations.js +3 -1
  62. package/dist/infra/system-presence.js +4 -1
  63. package/dist/infra/update-runner.js +4 -1
  64. package/dist/macos/gateway-daemon.js +6 -3
  65. package/dist/macos/relay-smoke.js +5 -1
  66. package/dist/macos/relay.js +2 -1
  67. package/dist/media/image-ops.js +3 -1
  68. package/dist/node-host/runner.js +2 -1
  69. package/dist/plugins/bundled-dir.js +2 -1
  70. package/dist/plugins/manifest-registry.js +2 -1
  71. package/dist/security/audit.js +2 -1
  72. package/dist/telegram/bot-message-dispatch.js +1 -1
  73. package/dist/telegram/network-config.js +4 -2
  74. package/dist/terminal/palette.js +8 -6
  75. package/dist/terminal/theme.js +12 -12
  76. package/dist/tui/gateway-chat.js +2 -1
  77. package/dist/tui/theme/theme.js +5 -5
  78. package/dist/tui/tui.js +12 -6
  79. package/dist/version.js +2 -1
  80. package/dist/wizard/onboarding.js +6 -2
  81. package/package.json +1 -1
@@ -3,7 +3,9 @@ import { resolveStateDir } from "../config/paths.js";
3
3
  import { DEFAULT_AGENT_ID } from "../routing/session-key.js";
4
4
  import { resolveUserPath } from "../utils.js";
5
5
  export function resolvePoolbotAgentDir() {
6
- const override = process.env.POOLBOT_AGENT_DIR?.trim() || process.env.CLAWDBOT_AGENT_DIR?.trim() || process.env.PI_CODING_AGENT_DIR?.trim();
6
+ const override = process.env.POOLBOT_AGENT_DIR?.trim() ||
7
+ process.env.CLAWDBOT_AGENT_DIR?.trim() ||
8
+ process.env.PI_CODING_AGENT_DIR?.trim();
7
9
  if (override)
8
10
  return resolveUserPath(override);
9
11
  const defaultAgentDir = path.join(resolveStateDir(), "agents", DEFAULT_AGENT_ID, "agent");
@@ -8,7 +8,8 @@ import { createSubsystemLogger } from "../logging/subsystem.js";
8
8
  const writers = new Map();
9
9
  const log = createSubsystemLogger("agent/anthropic-payload");
10
10
  function resolvePayloadLogConfig(env) {
11
- const enabled = parseBooleanValue(env.POOLBOT_ANTHROPIC_PAYLOAD_LOG ?? env.CLAWDBOT_ANTHROPIC_PAYLOAD_LOG) ?? false;
11
+ const enabled = parseBooleanValue(env.POOLBOT_ANTHROPIC_PAYLOAD_LOG ?? env.CLAWDBOT_ANTHROPIC_PAYLOAD_LOG) ??
12
+ false;
12
13
  const fileOverride = (env.POOLBOT_ANTHROPIC_PAYLOAD_LOG_FILE ?? env.CLAWDBOT_ANTHROPIC_PAYLOAD_LOG_FILE)?.trim();
13
14
  const filePath = fileOverride
14
15
  ? resolveUserPath(fileOverride)
@@ -56,7 +56,8 @@ function validateHostEnv(env) {
56
56
  }
57
57
  }
58
58
  const DEFAULT_MAX_OUTPUT = clampNumber(readEnvInt("PI_BASH_MAX_OUTPUT_CHARS"), 200_000, 1_000, 200_000);
59
- const DEFAULT_PENDING_MAX_OUTPUT = clampNumber(readEnvInt("POOLBOT_BASH_PENDING_MAX_OUTPUT_CHARS") ?? readEnvInt("CLAWDBOT_BASH_PENDING_MAX_OUTPUT_CHARS"), 200_000, 1_000, 200_000);
59
+ const DEFAULT_PENDING_MAX_OUTPUT = clampNumber(readEnvInt("POOLBOT_BASH_PENDING_MAX_OUTPUT_CHARS") ??
60
+ readEnvInt("CLAWDBOT_BASH_PENDING_MAX_OUTPUT_CHARS"), 200_000, 1_000, 200_000);
60
61
  const DEFAULT_PATH = process.env.PATH ?? "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
61
62
  const DEFAULT_NOTIFY_TAIL_CHARS = 400;
62
63
  const DEFAULT_APPROVAL_TIMEOUT_MS = 120_000;
@@ -10,13 +10,17 @@ function resolveCacheTraceConfig(params) {
10
10
  const config = params.cfg?.diagnostics?.cacheTrace;
11
11
  const envEnabled = parseBooleanValue(env.POOLBOT_CACHE_TRACE ?? env.CLAWDBOT_CACHE_TRACE);
12
12
  const enabled = envEnabled ?? config?.enabled ?? false;
13
- const fileOverride = config?.filePath?.trim() || (env.POOLBOT_CACHE_TRACE_FILE ?? env.CLAWDBOT_CACHE_TRACE_FILE)?.trim();
13
+ const fileOverride = config?.filePath?.trim() ||
14
+ (env.POOLBOT_CACHE_TRACE_FILE ?? env.CLAWDBOT_CACHE_TRACE_FILE)?.trim();
14
15
  const filePath = fileOverride
15
16
  ? resolveUserPath(fileOverride)
16
17
  : path.join(resolveStateDir(env), "logs", "cache-trace.jsonl");
17
- const includeMessages = parseBooleanValue(env.POOLBOT_CACHE_TRACE_MESSAGES ?? env.CLAWDBOT_CACHE_TRACE_MESSAGES) ?? config?.includeMessages;
18
- const includePrompt = parseBooleanValue(env.POOLBOT_CACHE_TRACE_PROMPT ?? env.CLAWDBOT_CACHE_TRACE_PROMPT) ?? config?.includePrompt;
19
- const includeSystem = parseBooleanValue(env.POOLBOT_CACHE_TRACE_SYSTEM ?? env.CLAWDBOT_CACHE_TRACE_SYSTEM) ?? config?.includeSystem;
18
+ const includeMessages = parseBooleanValue(env.POOLBOT_CACHE_TRACE_MESSAGES ?? env.CLAWDBOT_CACHE_TRACE_MESSAGES) ??
19
+ config?.includeMessages;
20
+ const includePrompt = parseBooleanValue(env.POOLBOT_CACHE_TRACE_PROMPT ?? env.CLAWDBOT_CACHE_TRACE_PROMPT) ??
21
+ config?.includePrompt;
22
+ const includeSystem = parseBooleanValue(env.POOLBOT_CACHE_TRACE_SYSTEM ?? env.CLAWDBOT_CACHE_TRACE_SYSTEM) ??
23
+ config?.includeSystem;
20
24
  return {
21
25
  enabled,
22
26
  filePath,
@@ -20,7 +20,8 @@ function collectEnvPrefixedKeys(prefix) {
20
20
  return keys;
21
21
  }
22
22
  export function collectAnthropicApiKeys() {
23
- const forcedSingle = (process.env.POOLBOT_LIVE_ANTHROPIC_KEY?.trim() || process.env.CLAWDBOT_LIVE_ANTHROPIC_KEY?.trim());
23
+ const forcedSingle = process.env.POOLBOT_LIVE_ANTHROPIC_KEY?.trim() ||
24
+ process.env.CLAWDBOT_LIVE_ANTHROPIC_KEY?.trim();
24
25
  if (forcedSingle)
25
26
  return [forcedSingle];
26
27
  const fromList = parseKeyList(process.env.POOLBOT_LIVE_ANTHROPIC_KEYS || process.env.CLAWDBOT_LIVE_ANTHROPIC_KEYS);
@@ -225,6 +225,7 @@ export function resolveEnvApiKey(provider) {
225
225
  opencode: "OPENCODE_API_KEY",
226
226
  together: "TOGETHER_API_KEY",
227
227
  qianfan: "QIANFAN_API_KEY",
228
+ nvidia: "NVIDIA_API_KEY",
228
229
  ollama: "OLLAMA_API_KEY",
229
230
  };
230
231
  const envVar = envMap[normalized];
@@ -0,0 +1,187 @@
1
+ import { DEFAULT_CONTEXT_TOKENS } from "./defaults.js";
2
+ import { normalizeModelCompat } from "./model-compat.js";
3
+ import { normalizeProviderId } from "./model-selection.js";
4
+ const OPENAI_CODEX_GPT_53_MODEL_ID = "gpt-5.3-codex";
5
+ const OPENAI_CODEX_TEMPLATE_MODEL_IDS = ["gpt-5.2-codex"];
6
+ const ANTHROPIC_OPUS_46_MODEL_ID = "claude-opus-4-6";
7
+ const ANTHROPIC_OPUS_46_DOT_MODEL_ID = "claude-opus-4.6";
8
+ const ANTHROPIC_OPUS_TEMPLATE_MODEL_IDS = ["claude-opus-4-5", "claude-opus-4.5"];
9
+ const ZAI_GLM5_MODEL_ID = "glm-5";
10
+ const ZAI_GLM5_TEMPLATE_MODEL_IDS = ["glm-4.7"];
11
+ const ANTIGRAVITY_OPUS_46_MODEL_ID = "claude-opus-4-6";
12
+ const ANTIGRAVITY_OPUS_46_DOT_MODEL_ID = "claude-opus-4.6";
13
+ const ANTIGRAVITY_OPUS_TEMPLATE_MODEL_IDS = ["claude-opus-4-5", "claude-opus-4.5"];
14
+ const ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID = "claude-opus-4-6-thinking";
15
+ const ANTIGRAVITY_OPUS_46_DOT_THINKING_MODEL_ID = "claude-opus-4.6-thinking";
16
+ const ANTIGRAVITY_OPUS_THINKING_TEMPLATE_MODEL_IDS = [
17
+ "claude-opus-4-5-thinking",
18
+ "claude-opus-4.5-thinking",
19
+ ];
20
+ export const ANTIGRAVITY_OPUS_46_FORWARD_COMPAT_CANDIDATES = [
21
+ {
22
+ id: ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID,
23
+ templatePrefixes: [
24
+ "google-antigravity/claude-opus-4-5-thinking",
25
+ "google-antigravity/claude-opus-4.5-thinking",
26
+ ],
27
+ },
28
+ {
29
+ id: ANTIGRAVITY_OPUS_46_MODEL_ID,
30
+ templatePrefixes: ["google-antigravity/claude-opus-4-5", "google-antigravity/claude-opus-4.5"],
31
+ },
32
+ ];
33
+ function resolveOpenAICodexGpt53FallbackModel(provider, modelId, modelRegistry) {
34
+ const normalizedProvider = normalizeProviderId(provider);
35
+ const trimmedModelId = modelId.trim();
36
+ if (normalizedProvider !== "openai-codex") {
37
+ return undefined;
38
+ }
39
+ if (trimmedModelId.toLowerCase() !== OPENAI_CODEX_GPT_53_MODEL_ID) {
40
+ return undefined;
41
+ }
42
+ for (const templateId of OPENAI_CODEX_TEMPLATE_MODEL_IDS) {
43
+ const template = modelRegistry.find(normalizedProvider, templateId);
44
+ if (!template) {
45
+ continue;
46
+ }
47
+ return normalizeModelCompat({
48
+ ...template,
49
+ id: trimmedModelId,
50
+ name: trimmedModelId,
51
+ });
52
+ }
53
+ return normalizeModelCompat({
54
+ id: trimmedModelId,
55
+ name: trimmedModelId,
56
+ api: "openai-codex-responses",
57
+ provider: normalizedProvider,
58
+ baseUrl: "https://chatgpt.com/backend-api",
59
+ reasoning: true,
60
+ input: ["text", "image"],
61
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
62
+ contextWindow: DEFAULT_CONTEXT_TOKENS,
63
+ maxTokens: DEFAULT_CONTEXT_TOKENS,
64
+ });
65
+ }
66
+ function resolveAnthropicOpus46ForwardCompatModel(provider, modelId, modelRegistry) {
67
+ const normalizedProvider = normalizeProviderId(provider);
68
+ if (normalizedProvider !== "anthropic") {
69
+ return undefined;
70
+ }
71
+ const trimmedModelId = modelId.trim();
72
+ const lower = trimmedModelId.toLowerCase();
73
+ const isOpus46 = lower === ANTHROPIC_OPUS_46_MODEL_ID ||
74
+ lower === ANTHROPIC_OPUS_46_DOT_MODEL_ID ||
75
+ lower.startsWith(`${ANTHROPIC_OPUS_46_MODEL_ID}-`) ||
76
+ lower.startsWith(`${ANTHROPIC_OPUS_46_DOT_MODEL_ID}-`);
77
+ if (!isOpus46) {
78
+ return undefined;
79
+ }
80
+ const templateIds = [];
81
+ if (lower.startsWith(ANTHROPIC_OPUS_46_MODEL_ID)) {
82
+ templateIds.push(lower.replace(ANTHROPIC_OPUS_46_MODEL_ID, "claude-opus-4-5"));
83
+ }
84
+ if (lower.startsWith(ANTHROPIC_OPUS_46_DOT_MODEL_ID)) {
85
+ templateIds.push(lower.replace(ANTHROPIC_OPUS_46_DOT_MODEL_ID, "claude-opus-4.5"));
86
+ }
87
+ 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
+ });
98
+ }
99
+ return undefined;
100
+ }
101
+ // Z.ai's GLM-5 may not be present in pi-ai's built-in model catalog yet.
102
+ // When a user configures zai/glm-5 without a models.json entry, clone glm-4.7 as a forward-compat fallback.
103
+ function resolveZaiGlm5ForwardCompatModel(provider, modelId, modelRegistry) {
104
+ if (normalizeProviderId(provider) !== "zai") {
105
+ return undefined;
106
+ }
107
+ const trimmed = modelId.trim();
108
+ const lower = trimmed.toLowerCase();
109
+ if (lower !== ZAI_GLM5_MODEL_ID && !lower.startsWith(`${ZAI_GLM5_MODEL_ID}-`)) {
110
+ return undefined;
111
+ }
112
+ for (const templateId of ZAI_GLM5_TEMPLATE_MODEL_IDS) {
113
+ const template = modelRegistry.find("zai", templateId);
114
+ if (!template) {
115
+ continue;
116
+ }
117
+ return normalizeModelCompat({
118
+ ...template,
119
+ id: trimmed,
120
+ name: trimmed,
121
+ reasoning: true,
122
+ });
123
+ }
124
+ return normalizeModelCompat({
125
+ id: trimmed,
126
+ name: trimmed,
127
+ api: "openai-completions",
128
+ provider: "zai",
129
+ reasoning: true,
130
+ input: ["text"],
131
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
132
+ contextWindow: DEFAULT_CONTEXT_TOKENS,
133
+ maxTokens: DEFAULT_CONTEXT_TOKENS,
134
+ });
135
+ }
136
+ function resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegistry) {
137
+ const normalizedProvider = normalizeProviderId(provider);
138
+ if (normalizedProvider !== "google-antigravity") {
139
+ return undefined;
140
+ }
141
+ const trimmedModelId = modelId.trim();
142
+ const lower = trimmedModelId.toLowerCase();
143
+ const isOpus46 = lower === ANTIGRAVITY_OPUS_46_MODEL_ID ||
144
+ lower === ANTIGRAVITY_OPUS_46_DOT_MODEL_ID ||
145
+ lower.startsWith(`${ANTIGRAVITY_OPUS_46_MODEL_ID}-`) ||
146
+ lower.startsWith(`${ANTIGRAVITY_OPUS_46_DOT_MODEL_ID}-`);
147
+ const isOpus46Thinking = lower === ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID ||
148
+ lower === ANTIGRAVITY_OPUS_46_DOT_THINKING_MODEL_ID ||
149
+ lower.startsWith(`${ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID}-`) ||
150
+ lower.startsWith(`${ANTIGRAVITY_OPUS_46_DOT_THINKING_MODEL_ID}-`);
151
+ if (!isOpus46 && !isOpus46Thinking) {
152
+ return undefined;
153
+ }
154
+ const templateIds = [];
155
+ if (lower.startsWith(ANTIGRAVITY_OPUS_46_MODEL_ID)) {
156
+ templateIds.push(lower.replace(ANTIGRAVITY_OPUS_46_MODEL_ID, "claude-opus-4-5"));
157
+ }
158
+ if (lower.startsWith(ANTIGRAVITY_OPUS_46_DOT_MODEL_ID)) {
159
+ templateIds.push(lower.replace(ANTIGRAVITY_OPUS_46_DOT_MODEL_ID, "claude-opus-4.5"));
160
+ }
161
+ if (lower.startsWith(ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID)) {
162
+ templateIds.push(lower.replace(ANTIGRAVITY_OPUS_46_THINKING_MODEL_ID, "claude-opus-4-5-thinking"));
163
+ }
164
+ if (lower.startsWith(ANTIGRAVITY_OPUS_46_DOT_THINKING_MODEL_ID)) {
165
+ templateIds.push(lower.replace(ANTIGRAVITY_OPUS_46_DOT_THINKING_MODEL_ID, "claude-opus-4.5-thinking"));
166
+ }
167
+ templateIds.push(...ANTIGRAVITY_OPUS_TEMPLATE_MODEL_IDS);
168
+ 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;
181
+ }
182
+ export function resolveForwardCompatModel(provider, modelId, modelRegistry) {
183
+ return (resolveOpenAICodexGpt53FallbackModel(provider, modelId, modelRegistry) ??
184
+ resolveAnthropicOpus46ForwardCompatModel(provider, modelId, modelRegistry) ??
185
+ resolveZaiGlm5ForwardCompatModel(provider, modelId, modelRegistry) ??
186
+ resolveAntigravityOpus46ForwardCompatModel(provider, modelId, modelRegistry));
187
+ }
@@ -1,8 +1,9 @@
1
- import { discoverAuthStorage, discoverModels } from "../pi-model-discovery.js";
2
1
  import { resolvePoolbotAgentDir } from "../agent-paths.js";
3
2
  import { DEFAULT_CONTEXT_TOKENS } from "../defaults.js";
4
3
  import { normalizeModelCompat } from "../model-compat.js";
4
+ import { resolveForwardCompatModel } from "../model-forward-compat.js";
5
5
  import { normalizeProviderId } from "../model-selection.js";
6
+ import { discoverAuthStorage, discoverModels, } from "../pi-model-discovery.js";
6
7
  export function buildInlineProviderModels(providers) {
7
8
  return Object.entries(providers).flatMap(([providerId, entry]) => {
8
9
  const trimmed = providerId.trim();
@@ -12,7 +13,7 @@ export function buildInlineProviderModels(providers) {
12
13
  ...model,
13
14
  provider: trimmed,
14
15
  baseUrl: entry?.baseUrl,
15
- ...(entry?.api && !model.api ? { api: entry.api } : {}),
16
+ api: model.api ?? entry?.api,
16
17
  }));
17
18
  });
18
19
  }
@@ -32,65 +33,12 @@ export function buildModelAliasLines(cfg) {
32
33
  .toSorted((a, b) => a.alias.localeCompare(b.alias))
33
34
  .map((entry) => `- ${entry.alias}: ${entry.model}`);
34
35
  }
35
- // Well-known model IDs for forward-compatible resolution
36
- export const OPENAI_CODEX_GPT_53_MODEL_ID = "codex-gpt-5.3";
37
- export const OPENAI_CODEX_TEMPLATE_MODEL_IDS = ["codex-mini-*"];
38
- export const ANTHROPIC_OPUS_46_MODEL_ID = "claude-opus-4-0624";
39
- export const ANTHROPIC_OPUS_46_DOT_MODEL_ID = "claude-opus-4.6";
40
- export const ANTHROPIC_OPUS_TEMPLATE_MODEL_IDS = ["claude-opus-4-*", "claude-opus-4.*"];
41
- /**
42
- * Resolve forward-compat fallback for OpenAI codex-gpt-5.3 requests.
43
- * If the exact model is not in the registry, try `codex-mini-*` template matches.
44
- */
45
- export function resolveOpenAICodexGpt53FallbackModel(modelRegistry, provider) {
46
- for (const templateId of OPENAI_CODEX_TEMPLATE_MODEL_IDS) {
47
- const match = modelRegistry.find(provider, templateId);
48
- if (match)
49
- return match;
50
- }
51
- return null;
52
- }
53
- /**
54
- * Resolve forward-compat fallback for Anthropic claude-opus-4.6 requests.
55
- * If the exact model is not in the registry, try `claude-opus-4-*` template matches.
56
- */
57
- export function resolveAnthropicOpus46ForwardCompatModel(modelRegistry, provider, modelId) {
58
- if (modelId !== ANTHROPIC_OPUS_46_MODEL_ID && modelId !== ANTHROPIC_OPUS_46_DOT_MODEL_ID) {
59
- return null;
60
- }
61
- for (const templateId of ANTHROPIC_OPUS_TEMPLATE_MODEL_IDS) {
62
- const match = modelRegistry.find(provider, templateId);
63
- if (match)
64
- return match;
65
- }
66
- return null;
67
- }
68
36
  export function resolveModel(provider, modelId, agentDir, cfg) {
69
37
  const resolvedAgentDir = agentDir ?? resolvePoolbotAgentDir();
70
38
  const authStorage = discoverAuthStorage(resolvedAgentDir);
71
39
  const modelRegistry = discoverModels(authStorage, resolvedAgentDir);
72
40
  const model = modelRegistry.find(provider, modelId);
73
41
  if (!model) {
74
- // Try codex forward-compat fallback
75
- if (modelId === OPENAI_CODEX_GPT_53_MODEL_ID) {
76
- const codexFallback = resolveOpenAICodexGpt53FallbackModel(modelRegistry, provider);
77
- if (codexFallback) {
78
- return {
79
- model: normalizeModelCompat(codexFallback),
80
- authStorage,
81
- modelRegistry,
82
- };
83
- }
84
- }
85
- // Try Anthropic opus forward-compat fallback
86
- const opusFallback = resolveAnthropicOpus46ForwardCompatModel(modelRegistry, provider, modelId);
87
- if (opusFallback) {
88
- return {
89
- model: normalizeModelCompat(opusFallback),
90
- authStorage,
91
- modelRegistry,
92
- };
93
- }
94
42
  const providers = cfg?.models?.providers ?? {};
95
43
  const inlineModels = buildInlineProviderModels(providers);
96
44
  const normalizedProvider = normalizeProviderId(provider);
@@ -103,6 +51,12 @@ export function resolveModel(provider, modelId, agentDir, cfg) {
103
51
  modelRegistry,
104
52
  };
105
53
  }
54
+ // Forward-compat fallbacks must be checked BEFORE the generic providerCfg fallback.
55
+ // Otherwise, configured providers can default to a generic API and break specific transports.
56
+ const forwardCompat = resolveForwardCompatModel(provider, modelId, modelRegistry);
57
+ if (forwardCompat) {
58
+ return { model: forwardCompat, authStorage, modelRegistry };
59
+ }
106
60
  const providerCfg = providers[provider];
107
61
  if (providerCfg || modelId.startsWith("mock-")) {
108
62
  const fallbackModel = normalizeModelCompat({
@@ -110,12 +64,12 @@ export function resolveModel(provider, modelId, agentDir, cfg) {
110
64
  name: modelId,
111
65
  api: providerCfg?.api ?? "openai-responses",
112
66
  provider,
67
+ baseUrl: providerCfg?.baseUrl,
113
68
  reasoning: false,
114
69
  input: ["text"],
115
70
  cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
116
71
  contextWindow: providerCfg?.models?.[0]?.contextWindow ?? DEFAULT_CONTEXT_TOKENS,
117
72
  maxTokens: providerCfg?.models?.[0]?.maxTokens ?? DEFAULT_CONTEXT_TOKENS,
118
- baseUrl: providerCfg?.baseUrl,
119
73
  });
120
74
  return { model: fallbackModel, authStorage, modelRegistry };
121
75
  }
@@ -5,7 +5,8 @@ const SESSION_MANAGER_CACHE = new Map();
5
5
  const DEFAULT_SESSION_MANAGER_TTL_MS = 45_000; // 45 seconds
6
6
  function getSessionManagerTtl() {
7
7
  return resolveCacheTtlMs({
8
- envValue: process.env.POOLBOT_SESSION_MANAGER_CACHE_TTL_MS || process.env.CLAWDBOT_SESSION_MANAGER_CACHE_TTL_MS,
8
+ envValue: process.env.POOLBOT_SESSION_MANAGER_CACHE_TTL_MS ||
9
+ process.env.CLAWDBOT_SESSION_MANAGER_CACHE_TTL_MS,
9
10
  defaultTtlMs: DEFAULT_SESSION_MANAGER_TTL_MS,
10
11
  });
11
12
  }
@@ -3,7 +3,8 @@ import path from "node:path";
3
3
  import { resolveStateDir } from "../config/paths.js";
4
4
  import { isTruthyEnvValue } from "../infra/env.js";
5
5
  const RAW_STREAM_ENABLED = isTruthyEnvValue(process.env.POOLBOT_RAW_STREAM || process.env.CLAWDBOT_RAW_STREAM);
6
- const RAW_STREAM_PATH = process.env.POOLBOT_RAW_STREAM_PATH?.trim() || process.env.CLAWDBOT_RAW_STREAM_PATH?.trim() ||
6
+ const RAW_STREAM_PATH = process.env.POOLBOT_RAW_STREAM_PATH?.trim() ||
7
+ process.env.CLAWDBOT_RAW_STREAM_PATH?.trim() ||
7
8
  path.join(resolveStateDir(), "logs", "raw-stream.jsonl");
8
9
  let rawStreamReady = false;
9
10
  export function appendRawStream(payload) {
@@ -25,7 +25,8 @@ function looksLikeSkillsDir(dir) {
25
25
  return false;
26
26
  }
27
27
  export function resolveBundledSkillsDir(opts = {}) {
28
- const override = process.env.POOLBOT_BUNDLED_SKILLS_DIR?.trim() || process.env.CLAWDBOT_BUNDLED_SKILLS_DIR?.trim();
28
+ const override = process.env.POOLBOT_BUNDLED_SKILLS_DIR?.trim() ||
29
+ process.env.CLAWDBOT_BUNDLED_SKILLS_DIR?.trim();
29
30
  if (override)
30
31
  return override;
31
32
  // bun --compile: ship a sibling `skills/` next to the executable.
@@ -1,6 +1,6 @@
1
1
  export const DEFAULT_CLAWD_BROWSER_ENABLED = true;
2
2
  export const DEFAULT_BROWSER_EVALUATE_ENABLED = true;
3
- export const DEFAULT_CLAWD_BROWSER_COLOR = "#FF4500";
3
+ export const DEFAULT_CLAWD_BROWSER_COLOR = "#A855F7";
4
4
  export const DEFAULT_CLAWD_BROWSER_PROFILE_NAME = "clawd";
5
5
  export const DEFAULT_BROWSER_DEFAULT_PROFILE_NAME = "chrome";
6
6
  export const DEFAULT_AI_SNAPSHOT_MAX_CHARS = 80_000;
@@ -63,7 +63,7 @@ export function getUsedPorts(profiles) {
63
63
  return used;
64
64
  }
65
65
  export const PROFILE_COLORS = [
66
- "#FF4500", // Orange-red (clawd default)
66
+ "#A855F7", // Purple (poolbot default)
67
67
  "#0066CC", // Blue
68
68
  "#00AA00", // Green
69
69
  "#9933FF", // Purple
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "2026.2.3",
3
- "commit": "84e7160aa161f8c42b9f4a276ea99d44597d7f19",
4
- "builtAt": "2026-02-14T00:56:24.316Z"
2
+ "version": "2026.2.5",
3
+ "commit": "b05c49be3d3a8a8bba6ab957a7ef10c3c4856f8d",
4
+ "builtAt": "2026-02-14T04:39:03.692Z"
5
5
  }
@@ -14,7 +14,12 @@ const DEFAULT_CATALOG_PATHS = [
14
14
  path.join(CONFIG_DIR, "mpm", "catalog.json"),
15
15
  path.join(CONFIG_DIR, "plugins", "catalog.json"),
16
16
  ];
17
- const ENV_CATALOG_PATHS = ["POOLBOT_PLUGIN_CATALOG_PATHS", "POOLBOT_MPM_CATALOG_PATHS", "CLAWDBOT_PLUGIN_CATALOG_PATHS", "CLAWDBOT_MPM_CATALOG_PATHS"];
17
+ const ENV_CATALOG_PATHS = [
18
+ "POOLBOT_PLUGIN_CATALOG_PATHS",
19
+ "POOLBOT_MPM_CATALOG_PATHS",
20
+ "CLAWDBOT_PLUGIN_CATALOG_PATHS",
21
+ "CLAWDBOT_MPM_CATALOG_PATHS",
22
+ ];
18
23
  function isRecord(value) {
19
24
  return Boolean(value && typeof value === "object" && !Array.isArray(value));
20
25
  }
@@ -73,7 +73,10 @@ export async function runDaemonInstall(opts) {
73
73
  const { programArguments, workingDirectory, environment } = await buildGatewayInstallPlan({
74
74
  env: process.env,
75
75
  port,
76
- token: opts.token || cfg.gateway?.auth?.token || process.env.POOLBOT_GATEWAY_TOKEN || process.env.CLAWDBOT_GATEWAY_TOKEN,
76
+ token: opts.token ||
77
+ cfg.gateway?.auth?.token ||
78
+ process.env.POOLBOT_GATEWAY_TOKEN ||
79
+ process.env.CLAWDBOT_GATEWAY_TOKEN,
77
80
  runtime: runtimeRaw,
78
81
  warn: (message) => {
79
82
  if (json)
@@ -106,10 +106,12 @@ export async function gatherDaemonStatus(opts) {
106
106
  ? await probeGatewayStatus({
107
107
  url: probeUrl,
108
108
  token: opts.rpc.token ||
109
- mergedDaemonEnv.POOLBOT_GATEWAY_TOKEN || mergedDaemonEnv.CLAWDBOT_GATEWAY_TOKEN ||
109
+ mergedDaemonEnv.POOLBOT_GATEWAY_TOKEN ||
110
+ mergedDaemonEnv.CLAWDBOT_GATEWAY_TOKEN ||
110
111
  daemonCfg.gateway?.auth?.token,
111
112
  password: opts.rpc.password ||
112
- mergedDaemonEnv.POOLBOT_GATEWAY_PASSWORD || mergedDaemonEnv.CLAWDBOT_GATEWAY_PASSWORD ||
113
+ mergedDaemonEnv.POOLBOT_GATEWAY_PASSWORD ||
114
+ mergedDaemonEnv.CLAWDBOT_GATEWAY_PASSWORD ||
113
115
  daemonCfg.gateway?.auth?.password,
114
116
  timeoutMs,
115
117
  json: opts.rpc.json,
@@ -161,7 +161,9 @@ export async function runMemoryStatus(opts) {
161
161
  getManager: () => getMemorySearchManager({ cfg, agentId }),
162
162
  onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
163
163
  onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
164
- close: async (manager) => { await manager.close?.(); },
164
+ close: async (manager) => {
165
+ await manager.close?.();
166
+ },
165
167
  run: async (manager) => {
166
168
  const deep = Boolean(opts.deep || opts.index);
167
169
  let embeddingProbe;
@@ -387,7 +389,9 @@ export function registerMemoryCli(program) {
387
389
  getManager: () => getMemorySearchManager({ cfg, agentId }),
388
390
  onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
389
391
  onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
390
- close: async (manager) => { await manager.close?.(); },
392
+ close: async (manager) => {
393
+ await manager.close?.();
394
+ },
391
395
  run: async (manager) => {
392
396
  try {
393
397
  if (opts.verbose) {
@@ -500,7 +504,9 @@ export function registerMemoryCli(program) {
500
504
  getManager: () => getMemorySearchManager({ cfg, agentId }),
501
505
  onMissing: (error) => defaultRuntime.log(error ?? "Memory search disabled."),
502
506
  onCloseError: (err) => defaultRuntime.error(`Memory manager close failed: ${formatErrorMessage(err)}`),
503
- close: async (manager) => { await manager.close?.(); },
507
+ close: async (manager) => {
508
+ await manager.close?.();
509
+ },
504
510
  run: async (manager) => {
505
511
  let results;
506
512
  try {
@@ -75,7 +75,9 @@ export function applyCliProfileEnv(params) {
75
75
  // Convenience only: fill defaults, never override explicit env values.
76
76
  env.POOLBOT_PROFILE = profile;
77
77
  env.CLAWDBOT_PROFILE = profile;
78
- const stateDir = env.POOLBOT_STATE_DIR?.trim() || env.CLAWDBOT_STATE_DIR?.trim() || resolveProfileStateDir(profile, homedir);
78
+ const stateDir = env.POOLBOT_STATE_DIR?.trim() ||
79
+ env.CLAWDBOT_STATE_DIR?.trim() ||
80
+ resolveProfileStateDir(profile, homedir);
79
81
  if (!env.POOLBOT_STATE_DIR?.trim())
80
82
  env.POOLBOT_STATE_DIR = stateDir;
81
83
  if (!env.CLAWDBOT_STATE_DIR?.trim())
@@ -85,7 +87,9 @@ export function applyCliProfileEnv(params) {
85
87
  env.POOLBOT_CONFIG_PATH = configPath;
86
88
  env.CLAWDBOT_CONFIG_PATH = configPath;
87
89
  }
88
- if (profile === "dev" && !env.POOLBOT_GATEWAY_PORT?.trim() && !env.CLAWDBOT_GATEWAY_PORT?.trim()) {
90
+ if (profile === "dev" &&
91
+ !env.POOLBOT_GATEWAY_PORT?.trim() &&
92
+ !env.CLAWDBOT_GATEWAY_PORT?.trim()) {
89
93
  env.POOLBOT_GATEWAY_PORT = "19001";
90
94
  env.CLAWDBOT_GATEWAY_PORT = "19001";
91
95
  }
@@ -46,6 +46,11 @@ export function registerOnboardCommand(program) {
46
46
  .option("--synthetic-api-key <key>", "Synthetic API key")
47
47
  .option("--venice-api-key <key>", "Venice API key")
48
48
  .option("--opencode-zen-api-key <key>", "OpenCode Zen API key")
49
+ .option("--xai-api-key <key>", "xAI API key")
50
+ .option("--together-api-key <key>", "Together AI API key")
51
+ .option("--qianfan-api-key <key>", "Qianfan API key")
52
+ .option("--xiaomi-api-key <key>", "Xiaomi API key")
53
+ .option("--nvidia-api-key <key>", "NVIDIA API key")
49
54
  .option("--gateway-port <port>", "Gateway port")
50
55
  .option("--gateway-bind <mode>", "Gateway bind: loopback|tailnet|lan|auto|custom")
51
56
  .option("--gateway-auth <mode>", "Gateway auth: token|password")
@@ -94,6 +99,11 @@ export function registerOnboardCommand(program) {
94
99
  syntheticApiKey: opts.syntheticApiKey,
95
100
  veniceApiKey: opts.veniceApiKey,
96
101
  opencodeZenApiKey: opts.opencodeZenApiKey,
102
+ xaiApiKey: opts.xaiApiKey,
103
+ togetherApiKey: opts.togetherApiKey,
104
+ qianfanApiKey: opts.qianfanApiKey,
105
+ xiaomiApiKey: opts.xiaomiApiKey,
106
+ nvidiaApiKey: opts.nvidiaApiKey,
97
107
  gatewayPort: typeof gatewayPort === "number" && Number.isFinite(gatewayPort)
98
108
  ? gatewayPort
99
109
  : undefined,
@@ -35,6 +35,12 @@ const AUTH_CHOICE_GROUP_DEFS = [
35
35
  hint: "API key",
36
36
  choices: ["xai-api-key"],
37
37
  },
38
+ {
39
+ value: "nvidia",
40
+ label: "NVIDIA (Free Tier)",
41
+ hint: "API key — 23+ frontier models",
42
+ choices: ["nvidia-api-key"],
43
+ },
38
44
  {
39
45
  value: "openrouter",
40
46
  label: "OpenRouter",
@@ -129,6 +135,11 @@ export function buildAuthChoiceOptions(params) {
129
135
  options.push({ value: "chutes", label: "Chutes (OAuth)" });
130
136
  options.push({ value: "openai-api-key", label: "OpenAI API key" });
131
137
  options.push({ value: "xai-api-key", label: "xAI (Grok) API key" });
138
+ options.push({
139
+ value: "nvidia-api-key",
140
+ label: "NVIDIA API key",
141
+ hint: "Free tier — Nemotron, DeepSeek, Kimi, Qwen, and more",
142
+ });
132
143
  options.push({
133
144
  value: "qianfan-api-key",
134
145
  label: "Qianfan API key",