mirror of
https://gitee.com/dromara/liteFlow.git
synced 2026-06-13 03:11:10 +08:00
feat(react-agent-gemini): add Gemini entry and GeminiSpec
Gemini.of(modelName) returns GeminiSpec exposing a thinking sub-builder that supports both Gemini 2.5's level() and the legacy budget() form. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
package com.yomahub.liteflow.agent.gemini;
|
||||
|
||||
public final class Gemini {
|
||||
private Gemini() {}
|
||||
public static GeminiSpec of(String modelName) {
|
||||
return new GeminiSpec(modelName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package com.yomahub.liteflow.agent.gemini;
|
||||
|
||||
import com.yomahub.liteflow.agent.model.CredentialResolver;
|
||||
import com.yomahub.liteflow.agent.model.ModelSpec;
|
||||
import com.yomahub.liteflow.property.agent.AgentConfig;
|
||||
import com.yomahub.liteflow.property.agent.PlatformCredential;
|
||||
import io.agentscope.core.model.GeminiChatModel;
|
||||
import io.agentscope.core.model.GenerateOptions;
|
||||
import io.agentscope.core.model.Model;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class GeminiSpec extends ModelSpec<GeminiSpec> {
|
||||
|
||||
private final String modelName;
|
||||
private String thinkingLevel;
|
||||
private Integer thinkingBudget;
|
||||
|
||||
public GeminiSpec(String modelName) { this.modelName = modelName; }
|
||||
|
||||
public GeminiSpec thinking(Consumer<GeminiThinking> c) {
|
||||
GeminiThinking t = new GeminiThinking();
|
||||
c.accept(t);
|
||||
this.thinkingLevel = t.getLevel();
|
||||
this.thinkingBudget = t.getBudget();
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getModelName() { return modelName; }
|
||||
public String getThinkingLevel() { return thinkingLevel; }
|
||||
public Integer getThinkingBudget() { return thinkingBudget; }
|
||||
|
||||
@Override
|
||||
public Model resolve(AgentConfig cfg) {
|
||||
PlatformCredential cred = CredentialResolver.requireFirstClass(
|
||||
cfg.getGemini(), "liteflow.agent.gemini");
|
||||
|
||||
GeminiChatModel.Builder builder = GeminiChatModel.builder()
|
||||
.apiKey(cred.getApiKey())
|
||||
.modelName(modelName);
|
||||
GenerateOptions options = buildGenerateOptions();
|
||||
if (options != null) {
|
||||
builder.defaultOptions(options);
|
||||
}
|
||||
if (getStream() != null) {
|
||||
builder.streamEnabled(getStream());
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
private GenerateOptions buildGenerateOptions() {
|
||||
if (getTemperature() == null && getTopP() == null && getTopK() == null
|
||||
&& getMaxTokens() == null && getSeed() == null
|
||||
&& thinkingLevel == null && thinkingBudget == null) {
|
||||
return null;
|
||||
}
|
||||
GenerateOptions.Builder b = GenerateOptions.builder();
|
||||
if (getTemperature() != null) b.temperature(getTemperature());
|
||||
if (getTopP() != null) b.topP(getTopP());
|
||||
if (getTopK() != null) b.topK(getTopK());
|
||||
if (getMaxTokens() != null) b.maxTokens(getMaxTokens());
|
||||
if (getSeed() != null) b.seed(getSeed());
|
||||
if (thinkingLevel != null) b.reasoningEffort(thinkingLevel);
|
||||
if (thinkingBudget != null) b.thinkingBudget(thinkingBudget);
|
||||
return b.build();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.yomahub.liteflow.agent.gemini;
|
||||
|
||||
/**
|
||||
* Gemini 平台 thinking 子构建器。
|
||||
* Gemini 2.5 使用 "thinking_level"(low/medium/high),老接口用 "thinking_budget"(token 数)。
|
||||
*/
|
||||
public final class GeminiThinking {
|
||||
private String level;
|
||||
private Integer budget;
|
||||
|
||||
public GeminiThinking level(String level) { this.level = level; return this; }
|
||||
public GeminiThinking budget(int tokens) { this.budget = tokens; return this; }
|
||||
|
||||
public String getLevel() { return level; }
|
||||
public Integer getBudget() { return budget; }
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.yomahub.liteflow.agent.gemini;
|
||||
|
||||
import com.yomahub.liteflow.agent.exception.AgentConfigException;
|
||||
import com.yomahub.liteflow.property.agent.AgentConfig;
|
||||
import io.agentscope.core.model.GeminiChatModel;
|
||||
import io.agentscope.core.model.Model;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
class GeminiEntryTest {
|
||||
|
||||
@Test
|
||||
void buildsGeminiChatModel() {
|
||||
AgentConfig cfg = new AgentConfig();
|
||||
cfg.getGemini().setApiKey("g-key");
|
||||
|
||||
Model model = Gemini.of("gemini-2.5-pro")
|
||||
.temperature(0.6)
|
||||
.thinking(t -> t.level("high"))
|
||||
.resolve(cfg);
|
||||
|
||||
assertTrue(model instanceof GeminiChatModel);
|
||||
assertEquals("gemini-2.5-pro", ((GeminiChatModel) model).getModelName());
|
||||
}
|
||||
|
||||
@Test
|
||||
void thinkingLevelAndBudgetStored() {
|
||||
GeminiSpec spec = Gemini.of("gemini-2.5-pro")
|
||||
.thinking(t -> t.level("medium").budget(1024));
|
||||
assertEquals("medium", spec.getThinkingLevel());
|
||||
assertEquals(1024, spec.getThinkingBudget());
|
||||
}
|
||||
|
||||
@Test
|
||||
void throwsWhenApiKeyMissing() {
|
||||
AgentConfig cfg = new AgentConfig();
|
||||
AgentConfigException ex = assertThrows(AgentConfigException.class,
|
||||
() -> Gemini.of("gemini-2.5-pro").resolve(cfg));
|
||||
assertTrue(ex.getMessage().contains("liteflow.agent.gemini.api-key"));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user