@poolzin/pool-bot 2026.2.0 → 2026.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/bash-tools.exec.js +76 -25
- package/dist/agents/cli-runner/helpers.js +9 -11
- package/dist/agents/identity.js +47 -7
- package/dist/agents/memory-search.js +25 -8
- package/dist/agents/model-selection.js +21 -0
- package/dist/agents/pi-embedded-block-chunker.js +117 -42
- package/dist/agents/pi-embedded-helpers/errors.js +183 -78
- package/dist/agents/pi-embedded-helpers.js +1 -1
- package/dist/agents/pi-embedded-runner/compact.js +1 -0
- package/dist/agents/pi-embedded-runner/model.js +61 -2
- package/dist/agents/pi-embedded-runner/run/attempt.js +21 -11
- package/dist/agents/pi-embedded-runner/run.js +199 -46
- package/dist/agents/pi-embedded-runner/system-prompt.js +10 -2
- package/dist/agents/pi-embedded-subscribe.js +118 -29
- package/dist/agents/pi-tools.js +10 -5
- package/dist/agents/poolbot-tools.js +15 -10
- package/dist/agents/sandbox-paths.js +31 -0
- package/dist/agents/session-tool-result-guard.js +94 -15
- package/dist/agents/shell-utils.js +51 -0
- package/dist/agents/skills/bundled-context.js +23 -0
- package/dist/agents/skills/bundled-dir.js +41 -7
- package/dist/agents/skills-install.js +60 -23
- package/dist/agents/subagent-announce.js +79 -34
- package/dist/agents/tool-policy.conformance.js +14 -0
- package/dist/agents/tool-policy.js +24 -0
- package/dist/agents/tools/cron-tool.js +166 -19
- package/dist/agents/tools/discord-actions-presence.js +78 -0
- package/dist/agents/tools/message-tool.js +56 -2
- package/dist/agents/tools/sessions-history-tool.js +69 -1
- package/dist/agents/tools/web-search.js +211 -42
- package/dist/agents/usage.js +23 -1
- package/dist/agents/workspace-run.js +67 -0
- package/dist/agents/workspace-templates.js +44 -0
- package/dist/auto-reply/command-auth.js +121 -6
- package/dist/auto-reply/envelope.js +50 -72
- package/dist/auto-reply/reply/commands-compact.js +1 -0
- package/dist/auto-reply/reply/commands-context-report.js +1 -0
- package/dist/auto-reply/reply/commands-context.js +1 -0
- package/dist/auto-reply/reply/commands-models.js +107 -60
- package/dist/auto-reply/reply/commands-ptt.js +171 -0
- package/dist/auto-reply/reply/get-reply-run.js +2 -1
- package/dist/auto-reply/reply/inbound-context.js +5 -1
- package/dist/auto-reply/reply/model-selection.js +3 -3
- package/dist/auto-reply/thinking.js +88 -43
- package/dist/browser/bridge-server.js +13 -0
- package/dist/browser/cdp.helpers.js +38 -24
- package/dist/browser/client-fetch.js +50 -7
- package/dist/browser/config.js +1 -10
- package/dist/browser/extension-relay.js +101 -40
- package/dist/browser/pw-ai.js +1 -1
- package/dist/browser/pw-session.js +143 -8
- package/dist/browser/pw-tools-core.interactions.js +125 -27
- package/dist/browser/pw-tools-core.responses.js +1 -1
- package/dist/browser/pw-tools-core.state.js +1 -1
- package/dist/browser/routes/agent.act.js +86 -41
- package/dist/browser/routes/dispatcher.js +4 -4
- package/dist/browser/screenshot.js +1 -1
- package/dist/browser/server.js +13 -0
- package/dist/build-info.json +3 -3
- package/dist/channels/reply-prefix.js +8 -1
- package/dist/cli/cron-cli/register.cron-add.js +61 -40
- package/dist/cli/cron-cli/register.cron-edit.js +60 -34
- package/dist/cli/cron-cli/shared.js +56 -41
- package/dist/cli/dns-cli.js +26 -14
- package/dist/cli/gateway-cli/register.js +37 -19
- package/dist/cli/memory-cli.js +5 -5
- package/dist/cli/parse-bytes.js +37 -0
- package/dist/cli/update-cli.js +173 -52
- package/dist/commands/agent.js +1 -0
- package/dist/commands/doctor-config-flow.js +61 -5
- package/dist/commands/doctor-state-migrations.js +1 -1
- package/dist/commands/health.js +1 -1
- package/dist/commands/model-allowlist.js +29 -0
- package/dist/commands/model-picker.js +2 -1
- package/dist/commands/models/list.status-command.js +43 -23
- package/dist/commands/models/shared.js +15 -0
- package/dist/commands/onboard-custom.js +384 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice-inference.js +35 -0
- package/dist/commands/onboard-non-interactive/local/auth-choice.js +6 -3
- package/dist/commands/onboard-skills.js +63 -38
- package/dist/commands/openai-model-default.js +41 -0
- package/dist/config/defaults.js +3 -2
- package/dist/config/paths.js +136 -35
- package/dist/config/plugin-auto-enable.js +21 -5
- package/dist/config/redact-snapshot.js +153 -0
- package/dist/config/schema.field-metadata.js +590 -0
- package/dist/config/schema.js +2 -2
- package/dist/config/sessions/store.js +291 -23
- package/dist/config/zod-schema.agent-defaults.js +3 -0
- package/dist/config/zod-schema.agent-runtime.js +13 -2
- package/dist/config/zod-schema.providers-core.js +142 -0
- package/dist/config/zod-schema.session.js +3 -0
- package/dist/cron/delivery.js +57 -0
- package/dist/cron/isolated-agent/delivery-target.js +18 -3
- package/dist/cron/isolated-agent/helpers.js +22 -5
- package/dist/cron/isolated-agent/run.js +171 -63
- package/dist/cron/isolated-agent/session.js +2 -0
- package/dist/cron/normalize.js +356 -28
- package/dist/cron/parse.js +10 -5
- package/dist/cron/run-log.js +35 -10
- package/dist/cron/schedule.js +41 -6
- package/dist/cron/service/jobs.js +208 -35
- package/dist/cron/service/ops.js +72 -16
- package/dist/cron/service/state.js +2 -0
- package/dist/cron/service/store.js +386 -14
- package/dist/cron/service/timer.js +390 -147
- package/dist/cron/session-reaper.js +86 -0
- package/dist/cron/store.js +23 -8
- package/dist/cron/validate-timestamp.js +43 -0
- package/dist/discord/monitor/agent-components.js +438 -0
- package/dist/discord/monitor/allow-list.js +28 -5
- package/dist/discord/monitor/gateway-registry.js +29 -0
- package/dist/discord/monitor/native-command.js +44 -23
- package/dist/discord/monitor/sender-identity.js +45 -0
- package/dist/discord/pluralkit.js +27 -0
- package/dist/discord/send.outbound.js +92 -5
- package/dist/discord/send.shared.js +60 -23
- package/dist/discord/targets.js +84 -1
- package/dist/entry.js +15 -9
- package/dist/extensionAPI.js +8 -0
- package/dist/gateway/control-ui.js +8 -1
- package/dist/gateway/hooks-mapping.js +3 -0
- package/dist/gateway/hooks.js +65 -0
- package/dist/gateway/net.js +96 -31
- package/dist/gateway/node-command-policy.js +50 -15
- package/dist/gateway/origin-check.js +56 -0
- package/dist/gateway/protocol/client-info.js +9 -0
- package/dist/gateway/protocol/index.js +9 -2
- package/dist/gateway/protocol/schema/agents-models-skills.js +71 -1
- package/dist/gateway/protocol/schema/cron.js +22 -10
- package/dist/gateway/protocol/schema/protocol-schemas.js +16 -2
- package/dist/gateway/protocol/schema/sessions.js +12 -0
- package/dist/gateway/server/hooks.js +1 -1
- package/dist/gateway/server-broadcast.js +26 -9
- package/dist/gateway/server-chat.js +112 -23
- package/dist/gateway/server-discovery-runtime.js +10 -2
- package/dist/gateway/server-http.js +109 -11
- package/dist/gateway/server-methods/agent-timestamp.js +60 -0
- package/dist/gateway/server-methods/agents.js +321 -2
- package/dist/gateway/server-methods/usage.js +559 -16
- package/dist/gateway/server-runtime-state.js +22 -8
- package/dist/gateway/server-startup-memory.js +16 -0
- package/dist/gateway/server.impl.js +5 -1
- package/dist/gateway/session-utils.fs.js +23 -25
- package/dist/gateway/session-utils.js +20 -10
- package/dist/gateway/sessions-patch.js +7 -22
- package/dist/gateway/test-helpers.server.js +35 -2
- package/dist/imessage/constants.js +2 -0
- package/dist/imessage/monitor/deliver.js +4 -1
- package/dist/imessage/monitor/monitor-provider.js +51 -1
- package/dist/infra/bonjour-discovery.js +131 -70
- package/dist/infra/control-ui-assets.js +134 -12
- package/dist/infra/errors.js +12 -0
- package/dist/infra/exec-approvals.js +266 -57
- package/dist/infra/format-time/format-datetime.js +79 -0
- package/dist/infra/format-time/format-duration.js +81 -0
- package/dist/infra/format-time/format-relative.js +80 -0
- package/dist/infra/heartbeat-runner.js +140 -49
- package/dist/infra/home-dir.js +54 -0
- package/dist/infra/net/fetch-guard.js +122 -0
- package/dist/infra/net/ssrf.js +65 -29
- package/dist/infra/outbound/abort.js +14 -0
- package/dist/infra/outbound/message-action-runner.js +77 -13
- package/dist/infra/outbound/outbound-session.js +143 -37
- package/dist/infra/poolbot-root.js +43 -1
- package/dist/infra/session-cost-usage.js +631 -41
- package/dist/infra/state-migrations.js +317 -47
- package/dist/infra/update-global.js +35 -0
- package/dist/infra/update-runner.js +149 -43
- package/dist/infra/warning-filter.js +65 -0
- package/dist/infra/widearea-dns.js +30 -9
- package/dist/logging/redact-identifier.js +12 -0
- package/dist/media/fetch.js +81 -58
- package/dist/media-understanding/apply.js +403 -3
- package/dist/media-understanding/attachments.js +38 -27
- package/dist/media-understanding/defaults.js +16 -0
- package/dist/media-understanding/providers/deepgram/audio.js +22 -14
- package/dist/media-understanding/providers/google/audio.js +24 -17
- package/dist/media-understanding/providers/google/video.js +24 -17
- package/dist/media-understanding/providers/image.js +2 -2
- package/dist/media-understanding/providers/index.js +4 -1
- package/dist/media-understanding/providers/openai/audio.js +22 -14
- package/dist/media-understanding/providers/shared.js +16 -11
- package/dist/media-understanding/providers/zai/index.js +6 -0
- package/dist/media-understanding/runner.js +158 -90
- package/dist/memory/batch-voyage.js +277 -0
- package/dist/memory/embeddings-voyage.js +75 -0
- package/dist/memory/embeddings.js +28 -16
- package/dist/memory/internal.js +101 -18
- package/dist/memory/manager.js +154 -48
- package/dist/memory/search-manager.js +173 -0
- package/dist/memory/session-files.js +9 -3
- package/dist/node-host/runner.js +34 -24
- package/dist/node-host/with-timeout.js +27 -0
- package/dist/plugins/commands.js +5 -1
- package/dist/plugins/config-state.js +86 -7
- package/dist/plugins/source-display.js +51 -0
- package/dist/process/exec.js +20 -2
- package/dist/routing/resolve-route.js +12 -0
- package/dist/routing/session-key.js +15 -0
- package/dist/runtime.js +2 -0
- package/dist/security/audit-extra.async.js +601 -0
- package/dist/security/audit-extra.js +2 -830
- package/dist/security/audit-extra.sync.js +505 -0
- package/dist/security/channel-metadata.js +34 -0
- package/dist/security/external-content.js +88 -6
- package/dist/security/skill-scanner.js +330 -0
- package/dist/sessions/session-key-utils.js +7 -0
- package/dist/signal/monitor/event-handler.js +80 -1
- package/dist/slack/monitor/media.js +85 -15
- package/dist/tailscale/detect.js +1 -2
- package/dist/telegram/bot/helpers.js +109 -28
- package/dist/telegram/bot-handlers.js +144 -3
- package/dist/telegram/bot-message-context.js +37 -10
- package/dist/telegram/bot-message-dispatch.js +48 -15
- package/dist/telegram/bot-native-commands.js +86 -29
- package/dist/telegram/bot.js +30 -29
- package/dist/telegram/model-buttons.js +163 -0
- package/dist/telegram/monitor.js +110 -85
- package/dist/telegram/send.js +129 -47
- package/dist/terminal/restore.js +45 -0
- package/dist/test-helpers/state-dir-env.js +16 -0
- package/dist/tts/tts.js +12 -6
- package/dist/tui/tui-session-actions.js +166 -54
- package/dist/utils/fetch-timeout.js +20 -0
- package/dist/utils/normalize-secret-input.js +19 -0
- package/dist/utils/transcript-tools.js +58 -0
- package/dist/utils.js +45 -14
- package/dist/version.js +42 -5
- package/package.json +1 -1
|
@@ -1,38 +1,49 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { resolvePoolbotAgentDir } from "../../agents/agent-paths.js";
|
|
3
|
+
import { resolveAgentDir, resolveAgentModelFallbacksOverride, resolveAgentModelPrimary, } from "../../agents/agent-scope.js";
|
|
3
4
|
import { buildAuthHealthSummary, DEFAULT_OAUTH_WARN_MS, formatRemainingShort, } from "../../agents/auth-health.js";
|
|
4
5
|
import { ensureAuthProfileStore, resolveAuthStorePathForDisplay, resolveProfileUnusableUntilForDisplay, } from "../../agents/auth-profiles.js";
|
|
5
6
|
import { resolveEnvApiKey } from "../../agents/model-auth.js";
|
|
6
|
-
import { buildModelAliasIndex, parseModelRef, resolveConfiguredModelRef, resolveModelRefFromString, } from "../../agents/model-selection.js";
|
|
7
|
-
import {
|
|
8
|
-
import { getShellEnvAppliedKeys, shouldEnableShellEnvFallback } from "../../infra/shell-env.js";
|
|
7
|
+
import { buildModelAliasIndex, parseModelRef, resolveConfiguredModelRef, resolveDefaultModelForAgent, resolveModelRefFromString, } from "../../agents/model-selection.js";
|
|
8
|
+
import { formatCliCommand } from "../../cli/command-format.js";
|
|
9
9
|
import { withProgressTotals } from "../../cli/progress.js";
|
|
10
|
+
import { CONFIG_PATH, loadConfig } from "../../config/config.js";
|
|
10
11
|
import { formatUsageWindowSummary, loadProviderUsageSummary, resolveUsageProviderId, } from "../../infra/provider-usage.js";
|
|
11
|
-
import {
|
|
12
|
+
import { getShellEnvAppliedKeys, shouldEnableShellEnvFallback } from "../../infra/shell-env.js";
|
|
12
13
|
import { renderTable } from "../../terminal/table.js";
|
|
13
|
-
import {
|
|
14
|
+
import { colorize, theme } from "../../terminal/theme.js";
|
|
14
15
|
import { shortenHomePath } from "../../utils.js";
|
|
15
16
|
import { resolveProviderAuthOverview } from "./list.auth-overview.js";
|
|
16
17
|
import { isRich } from "./list.format.js";
|
|
17
18
|
import { describeProbeSummary, formatProbeLatency, runAuthProbes, sortProbeResults, } from "./list.probe.js";
|
|
18
|
-
import { DEFAULT_MODEL, DEFAULT_PROVIDER, ensureFlagCompatibility } from "./shared.js";
|
|
19
|
+
import { DEFAULT_MODEL, DEFAULT_PROVIDER, ensureFlagCompatibility, resolveKnownAgentId, } from "./shared.js";
|
|
19
20
|
export async function modelsStatusCommand(opts, runtime) {
|
|
20
21
|
ensureFlagCompatibility(opts);
|
|
21
22
|
if (opts.plain && opts.probe) {
|
|
22
23
|
throw new Error("--probe cannot be used with --plain output.");
|
|
23
24
|
}
|
|
24
25
|
const cfg = loadConfig();
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
const agentId = resolveKnownAgentId({ cfg, rawAgentId: opts.agent });
|
|
27
|
+
const agentDir = agentId ? resolveAgentDir(cfg, agentId) : resolvePoolbotAgentDir();
|
|
28
|
+
const agentModelPrimary = agentId ? resolveAgentModelPrimary(cfg, agentId) : undefined;
|
|
29
|
+
const agentFallbacksOverride = agentId
|
|
30
|
+
? resolveAgentModelFallbacksOverride(cfg, agentId)
|
|
31
|
+
: undefined;
|
|
32
|
+
const resolved = agentId
|
|
33
|
+
? resolveDefaultModelForAgent({ cfg, agentId })
|
|
34
|
+
: resolveConfiguredModelRef({
|
|
35
|
+
cfg,
|
|
36
|
+
defaultProvider: DEFAULT_PROVIDER,
|
|
37
|
+
defaultModel: DEFAULT_MODEL,
|
|
38
|
+
});
|
|
30
39
|
const modelConfig = cfg.agents?.defaults?.model;
|
|
31
40
|
const imageConfig = cfg.agents?.defaults?.imageModel;
|
|
32
|
-
const
|
|
41
|
+
const rawDefaultsModel = typeof modelConfig === "string" ? modelConfig.trim() : (modelConfig?.primary?.trim() ?? "");
|
|
42
|
+
const rawModel = agentModelPrimary ?? rawDefaultsModel;
|
|
33
43
|
const resolvedLabel = `${resolved.provider}/${resolved.model}`;
|
|
34
44
|
const defaultLabel = rawModel || resolvedLabel;
|
|
35
|
-
const
|
|
45
|
+
const defaultsFallbacks = typeof modelConfig === "object" ? (modelConfig?.fallbacks ?? []) : [];
|
|
46
|
+
const fallbacks = agentFallbacksOverride ?? defaultsFallbacks;
|
|
36
47
|
const imageModel = typeof imageConfig === "string" ? imageConfig.trim() : (imageConfig?.primary?.trim() ?? "");
|
|
37
48
|
const imageFallbacks = typeof imageConfig === "object" ? (imageConfig?.fallbacks ?? []) : [];
|
|
38
49
|
const aliases = Object.entries(cfg.agents?.defaults?.models ?? {}).reduce((acc, [key, entry]) => {
|
|
@@ -42,8 +53,7 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
42
53
|
return acc;
|
|
43
54
|
}, {});
|
|
44
55
|
const allowed = Object.keys(cfg.agents?.defaults?.models ?? {});
|
|
45
|
-
const
|
|
46
|
-
const store = ensureAuthProfileStore();
|
|
56
|
+
const store = ensureAuthProfileStore(agentDir);
|
|
47
57
|
const modelsPath = path.join(agentDir, "models.json");
|
|
48
58
|
const providersFromStore = new Set(Object.values(store.profiles)
|
|
49
59
|
.map((profile) => profile.provider)
|
|
@@ -92,7 +102,7 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
92
102
|
]))
|
|
93
103
|
.map((p) => p.trim())
|
|
94
104
|
.filter(Boolean)
|
|
95
|
-
.
|
|
105
|
+
.toSorted((a, b) => a.localeCompare(b));
|
|
96
106
|
const applied = getShellEnvAppliedKeys();
|
|
97
107
|
const shellFallbackEnabled = shouldEnableShellEnvFallback(process.env) || cfg.env?.shellEnv?.enabled === true;
|
|
98
108
|
const providerAuth = providers
|
|
@@ -104,7 +114,7 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
104
114
|
const providerAuthMap = new Map(providerAuth.map((entry) => [entry.provider, entry]));
|
|
105
115
|
const missingProvidersInUse = Array.from(providersInUse)
|
|
106
116
|
.filter((provider) => !providerAuthMap.has(provider))
|
|
107
|
-
.
|
|
117
|
+
.toSorted((a, b) => a.localeCompare(b));
|
|
108
118
|
const probeProfileIds = (() => {
|
|
109
119
|
if (!opts.probeProfile)
|
|
110
120
|
return [];
|
|
@@ -193,7 +203,7 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
193
203
|
remainingMs: unusableUntil - now,
|
|
194
204
|
});
|
|
195
205
|
}
|
|
196
|
-
return out.
|
|
206
|
+
return out.toSorted((a, b) => a.remainingMs - b.remainingMs);
|
|
197
207
|
})();
|
|
198
208
|
const checkStatus = (() => {
|
|
199
209
|
const hasExpiredOrMissing = oauthProfiles.some((profile) => ["expired", "missing"].includes(profile.status)) ||
|
|
@@ -208,16 +218,25 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
208
218
|
if (opts.json) {
|
|
209
219
|
runtime.log(JSON.stringify({
|
|
210
220
|
configPath: CONFIG_PATH,
|
|
221
|
+
...(agentId ? { agentId } : {}),
|
|
211
222
|
agentDir,
|
|
212
223
|
defaultModel: defaultLabel,
|
|
213
224
|
resolvedDefault: resolvedLabel,
|
|
214
225
|
fallbacks,
|
|
215
226
|
imageModel: imageModel || null,
|
|
216
227
|
imageFallbacks,
|
|
228
|
+
...(agentId
|
|
229
|
+
? {
|
|
230
|
+
modelConfig: {
|
|
231
|
+
defaultSource: agentModelPrimary ? "agent" : "defaults",
|
|
232
|
+
fallbacksSource: agentFallbacksOverride !== undefined ? "agent" : "defaults",
|
|
233
|
+
},
|
|
234
|
+
}
|
|
235
|
+
: {}),
|
|
217
236
|
aliases,
|
|
218
237
|
allowed,
|
|
219
238
|
auth: {
|
|
220
|
-
storePath: resolveAuthStorePathForDisplay(),
|
|
239
|
+
storePath: resolveAuthStorePathForDisplay(agentDir),
|
|
221
240
|
shellEnvFallback: {
|
|
222
241
|
enabled: shellFallbackEnabled,
|
|
223
242
|
appliedKeys: applied,
|
|
@@ -246,13 +265,14 @@ export async function modelsStatusCommand(opts, runtime) {
|
|
|
246
265
|
}
|
|
247
266
|
const rich = isRich(opts);
|
|
248
267
|
const label = (value) => colorize(rich, theme.accent, value.padEnd(14));
|
|
268
|
+
const labelWithSource = (value, source) => label(source ? `${value} (${source})` : value);
|
|
249
269
|
const displayDefault = rawModel && rawModel !== resolvedLabel ? `${resolvedLabel} (from ${rawModel})` : resolvedLabel;
|
|
250
270
|
runtime.log(`${label("Config")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, shortenHomePath(CONFIG_PATH))}`);
|
|
251
271
|
runtime.log(`${label("Agent dir")}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.info, shortenHomePath(agentDir))}`);
|
|
252
|
-
runtime.log(`${
|
|
253
|
-
runtime.log(`${
|
|
254
|
-
runtime.log(`${
|
|
255
|
-
runtime.log(`${
|
|
272
|
+
runtime.log(`${labelWithSource("Default", agentId ? (agentModelPrimary ? "agent" : "defaults") : undefined)}${colorize(rich, theme.muted, ":")} ${colorize(rich, theme.success, displayDefault)}`);
|
|
273
|
+
runtime.log(`${labelWithSource(`Fallbacks (${fallbacks.length || 0})`, agentId ? (agentFallbacksOverride !== undefined ? "agent" : "defaults") : undefined)}${colorize(rich, theme.muted, ":")} ${colorize(rich, fallbacks.length ? theme.warn : theme.muted, fallbacks.length ? fallbacks.join(", ") : "-")}`);
|
|
274
|
+
runtime.log(`${labelWithSource("Image model", agentId ? "defaults" : undefined)}${colorize(rich, theme.muted, ":")} ${colorize(rich, imageModel ? theme.accentBright : theme.muted, imageModel || "-")}`);
|
|
275
|
+
runtime.log(`${labelWithSource(`Image fallbacks (${imageFallbacks.length || 0})`, agentId ? "defaults" : undefined)}${colorize(rich, theme.muted, ":")} ${colorize(rich, imageFallbacks.length ? theme.accentBright : theme.muted, imageFallbacks.length ? imageFallbacks.join(", ") : "-")}`);
|
|
256
276
|
runtime.log(`${label(`Aliases (${Object.keys(aliases).length || 0})`)}${colorize(rich, theme.muted, ":")} ${colorize(rich, Object.keys(aliases).length ? theme.accent : theme.muted, Object.keys(aliases).length
|
|
257
277
|
? Object.entries(aliases)
|
|
258
278
|
.map(([alias, target]) => rich
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import { listAgentIds } from "../../agents/agent-scope.js";
|
|
1
2
|
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from "../../agents/defaults.js";
|
|
2
3
|
import { buildModelAliasIndex, modelKey, parseModelRef, resolveModelRefFromString, } from "../../agents/model-selection.js";
|
|
4
|
+
import { formatCliCommand } from "../../cli/command-format.js";
|
|
3
5
|
import { readConfigFileSnapshot, writeConfigFile, } from "../../config/config.js";
|
|
6
|
+
import { normalizeAgentId } from "../../routing/session-key.js";
|
|
4
7
|
export const ensureFlagCompatibility = (opts) => {
|
|
5
8
|
if (opts.json && opts.plain) {
|
|
6
9
|
throw new Error("Choose either --json or --plain, not both.");
|
|
@@ -67,6 +70,18 @@ export function normalizeAlias(alias) {
|
|
|
67
70
|
}
|
|
68
71
|
return trimmed;
|
|
69
72
|
}
|
|
73
|
+
export function resolveKnownAgentId(params) {
|
|
74
|
+
const raw = params.rawAgentId?.trim();
|
|
75
|
+
if (!raw) {
|
|
76
|
+
return undefined;
|
|
77
|
+
}
|
|
78
|
+
const agentId = normalizeAgentId(raw);
|
|
79
|
+
const knownAgents = listAgentIds(params.cfg);
|
|
80
|
+
if (!knownAgents.includes(agentId)) {
|
|
81
|
+
throw new Error(`Unknown agent id "${raw}". Use "${formatCliCommand("poolbot agents list")}" to see configured agents.`);
|
|
82
|
+
}
|
|
83
|
+
return agentId;
|
|
84
|
+
}
|
|
70
85
|
export { modelKey };
|
|
71
86
|
export { DEFAULT_MODEL, DEFAULT_PROVIDER };
|
|
72
87
|
/**
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import { DEFAULT_PROVIDER } from "../agents/defaults.js";
|
|
2
|
+
import { buildModelAliasIndex, modelKey } from "../agents/model-selection.js";
|
|
3
|
+
import { fetchWithTimeout } from "../utils/fetch-timeout.js";
|
|
4
|
+
import { applyPrimaryModel } from "./model-picker.js";
|
|
5
|
+
import { normalizeAlias } from "./models/shared.js";
|
|
6
|
+
const DEFAULT_OLLAMA_BASE_URL = "http://127.0.0.1:11434/v1";
|
|
7
|
+
const DEFAULT_CONTEXT_WINDOW = 4096;
|
|
8
|
+
const DEFAULT_MAX_TOKENS = 4096;
|
|
9
|
+
const VERIFY_TIMEOUT_MS = 10000;
|
|
10
|
+
const COMPATIBILITY_OPTIONS = [
|
|
11
|
+
{
|
|
12
|
+
value: "openai",
|
|
13
|
+
label: "OpenAI-compatible",
|
|
14
|
+
hint: "Uses /chat/completions",
|
|
15
|
+
api: "openai-completions",
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
value: "anthropic",
|
|
19
|
+
label: "Anthropic-compatible",
|
|
20
|
+
hint: "Uses /messages",
|
|
21
|
+
api: "anthropic-messages",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
value: "unknown",
|
|
25
|
+
label: "Unknown (detect automatically)",
|
|
26
|
+
hint: "Probes OpenAI then Anthropic endpoints",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
function normalizeEndpointId(raw) {
|
|
30
|
+
const trimmed = raw.trim().toLowerCase();
|
|
31
|
+
if (!trimmed) {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
return trimmed.replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
35
|
+
}
|
|
36
|
+
function buildEndpointIdFromUrl(baseUrl) {
|
|
37
|
+
try {
|
|
38
|
+
const url = new URL(baseUrl);
|
|
39
|
+
const host = url.hostname.replace(/[^a-z0-9]+/gi, "-").toLowerCase();
|
|
40
|
+
const port = url.port ? `-${url.port}` : "";
|
|
41
|
+
const candidate = `custom-${host}${port}`;
|
|
42
|
+
return normalizeEndpointId(candidate) || "custom";
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return "custom";
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function resolveUniqueEndpointId(params) {
|
|
49
|
+
const normalized = normalizeEndpointId(params.requestedId) || "custom";
|
|
50
|
+
const existing = params.providers[normalized];
|
|
51
|
+
if (!existing?.baseUrl || existing.baseUrl === params.baseUrl) {
|
|
52
|
+
return { providerId: normalized, renamed: false };
|
|
53
|
+
}
|
|
54
|
+
let suffix = 2;
|
|
55
|
+
let candidate = `${normalized}-${suffix}`;
|
|
56
|
+
while (params.providers[candidate]) {
|
|
57
|
+
suffix += 1;
|
|
58
|
+
candidate = `${normalized}-${suffix}`;
|
|
59
|
+
}
|
|
60
|
+
return { providerId: candidate, renamed: true };
|
|
61
|
+
}
|
|
62
|
+
function resolveAliasError(params) {
|
|
63
|
+
const trimmed = params.raw.trim();
|
|
64
|
+
if (!trimmed) {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
let normalized;
|
|
68
|
+
try {
|
|
69
|
+
normalized = normalizeAlias(trimmed);
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
return err instanceof Error ? err.message : "Alias is invalid.";
|
|
73
|
+
}
|
|
74
|
+
const aliasIndex = buildModelAliasIndex({
|
|
75
|
+
cfg: params.cfg,
|
|
76
|
+
defaultProvider: DEFAULT_PROVIDER,
|
|
77
|
+
});
|
|
78
|
+
const aliasKey = normalized.toLowerCase();
|
|
79
|
+
const existing = aliasIndex.byAlias.get(aliasKey);
|
|
80
|
+
if (!existing) {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
const existingKey = modelKey(existing.ref.provider, existing.ref.model);
|
|
84
|
+
if (existingKey === params.modelRef) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
return `Alias ${normalized} already points to ${existingKey}.`;
|
|
88
|
+
}
|
|
89
|
+
function buildOpenAiHeaders(apiKey) {
|
|
90
|
+
const headers = {};
|
|
91
|
+
if (apiKey) {
|
|
92
|
+
headers.Authorization = `Bearer ${apiKey}`;
|
|
93
|
+
}
|
|
94
|
+
return headers;
|
|
95
|
+
}
|
|
96
|
+
function buildAnthropicHeaders(apiKey) {
|
|
97
|
+
const headers = {
|
|
98
|
+
"anthropic-version": "2023-06-01",
|
|
99
|
+
};
|
|
100
|
+
if (apiKey) {
|
|
101
|
+
headers["x-api-key"] = apiKey;
|
|
102
|
+
}
|
|
103
|
+
return headers;
|
|
104
|
+
}
|
|
105
|
+
function formatVerificationError(error) {
|
|
106
|
+
if (!error) {
|
|
107
|
+
return "unknown error";
|
|
108
|
+
}
|
|
109
|
+
if (error instanceof Error) {
|
|
110
|
+
return error.message;
|
|
111
|
+
}
|
|
112
|
+
if (typeof error === "string") {
|
|
113
|
+
return error;
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
return JSON.stringify(error);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
return "unknown error";
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
async function requestOpenAiVerification(params) {
|
|
123
|
+
const endpoint = new URL("chat/completions", params.baseUrl.endsWith("/") ? params.baseUrl : `${params.baseUrl}/`).href;
|
|
124
|
+
try {
|
|
125
|
+
const res = await fetchWithTimeout(endpoint, {
|
|
126
|
+
method: "POST",
|
|
127
|
+
headers: {
|
|
128
|
+
"Content-Type": "application/json",
|
|
129
|
+
...buildOpenAiHeaders(params.apiKey),
|
|
130
|
+
},
|
|
131
|
+
body: JSON.stringify({
|
|
132
|
+
model: params.modelId,
|
|
133
|
+
messages: [{ role: "user", content: "Hi" }],
|
|
134
|
+
max_tokens: 5,
|
|
135
|
+
}),
|
|
136
|
+
}, VERIFY_TIMEOUT_MS);
|
|
137
|
+
return { ok: res.ok, status: res.status };
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
return { ok: false, error };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async function requestAnthropicVerification(params) {
|
|
144
|
+
const endpoint = new URL("messages", params.baseUrl.endsWith("/") ? params.baseUrl : `${params.baseUrl}/`).href;
|
|
145
|
+
try {
|
|
146
|
+
const res = await fetchWithTimeout(endpoint, {
|
|
147
|
+
method: "POST",
|
|
148
|
+
headers: {
|
|
149
|
+
"Content-Type": "application/json",
|
|
150
|
+
...buildAnthropicHeaders(params.apiKey),
|
|
151
|
+
},
|
|
152
|
+
body: JSON.stringify({
|
|
153
|
+
model: params.modelId,
|
|
154
|
+
max_tokens: 16,
|
|
155
|
+
messages: [{ role: "user", content: "Hi" }],
|
|
156
|
+
}),
|
|
157
|
+
}, VERIFY_TIMEOUT_MS);
|
|
158
|
+
return { ok: res.ok, status: res.status };
|
|
159
|
+
}
|
|
160
|
+
catch (error) {
|
|
161
|
+
return { ok: false, error };
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function promptBaseUrlAndKey(params) {
|
|
165
|
+
const baseUrlInput = await params.prompter.text({
|
|
166
|
+
message: "API Base URL",
|
|
167
|
+
initialValue: params.initialBaseUrl ?? DEFAULT_OLLAMA_BASE_URL,
|
|
168
|
+
placeholder: "https://api.example.com/v1",
|
|
169
|
+
validate: (val) => {
|
|
170
|
+
try {
|
|
171
|
+
new URL(val);
|
|
172
|
+
return undefined;
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return "Please enter a valid URL (e.g. http://...)";
|
|
176
|
+
}
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
const apiKeyInput = await params.prompter.text({
|
|
180
|
+
message: "API Key (leave blank if not required)",
|
|
181
|
+
placeholder: "sk-...",
|
|
182
|
+
initialValue: "",
|
|
183
|
+
});
|
|
184
|
+
return { baseUrl: baseUrlInput.trim(), apiKey: apiKeyInput.trim() };
|
|
185
|
+
}
|
|
186
|
+
export async function promptCustomApiConfig(params) {
|
|
187
|
+
const { prompter, runtime, config } = params;
|
|
188
|
+
const baseInput = await promptBaseUrlAndKey({ prompter });
|
|
189
|
+
let baseUrl = baseInput.baseUrl;
|
|
190
|
+
let apiKey = baseInput.apiKey;
|
|
191
|
+
const compatibilityChoice = await prompter.select({
|
|
192
|
+
message: "Endpoint compatibility",
|
|
193
|
+
options: COMPATIBILITY_OPTIONS.map((option) => ({
|
|
194
|
+
value: option.value,
|
|
195
|
+
label: option.label,
|
|
196
|
+
hint: option.hint,
|
|
197
|
+
})),
|
|
198
|
+
});
|
|
199
|
+
let modelId = (await prompter.text({
|
|
200
|
+
message: "Model ID",
|
|
201
|
+
placeholder: "e.g. llama3, claude-3-7-sonnet",
|
|
202
|
+
validate: (val) => (val.trim() ? undefined : "Model ID is required"),
|
|
203
|
+
})).trim();
|
|
204
|
+
let compatibility = compatibilityChoice === "unknown" ? null : compatibilityChoice;
|
|
205
|
+
let providerApi = COMPATIBILITY_OPTIONS.find((entry) => entry.value === compatibility)?.api ??
|
|
206
|
+
"openai-completions";
|
|
207
|
+
while (true) {
|
|
208
|
+
let verifiedFromProbe = false;
|
|
209
|
+
if (!compatibility) {
|
|
210
|
+
const probeSpinner = prompter.progress("Detecting endpoint type...");
|
|
211
|
+
const openaiProbe = await requestOpenAiVerification({ baseUrl, apiKey, modelId });
|
|
212
|
+
if (openaiProbe.ok) {
|
|
213
|
+
probeSpinner.stop("Detected OpenAI-compatible endpoint.");
|
|
214
|
+
compatibility = "openai";
|
|
215
|
+
providerApi = "openai-completions";
|
|
216
|
+
verifiedFromProbe = true;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
const anthropicProbe = await requestAnthropicVerification({ baseUrl, apiKey, modelId });
|
|
220
|
+
if (anthropicProbe.ok) {
|
|
221
|
+
probeSpinner.stop("Detected Anthropic-compatible endpoint.");
|
|
222
|
+
compatibility = "anthropic";
|
|
223
|
+
providerApi = "anthropic-messages";
|
|
224
|
+
verifiedFromProbe = true;
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
probeSpinner.stop("Could not detect endpoint type.");
|
|
228
|
+
await prompter.note("This endpoint did not respond to OpenAI or Anthropic style requests.", "Endpoint detection");
|
|
229
|
+
const retryChoice = await prompter.select({
|
|
230
|
+
message: "What would you like to change?",
|
|
231
|
+
options: [
|
|
232
|
+
{ value: "baseUrl", label: "Change base URL" },
|
|
233
|
+
{ value: "model", label: "Change model" },
|
|
234
|
+
{ value: "both", label: "Change base URL and model" },
|
|
235
|
+
],
|
|
236
|
+
});
|
|
237
|
+
if (retryChoice === "baseUrl" || retryChoice === "both") {
|
|
238
|
+
const retryInput = await promptBaseUrlAndKey({
|
|
239
|
+
prompter,
|
|
240
|
+
initialBaseUrl: baseUrl,
|
|
241
|
+
});
|
|
242
|
+
baseUrl = retryInput.baseUrl;
|
|
243
|
+
apiKey = retryInput.apiKey;
|
|
244
|
+
}
|
|
245
|
+
if (retryChoice === "model" || retryChoice === "both") {
|
|
246
|
+
modelId = (await prompter.text({
|
|
247
|
+
message: "Model ID",
|
|
248
|
+
placeholder: "e.g. llama3, claude-3-7-sonnet",
|
|
249
|
+
validate: (val) => (val.trim() ? undefined : "Model ID is required"),
|
|
250
|
+
})).trim();
|
|
251
|
+
}
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (verifiedFromProbe) {
|
|
257
|
+
break;
|
|
258
|
+
}
|
|
259
|
+
const verifySpinner = prompter.progress("Verifying...");
|
|
260
|
+
const result = compatibility === "anthropic"
|
|
261
|
+
? await requestAnthropicVerification({ baseUrl, apiKey, modelId })
|
|
262
|
+
: await requestOpenAiVerification({ baseUrl, apiKey, modelId });
|
|
263
|
+
if (result.ok) {
|
|
264
|
+
verifySpinner.stop("Verification successful.");
|
|
265
|
+
break;
|
|
266
|
+
}
|
|
267
|
+
if (result.status !== undefined) {
|
|
268
|
+
verifySpinner.stop(`Verification failed: status ${result.status}`);
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
verifySpinner.stop(`Verification failed: ${formatVerificationError(result.error)}`);
|
|
272
|
+
}
|
|
273
|
+
const retryChoice = await prompter.select({
|
|
274
|
+
message: "What would you like to change?",
|
|
275
|
+
options: [
|
|
276
|
+
{ value: "baseUrl", label: "Change base URL" },
|
|
277
|
+
{ value: "model", label: "Change model" },
|
|
278
|
+
{ value: "both", label: "Change base URL and model" },
|
|
279
|
+
],
|
|
280
|
+
});
|
|
281
|
+
if (retryChoice === "baseUrl" || retryChoice === "both") {
|
|
282
|
+
const retryInput = await promptBaseUrlAndKey({
|
|
283
|
+
prompter,
|
|
284
|
+
initialBaseUrl: baseUrl,
|
|
285
|
+
});
|
|
286
|
+
baseUrl = retryInput.baseUrl;
|
|
287
|
+
apiKey = retryInput.apiKey;
|
|
288
|
+
}
|
|
289
|
+
if (retryChoice === "model" || retryChoice === "both") {
|
|
290
|
+
modelId = (await prompter.text({
|
|
291
|
+
message: "Model ID",
|
|
292
|
+
placeholder: "e.g. llama3, claude-3-7-sonnet",
|
|
293
|
+
validate: (val) => (val.trim() ? undefined : "Model ID is required"),
|
|
294
|
+
})).trim();
|
|
295
|
+
}
|
|
296
|
+
if (compatibilityChoice === "unknown") {
|
|
297
|
+
compatibility = null;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const providers = config.models?.providers ?? {};
|
|
301
|
+
const suggestedId = buildEndpointIdFromUrl(baseUrl);
|
|
302
|
+
const providerIdInput = await prompter.text({
|
|
303
|
+
message: "Endpoint ID",
|
|
304
|
+
initialValue: suggestedId,
|
|
305
|
+
placeholder: "custom",
|
|
306
|
+
validate: (value) => {
|
|
307
|
+
const normalized = normalizeEndpointId(value);
|
|
308
|
+
if (!normalized) {
|
|
309
|
+
return "Endpoint ID is required.";
|
|
310
|
+
}
|
|
311
|
+
return undefined;
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
const providerIdResult = resolveUniqueEndpointId({
|
|
315
|
+
requestedId: providerIdInput,
|
|
316
|
+
baseUrl,
|
|
317
|
+
providers,
|
|
318
|
+
});
|
|
319
|
+
if (providerIdResult.renamed) {
|
|
320
|
+
await prompter.note(`Endpoint ID "${providerIdInput}" already exists for a different base URL. Using "${providerIdResult.providerId}".`, "Endpoint ID");
|
|
321
|
+
}
|
|
322
|
+
const providerId = providerIdResult.providerId;
|
|
323
|
+
const modelRef = modelKey(providerId, modelId);
|
|
324
|
+
const aliasInput = await prompter.text({
|
|
325
|
+
message: "Model alias (optional)",
|
|
326
|
+
placeholder: "e.g. local, ollama",
|
|
327
|
+
initialValue: "",
|
|
328
|
+
validate: (value) => resolveAliasError({ raw: value, cfg: config, modelRef }),
|
|
329
|
+
});
|
|
330
|
+
const alias = aliasInput.trim();
|
|
331
|
+
const existingProvider = providers[providerId];
|
|
332
|
+
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
|
|
333
|
+
const hasModel = existingModels.some((model) => model.id === modelId);
|
|
334
|
+
const nextModel = {
|
|
335
|
+
id: modelId,
|
|
336
|
+
name: `${modelId} (Custom Provider)`,
|
|
337
|
+
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
|
338
|
+
maxTokens: DEFAULT_MAX_TOKENS,
|
|
339
|
+
input: ["text"],
|
|
340
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
341
|
+
reasoning: false,
|
|
342
|
+
};
|
|
343
|
+
const mergedModels = hasModel ? existingModels : [...existingModels, nextModel];
|
|
344
|
+
const { apiKey: existingApiKey, ...existingProviderRest } = existingProvider ?? {};
|
|
345
|
+
const normalizedApiKey = apiKey.trim() || (existingApiKey ? existingApiKey.trim() : undefined);
|
|
346
|
+
let newConfig = {
|
|
347
|
+
...config,
|
|
348
|
+
models: {
|
|
349
|
+
...config.models,
|
|
350
|
+
mode: config.models?.mode ?? "merge",
|
|
351
|
+
providers: {
|
|
352
|
+
...providers,
|
|
353
|
+
[providerId]: {
|
|
354
|
+
...existingProviderRest,
|
|
355
|
+
baseUrl,
|
|
356
|
+
api: providerApi,
|
|
357
|
+
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
|
|
358
|
+
models: mergedModels.length > 0 ? mergedModels : [nextModel],
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
};
|
|
363
|
+
newConfig = applyPrimaryModel(newConfig, modelRef);
|
|
364
|
+
if (alias) {
|
|
365
|
+
newConfig = {
|
|
366
|
+
...newConfig,
|
|
367
|
+
agents: {
|
|
368
|
+
...newConfig.agents,
|
|
369
|
+
defaults: {
|
|
370
|
+
...newConfig.agents?.defaults,
|
|
371
|
+
models: {
|
|
372
|
+
...newConfig.agents?.defaults?.models,
|
|
373
|
+
[modelRef]: {
|
|
374
|
+
...newConfig.agents?.defaults?.models?.[modelRef],
|
|
375
|
+
alias,
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
runtime.log(`Configured custom provider: ${providerId}/${modelId}`);
|
|
383
|
+
return { config: newConfig, providerId, modelId };
|
|
384
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const AUTH_CHOICE_FLAG_MAP = [
|
|
2
|
+
{ flag: "anthropicApiKey", authChoice: "apiKey", label: "--anthropic-api-key" },
|
|
3
|
+
{ flag: "geminiApiKey", authChoice: "gemini-api-key", label: "--gemini-api-key" },
|
|
4
|
+
{ flag: "openaiApiKey", authChoice: "openai-api-key", label: "--openai-api-key" },
|
|
5
|
+
{ flag: "openrouterApiKey", authChoice: "openrouter-api-key", label: "--openrouter-api-key" },
|
|
6
|
+
{ flag: "aiGatewayApiKey", authChoice: "ai-gateway-api-key", label: "--ai-gateway-api-key" },
|
|
7
|
+
{
|
|
8
|
+
flag: "cloudflareAiGatewayApiKey",
|
|
9
|
+
authChoice: "cloudflare-ai-gateway-api-key",
|
|
10
|
+
label: "--cloudflare-ai-gateway-api-key",
|
|
11
|
+
},
|
|
12
|
+
{ flag: "moonshotApiKey", authChoice: "moonshot-api-key", label: "--moonshot-api-key" },
|
|
13
|
+
{ flag: "kimiCodeApiKey", authChoice: "kimi-code-api-key", label: "--kimi-code-api-key" },
|
|
14
|
+
{ flag: "syntheticApiKey", authChoice: "synthetic-api-key", label: "--synthetic-api-key" },
|
|
15
|
+
{ flag: "veniceApiKey", authChoice: "venice-api-key", label: "--venice-api-key" },
|
|
16
|
+
{ flag: "zaiApiKey", authChoice: "zai-api-key", label: "--zai-api-key" },
|
|
17
|
+
{ flag: "xiaomiApiKey", authChoice: "xiaomi-api-key", label: "--xiaomi-api-key" },
|
|
18
|
+
{ flag: "xaiApiKey", authChoice: "xai-api-key", label: "--xai-api-key" },
|
|
19
|
+
{ flag: "minimaxApiKey", authChoice: "minimax-api", label: "--minimax-api-key" },
|
|
20
|
+
{ flag: "opencodeZenApiKey", authChoice: "opencode-zen", label: "--opencode-zen-api-key" },
|
|
21
|
+
];
|
|
22
|
+
// Infer auth choice from explicit provider API key flags.
|
|
23
|
+
export function inferAuthChoiceFromFlags(opts) {
|
|
24
|
+
const matches = AUTH_CHOICE_FLAG_MAP.filter(({ flag }) => {
|
|
25
|
+
const value = opts[flag];
|
|
26
|
+
if (typeof value === "string") {
|
|
27
|
+
return value.trim().length > 0;
|
|
28
|
+
}
|
|
29
|
+
return Boolean(value);
|
|
30
|
+
});
|
|
31
|
+
return {
|
|
32
|
+
choice: matches[0]?.authChoice,
|
|
33
|
+
matches,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -2,8 +2,10 @@ import { upsertAuthProfile } from "../../../agents/auth-profiles.js";
|
|
|
2
2
|
import { normalizeProviderId } from "../../../agents/model-selection.js";
|
|
3
3
|
import { parseDurationMs } from "../../../cli/parse-duration.js";
|
|
4
4
|
import { upsertSharedEnvVar } from "../../../infra/env-file.js";
|
|
5
|
+
import { normalizeSecretInput } from "../../../utils/normalize-secret-input.js";
|
|
5
6
|
import { buildTokenProfileId, validateAnthropicSetupToken } from "../../auth-token.js";
|
|
6
7
|
import { applyGoogleGeminiModelDefault } from "../../google-gemini-model-default.js";
|
|
8
|
+
import { applyOpenAIConfig } from "../../openai-model-default.js";
|
|
7
9
|
import { applyAuthProfileConfig, applyCloudflareAiGatewayConfig, applyKimiCodeConfig, applyMinimaxApiConfig, applyMinimaxConfig, applyMoonshotConfig, applyMoonshotConfigCn, applyOpencodeZenConfig, applyOpenrouterConfig, applyQianfanConfig, applySyntheticConfig, applyTogetherConfig, applyVeniceConfig, applyVercelAiGatewayConfig, applyXaiConfig, applyXiaomiConfig, applyZaiConfig, setAnthropicApiKey, setCloudflareAiGatewayConfig, setGeminiApiKey, setKimiCodingApiKey, setMinimaxApiKey, setMoonshotApiKey, setOpencodeZenApiKey, setOpenrouterApiKey, setQianfanApiKey, setSyntheticApiKey, setTogetherApiKey, setVeniceApiKey, setVercelAiGatewayApiKey, setXaiApiKey, setXiaomiApiKey, setZaiApiKey, } from "../../onboard-auth.js";
|
|
8
10
|
import { resolveNonInteractiveApiKey } from "../api-keys.js";
|
|
9
11
|
import { shortenHomePath } from "../../../utils.js";
|
|
@@ -58,7 +60,7 @@ export async function applyNonInteractiveAuthChoice(params) {
|
|
|
58
60
|
runtime.exit(1);
|
|
59
61
|
return null;
|
|
60
62
|
}
|
|
61
|
-
const tokenRaw = opts.token
|
|
63
|
+
const tokenRaw = normalizeSecretInput(opts.token);
|
|
62
64
|
if (!tokenRaw) {
|
|
63
65
|
runtime.error("Missing --token for --auth-choice token.");
|
|
64
66
|
runtime.exit(1);
|
|
@@ -154,7 +156,7 @@ export async function applyNonInteractiveAuthChoice(params) {
|
|
|
154
156
|
const result = upsertSharedEnvVar({ key: "OPENAI_API_KEY", value: key });
|
|
155
157
|
process.env.OPENAI_API_KEY = key;
|
|
156
158
|
runtime.log(`Saved OPENAI_API_KEY to ${shortenHomePath(result.path)}`);
|
|
157
|
-
return nextConfig;
|
|
159
|
+
return applyOpenAIConfig(nextConfig);
|
|
158
160
|
}
|
|
159
161
|
if (authChoice === "openrouter-api-key") {
|
|
160
162
|
const resolved = await resolveNonInteractiveApiKey({
|
|
@@ -458,7 +460,8 @@ export async function applyNonInteractiveAuthChoice(params) {
|
|
|
458
460
|
if (authChoice === "oauth" ||
|
|
459
461
|
authChoice === "chutes" ||
|
|
460
462
|
authChoice === "openai-codex" ||
|
|
461
|
-
authChoice === "qwen-portal"
|
|
463
|
+
authChoice === "qwen-portal" ||
|
|
464
|
+
authChoice === "minimax-portal") {
|
|
462
465
|
runtime.error("OAuth requires interactive mode.");
|
|
463
466
|
runtime.exit(1);
|
|
464
467
|
return null;
|