fix: read api_key_env from .env file for provider auth

Supports api_key_env field in custom_providers config, reads
from process.env first then falls back to ~/.hermes/.env.

Signed-off-by: Xiaonuo <xiaonuo@shazhou.work>
This commit is contained in:
Xiaonuo 2026-04-21 10:22:55 +08:00
parent f195e6a8aa
commit d78116ed26

View File

@ -12,6 +12,7 @@ interface CustomProvider {
name: string;
base_url: string;
api_key?: string;
api_key_env?: string;
api_mode?: string;
}
@ -84,6 +85,28 @@ function getProviderBaseUrl(config: Config, name: string): string | null {
return envMap[name] || null;
}
function getProviderApiKey(provider: CustomProvider): string {
if (provider.api_key) return provider.api_key;
if (provider.api_key_env) {
// Try process.env first, then read from .env file
const envVal = process.env[provider.api_key_env];
if (envVal) return envVal;
if (existsSync(ENV_PATH)) {
for (const line of readFileSync(ENV_PATH, "utf-8").split("\n")) {
if (line.startsWith(`${provider.api_key_env}=`)) {
return line.split("=").slice(1).join("=").trim();
}
}
}
}
return "";
}
function getAuthHeaders(provider: CustomProvider): Record<string, string> {
const key = getProviderApiKey(provider);
return key ? { Authorization: `Bearer ${key}` } : {};
}
// ── providers ──────────────────────────────────────────────────────────
function providers() {
@ -136,9 +159,7 @@ async function list(providerName?: string) {
try {
const modelsUrl = provider.base_url.replace(/\/+$/, "") + "/models";
const resp = await fetch(modelsUrl, {
headers: provider.api_key
? { Authorization: `Bearer ${provider.api_key}` }
: {},
headers: getAuthHeaders(provider),
signal: AbortSignal.timeout(10000),
});
@ -209,9 +230,7 @@ async function test(providerName?: string) {
try {
const resp = await fetch(modelsUrl, {
headers: provider.api_key
? { Authorization: `Bearer ${provider.api_key}` }
: {},
headers: getAuthHeaders(provider),
signal: AbortSignal.timeout(10000),
});