feat: add zai coding plan byok (#1434)

This commit is contained in:
Ari Webb
2026-03-18 14:35:18 -07:00
committed by GitHub
parent 3ada498f72
commit 8b8885c891
4 changed files with 58 additions and 9 deletions

View File

@@ -9,6 +9,7 @@ export type ConnectProviderCanonical =
| "anthropic" | "anthropic"
| "openai" | "openai"
| "zai" | "zai"
| "zai-coding"
| "minimax" | "minimax"
| "gemini" | "gemini"
| "openrouter" | "openrouter"
@@ -20,6 +21,7 @@ const ALIAS_TO_CANONICAL: Record<string, ConnectProviderCanonical> = {
anthropic: "anthropic", anthropic: "anthropic",
openai: "openai", openai: "openai",
zai: "zai", zai: "zai",
"zai-coding": "zai-coding",
minimax: "minimax", minimax: "minimax",
gemini: "gemini", gemini: "gemini",
openrouter: "openrouter", openrouter: "openrouter",
@@ -31,6 +33,7 @@ const CANONICAL_ORDER: ConnectProviderCanonical[] = [
"anthropic", "anthropic",
"openai", "openai",
"zai", "zai",
"zai-coding",
"minimax", "minimax",
"gemini", "gemini",
"openrouter", "openrouter",
@@ -40,7 +43,8 @@ const CANONICAL_ORDER: ConnectProviderCanonical[] = [
function canonicalToByokId( function canonicalToByokId(
canonical: ConnectProviderCanonical, canonical: ConnectProviderCanonical,
): ByokProviderId { ): ByokProviderId {
return canonical === "chatgpt" ? "codex" : canonical; if (canonical === "chatgpt") return "codex";
return canonical;
} }
export interface ResolvedConnectProvider { export interface ResolvedConnectProvider {
@@ -113,3 +117,9 @@ export function isConnectApiKeyProvider(
!isConnectOAuthProvider(provider) && !isConnectBedrockProvider(provider) !isConnectOAuthProvider(provider) && !isConnectBedrockProvider(provider)
); );
} }
export function isConnectZaiBaseProvider(
provider: ResolvedConnectProvider,
): boolean {
return provider.canonical === "zai";
}

View File

@@ -20,6 +20,7 @@ import {
isConnectApiKeyProvider, isConnectApiKeyProvider,
isConnectBedrockProvider, isConnectBedrockProvider,
isConnectOAuthProvider, isConnectOAuthProvider,
isConnectZaiBaseProvider,
listConnectProvidersForHelp, listConnectProvidersForHelp,
listConnectProviderTokens, listConnectProviderTokens,
type ResolvedConnectProvider, type ResolvedConnectProvider,
@@ -208,6 +209,18 @@ function formatApiKeyUsage(provider: ResolvedConnectProvider): string {
].join("\n"); ].join("\n");
} }
function formatZaiCodingPlanPrompt(apiKey?: string): string {
const keyHint = apiKey ? ` ${apiKey}` : " <api_key>";
return [
"Connect to Z.ai",
"",
"Do you have a Z.ai Coding plan?",
"",
` • Coding plan: /connect zai-coding${keyHint}`,
` • Regular API: /connect zai${keyHint}`,
].join("\n");
}
async function handleConnectChatGPT( async function handleConnectChatGPT(
ctx: ConnectCommandContext, ctx: ConnectCommandContext,
msg: string, msg: string,
@@ -501,13 +514,23 @@ export async function handleConnect(
if (isConnectApiKeyProvider(provider)) { if (isConnectApiKeyProvider(provider)) {
const apiKey = parts.slice(2).join(""); const apiKey = parts.slice(2).join("");
if (!apiKey) { if (!apiKey) {
addCommandResult( if (isConnectZaiBaseProvider(provider)) {
ctx.buffersRef, addCommandResult(
ctx.refreshDerived, ctx.buffersRef,
msg, ctx.refreshDerived,
formatApiKeyUsage(provider), msg,
false, formatZaiCodingPlanPrompt(),
); false,
);
} else {
addCommandResult(
ctx.buffersRef,
ctx.refreshDerived,
msg,
formatApiKeyUsage(provider),
false,
);
}
return; return;
} }
await handleConnectApiKeyProvider(ctx, msg, provider, apiKey); await handleConnectApiKeyProvider(ctx, msg, provider, apiKey);

View File

@@ -10,6 +10,7 @@ import {
isConnectApiKeyProvider, isConnectApiKeyProvider,
isConnectBedrockProvider, isConnectBedrockProvider,
isConnectOAuthProvider, isConnectOAuthProvider,
isConnectZaiBaseProvider,
listConnectProvidersForHelp, listConnectProvidersForHelp,
listConnectProviderTokens, listConnectProviderTokens,
resolveConnectProvider, resolveConnectProvider,
@@ -261,6 +262,14 @@ export async function runConnectSubcommand(
if (isConnectApiKeyProvider(provider)) { if (isConnectApiKeyProvider(provider)) {
let apiKey = let apiKey =
readStringOption(parsed.values["api-key"]) ?? restPositionals[0] ?? ""; readStringOption(parsed.values["api-key"]) ?? restPositionals[0] ?? "";
if (!apiKey && isConnectZaiBaseProvider(provider)) {
io.stdout(
"Do you have a Z.ai Coding plan?\n" +
" • Coding plan: letta connect zai-coding [--api-key <key>]\n" +
" • Regular API: letta connect zai [--api-key <key>]",
);
return 0;
}
if (!apiKey) { if (!apiKey) {
if (!io.isTTY()) { if (!io.isTTY()) {
io.stderr( io.stderr(

View File

@@ -50,10 +50,17 @@ export const BYOK_PROVIDERS = [
{ {
id: "zai", id: "zai",
displayName: "zAI API", displayName: "zAI API",
description: "Connect a zAI key or coding plan", description: "Connect a zAI API key",
providerType: "zai", providerType: "zai",
providerName: "lc-zai", providerName: "lc-zai",
}, },
{
id: "zai-coding",
displayName: "zAI Coding Plan",
description: "Connect a zAI Coding plan key",
providerType: "zai_coding",
providerName: "lc-zai-coding",
},
{ {
id: "minimax", id: "minimax",
displayName: "MiniMax API", displayName: "MiniMax API",