Merge 0a269c6ed5 into 06289b36da
This commit is contained in:
commit
43179d1bd3
@ -124,6 +124,32 @@ Moltbot ships with the pi‑ai catalog. These providers require **no**
|
|||||||
Use `models.providers` (or `models.json`) to add **custom** providers or
|
Use `models.providers` (or `models.json`) to add **custom** providers or
|
||||||
OpenAI/Anthropic‑compatible proxies.
|
OpenAI/Anthropic‑compatible proxies.
|
||||||
|
|
||||||
|
### Modelverse
|
||||||
|
|
||||||
|
Modelverse (UCloud) provides an OpenAI-compatible API for multiple model families.
|
||||||
|
|
||||||
|
- Provider: `modelverse`
|
||||||
|
- Auth: `MODELVERSE_API_KEY`
|
||||||
|
- Base URL: `https://api.modelverse.cn/v1`
|
||||||
|
- Example model: `modelverse/gpt-5.2`
|
||||||
|
- CLI: `clawdbot onboard --auth-choice modelverse-api-key`
|
||||||
|
|
||||||
|
Model refs:
|
||||||
|
- `modelverse/gpt-5.2`
|
||||||
|
- `modelverse/claude-opus-4-5-20251101`
|
||||||
|
- `modelverse/claude-sonnet-4-5-20250929`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-V3.2`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-R1`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-V3-0324`
|
||||||
|
- `modelverse/openai/gpt-4o`
|
||||||
|
- `modelverse/zai-org/glm-4.7`
|
||||||
|
- `modelverse/gemini-3-flash-preview`
|
||||||
|
- `modelverse/gemini-3-pro-preview`
|
||||||
|
- `modelverse/gemini-2.5-flash`
|
||||||
|
- `modelverse/gemini-2.5-pro`
|
||||||
|
|
||||||
|
See [/providers/modelverse](/providers/modelverse).
|
||||||
|
|
||||||
### Moonshot AI (Kimi)
|
### Moonshot AI (Kimi)
|
||||||
|
|
||||||
Moonshot uses OpenAI-compatible endpoints, so configure it as a custom provider:
|
Moonshot uses OpenAI-compatible endpoints, so configure it as a custom provider:
|
||||||
|
|||||||
@ -44,6 +44,7 @@ See [Venice AI](/providers/venice).
|
|||||||
- [Z.AI](/providers/zai)
|
- [Z.AI](/providers/zai)
|
||||||
- [GLM models](/providers/glm)
|
- [GLM models](/providers/glm)
|
||||||
- [MiniMax](/providers/minimax)
|
- [MiniMax](/providers/minimax)
|
||||||
|
- [Modelverse (OpenAI-compatible)](/providers/modelverse)
|
||||||
- [Venius (Venice AI, privacy-focused)](/providers/venice)
|
- [Venius (Venice AI, privacy-focused)](/providers/venice)
|
||||||
- [Ollama (local models)](/providers/ollama)
|
- [Ollama (local models)](/providers/ollama)
|
||||||
|
|
||||||
|
|||||||
@ -41,6 +41,7 @@ See [Venice AI](/providers/venice).
|
|||||||
- [Z.AI](/providers/zai)
|
- [Z.AI](/providers/zai)
|
||||||
- [GLM models](/providers/glm)
|
- [GLM models](/providers/glm)
|
||||||
- [MiniMax](/providers/minimax)
|
- [MiniMax](/providers/minimax)
|
||||||
|
- [Modelverse (OpenAI-compatible)](/providers/modelverse)
|
||||||
- [Venius (Venice AI)](/providers/venice)
|
- [Venius (Venice AI)](/providers/venice)
|
||||||
- [Amazon Bedrock](/bedrock)
|
- [Amazon Bedrock](/bedrock)
|
||||||
|
|
||||||
|
|||||||
66
docs/providers/modelverse.md
Normal file
66
docs/providers/modelverse.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
---
|
||||||
|
summary: "Use Modelverse (UCloud) as an OpenAI-compatible model provider in Clawdbot"
|
||||||
|
read_when:
|
||||||
|
- You want to use Modelverse models in Clawdbot
|
||||||
|
- You need the base URL, API key setup, and model refs for Modelverse
|
||||||
|
---
|
||||||
|
# Modelverse
|
||||||
|
|
||||||
|
Modelverse (UCloud) exposes an **OpenAI-compatible** API that can route to multiple model families.
|
||||||
|
|
||||||
|
## Authenticate
|
||||||
|
|
||||||
|
Get an API key:
|
||||||
|
https://console.ucloud-global.com/modelverse/experience/api-keys
|
||||||
|
|
||||||
|
Then run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clawdbot onboard --auth-choice modelverse-api-key
|
||||||
|
```
|
||||||
|
|
||||||
|
This stores the key in Clawdbot's auth profiles and writes a `models.providers.modelverse` entry.
|
||||||
|
|
||||||
|
## Model refs
|
||||||
|
|
||||||
|
Use `modelverse/<modelId>`:
|
||||||
|
|
||||||
|
- `modelverse/gpt-5.2`
|
||||||
|
- `modelverse/claude-opus-4-5-20251101`
|
||||||
|
- `modelverse/claude-sonnet-4-5-20250929`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-V3.2`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-R1`
|
||||||
|
- `modelverse/deepseek-ai/DeepSeek-V3-0324`
|
||||||
|
- `modelverse/openai/gpt-4o`
|
||||||
|
- `modelverse/zai-org/glm-4.7`
|
||||||
|
- `modelverse/gemini-3-flash-preview`
|
||||||
|
- `modelverse/gemini-3-pro-preview`
|
||||||
|
- `modelverse/gemini-2.5-flash`
|
||||||
|
- `modelverse/gemini-2.5-pro`
|
||||||
|
|
||||||
|
Switch models with:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
clawdbot models set modelverse/gpt-5.2
|
||||||
|
```
|
||||||
|
|
||||||
|
## Config snippet (manual)
|
||||||
|
|
||||||
|
```json5
|
||||||
|
{
|
||||||
|
env: { MODELVERSE_API_KEY: "sk-..." },
|
||||||
|
agents: { defaults: { model: { primary: "modelverse/gpt-5.2" } } },
|
||||||
|
models: {
|
||||||
|
mode: "merge",
|
||||||
|
providers: {
|
||||||
|
modelverse: {
|
||||||
|
baseUrl: "https://api.modelverse.cn/v1",
|
||||||
|
apiKey: "${MODELVERSE_API_KEY}",
|
||||||
|
api: "openai-completions",
|
||||||
|
models: [{ id: "gpt-5.2", name: "GPT-5.2" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
@ -271,6 +271,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null {
|
|||||||
|
|
||||||
const envMap: Record<string, string> = {
|
const envMap: Record<string, string> = {
|
||||||
openai: "OPENAI_API_KEY",
|
openai: "OPENAI_API_KEY",
|
||||||
|
modelverse: "MODELVERSE_API_KEY",
|
||||||
google: "GEMINI_API_KEY",
|
google: "GEMINI_API_KEY",
|
||||||
groq: "GROQ_API_KEY",
|
groq: "GROQ_API_KEY",
|
||||||
deepgram: "DEEPGRAM_API_KEY",
|
deepgram: "DEEPGRAM_API_KEY",
|
||||||
|
|||||||
37
src/agents/models-config.providers.modelverse.test.ts
Normal file
37
src/agents/models-config.providers.modelverse.test.ts
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
import { afterEach, describe, expect, it } from "vitest";
|
||||||
|
import { resolveImplicitProviders } from "./models-config.providers.js";
|
||||||
|
import { mkdtempSync } from "node:fs";
|
||||||
|
import { join } from "node:path";
|
||||||
|
import { tmpdir } from "node:os";
|
||||||
|
|
||||||
|
describe("Modelverse provider", () => {
|
||||||
|
const previousKey = process.env.MODELVERSE_API_KEY;
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
if (previousKey === undefined) {
|
||||||
|
delete process.env.MODELVERSE_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.MODELVERSE_API_KEY = previousKey;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not include modelverse when no API key is configured", async () => {
|
||||||
|
const agentDir = mkdtempSync(join(tmpdir(), "clawd-test-"));
|
||||||
|
const providers = await resolveImplicitProviders({ agentDir });
|
||||||
|
|
||||||
|
expect(providers?.modelverse).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should include modelverse when MODELVERSE_API_KEY is configured", async () => {
|
||||||
|
process.env.MODELVERSE_API_KEY = "sk-modelverse-test";
|
||||||
|
const agentDir = mkdtempSync(join(tmpdir(), "clawd-test-"));
|
||||||
|
const providers = await resolveImplicitProviders({ agentDir });
|
||||||
|
|
||||||
|
expect(providers?.modelverse).toBeDefined();
|
||||||
|
expect(providers.modelverse).toMatchObject({
|
||||||
|
baseUrl: "https://api.modelverse.cn/v1",
|
||||||
|
api: "openai-completions",
|
||||||
|
});
|
||||||
|
expect(providers.modelverse.models.some((model) => model.id === "gpt-5.2")).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -13,6 +13,11 @@ import {
|
|||||||
SYNTHETIC_MODEL_CATALOG,
|
SYNTHETIC_MODEL_CATALOG,
|
||||||
} from "./synthetic-models.js";
|
} from "./synthetic-models.js";
|
||||||
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
|
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
|
||||||
|
import {
|
||||||
|
buildModelverseModelDefinition,
|
||||||
|
MODELVERSE_BASE_URL,
|
||||||
|
MODELVERSE_MODEL_CATALOG,
|
||||||
|
} from "./modelverse-models.js";
|
||||||
|
|
||||||
type ModelsConfig = NonNullable<MoltbotConfig["models"]>;
|
type ModelsConfig = NonNullable<MoltbotConfig["models"]>;
|
||||||
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
|
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
|
||||||
@ -359,6 +364,14 @@ async function buildOllamaProvider(): Promise<ProviderConfig> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildModelverseProvider(): ProviderConfig {
|
||||||
|
return {
|
||||||
|
baseUrl: MODELVERSE_BASE_URL,
|
||||||
|
api: "openai-completions",
|
||||||
|
models: MODELVERSE_MODEL_CATALOG.map(buildModelverseModelDefinition),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export async function resolveImplicitProviders(params: {
|
export async function resolveImplicitProviders(params: {
|
||||||
agentDir: string;
|
agentDir: string;
|
||||||
}): Promise<ModelsConfig["providers"]> {
|
}): Promise<ModelsConfig["providers"]> {
|
||||||
@ -402,6 +415,13 @@ export async function resolveImplicitProviders(params: {
|
|||||||
providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey };
|
providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const modelverseKey =
|
||||||
|
resolveEnvApiKeyVarName("modelverse") ??
|
||||||
|
resolveApiKeyFromProfiles({ provider: "modelverse", store: authStore });
|
||||||
|
if (modelverseKey) {
|
||||||
|
providers.modelverse = { ...buildModelverseProvider(), apiKey: modelverseKey };
|
||||||
|
}
|
||||||
|
|
||||||
const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal");
|
const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal");
|
||||||
if (qwenProfiles.length > 0) {
|
if (qwenProfiles.length > 0) {
|
||||||
providers["qwen-portal"] = {
|
providers["qwen-portal"] = {
|
||||||
|
|||||||
132
src/agents/modelverse-models.ts
Normal file
132
src/agents/modelverse-models.ts
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
import type { ModelDefinitionConfig } from "../config/types.js";
|
||||||
|
|
||||||
|
export const MODELVERSE_BASE_URL = "https://api.modelverse.cn/v1";
|
||||||
|
export const MODELVERSE_DEFAULT_MODEL_ID = "gpt-5.2";
|
||||||
|
export const MODELVERSE_DEFAULT_MODEL_REF = `modelverse/${MODELVERSE_DEFAULT_MODEL_ID}`;
|
||||||
|
|
||||||
|
export const MODELVERSE_DEFAULT_COST = {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
cacheRead: 0,
|
||||||
|
cacheWrite: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Modelverse is an OpenAI-compatible proxy; metadata is best-effort and can be overridden via
|
||||||
|
// models.providers.modelverse.models in config.
|
||||||
|
const DEFAULT_CONTEXT_WINDOW = 200_000;
|
||||||
|
const DEFAULT_MAX_TOKENS = 8192;
|
||||||
|
|
||||||
|
export const MODELVERSE_MODEL_CATALOG = [
|
||||||
|
{
|
||||||
|
id: MODELVERSE_DEFAULT_MODEL_ID,
|
||||||
|
name: "GPT-5.2",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "claude-opus-4-5-20251101",
|
||||||
|
name: "Claude Opus 4.5 (20251101)",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "claude-sonnet-4-5-20250929",
|
||||||
|
name: "Claude Sonnet 4.5 (20250929)",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "deepseek-ai/DeepSeek-V3.2",
|
||||||
|
name: "DeepSeek V3.2",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "deepseek-ai/DeepSeek-R1",
|
||||||
|
name: "DeepSeek R1",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "deepseek-ai/DeepSeek-V3-0324",
|
||||||
|
name: "DeepSeek V3 0324",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "openai/gpt-4o",
|
||||||
|
name: "GPT-4o",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "zai-org/glm-4.7",
|
||||||
|
name: "GLM-4.7",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "gemini-3-flash-preview",
|
||||||
|
name: "Gemini 3 Flash Preview",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "gemini-3-pro-preview",
|
||||||
|
name: "Gemini 3 Pro Preview",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "gemini-2.5-flash",
|
||||||
|
name: "Gemini 2.5 Flash",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: "gemini-2.5-pro",
|
||||||
|
name: "Gemini 2.5 Pro",
|
||||||
|
reasoning: false,
|
||||||
|
input: ["text"],
|
||||||
|
contextWindow: DEFAULT_CONTEXT_WINDOW,
|
||||||
|
maxTokens: DEFAULT_MAX_TOKENS,
|
||||||
|
},
|
||||||
|
] as const;
|
||||||
|
|
||||||
|
export type ModelverseCatalogEntry = (typeof MODELVERSE_MODEL_CATALOG)[number];
|
||||||
|
|
||||||
|
export function buildModelverseModelDefinition(
|
||||||
|
entry: ModelverseCatalogEntry,
|
||||||
|
): ModelDefinitionConfig {
|
||||||
|
return {
|
||||||
|
id: entry.id,
|
||||||
|
name: entry.name,
|
||||||
|
reasoning: entry.reasoning,
|
||||||
|
input: [...entry.input],
|
||||||
|
cost: MODELVERSE_DEFAULT_COST,
|
||||||
|
contextWindow: entry.contextWindow,
|
||||||
|
maxTokens: entry.maxTokens,
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -52,7 +52,7 @@ export function registerOnboardCommand(program: Command) {
|
|||||||
.option("--mode <mode>", "Wizard mode: local|remote")
|
.option("--mode <mode>", "Wizard mode: local|remote")
|
||||||
.option(
|
.option(
|
||||||
"--auth-choice <choice>",
|
"--auth-choice <choice>",
|
||||||
"Auth: setup-token|token|chutes|openai-codex|openai-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip",
|
"Auth: setup-token|token|chutes|openai-codex|openai-api-key|modelverse-api-key|openrouter-api-key|ai-gateway-api-key|moonshot-api-key|kimi-code-api-key|synthetic-api-key|venice-api-key|gemini-api-key|zai-api-key|apiKey|minimax-api|minimax-api-lightning|opencode-zen|skip",
|
||||||
)
|
)
|
||||||
.option(
|
.option(
|
||||||
"--token-provider <id>",
|
"--token-provider <id>",
|
||||||
@ -66,6 +66,7 @@ export function registerOnboardCommand(program: Command) {
|
|||||||
.option("--token-expires-in <duration>", "Optional token expiry duration (e.g. 365d, 12h)")
|
.option("--token-expires-in <duration>", "Optional token expiry duration (e.g. 365d, 12h)")
|
||||||
.option("--anthropic-api-key <key>", "Anthropic API key")
|
.option("--anthropic-api-key <key>", "Anthropic API key")
|
||||||
.option("--openai-api-key <key>", "OpenAI API key")
|
.option("--openai-api-key <key>", "OpenAI API key")
|
||||||
|
.option("--modelverse-api-key <key>", "Modelverse API key")
|
||||||
.option("--openrouter-api-key <key>", "OpenRouter API key")
|
.option("--openrouter-api-key <key>", "OpenRouter API key")
|
||||||
.option("--ai-gateway-api-key <key>", "Vercel AI Gateway API key")
|
.option("--ai-gateway-api-key <key>", "Vercel AI Gateway API key")
|
||||||
.option("--moonshot-api-key <key>", "Moonshot API key")
|
.option("--moonshot-api-key <key>", "Moonshot API key")
|
||||||
@ -116,6 +117,7 @@ export function registerOnboardCommand(program: Command) {
|
|||||||
tokenExpiresIn: opts.tokenExpiresIn as string | undefined,
|
tokenExpiresIn: opts.tokenExpiresIn as string | undefined,
|
||||||
anthropicApiKey: opts.anthropicApiKey as string | undefined,
|
anthropicApiKey: opts.anthropicApiKey as string | undefined,
|
||||||
openaiApiKey: opts.openaiApiKey as string | undefined,
|
openaiApiKey: opts.openaiApiKey as string | undefined,
|
||||||
|
modelverseApiKey: opts.modelverseApiKey as string | undefined,
|
||||||
openrouterApiKey: opts.openrouterApiKey as string | undefined,
|
openrouterApiKey: opts.openrouterApiKey as string | undefined,
|
||||||
aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined,
|
aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined,
|
||||||
moonshotApiKey: opts.moonshotApiKey as string | undefined,
|
moonshotApiKey: opts.moonshotApiKey as string | undefined,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ export type AuthChoiceOption = {
|
|||||||
|
|
||||||
export type AuthChoiceGroupId =
|
export type AuthChoiceGroupId =
|
||||||
| "openai"
|
| "openai"
|
||||||
|
| "modelverse"
|
||||||
| "anthropic"
|
| "anthropic"
|
||||||
| "google"
|
| "google"
|
||||||
| "copilot"
|
| "copilot"
|
||||||
@ -41,6 +42,12 @@ const AUTH_CHOICE_GROUP_DEFS: {
|
|||||||
hint: "Codex OAuth + API key",
|
hint: "Codex OAuth + API key",
|
||||||
choices: ["openai-codex", "openai-api-key"],
|
choices: ["openai-codex", "openai-api-key"],
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
value: "modelverse",
|
||||||
|
label: "Modelverse",
|
||||||
|
hint: "MODELVERSE-API-KEY",
|
||||||
|
choices: ["modelverse-api-key"],
|
||||||
|
},
|
||||||
{
|
{
|
||||||
value: "anthropic",
|
value: "anthropic",
|
||||||
label: "Anthropic",
|
label: "Anthropic",
|
||||||
@ -134,6 +141,11 @@ export function buildAuthChoiceOptions(params: {
|
|||||||
});
|
});
|
||||||
options.push({ value: "chutes", label: "Chutes (OAuth)" });
|
options.push({ value: "chutes", label: "Chutes (OAuth)" });
|
||||||
options.push({ value: "openai-api-key", label: "OpenAI API key" });
|
options.push({ value: "openai-api-key", label: "OpenAI API key" });
|
||||||
|
options.push({
|
||||||
|
value: "modelverse-api-key",
|
||||||
|
label: "Modelverse API key",
|
||||||
|
hint: "OpenAI-compatible proxy (api.modelverse.cn)",
|
||||||
|
});
|
||||||
options.push({ value: "openrouter-api-key", label: "OpenRouter API key" });
|
options.push({ value: "openrouter-api-key", label: "OpenRouter API key" });
|
||||||
options.push({
|
options.push({
|
||||||
value: "ai-gateway-api-key",
|
value: "ai-gateway-api-key",
|
||||||
|
|||||||
@ -15,6 +15,8 @@ import {
|
|||||||
applyAuthProfileConfig,
|
applyAuthProfileConfig,
|
||||||
applyKimiCodeConfig,
|
applyKimiCodeConfig,
|
||||||
applyKimiCodeProviderConfig,
|
applyKimiCodeProviderConfig,
|
||||||
|
applyModelverseConfig,
|
||||||
|
applyModelverseProviderConfig,
|
||||||
applyMoonshotConfig,
|
applyMoonshotConfig,
|
||||||
applyMoonshotProviderConfig,
|
applyMoonshotProviderConfig,
|
||||||
applyOpencodeZenConfig,
|
applyOpencodeZenConfig,
|
||||||
@ -29,6 +31,7 @@ import {
|
|||||||
applyVercelAiGatewayProviderConfig,
|
applyVercelAiGatewayProviderConfig,
|
||||||
applyZaiConfig,
|
applyZaiConfig,
|
||||||
KIMI_CODE_MODEL_REF,
|
KIMI_CODE_MODEL_REF,
|
||||||
|
MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
MOONSHOT_DEFAULT_MODEL_REF,
|
MOONSHOT_DEFAULT_MODEL_REF,
|
||||||
OPENROUTER_DEFAULT_MODEL_REF,
|
OPENROUTER_DEFAULT_MODEL_REF,
|
||||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||||
@ -36,6 +39,7 @@ import {
|
|||||||
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
|
||||||
setGeminiApiKey,
|
setGeminiApiKey,
|
||||||
setKimiCodeApiKey,
|
setKimiCodeApiKey,
|
||||||
|
setModelverseApiKey,
|
||||||
setMoonshotApiKey,
|
setMoonshotApiKey,
|
||||||
setOpencodeZenApiKey,
|
setOpencodeZenApiKey,
|
||||||
setOpenrouterApiKey,
|
setOpenrouterApiKey,
|
||||||
@ -69,6 +73,8 @@ export async function applyAuthChoiceApiProviders(
|
|||||||
) {
|
) {
|
||||||
if (params.opts.tokenProvider === "openrouter") {
|
if (params.opts.tokenProvider === "openrouter") {
|
||||||
authChoice = "openrouter-api-key";
|
authChoice = "openrouter-api-key";
|
||||||
|
} else if (params.opts.tokenProvider === "modelverse") {
|
||||||
|
authChoice = "modelverse-api-key";
|
||||||
} else if (params.opts.tokenProvider === "vercel-ai-gateway") {
|
} else if (params.opts.tokenProvider === "vercel-ai-gateway") {
|
||||||
authChoice = "ai-gateway-api-key";
|
authChoice = "ai-gateway-api-key";
|
||||||
} else if (params.opts.tokenProvider === "moonshot") {
|
} else if (params.opts.tokenProvider === "moonshot") {
|
||||||
@ -166,6 +172,65 @@ export async function applyAuthChoiceApiProviders(
|
|||||||
return { config: nextConfig, agentModelOverride };
|
return { config: nextConfig, agentModelOverride };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (authChoice === "modelverse-api-key") {
|
||||||
|
let hasCredential = false;
|
||||||
|
|
||||||
|
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "modelverse") {
|
||||||
|
await setModelverseApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
|
||||||
|
hasCredential = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasCredential) {
|
||||||
|
await params.prompter.note(
|
||||||
|
[
|
||||||
|
"Modelverse provides an OpenAI-compatible API for multiple model families.",
|
||||||
|
"Get your API key at: https://console.ucloud-global.com/modelverse/experience/api-keys",
|
||||||
|
].join("\n"),
|
||||||
|
"Modelverse",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const envKey = resolveEnvApiKey("modelverse");
|
||||||
|
if (envKey) {
|
||||||
|
const useExisting = await params.prompter.confirm({
|
||||||
|
message: `Use existing MODELVERSE_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
|
||||||
|
initialValue: true,
|
||||||
|
});
|
||||||
|
if (useExisting) {
|
||||||
|
await setModelverseApiKey(envKey.apiKey, params.agentDir);
|
||||||
|
hasCredential = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hasCredential) {
|
||||||
|
const key = await params.prompter.text({
|
||||||
|
message: "Enter Modelverse API key",
|
||||||
|
validate: validateApiKeyInput,
|
||||||
|
});
|
||||||
|
await setModelverseApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||||
|
profileId: "modelverse:default",
|
||||||
|
provider: "modelverse",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
|
{
|
||||||
|
const applied = await applyDefaultModelChoice({
|
||||||
|
config: nextConfig,
|
||||||
|
setDefaultModel: params.setDefaultModel,
|
||||||
|
defaultModel: MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
|
applyDefaultConfig: applyModelverseConfig,
|
||||||
|
applyProviderConfig: applyModelverseProviderConfig,
|
||||||
|
noteDefault: MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
|
noteAgentModel,
|
||||||
|
prompter: params.prompter,
|
||||||
|
});
|
||||||
|
nextConfig = applied.config;
|
||||||
|
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
|
||||||
|
}
|
||||||
|
return { config: nextConfig, agentModelOverride };
|
||||||
|
}
|
||||||
|
|
||||||
if (authChoice === "ai-gateway-api-key") {
|
if (authChoice === "ai-gateway-api-key") {
|
||||||
let hasCredential = false;
|
let hasCredential = false;
|
||||||
|
|
||||||
|
|||||||
@ -10,6 +10,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
|
|||||||
"codex-cli": "openai-codex",
|
"codex-cli": "openai-codex",
|
||||||
chutes: "chutes",
|
chutes: "chutes",
|
||||||
"openai-api-key": "openai",
|
"openai-api-key": "openai",
|
||||||
|
"modelverse-api-key": "modelverse",
|
||||||
"openrouter-api-key": "openrouter",
|
"openrouter-api-key": "openrouter",
|
||||||
"ai-gateway-api-key": "vercel-ai-gateway",
|
"ai-gateway-api-key": "vercel-ai-gateway",
|
||||||
"moonshot-api-key": "moonshot",
|
"moonshot-api-key": "moonshot",
|
||||||
|
|||||||
@ -31,6 +31,7 @@ describe("applyAuthChoice", () => {
|
|||||||
const previousStateDir = process.env.CLAWDBOT_STATE_DIR;
|
const previousStateDir = process.env.CLAWDBOT_STATE_DIR;
|
||||||
const previousAgentDir = process.env.CLAWDBOT_AGENT_DIR;
|
const previousAgentDir = process.env.CLAWDBOT_AGENT_DIR;
|
||||||
const previousPiAgentDir = process.env.PI_CODING_AGENT_DIR;
|
const previousPiAgentDir = process.env.PI_CODING_AGENT_DIR;
|
||||||
|
const previousModelverseKey = process.env.MODELVERSE_API_KEY;
|
||||||
const previousOpenrouterKey = process.env.OPENROUTER_API_KEY;
|
const previousOpenrouterKey = process.env.OPENROUTER_API_KEY;
|
||||||
const previousAiGatewayKey = process.env.AI_GATEWAY_API_KEY;
|
const previousAiGatewayKey = process.env.AI_GATEWAY_API_KEY;
|
||||||
const previousSshTty = process.env.SSH_TTY;
|
const previousSshTty = process.env.SSH_TTY;
|
||||||
@ -59,6 +60,11 @@ describe("applyAuthChoice", () => {
|
|||||||
} else {
|
} else {
|
||||||
process.env.PI_CODING_AGENT_DIR = previousPiAgentDir;
|
process.env.PI_CODING_AGENT_DIR = previousPiAgentDir;
|
||||||
}
|
}
|
||||||
|
if (previousModelverseKey === undefined) {
|
||||||
|
delete process.env.MODELVERSE_API_KEY;
|
||||||
|
} else {
|
||||||
|
process.env.MODELVERSE_API_KEY = previousModelverseKey;
|
||||||
|
}
|
||||||
if (previousOpenrouterKey === undefined) {
|
if (previousOpenrouterKey === undefined) {
|
||||||
delete process.env.OPENROUTER_API_KEY;
|
delete process.env.OPENROUTER_API_KEY;
|
||||||
} else {
|
} else {
|
||||||
@ -187,6 +193,64 @@ describe("applyAuthChoice", () => {
|
|||||||
expect(parsed.profiles?.["synthetic:default"]?.key).toBe("sk-synthetic-test");
|
expect(parsed.profiles?.["synthetic:default"]?.key).toBe("sk-synthetic-test");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("prompts and writes Modelverse API key when selecting modelverse-api-key", async () => {
|
||||||
|
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "clawdbot-auth-"));
|
||||||
|
process.env.CLAWDBOT_STATE_DIR = tempStateDir;
|
||||||
|
process.env.CLAWDBOT_AGENT_DIR = path.join(tempStateDir, "agent");
|
||||||
|
process.env.PI_CODING_AGENT_DIR = process.env.CLAWDBOT_AGENT_DIR;
|
||||||
|
|
||||||
|
const text = vi.fn().mockResolvedValue("sk-modelverse-test");
|
||||||
|
const select: WizardPrompter["select"] = vi.fn(
|
||||||
|
async (params) => params.options[0]?.value as never,
|
||||||
|
);
|
||||||
|
const multiselect: WizardPrompter["multiselect"] = vi.fn(async () => []);
|
||||||
|
const prompter: WizardPrompter = {
|
||||||
|
intro: vi.fn(noopAsync),
|
||||||
|
outro: vi.fn(noopAsync),
|
||||||
|
note: vi.fn(noopAsync),
|
||||||
|
select,
|
||||||
|
multiselect,
|
||||||
|
text,
|
||||||
|
confirm: vi.fn(async () => false),
|
||||||
|
progress: vi.fn(() => ({ update: noop, stop: noop })),
|
||||||
|
};
|
||||||
|
const runtime: RuntimeEnv = {
|
||||||
|
log: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
exit: vi.fn((code: number) => {
|
||||||
|
throw new Error(`exit:${code}`);
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = await applyAuthChoice({
|
||||||
|
authChoice: "modelverse-api-key",
|
||||||
|
config: {},
|
||||||
|
prompter,
|
||||||
|
runtime,
|
||||||
|
setDefaultModel: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(text).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ message: "Enter Modelverse API key" }),
|
||||||
|
);
|
||||||
|
expect(result.config.auth?.profiles?.["modelverse:default"]).toMatchObject({
|
||||||
|
provider: "modelverse",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
|
expect(result.config.agents?.defaults?.model?.primary).toBe("modelverse/gpt-5.2");
|
||||||
|
expect(result.config.models?.providers?.modelverse).toMatchObject({
|
||||||
|
baseUrl: "https://api.modelverse.cn/v1",
|
||||||
|
api: "openai-completions",
|
||||||
|
});
|
||||||
|
|
||||||
|
const authProfilePath = authProfilePathFor(requireAgentDir());
|
||||||
|
const raw = await fs.readFile(authProfilePath, "utf8");
|
||||||
|
const parsed = JSON.parse(raw) as {
|
||||||
|
profiles?: Record<string, { key?: string }>;
|
||||||
|
};
|
||||||
|
expect(parsed.profiles?.["modelverse:default"]?.key).toBe("sk-modelverse-test");
|
||||||
|
});
|
||||||
|
|
||||||
it("sets default model when selecting github-copilot", async () => {
|
it("sets default model when selecting github-copilot", async () => {
|
||||||
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-auth-"));
|
tempStateDir = await fs.mkdtemp(path.join(os.tmpdir(), "moltbot-auth-"));
|
||||||
process.env.CLAWDBOT_STATE_DIR = tempStateDir;
|
process.env.CLAWDBOT_STATE_DIR = tempStateDir;
|
||||||
@ -597,6 +661,10 @@ describe("resolvePreferredProviderForAuthChoice", () => {
|
|||||||
expect(resolvePreferredProviderForAuthChoice("qwen-portal")).toBe("qwen-portal");
|
expect(resolvePreferredProviderForAuthChoice("qwen-portal")).toBe("qwen-portal");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("maps modelverse-api-key to the provider", () => {
|
||||||
|
expect(resolvePreferredProviderForAuthChoice("modelverse-api-key")).toBe("modelverse");
|
||||||
|
});
|
||||||
|
|
||||||
it("returns undefined for unknown choices", () => {
|
it("returns undefined for unknown choices", () => {
|
||||||
expect(resolvePreferredProviderForAuthChoice("unknown" as AuthChoice)).toBeUndefined();
|
expect(resolvePreferredProviderForAuthChoice("unknown" as AuthChoice)).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,12 @@ import {
|
|||||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||||
SYNTHETIC_MODEL_CATALOG,
|
SYNTHETIC_MODEL_CATALOG,
|
||||||
} from "../agents/synthetic-models.js";
|
} from "../agents/synthetic-models.js";
|
||||||
|
import {
|
||||||
|
buildModelverseModelDefinition,
|
||||||
|
MODELVERSE_BASE_URL,
|
||||||
|
MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
|
MODELVERSE_MODEL_CATALOG,
|
||||||
|
} from "../agents/modelverse-models.js";
|
||||||
import {
|
import {
|
||||||
buildVeniceModelDefinition,
|
buildVeniceModelDefinition,
|
||||||
VENICE_BASE_URL,
|
VENICE_BASE_URL,
|
||||||
@ -202,6 +208,75 @@ export function applyMoonshotConfig(cfg: MoltbotConfig): MoltbotConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function applyModelverseProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
|
||||||
|
const models = { ...cfg.agents?.defaults?.models };
|
||||||
|
models[MODELVERSE_DEFAULT_MODEL_REF] = {
|
||||||
|
...models[MODELVERSE_DEFAULT_MODEL_REF],
|
||||||
|
alias: models[MODELVERSE_DEFAULT_MODEL_REF]?.alias ?? "Modelverse",
|
||||||
|
};
|
||||||
|
|
||||||
|
const providers = { ...cfg.models?.providers };
|
||||||
|
const existingProvider = providers.modelverse;
|
||||||
|
const existingModels = Array.isArray(existingProvider?.models) ? existingProvider.models : [];
|
||||||
|
const modelverseModels = MODELVERSE_MODEL_CATALOG.map(buildModelverseModelDefinition);
|
||||||
|
const mergedModels = [
|
||||||
|
...existingModels,
|
||||||
|
...modelverseModels.filter(
|
||||||
|
(model) => !existingModels.some((existing) => existing.id === model.id),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record<
|
||||||
|
string,
|
||||||
|
unknown
|
||||||
|
> as { apiKey?: string };
|
||||||
|
const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined;
|
||||||
|
const normalizedApiKey = resolvedApiKey?.trim();
|
||||||
|
providers.modelverse = {
|
||||||
|
...existingProviderRest,
|
||||||
|
baseUrl: MODELVERSE_BASE_URL,
|
||||||
|
api: "openai-completions",
|
||||||
|
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
|
||||||
|
models: mergedModels.length > 0 ? mergedModels : modelverseModels,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
...cfg,
|
||||||
|
agents: {
|
||||||
|
...cfg.agents,
|
||||||
|
defaults: {
|
||||||
|
...cfg.agents?.defaults,
|
||||||
|
models,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
models: {
|
||||||
|
mode: cfg.models?.mode ?? "merge",
|
||||||
|
providers,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function applyModelverseConfig(cfg: MoltbotConfig): MoltbotConfig {
|
||||||
|
const next = applyModelverseProviderConfig(cfg);
|
||||||
|
const existingModel = next.agents?.defaults?.model;
|
||||||
|
return {
|
||||||
|
...next,
|
||||||
|
agents: {
|
||||||
|
...next.agents,
|
||||||
|
defaults: {
|
||||||
|
...next.agents?.defaults,
|
||||||
|
model: {
|
||||||
|
...(existingModel && "fallbacks" in (existingModel as Record<string, unknown>)
|
||||||
|
? {
|
||||||
|
fallbacks: (existingModel as { fallbacks?: string[] }).fallbacks,
|
||||||
|
}
|
||||||
|
: undefined),
|
||||||
|
primary: MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
export function applyKimiCodeProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
|
export function applyKimiCodeProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
|
||||||
const models = { ...cfg.agents?.defaults?.models };
|
const models = { ...cfg.agents?.defaults?.models };
|
||||||
models[KIMI_CODE_MODEL_REF] = {
|
models[KIMI_CODE_MODEL_REF] = {
|
||||||
|
|||||||
@ -73,6 +73,19 @@ export async function setMoonshotApiKey(key: string, agentDir?: string) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function setModelverseApiKey(key: string, agentDir?: string) {
|
||||||
|
// Write to resolved agent dir so gateway finds credentials on startup.
|
||||||
|
upsertAuthProfile({
|
||||||
|
profileId: "modelverse:default",
|
||||||
|
credential: {
|
||||||
|
type: "api_key",
|
||||||
|
provider: "modelverse",
|
||||||
|
key,
|
||||||
|
},
|
||||||
|
agentDir: resolveAuthAgentDir(agentDir),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
export async function setKimiCodeApiKey(key: string, agentDir?: string) {
|
export async function setKimiCodeApiKey(key: string, agentDir?: string) {
|
||||||
// Write to resolved agent dir so gateway finds credentials on startup.
|
// Write to resolved agent dir so gateway finds credentials on startup.
|
||||||
upsertAuthProfile({
|
upsertAuthProfile({
|
||||||
|
|||||||
@ -3,10 +3,16 @@ export {
|
|||||||
SYNTHETIC_DEFAULT_MODEL_REF,
|
SYNTHETIC_DEFAULT_MODEL_REF,
|
||||||
} from "../agents/synthetic-models.js";
|
} from "../agents/synthetic-models.js";
|
||||||
export { VENICE_DEFAULT_MODEL_ID, VENICE_DEFAULT_MODEL_REF } from "../agents/venice-models.js";
|
export { VENICE_DEFAULT_MODEL_ID, VENICE_DEFAULT_MODEL_REF } from "../agents/venice-models.js";
|
||||||
|
export {
|
||||||
|
MODELVERSE_DEFAULT_MODEL_ID,
|
||||||
|
MODELVERSE_DEFAULT_MODEL_REF,
|
||||||
|
} from "../agents/modelverse-models.js";
|
||||||
export {
|
export {
|
||||||
applyAuthProfileConfig,
|
applyAuthProfileConfig,
|
||||||
applyKimiCodeConfig,
|
applyKimiCodeConfig,
|
||||||
applyKimiCodeProviderConfig,
|
applyKimiCodeProviderConfig,
|
||||||
|
applyModelverseConfig,
|
||||||
|
applyModelverseProviderConfig,
|
||||||
applyMoonshotConfig,
|
applyMoonshotConfig,
|
||||||
applyMoonshotProviderConfig,
|
applyMoonshotProviderConfig,
|
||||||
applyOpenrouterConfig,
|
applyOpenrouterConfig,
|
||||||
@ -37,6 +43,7 @@ export {
|
|||||||
setAnthropicApiKey,
|
setAnthropicApiKey,
|
||||||
setGeminiApiKey,
|
setGeminiApiKey,
|
||||||
setKimiCodeApiKey,
|
setKimiCodeApiKey,
|
||||||
|
setModelverseApiKey,
|
||||||
setMinimaxApiKey,
|
setMinimaxApiKey,
|
||||||
setMoonshotApiKey,
|
setMoonshotApiKey,
|
||||||
setOpencodeZenApiKey,
|
setOpencodeZenApiKey,
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import {
|
|||||||
applyKimiCodeConfig,
|
applyKimiCodeConfig,
|
||||||
applyMinimaxApiConfig,
|
applyMinimaxApiConfig,
|
||||||
applyMinimaxConfig,
|
applyMinimaxConfig,
|
||||||
|
applyModelverseConfig,
|
||||||
applyMoonshotConfig,
|
applyMoonshotConfig,
|
||||||
applyOpencodeZenConfig,
|
applyOpencodeZenConfig,
|
||||||
applyOpenrouterConfig,
|
applyOpenrouterConfig,
|
||||||
@ -21,6 +22,7 @@ import {
|
|||||||
setAnthropicApiKey,
|
setAnthropicApiKey,
|
||||||
setGeminiApiKey,
|
setGeminiApiKey,
|
||||||
setKimiCodeApiKey,
|
setKimiCodeApiKey,
|
||||||
|
setModelverseApiKey,
|
||||||
setMinimaxApiKey,
|
setMinimaxApiKey,
|
||||||
setMoonshotApiKey,
|
setMoonshotApiKey,
|
||||||
setOpencodeZenApiKey,
|
setOpencodeZenApiKey,
|
||||||
@ -195,6 +197,25 @@ export async function applyNonInteractiveAuthChoice(params: {
|
|||||||
return nextConfig;
|
return nextConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (authChoice === "modelverse-api-key") {
|
||||||
|
const resolved = await resolveNonInteractiveApiKey({
|
||||||
|
provider: "modelverse",
|
||||||
|
cfg: baseConfig,
|
||||||
|
flagValue: opts.modelverseApiKey,
|
||||||
|
flagName: "--modelverse-api-key",
|
||||||
|
envVar: "MODELVERSE_API_KEY",
|
||||||
|
runtime,
|
||||||
|
});
|
||||||
|
if (!resolved) return null;
|
||||||
|
if (resolved.source !== "profile") await setModelverseApiKey(resolved.key);
|
||||||
|
nextConfig = applyAuthProfileConfig(nextConfig, {
|
||||||
|
profileId: "modelverse:default",
|
||||||
|
provider: "modelverse",
|
||||||
|
mode: "api_key",
|
||||||
|
});
|
||||||
|
return applyModelverseConfig(nextConfig);
|
||||||
|
}
|
||||||
|
|
||||||
if (authChoice === "openrouter-api-key") {
|
if (authChoice === "openrouter-api-key") {
|
||||||
const resolved = await resolveNonInteractiveApiKey({
|
const resolved = await resolveNonInteractiveApiKey({
|
||||||
provider: "openrouter",
|
provider: "openrouter",
|
||||||
|
|||||||
@ -11,6 +11,7 @@ export type AuthChoice =
|
|||||||
| "chutes"
|
| "chutes"
|
||||||
| "openai-codex"
|
| "openai-codex"
|
||||||
| "openai-api-key"
|
| "openai-api-key"
|
||||||
|
| "modelverse-api-key"
|
||||||
| "openrouter-api-key"
|
| "openrouter-api-key"
|
||||||
| "ai-gateway-api-key"
|
| "ai-gateway-api-key"
|
||||||
| "moonshot-api-key"
|
| "moonshot-api-key"
|
||||||
@ -61,6 +62,7 @@ export type OnboardOptions = {
|
|||||||
tokenExpiresIn?: string;
|
tokenExpiresIn?: string;
|
||||||
anthropicApiKey?: string;
|
anthropicApiKey?: string;
|
||||||
openaiApiKey?: string;
|
openaiApiKey?: string;
|
||||||
|
modelverseApiKey?: string;
|
||||||
openrouterApiKey?: string;
|
openrouterApiKey?: string;
|
||||||
aiGatewayApiKey?: string;
|
aiGatewayApiKey?: string;
|
||||||
moonshotApiKey?: string;
|
moonshotApiKey?: string;
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user