mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-06-10 03:07:32 +08:00
feat(react-agent-openai): add OpenAI-compatible vendor entries
DeepSeek/Kimi/GLM/Minimax static entries with default baseUrls, plus OpenAICompatible.custom() fallback for arbitrary vendors. All read credentials from liteflow.agent.openai-compatible.<key>. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
public final class DeepSeek {
|
||||
private static final String CONFIG_KEY = "deepseek";
|
||||
private static final String BASE_URL = "https://api.deepseek.com/v1";
|
||||
private DeepSeek() {}
|
||||
|
||||
public static OpenAICompatibleSpec of(String modelName) {
|
||||
return new OpenAICompatibleSpec(CONFIG_KEY, modelName, BASE_URL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
public final class GLM {
|
||||
private static final String CONFIG_KEY = "glm";
|
||||
private static final String BASE_URL = "https://open.bigmodel.cn/api/paas/v4";
|
||||
private GLM() {}
|
||||
|
||||
public static OpenAICompatibleSpec of(String modelName) {
|
||||
return new OpenAICompatibleSpec(CONFIG_KEY, modelName, BASE_URL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
public final class Kimi {
|
||||
private static final String CONFIG_KEY = "kimi";
|
||||
private static final String BASE_URL = "https://api.moonshot.cn/v1";
|
||||
private Kimi() {}
|
||||
|
||||
public static OpenAICompatibleSpec of(String modelName) {
|
||||
return new OpenAICompatibleSpec(CONFIG_KEY, modelName, BASE_URL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
public final class Minimax {
|
||||
private static final String CONFIG_KEY = "minimax";
|
||||
private static final String BASE_URL = "https://api.minimax.chat/v1";
|
||||
private Minimax() {}
|
||||
|
||||
public static OpenAICompatibleSpec of(String modelName) {
|
||||
return new OpenAICompatibleSpec(CONFIG_KEY, modelName, BASE_URL);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
/**
|
||||
* 自定义 OpenAI 兼容厂商兜底入口。
|
||||
* 用户在配置中挂 {@code liteflow.agent.openai-compatible.<configKey>},
|
||||
* 至少要提供 api-key;base-url 也由用户配置决定(无默认值)。
|
||||
*/
|
||||
public final class OpenAICompatible {
|
||||
private OpenAICompatible() {}
|
||||
|
||||
public static OpenAICompatibleSpec custom(String configKey, String modelName) {
|
||||
return new OpenAICompatibleSpec(configKey, modelName, null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
import com.yomahub.liteflow.agent.model.CredentialResolver;
|
||||
import com.yomahub.liteflow.property.agent.AgentConfig;
|
||||
import com.yomahub.liteflow.property.agent.PlatformCredential;
|
||||
import io.agentscope.core.model.Model;
|
||||
|
||||
/**
|
||||
* OpenAI 兼容族 spec。与 {@link OpenAISpec} 共享所有可调参数,
|
||||
* 但 credential 来源换成 {@code liteflow.agent.openai-compatible.<configKey>}。
|
||||
* 子类内置默认 baseUrl,用户配置中的 baseUrl 优先生效。
|
||||
*/
|
||||
public class OpenAICompatibleSpec extends OpenAISpec {
|
||||
|
||||
private final String configKey;
|
||||
private final String defaultBaseUrl;
|
||||
|
||||
public OpenAICompatibleSpec(String configKey, String modelName, String defaultBaseUrl) {
|
||||
super(modelName);
|
||||
this.configKey = configKey;
|
||||
this.defaultBaseUrl = defaultBaseUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Model resolve(AgentConfig cfg) {
|
||||
PlatformCredential cred = CredentialResolver.requireCompatible(
|
||||
cfg.getOpenaiCompatible(), configKey, "liteflow.agent.openai-compatible");
|
||||
String baseUrl = (cred.getBaseUrl() != null && !cred.getBaseUrl().isBlank())
|
||||
? cred.getBaseUrl()
|
||||
: defaultBaseUrl;
|
||||
return buildModel(cred.getApiKey(), baseUrl);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.yomahub.liteflow.agent.openai;
|
||||
|
||||
import com.yomahub.liteflow.agent.exception.AgentConfigException;
|
||||
import com.yomahub.liteflow.property.agent.AgentConfig;
|
||||
import com.yomahub.liteflow.property.agent.PlatformCredential;
|
||||
import io.agentscope.core.model.Model;
|
||||
import io.agentscope.core.model.OpenAIChatModel;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class OpenAICompatibleEntryTest {
|
||||
|
||||
private static AgentConfig cfgWith(String key, String apiKey) {
|
||||
AgentConfig cfg = new AgentConfig();
|
||||
PlatformCredential c = new PlatformCredential();
|
||||
c.setApiKey(apiKey);
|
||||
cfg.getOpenaiCompatible().put(key, c);
|
||||
return cfg;
|
||||
}
|
||||
|
||||
@Test
|
||||
void deepseekResolvesFromOpenaiCompatibleDeepseek() {
|
||||
AgentConfig cfg = cfgWith("deepseek", "ds-key");
|
||||
Model model = DeepSeek.of("deepseek-chat").temperature(0.7).resolve(cfg);
|
||||
assertTrue(model instanceof OpenAIChatModel);
|
||||
assertEquals("deepseek-chat", ((OpenAIChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void kimiResolvesFromOpenaiCompatibleKimi() {
|
||||
AgentConfig cfg = cfgWith("kimi", "kimi-key");
|
||||
Model model = Kimi.of("kimi-k2").resolve(cfg);
|
||||
assertEquals("kimi-k2", ((OpenAIChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void glmResolvesFromOpenaiCompatibleGlm() {
|
||||
AgentConfig cfg = cfgWith("glm", "glm-key");
|
||||
Model model = GLM.of("glm-4").resolve(cfg);
|
||||
assertEquals("glm-4", ((OpenAIChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void minimaxResolvesFromOpenaiCompatibleMinimax() {
|
||||
AgentConfig cfg = cfgWith("minimax", "mm-key");
|
||||
Model model = Minimax.of("abab6.5").resolve(cfg);
|
||||
assertEquals("abab6.5", ((OpenAIChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void customResolvesFromGivenConfigKey() {
|
||||
AgentConfig cfg = cfgWith("myvendor", "my-key");
|
||||
PlatformCredential c = cfg.getOpenaiCompatible().get("myvendor");
|
||||
c.setBaseUrl("https://my.vendor/v1");
|
||||
|
||||
Model model = OpenAICompatible.custom("myvendor", "my-model").resolve(cfg);
|
||||
assertEquals("my-model", ((OpenAIChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void customThrowsWhenKeyMissing() {
|
||||
AgentConfig cfg = new AgentConfig();
|
||||
AgentConfigException ex = assertThrows(AgentConfigException.class,
|
||||
() -> OpenAICompatible.custom("myvendor", "x").resolve(cfg));
|
||||
assertTrue(ex.getMessage().contains("openai-compatible.myvendor"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void deepseekThrowsWhenCredentialMissing() {
|
||||
AgentConfig cfg = new AgentConfig();
|
||||
AgentConfigException ex = assertThrows(AgentConfigException.class,
|
||||
() -> DeepSeek.of("deepseek-chat").resolve(cfg));
|
||||
assertTrue(ex.getMessage().contains("openai-compatible.deepseek"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user