From e0f66eef250ed19dd425ec3afd11a61856e9594d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=80=AA=E7=A8=8B=E4=BC=9F?= Date: Wed, 20 May 2026 09:25:16 +0800 Subject: [PATCH] fix(embedding): respect requireApiKey flag in OpenAI-compatible embedding factory (#171) Closes #167 EmbeddingModelFactory.buildOpenAi() hard-failed on any provider whose API key was empty or unusable, so keyless providers like Ollama and OpenCode (declared with requireApiKey=false) could pass the chat connectivity test but bounce when the same provider's embedding model was tested. Mirror the chat path in OpenAiCompatibleChatModelBuilder.buildOpenAiApi: - If requireApiKey is not explicitly false, an unusable key still throws. - If requireApiKey == false, the key check is skipped and an empty string is passed to OpenAiApi.builder() so no Authorization: Bearer header is attached to the outgoing request. --- .../vip/mate/llm/embedding/EmbeddingModelFactory.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/mateclaw-server/src/main/java/vip/mate/llm/embedding/EmbeddingModelFactory.java b/mateclaw-server/src/main/java/vip/mate/llm/embedding/EmbeddingModelFactory.java index d47b44a8..0184a1f7 100644 --- a/mateclaw-server/src/main/java/vip/mate/llm/embedding/EmbeddingModelFactory.java +++ b/mateclaw-server/src/main/java/vip/mate/llm/embedding/EmbeddingModelFactory.java @@ -165,7 +165,11 @@ public class EmbeddingModelFactory { "Provider '" + provider.getProviderId() + "' 未完成配置(缺少 API Key 或 Base URL)"); } String apiKey = provider.getApiKey(); - if (!providerService.hasUsableApiKey(apiKey)) { + // Mirror the chat model builder: only require an API key when the provider row says so. + // Keyless providers (requireApiKey=false, e.g. OpenCode, local Ollama) must be allowed + // through; otherwise their cloud-model connection test passes but embedding test fails. + boolean keyRequired = !Boolean.FALSE.equals(provider.getRequireApiKey()); + if (keyRequired && !providerService.hasUsableApiKey(apiKey)) { throw new MateClawException("err.embedding.openai_key_invalid", "Provider API Key 未配置或无效: " + provider.getProviderId()); } @@ -175,10 +179,11 @@ public class EmbeddingModelFactory { "Provider Base URL 未配置: " + provider.getProviderId()); } + String effectiveApiKey = providerService.hasUsableApiKey(apiKey) ? apiKey.trim() : ""; // 最简构造:不做 chat-specific 的 header 重写、reasoning patch 等 OpenAiApi api = OpenAiApi.builder() .baseUrl(baseUrl) - .apiKey(apiKey.trim()) + .apiKey(effectiveApiKey) .embeddingsPath(resolveEmbeddingsPath(baseUrl)) .build();