Merge pull request #1 from tududes/main

Model Providers: add Chutes AI as a provider (#2404)
This commit is contained in:
V 2026-01-28 12:26:48 -05:00 committed by GitHub
commit 78c56516d6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 446 additions and 3 deletions

View File

@ -6,6 +6,7 @@ Docs: https://docs.molt.bot
Status: beta.
### Changes
- Model Providers: add Chutes AI as a provider with dynamic model discovery and TEE support. (#2404)
- Rebrand: rename the npm package/CLI to `moltbot`, add a `moltbot` compatibility shim, and move extensions to the `@moltbot/*` scope.
- Commands: group /help and /commands output with Telegram paging. (#2504) Thanks @hougangdev.
- macOS: limit project-local `node_modules/.bin` PATH preference to debug builds (reduce PATH hijacking risk).

81
docs/providers/chutes.md Normal file
View File

@ -0,0 +1,81 @@
---
summary: "Use Chutes AI with Moltbot"
read_when:
- You want to use Chutes AI models in Moltbot
- You need to configure Chutes via OAuth or API key
---
# Chutes AI
Chutes provides high-performance inference for open-weight models, including GLM 4.7 Flash. Moltbot supports Chutes via both OAuth and API key authentication.
Models are fetched dynamically from the Chutes API, ensuring you always have access to the latest models, accurate pricing, and context window limits.
## CLI setup
To configure Chutes with an API key:
```bash
moltbot onboard --auth-choice chutes-api-key
# or non-interactive
moltbot onboard --chutes-api-key "$CHUTES_API_KEY"
```
To configure Chutes with OAuth (browser-based):
```bash
moltbot onboard --auth-choice chutes
```
OAuth allows you to use your Chutes account without manually managing API keys. Moltbot uses the standard [Sign in with Chutes](https://github.com/chutesai/Sign-in-with-Chutes) flow.
### OAuth Scopes
Moltbot requests the following scopes by default:
- `openid` (Required for authentication)
- `profile` (Access to username)
- `chutes:invoke` (Required to make AI API calls on your behalf)
### Custom OAuth App (Advanced)
If you wish to use your own OAuth application instead of the default, set these environment variables before running onboarding:
- `CHUTES_CLIENT_ID`: Your OAuth client ID
- `CHUTES_CLIENT_SECRET`: Your OAuth client secret (if applicable)
- `CHUTES_OAUTH_REDIRECT_URI`: Your redirect URI (default: `http://127.0.0.1:1456/oauth-callback`)
## Config snippet
```json5
{
env: { CHUTES_API_KEY: "sk-..." },
agents: { defaults: { model: { primary: "chutes/zai-org/GLM-4.7-Flash" } } },
models: {
providers: {
chutes: {
baseUrl: "https://llm.chutes.ai/v1",
api: "openai-completions",
apiKey: "${CHUTES_API_KEY}",
teeOnly: false // Set to true to filter models by Trusted Execution Environment
}
}
}
}
```
## Notes
- Chutes models are available under the `chutes/` provider prefix.
- The default model is `chutes/zai-org/GLM-4.7-Flash`.
- Chutes uses OpenAI-compatible endpoints.
- **Trusted Execution Environment (TEE)**: Models running in a TEE are marked with a "TEE" badge in the model picker. You can filter for these models by setting `teeOnly: true` in your provider config.
- Many top models on Chutes support tool calling, including:
- `Qwen/Qwen3-235B-A22B-Instruct-2507-TEE` (TEE)
- `deepseek-ai/DeepSeek-V3.2-TEE` (TEE)
- `chutesai/Mistral-Small-3.1-24B-Instruct-2503`
- `NousResearch/Hermes-4-14B`
- For a full list of available models, see the [Chutes Models API](https://llm.chutes.ai/v1/models). Popular models include:
- `deepseek-ai/DeepSeek-V3.2-TEE`
- `Qwen/Qwen3-235B-A22B-Instruct-2507-TEE`
- `mistralai/Mistral-Small-24B-Instruct-2501-TEE`
- `NousResearch/Hermes-4-14B`

View File

@ -41,7 +41,8 @@ See [Venice AI](/providers/venice).
- [Moonshot AI (Kimi + Kimi Code)](/providers/moonshot)
- [OpenCode Zen](/providers/opencode)
- [Amazon Bedrock](/bedrock)
- [Z.AI](/providers/zai)
|- [Z.AI](/providers/zai)
- [Chutes AI](/providers/chutes)
- [GLM models](/providers/glm)
- [MiniMax](/providers/minimax)
- [Venius (Venice AI, privacy-focused)](/providers/venice)

View File

@ -0,0 +1,87 @@
import type { ModelDefinitionConfig } from "../config/types.models.js";
import {
CHUTES_BASE_URL,
CHUTES_DEFAULT_MODEL_ID,
CHUTES_DEFAULT_MODEL_REF,
} from "../commands/onboard-auth.models.js";
export { CHUTES_BASE_URL, CHUTES_DEFAULT_MODEL_ID, CHUTES_DEFAULT_MODEL_REF };
export interface ChutesModelEntry {
id: string;
name?: string;
context_length?: number;
max_output_length?: number;
confidential_compute?: boolean;
pricing?: { prompt: number; completion: number };
supported_features?: string[];
}
export async function fetchChutesModels(): Promise<ChutesModelEntry[]> {
// Skip dynamic fetching in test environments to avoid network issues and timeouts
if (
process.env.VITEST ||
process.env.NODE_ENV === "test" ||
process.env.MOLTBOT_SKIP_DYNAMIC_MODELS === "1"
) {
return [];
}
try {
const response = await fetch(`${CHUTES_BASE_URL}/models`, {
signal: AbortSignal.timeout(5000),
});
if (!response.ok) {
throw new Error(`Failed to fetch Chutes models: ${response.statusText}`);
}
const data = (await response.json()) as { data: ChutesModelEntry[] };
return data.data || [];
} catch (error) {
console.warn(`[chutes-models] Failed to fetch models: ${String(error)}`);
return [];
}
}
export function mapChutesModelToDefinition(entry: ChutesModelEntry): ModelDefinitionConfig {
return {
id: entry.id,
name: entry.name || entry.id,
reasoning: entry.supported_features?.includes("reasoning") ?? false,
input: ["text"],
cost: {
input: entry.pricing?.prompt ?? 0,
output: entry.pricing?.completion ?? 0,
cacheRead: 0,
cacheWrite: 0,
},
contextWindow: entry.context_length || 128000,
maxTokens: entry.max_output_length || 4096,
confidentialCompute: entry.confidential_compute,
};
}
export async function discoverChutesModels(opts?: {
teeOnly?: boolean;
}): Promise<ModelDefinitionConfig[]> {
const models = await fetchChutesModels();
if (models.length === 0) {
// Fallback to minimal list
return [
{
id: CHUTES_DEFAULT_MODEL_ID,
name: "GLM 4.7 Flash",
reasoning: false,
input: ["text"],
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
contextWindow: 128000,
maxTokens: 4096,
},
];
}
let filtered = models;
if (opts?.teeOnly) {
filtered = models.filter((m) => m.confidential_compute === true);
}
return filtered.map(mapChutesModelToDefinition);
}

View File

@ -283,6 +283,7 @@ export function resolveEnvApiKey(provider: string): EnvApiKeyResult | null {
minimax: "MINIMAX_API_KEY",
synthetic: "SYNTHETIC_API_KEY",
venice: "VENICE_API_KEY",
chutes: "CHUTES_API_KEY",
mistral: "MISTRAL_API_KEY",
opencode: "OPENCODE_API_KEY",
};

View File

@ -13,6 +13,7 @@ import {
SYNTHETIC_MODEL_CATALOG,
} from "./synthetic-models.js";
import { discoverVeniceModels, VENICE_BASE_URL } from "./venice-models.js";
import { discoverChutesModels, CHUTES_BASE_URL } from "./chutes-models.js";
type ModelsConfig = NonNullable<MoltbotConfig["models"]>;
export type ProviderConfig = NonNullable<ModelsConfig["providers"]>[string];
@ -350,6 +351,16 @@ async function buildVeniceProvider(): Promise<ProviderConfig> {
};
}
async function buildChutesProvider(opts?: { teeOnly?: boolean }): Promise<ProviderConfig> {
const models = await discoverChutesModels(opts);
return {
baseUrl: CHUTES_BASE_URL,
api: "openai-completions",
models,
teeOnly: opts?.teeOnly,
};
}
async function buildOllamaProvider(): Promise<ProviderConfig> {
const models = await discoverOllamaModels();
return {
@ -361,6 +372,7 @@ async function buildOllamaProvider(): Promise<ProviderConfig> {
export async function resolveImplicitProviders(params: {
agentDir: string;
config?: MoltbotConfig;
}): Promise<ModelsConfig["providers"]> {
const providers: Record<string, ProviderConfig> = {};
const authStore = ensureAuthProfileStore(params.agentDir, {
@ -402,6 +414,15 @@ export async function resolveImplicitProviders(params: {
providers.venice = { ...(await buildVeniceProvider()), apiKey: veniceKey };
}
const chutesKey =
resolveEnvApiKeyVarName("chutes") ??
resolveApiKeyFromProfiles({ provider: "chutes", store: authStore });
if (chutesKey) {
const chutesCfg = params.config?.models?.providers?.chutes;
const teeOnly = chutesCfg?.teeOnly === true;
providers.chutes = { ...(await buildChutesProvider({ teeOnly })), apiKey: chutesKey };
}
const qwenProfiles = listProfilesForProvider(authStore, "qwen-portal");
if (qwenProfiles.length > 0) {
providers["qwen-portal"] = {

View File

@ -80,7 +80,7 @@ export async function ensureMoltbotModelsJson(
const agentDir = agentDirOverride?.trim() ? agentDirOverride.trim() : resolveMoltbotAgentDir();
const explicitProviders = (cfg.models?.providers ?? {}) as Record<string, ProviderConfig>;
const implicitProviders = await resolveImplicitProviders({ agentDir });
const implicitProviders = await resolveImplicitProviders({ agentDir, config: cfg });
const providers: Record<string, ProviderConfig> = mergeProviders({
implicit: implicitProviders,
explicit: explicitProviders,

View File

@ -52,7 +52,7 @@ export function registerOnboardCommand(program: Command) {
.option("--mode <mode>", "Wizard mode: local|remote")
.option(
"--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|chutes-api-key|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",
)
.option(
"--token-provider <id>",
@ -69,6 +69,7 @@ export function registerOnboardCommand(program: Command) {
.option("--openrouter-api-key <key>", "OpenRouter API key")
.option("--ai-gateway-api-key <key>", "Vercel AI Gateway API key")
.option("--moonshot-api-key <key>", "Moonshot API key")
.option("--chutes-api-key <key>", "Chutes API key")
.option("--kimi-code-api-key <key>", "Kimi Code API key")
.option("--gemini-api-key <key>", "Gemini API key")
.option("--zai-api-key <key>", "Z.AI API key")
@ -119,6 +120,7 @@ export function registerOnboardCommand(program: Command) {
openrouterApiKey: opts.openrouterApiKey as string | undefined,
aiGatewayApiKey: opts.aiGatewayApiKey as string | undefined,
moonshotApiKey: opts.moonshotApiKey as string | undefined,
chutesApiKey: opts.chutesApiKey as string | undefined,
kimiCodeApiKey: opts.kimiCodeApiKey as string | undefined,
geminiApiKey: opts.geminiApiKey as string | undefined,
zaiApiKey: opts.zaiApiKey as string | undefined,

View File

@ -20,6 +20,7 @@ export type AuthChoiceGroupId =
| "minimax"
| "synthetic"
| "venice"
| "chutes"
| "qwen";
export type AuthChoiceGroup = {
@ -53,6 +54,12 @@ const AUTH_CHOICE_GROUP_DEFS: {
hint: "M2.1 (recommended)",
choices: ["minimax-api", "minimax-api-lightning"],
},
{
value: "chutes",
label: "Chutes AI",
hint: "OAuth + API key",
choices: ["chutes", "chutes-api-key"],
},
{
value: "qwen",
label: "Qwen",
@ -133,6 +140,7 @@ export function buildAuthChoiceOptions(params: {
label: "OpenAI Codex (ChatGPT OAuth)",
});
options.push({ value: "chutes", label: "Chutes (OAuth)" });
options.push({ value: "chutes-api-key", label: "Chutes API key" });
options.push({ value: "openai-api-key", label: "OpenAI API key" });
options.push({ value: "openrouter-api-key", label: "OpenRouter API key" });
options.push({

View File

@ -13,6 +13,8 @@ import {
} from "./google-gemini-model-default.js";
import {
applyAuthProfileConfig,
applyChutesConfig,
applyChutesProviderConfig,
applyKimiCodeConfig,
applyKimiCodeProviderConfig,
applyMoonshotConfig,
@ -28,12 +30,14 @@ import {
applyVercelAiGatewayConfig,
applyVercelAiGatewayProviderConfig,
applyZaiConfig,
CHUTES_DEFAULT_MODEL_REF,
KIMI_CODE_MODEL_REF,
MOONSHOT_DEFAULT_MODEL_REF,
OPENROUTER_DEFAULT_MODEL_REF,
SYNTHETIC_DEFAULT_MODEL_REF,
VENICE_DEFAULT_MODEL_REF,
VERCEL_AI_GATEWAY_DEFAULT_MODEL_REF,
setChutesApiKey,
setGeminiApiKey,
setKimiCodeApiKey,
setMoonshotApiKey,
@ -73,6 +77,8 @@ export async function applyAuthChoiceApiProviders(
authChoice = "ai-gateway-api-key";
} else if (params.opts.tokenProvider === "moonshot") {
authChoice = "moonshot-api-key";
} else if (params.opts.tokenProvider === "chutes") {
authChoice = "chutes-api-key";
} else if (params.opts.tokenProvider === "kimi-code") {
authChoice = "kimi-code-api-key";
} else if (params.opts.tokenProvider === "google") {
@ -265,6 +271,53 @@ export async function applyAuthChoiceApiProviders(
return { config: nextConfig, agentModelOverride };
}
if (authChoice === "chutes-api-key") {
let hasCredential = false;
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "chutes") {
await setChutesApiKey(normalizeApiKeyInput(params.opts.token), params.agentDir);
hasCredential = true;
}
const envKey = resolveEnvApiKey("chutes");
if (envKey) {
const useExisting = await params.prompter.confirm({
message: `Use existing CHUTES_API_KEY (${envKey.source}, ${formatApiKeyPreview(envKey.apiKey)})?`,
initialValue: true,
});
if (useExisting) {
await setChutesApiKey(envKey.apiKey, params.agentDir);
hasCredential = true;
}
}
if (!hasCredential) {
const key = await params.prompter.text({
message: "Enter Chutes API key",
validate: validateApiKeyInput,
});
await setChutesApiKey(normalizeApiKeyInput(String(key)), params.agentDir);
}
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "chutes:default",
provider: "chutes",
mode: "api_key",
});
{
const applied = await applyDefaultModelChoice({
config: nextConfig,
setDefaultModel: params.setDefaultModel,
defaultModel: CHUTES_DEFAULT_MODEL_REF,
applyDefaultConfig: applyChutesConfig,
applyProviderConfig: applyChutesProviderConfig,
noteAgentModel,
prompter: params.prompter,
});
nextConfig = applied.config;
agentModelOverride = applied.agentModelOverride ?? agentModelOverride;
}
return { config: nextConfig, agentModelOverride };
}
if (authChoice === "kimi-code-api-key") {
let hasCredential = false;
if (!hasCredential && params.opts?.token && params.opts?.tokenProvider === "kimi-code") {

View File

@ -13,6 +13,7 @@ const PREFERRED_PROVIDER_BY_AUTH_CHOICE: Partial<Record<AuthChoice, string>> = {
"openrouter-api-key": "openrouter",
"ai-gateway-api-key": "vercel-ai-gateway",
"moonshot-api-key": "moonshot",
"chutes-api-key": "chutes",
"kimi-code-api-key": "kimi-code",
"gemini-api-key": "google",
"google-antigravity": "google-antigravity",

View File

@ -25,6 +25,9 @@ import {
MOONSHOT_BASE_URL,
MOONSHOT_DEFAULT_MODEL_ID,
MOONSHOT_DEFAULT_MODEL_REF,
CHUTES_BASE_URL,
CHUTES_DEFAULT_MODEL_REF,
buildChutesModelDefinition,
} from "./onboard-auth.models.js";
export function applyZaiConfig(cfg: MoltbotConfig): MoltbotConfig {
@ -202,6 +205,70 @@ export function applyMoonshotConfig(cfg: MoltbotConfig): MoltbotConfig {
};
}
export function applyChutesProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
const models = { ...cfg.agents?.defaults?.models };
models[CHUTES_DEFAULT_MODEL_REF] = {
...models[CHUTES_DEFAULT_MODEL_REF],
alias: models[CHUTES_DEFAULT_MODEL_REF]?.alias ?? "GLM 4.7 Flash",
};
const providers = { ...cfg.models?.providers };
const existingProvider = providers.chutes;
const { apiKey: existingApiKey, ...existingProviderRest } = (existingProvider ?? {}) as Record<
string,
unknown
> as { apiKey?: string; teeOnly?: boolean };
const resolvedApiKey = typeof existingApiKey === "string" ? existingApiKey : undefined;
const normalizedApiKey = resolvedApiKey?.trim();
providers.chutes = {
...existingProviderRest,
baseUrl: CHUTES_BASE_URL,
api: "openai-completions",
...(normalizedApiKey ? { apiKey: normalizedApiKey } : {}),
// Models will be refreshed dynamically at startup,
// but we can pre-populate the default one for onboarding.
models: existingProvider?.models || [buildChutesModelDefinition()],
};
return {
...cfg,
agents: {
...cfg.agents,
defaults: {
...cfg.agents?.defaults,
models,
},
},
models: {
mode: cfg.models?.mode ?? "merge",
providers,
},
};
}
export function applyChutesConfig(cfg: MoltbotConfig): MoltbotConfig {
const next = applyChutesProviderConfig(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: CHUTES_DEFAULT_MODEL_REF,
},
},
},
};
}
export function applyKimiCodeProviderConfig(cfg: MoltbotConfig): MoltbotConfig {
const models = { ...cfg.agents?.defaults?.models };
models[KIMI_CODE_MODEL_REF] = {

View File

@ -73,6 +73,19 @@ export async function setMoonshotApiKey(key: string, agentDir?: string) {
});
}
export async function setChutesApiKey(key: string, agentDir?: string) {
// Write to resolved agent dir so gateway finds credentials on startup.
upsertAuthProfile({
profileId: "chutes:default",
credential: {
type: "api_key",
provider: "chutes",
key,
},
agentDir: resolveAuthAgentDir(agentDir),
});
}
export async function setKimiCodeApiKey(key: string, agentDir?: string) {
// Write to resolved agent dir so gateway finds credentials on startup.
upsertAuthProfile({

View File

@ -12,6 +12,13 @@ export const MOONSHOT_DEFAULT_MODEL_ID = "kimi-k2-0905-preview";
export const MOONSHOT_DEFAULT_MODEL_REF = `moonshot/${MOONSHOT_DEFAULT_MODEL_ID}`;
export const MOONSHOT_DEFAULT_CONTEXT_WINDOW = 256000;
export const MOONSHOT_DEFAULT_MAX_TOKENS = 8192;
export const CHUTES_BASE_URL = "https://llm.chutes.ai/v1";
export const CHUTES_DEFAULT_MODEL_ID = "zai-org/GLM-4.7-Flash";
export const CHUTES_DEFAULT_MODEL_REF = `chutes/${CHUTES_DEFAULT_MODEL_ID}`;
export const CHUTES_DEFAULT_CONTEXT_WINDOW = 128000;
export const CHUTES_DEFAULT_MAX_TOKENS = 4096;
export const KIMI_CODE_BASE_URL = "https://api.kimi.com/coding/v1";
export const KIMI_CODE_MODEL_ID = "kimi-for-coding";
export const KIMI_CODE_MODEL_REF = `kimi-code/${KIMI_CODE_MODEL_ID}`;
@ -45,6 +52,12 @@ export const MOONSHOT_DEFAULT_COST = {
cacheRead: 0,
cacheWrite: 0,
};
export const CHUTES_DEFAULT_COST = {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0,
};
export const KIMI_CODE_DEFAULT_COST = {
input: 0,
output: 0,
@ -103,6 +116,64 @@ export function buildMoonshotModelDefinition(): ModelDefinitionConfig {
};
}
export function buildChutesModelDefinition(
modelId: string = CHUTES_DEFAULT_MODEL_ID,
): ModelDefinitionConfig {
if (modelId === "Qwen/Qwen3-235B-A22B-Instruct-2507-TEE") {
return {
id: modelId,
name: "Qwen 3 235B (Tools)",
reasoning: false,
input: ["text"],
cost: CHUTES_DEFAULT_COST,
contextWindow: 262144,
maxTokens: 4096,
};
}
if (modelId === "deepseek-ai/DeepSeek-V3.2-TEE") {
return {
id: modelId,
name: "DeepSeek V3.2 (Tools)",
reasoning: false,
input: ["text"],
cost: CHUTES_DEFAULT_COST,
contextWindow: 202752,
maxTokens: 4096,
};
}
if (modelId === "chutesai/Mistral-Small-3.1-24B-Instruct-2503") {
return {
id: modelId,
name: "Mistral Small 3.1 (Tools)",
reasoning: false,
input: ["text"],
cost: CHUTES_DEFAULT_COST,
contextWindow: 131072,
maxTokens: 4096,
};
}
if (modelId === "NousResearch/Hermes-4-14B") {
return {
id: modelId,
name: "Hermes 4 14B (Tools)",
reasoning: false,
input: ["text"],
cost: CHUTES_DEFAULT_COST,
contextWindow: 40960,
maxTokens: 4096,
};
}
return {
id: CHUTES_DEFAULT_MODEL_ID,
name: "GLM 4.7 Flash",
reasoning: false,
input: ["text"],
cost: CHUTES_DEFAULT_COST,
contextWindow: CHUTES_DEFAULT_CONTEXT_WINDOW,
maxTokens: CHUTES_DEFAULT_MAX_TOKENS,
};
}
export function buildKimiCodeModelDefinition(): ModelDefinitionConfig {
return {
id: KIMI_CODE_MODEL_ID,

View File

@ -5,6 +5,8 @@ export {
export { VENICE_DEFAULT_MODEL_ID, VENICE_DEFAULT_MODEL_REF } from "../agents/venice-models.js";
export {
applyAuthProfileConfig,
applyChutesConfig,
applyChutesProviderConfig,
applyKimiCodeConfig,
applyKimiCodeProviderConfig,
applyMoonshotConfig,
@ -35,6 +37,7 @@ export {
export {
OPENROUTER_DEFAULT_MODEL_REF,
setAnthropicApiKey,
setChutesApiKey,
setGeminiApiKey,
setKimiCodeApiKey,
setMinimaxApiKey,
@ -50,10 +53,14 @@ export {
ZAI_DEFAULT_MODEL_REF,
} from "./onboard-auth.credentials.js";
export {
buildChutesModelDefinition,
buildKimiCodeModelDefinition,
buildMinimaxApiModelDefinition,
buildMinimaxModelDefinition,
buildMoonshotModelDefinition,
CHUTES_BASE_URL,
CHUTES_DEFAULT_MODEL_ID,
CHUTES_DEFAULT_MODEL_REF,
DEFAULT_MINIMAX_BASE_URL,
KIMI_CODE_BASE_URL,
KIMI_CODE_MODEL_ID,

View File

@ -8,6 +8,7 @@ import { buildTokenProfileId, validateAnthropicSetupToken } from "../../auth-tok
import { applyGoogleGeminiModelDefault } from "../../google-gemini-model-default.js";
import {
applyAuthProfileConfig,
applyChutesConfig,
applyKimiCodeConfig,
applyMinimaxApiConfig,
applyMinimaxConfig,
@ -19,6 +20,7 @@ import {
applyVercelAiGatewayConfig,
applyZaiConfig,
setAnthropicApiKey,
setChutesApiKey,
setGeminiApiKey,
setKimiCodeApiKey,
setMinimaxApiKey,
@ -252,6 +254,25 @@ export async function applyNonInteractiveAuthChoice(params: {
return applyMoonshotConfig(nextConfig);
}
if (authChoice === "chutes-api-key") {
const resolved = await resolveNonInteractiveApiKey({
provider: "chutes",
cfg: baseConfig,
flagValue: opts.chutesApiKey,
flagName: "--chutes-api-key",
envVar: "CHUTES_API_KEY",
runtime,
});
if (!resolved) return null;
if (resolved.source !== "profile") await setChutesApiKey(resolved.key);
nextConfig = applyAuthProfileConfig(nextConfig, {
profileId: "chutes:default",
provider: "chutes",
mode: "api_key",
});
return applyChutesConfig(nextConfig);
}
if (authChoice === "kimi-code-api-key") {
const resolved = await resolveNonInteractiveApiKey({
provider: "kimi-code",

View File

@ -14,6 +14,7 @@ export type AuthChoice =
| "openrouter-api-key"
| "ai-gateway-api-key"
| "moonshot-api-key"
| "chutes-api-key"
| "kimi-code-api-key"
| "synthetic-api-key"
| "venice-api-key"
@ -64,6 +65,7 @@ export type OnboardOptions = {
openrouterApiKey?: string;
aiGatewayApiKey?: string;
moonshotApiKey?: string;
chutesApiKey?: string;
kimiCodeApiKey?: string;
geminiApiKey?: string;
zaiApiKey?: string;

View File

@ -31,6 +31,8 @@ export type ModelDefinitionConfig = {
maxTokens: number;
headers?: Record<string, string>;
compat?: ModelCompatConfig;
/** Chutes-only: indicates the model runs in a Trusted Execution Environment */
confidentialCompute?: boolean;
};
export type ModelProviderConfig = {
@ -41,6 +43,8 @@ export type ModelProviderConfig = {
headers?: Record<string, string>;
authHeader?: boolean;
models: ModelDefinitionConfig[];
/** Chutes-only: filter models by confidential_compute: true */
teeOnly?: boolean;
};
export type BedrockDiscoveryConfig = {

View File

@ -43,6 +43,7 @@ export const ModelDefinitionSchema = z
maxTokens: z.number().positive().optional(),
headers: z.record(z.string(), z.string()).optional(),
compat: ModelCompatSchema,
confidentialCompute: z.boolean().optional(),
})
.strict();
@ -57,6 +58,7 @@ export const ModelProviderSchema = z
headers: z.record(z.string(), z.string()).optional(),
authHeader: z.boolean().optional(),
models: z.array(ModelDefinitionSchema),
teeOnly: z.boolean().optional(),
})
.strict();