openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
324 lines (323 loc) • 12.7 kB
JavaScript
import { u as asPositiveFiniteNumber } from "./number-coercion-CLj0HTDM.js";
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { l as normalizeOptionalString } from "./string-coerce-CIXf7egm.js";
import "./number-runtime-Cy4drVnh.js";
import "./string-coerce-runtime-GQa0ehRA.js";
import { n as childRecord } from "./helpers-DWNr52wp.js";
import { n as normalizeHermesCustomProviderId, r as normalizeHermesProviderId } from "./model-jtqSnRdw.js";
import { i as resolveMcpEnvReferences, n as mcpValueHasEnvReferences, r as normalizeHermesEnvReferenceName, t as MCP_ENV_REFERENCE_RE } from "./config-env-D-ZcknMk.js";
//#region extensions/migrate-hermes/config-provider-contract.ts
const HERMES_TRANSPORTS = {
anthropic_messages: "anthropic-messages",
chat_completions: "openai-completions",
codex_responses: "openai-responses",
openai_chat: "openai-completions"
};
const HERMES_TRANSPORT_ALIASES = {
openai: "chat_completions",
"openai-chat": "chat_completions",
"chat-completions": "chat_completions",
chatcompletions: "chat_completions",
responses: "codex_responses",
openai_responses: "codex_responses",
"openai-responses": "codex_responses",
anthropic: "anthropic_messages",
"anthropic-messages": "anthropic_messages",
messages: "anthropic_messages"
};
function readProviderTransport(raw) {
const transport = (normalizeOptionalString(raw.api_mode) ?? normalizeOptionalString(raw.apiMode) ?? normalizeOptionalString(raw.transport))?.toLowerCase();
return transport ? HERMES_TRANSPORT_ALIASES[transport] ?? transport : void 0;
}
const HERMES_MOONSHOT_CN_BASE_URL = "https://api.moonshot.cn/v1";
const HERMES_MINIMAX_CN_BASE_URL = "https://api.minimaxi.com/anthropic";
const HERMES_ALIBABA_BASE_URL = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
const HERMES_SPECIAL_BASE_URL_ENV_VARS = {
custom: ["CUSTOM_BASE_URL", "OPENAI_BASE_URL"],
"openai-api": ["OPENAI_BASE_URL"],
"xai-oauth": ["HERMES_XAI_BASE_URL", "XAI_BASE_URL"],
"qwen-oauth": ["HERMES_QWEN_BASE_URL"],
"qwen-cli": ["HERMES_QWEN_BASE_URL"],
"qwen-portal": ["HERMES_QWEN_BASE_URL"],
"minimax-cn": ["MINIMAX_CN_BASE_URL"],
"alibaba-coding-plan": ["ALIBABA_CODING_PLAN_BASE_URL"]
};
const HERMES_BASE_URL_ENV_VARS = {
anthropic: ["ANTHROPIC_BASE_URL"],
arcee: ["ARCEE_BASE_URL"],
"azure-foundry": ["AZURE_FOUNDRY_BASE_URL"],
deepseek: ["DEEPSEEK_BASE_URL"],
gmi: ["GMI_BASE_URL"],
google: ["GEMINI_BASE_URL"],
huggingface: ["HF_BASE_URL"],
kilocode: ["KILOCODE_BASE_URL"],
kimi: ["KIMI_BASE_URL"],
lmstudio: ["LM_BASE_URL"],
minimax: ["MINIMAX_BASE_URL"],
novita: ["NOVITA_BASE_URL"],
nvidia: ["NVIDIA_BASE_URL"],
"ollama-cloud": ["OLLAMA_BASE_URL"],
opencode: ["OPENCODE_ZEN_BASE_URL"],
"opencode-go": ["OPENCODE_GO_BASE_URL"],
openrouter: ["OPENROUTER_BASE_URL"],
qwen: ["DASHSCOPE_BASE_URL"],
stepfun: ["STEPFUN_BASE_URL"],
"tencent-tokenhub": ["TOKENHUB_BASE_URL"],
xai: ["XAI_BASE_URL"],
xiaomi: ["XIAOMI_BASE_URL"],
zai: ["GLM_BASE_URL"]
};
const HERMES_SPECIAL_API_KEY_ENV_VARS = {
custom: "OPENAI_API_KEY",
"openai-api": "OPENAI_API_KEY",
"minimax-cn": "MINIMAX_CN_API_KEY",
"alibaba-coding-plan": "ALIBABA_CODING_PLAN_API_KEY"
};
const HERMES_API_KEY_ENV_VARS = {
anthropic: "ANTHROPIC_API_KEY",
arcee: "ARCEEAI_API_KEY",
deepseek: "DEEPSEEK_API_KEY",
google: "GOOGLE_API_KEY",
huggingface: "HF_TOKEN",
kilocode: "KILOCODE_API_KEY",
kimi: "KIMI_API_KEY",
lmstudio: "LM_API_KEY",
minimax: "MINIMAX_API_KEY",
nvidia: "NVIDIA_API_KEY",
opencode: "OPENCODE_ZEN_API_KEY",
"opencode-go": "OPENCODE_GO_API_KEY",
openrouter: "OPENROUTER_API_KEY",
qwen: "DASHSCOPE_API_KEY",
stepfun: "STEPFUN_API_KEY",
xai: "XAI_API_KEY",
xiaomi: "XIAOMI_API_KEY",
zai: "ZAI_API_KEY"
};
function resolveHermesProviderEnvValue(providerId, env, special, canonical) {
if (!providerId) return;
const sourceProvider = normalizeHermesCustomProviderId(providerId);
const provider = normalizeHermesProviderId(sourceProvider);
const names = special[sourceProvider] ?? canonical[provider] ?? [];
for (const name of names) {
const value = env[name]?.trim();
if (value) return value;
}
}
function resolveHermesProviderBaseUrlEnv(providerId, env) {
return resolveHermesProviderEnvValue(providerId, env, HERMES_SPECIAL_BASE_URL_ENV_VARS, HERMES_BASE_URL_ENV_VARS);
}
function resolveHermesProviderApiKeyEnv(providerId) {
if (!providerId) return;
const sourceProvider = normalizeHermesCustomProviderId(providerId);
const provider = normalizeHermesProviderId(sourceProvider);
return HERMES_SPECIAL_API_KEY_ENV_VARS[sourceProvider] ?? HERMES_API_KEY_ENV_VARS[provider];
}
function resolveHermesImplicitBaseUrl(providerId) {
const provider = providerId?.trim().toLowerCase();
if (provider && [
"alibaba",
"alibaba-cloud",
"aliyun",
"dashscope"
].includes(provider)) return HERMES_ALIBABA_BASE_URL;
if (provider && [
"kimi-coding-cn",
"kimi-cn",
"moonshot-cn"
].includes(provider)) return HERMES_MOONSHOT_CN_BASE_URL;
return provider && [
"minimax-cn",
"minimax-china",
"minimax_cn"
].includes(provider) ? HERMES_MINIMAX_CN_BASE_URL : void 0;
}
function resolveProviderApi(raw, providerId) {
const transport = readProviderTransport(raw);
const sourceProvider = providerId?.trim().toLowerCase() ?? "";
if (sourceProvider === "openai-codex") return "openai-chatgpt-responses";
if (transport && transport !== "codex_responses") return HERMES_TRANSPORTS[transport];
const provider = sourceProvider ? normalizeHermesProviderId(sourceProvider) : "";
const baseUrl = normalizeOptionalString(raw.base_url) ?? normalizeOptionalString(raw.baseUrl) ?? normalizeOptionalString(raw.url) ?? normalizeOptionalString(raw.api);
let hostname = "";
let pathname = "";
try {
const parsed = baseUrl ? new URL(baseUrl) : void 0;
hostname = parsed?.hostname.toLowerCase() ?? "";
pathname = parsed?.pathname.toLowerCase().replace(/\/+$/u, "") ?? "";
} catch {}
if (transport === "codex_responses" && sourceProvider !== "custom") return "openai-responses";
if ([
"anthropic",
"minimax",
"minimax-cn",
"minimax-oauth"
].includes(provider) || hostname === "api.anthropic.com" || hostname === "api.kimi.com" && (pathname === "/coding" || pathname.startsWith("/coding/")) || pathname.endsWith("/anthropic") || pathname.endsWith("/anthropic/v1")) return "anthropic-messages";
if (hostname === "chatgpt.com" && pathname.includes("/backend-api/codex")) return "openai-chatgpt-responses";
if (sourceProvider === "openai-api") return "openai-responses";
if (transport === "codex_responses") return "openai-responses";
if (provider === "xai" || hostname === "api.x.ai" || hostname === "api.openai.com") return "openai-responses";
return "openai-completions";
}
function normalizeProviderBaseUrl(baseUrl, api) {
if (api !== "anthropic-messages") return baseUrl;
try {
const parsed = new URL(baseUrl);
parsed.pathname = parsed.pathname.replace(/\/v1\/?$/u, "");
return parsed.toString().replace(/\/$/u, "");
} catch {
return baseUrl;
}
}
function readEnvReference(value) {
const match = normalizeOptionalString(value)?.match(/^\$\{([^}]+)\}$/u);
return match ? normalizeHermesEnvReferenceName(match[1] ?? "") : void 0;
}
function readProviderApiKeyEnv(raw) {
return normalizeOptionalString(raw.key_env) ?? normalizeOptionalString(raw.api_key_env) ?? normalizeOptionalString(raw.keyEnv) ?? normalizeOptionalString(raw.apiKeyEnv) ?? normalizeOptionalString(raw.env) ?? readEnvReference(raw.api_key ?? raw.apiKey);
}
function resolveHermesEndpointApiKeyEnv(baseUrl) {
try {
const hostname = new URL(baseUrl).hostname.toLowerCase();
return hostname === "openai.com" || hostname.endsWith(".openai.com") || hostname === "openai.azure.com" || hostname.endsWith(".openai.azure.com") ? "OPENAI_API_KEY" : void 0;
} catch {
return;
}
}
function readModelMetadata(raw) {
const contextWindow = asPositiveFiniteNumber(raw.context_length) ?? asPositiveFiniteNumber(raw.contextLength) ?? asPositiveFiniteNumber(raw.contextWindow);
const maxTokens = asPositiveFiniteNumber(raw.max_tokens) ?? asPositiveFiniteNumber(raw.max_output_tokens) ?? asPositiveFiniteNumber(raw.maxTokens);
const supportsVision = raw.supports_vision ?? raw.supportsVision;
return {
...contextWindow ? { contextWindow } : {},
...maxTokens ? { maxTokens } : {},
...typeof supportsVision === "boolean" ? { supportsVision } : {}
};
}
function collectProviderModels(raw) {
const models = /* @__PURE__ */ new Map();
const rootMetadata = readModelMetadata(raw);
const entries = Array.isArray(raw.models) ? raw.models.map((model) => isRecord(model) ? [normalizeOptionalString(model.id) ?? normalizeOptionalString(model.name), model] : [normalizeOptionalString(model), {}]) : Object.entries(childRecord(raw, "models")).filter(([id]) => !["__discovered_model_catalog__", "__explicit_model_allowlist__"].includes(id));
for (const [modelId, metadata] of entries) {
if (!modelId) continue;
models.set(modelId, {
id: modelId,
...rootMetadata,
...isRecord(metadata) ? readModelMetadata(metadata) : {}
});
}
for (const modelId of [
normalizeOptionalString(raw.default_model) ?? normalizeOptionalString(raw.defaultModel),
normalizeOptionalString(raw.default),
normalizeOptionalString(raw.model)
]) if (modelId && !models.has(modelId)) models.set(modelId, {
id: modelId,
...rootMetadata
});
return [...models.values()];
}
function modelDefinition(model, entry) {
const baseUrl = normalizeProviderBaseUrl(entry.baseUrl, entry.api);
return {
id: model.id,
name: model.id,
api: entry.api,
reasoning: false,
input: model.supportsVision ? ["text", "image"] : ["text"],
cost: {
input: 0,
output: 0,
cacheRead: 0,
cacheWrite: 0
},
contextWindow: model.contextWindow ?? 128e3,
maxTokens: model.maxTokens ?? 8192,
baseUrl,
metadataSource: "models-add"
};
}
function providerConfig(entry) {
const models = entry.models.length > 0 ? entry.models : [{ id: "default" }];
return {
baseUrl: normalizeProviderBaseUrl(entry.baseUrl, entry.api),
api: entry.api,
...entry.headers ? { headers: entry.headers } : {},
models: models.map((model) => modelDefinition(model, entry))
};
}
function readProviderBaseUrl(raw, env) {
const value = normalizeOptionalString(raw.base_url) ?? normalizeOptionalString(raw.baseUrl) ?? normalizeOptionalString(raw.url) ?? normalizeOptionalString(raw.api);
if (!value) return {
sensitive: false,
unresolved: false
};
const sensitive = MCP_ENV_REFERENCE_RE.test(value);
MCP_ENV_REFERENCE_RE.lastIndex = 0;
if (!sensitive) return {
baseUrl: value,
sensitive: false,
unresolved: false
};
const resolved = resolveMcpEnvReferences(value, env);
return {
baseUrl: !resolved.unresolved && typeof resolved.value === "string" ? resolved.value : void 0,
sensitive: true,
unresolved: resolved.unresolved
};
}
function readProviderHeaders(raw, env, includeSecrets) {
const source = isRecord(raw.extra_headers) ? raw.extra_headers : void 0;
if (!source || Object.keys(source).length === 0) return {
blocked: false,
invalid: false,
sensitive: false,
unresolved: false
};
const headers = {};
let blocked = false;
let invalid = false;
let sensitive = false;
let unresolved = false;
for (const [name, rawValue] of Object.entries(source)) {
if (rawValue === null || rawValue === void 0) continue;
if (typeof rawValue !== "string" && typeof rawValue !== "number" && typeof rawValue !== "boolean") {
invalid = true;
continue;
}
const value = String(rawValue);
const envName = readEnvReference(value);
const hasReference = mcpValueHasEnvReferences(value);
if (!includeSecrets) {
blocked = true;
continue;
}
sensitive = true;
if (envName) {
const resolved = env[envName];
if (resolved === void 0) {
unresolved = true;
continue;
}
headers[name] = resolved;
continue;
}
if (hasReference) {
const resolved = resolveMcpEnvReferences(value, env);
if (resolved.unresolved || typeof resolved.value !== "string") {
unresolved = true;
continue;
}
headers[name] = resolved.value;
continue;
}
headers[name] = value;
}
return {
blocked,
headers: Object.keys(headers).length > 0 ? headers : void 0,
invalid,
sensitive,
unresolved
};
}
//#endregion
export { readProviderApiKeyEnv as a, readProviderTransport as c, resolveHermesProviderApiKeyEnv as d, resolveHermesProviderBaseUrlEnv as f, readEnvReference as i, resolveHermesEndpointApiKeyEnv as l, collectProviderModels as n, readProviderBaseUrl as o, resolveProviderApi as p, providerConfig as r, readProviderHeaders as s, HERMES_TRANSPORTS as t, resolveHermesImplicitBaseUrl as u };