Skip to content
Open
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
105 commits
Select commit Hold shift + click to select a range
92fd3fd
feat: Introduce dedicated DTOs for Gemini API request and response st…
Aias00 Dec 16, 2025
b0b02b4
Update agentscope-extensions/agentscope-extensions-mem0/pom.xml
Aias00 Dec 16, 2025
16896c7
Update agentscope-core/src/main/java/io/agentscope/core/formatter/gem…
Aias00 Dec 16, 2025
364901f
Update agentscope-core/src/main/java/io/agentscope/core/model/GeminiC…
Aias00 Dec 16, 2025
d2bacf1
Update agentscope-core/src/main/java/io/agentscope/core/model/GeminiC…
Aias00 Dec 16, 2025
27ebc28
feat: Enhance Gemini integration by converting ThinkingBlock messages…
Aias00 Dec 16, 2025
ab9db03
feat: Add Gemini 3 compatibility adjustments, move API key to header,…
Aias00 Dec 16, 2025
5f0f0ab
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Dec 16, 2025
8444d7b
feat: Introduce accessToken authentication and configurable base URL …
Aias00 Dec 16, 2025
19d0c78
feat: Add GeminiChatExample demonstrating basic Agent setup with Goog…
Aias00 Dec 17, 2025
4ec28cb
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Dec 17, 2025
21dca17
refactor: Remove unnecessary whitespace in GeminiChatExample.java
Aias00 Dec 17, 2025
75375bb
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Dec 17, 2025
dea16ab
feat: Add thoughtSignature support and Gemini 3 provider integration
Aias00 Dec 17, 2025
f323fd6
feat: Enhance Gemini integration with schema cleaning and support for…
Aias00 Dec 18, 2025
764bc52
feat: Improve code readability with formatting adjustments and enhanc…
Aias00 Dec 25, 2025
83094c8
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Dec 25, 2025
3148701
feat: Update conversation history prompt and comment out unused Gemin…
Aias00 Dec 25, 2025
3f89137
feat(gemini): add support for custom system prompts in ReActAgent cre…
Aias00 Dec 25, 2025
c2deeb6
feat(gemini): enhance agent initialization with personalized prompts …
Aias00 Dec 25, 2025
efa68e7
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Dec 25, 2025
da39722
feat(gemini): simplify response formatting by removing unnecessary pr…
Aias00 Dec 25, 2025
bc49486
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Dec 25, 2025
a98f20f
feat(gemini): enhance signature handling and metadata integration in …
Aias00 Dec 25, 2025
da7880e
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Dec 25, 2025
4367218
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Dec 30, 2025
6bd25cc
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 4, 2026
65d8716
feat(gemini): add prompt feedback handling and system instruction sup…
Aias00 Jan 5, 2026
cbea7ab
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 5, 2026
809b2b6
refactor(gemini): remove unused ObjectMapper import and simplify logg…
Aias00 Jan 5, 2026
dd2a9a6
chore(gemini): update copyright year to 2026 and fix license URL
Aias00 Jan 5, 2026
79263fa
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Jan 5, 2026
ebdf77b
chore(gemini): update copyright year to 2026 and fix license URL
Aias00 Jan 5, 2026
4d6a4e3
feat(gemini): preserve tool call roles in message formatting
Aias00 Jan 6, 2026
fe54012
feat(gemini): preserve tool call roles in message formatting
Aias00 Jan 6, 2026
191b3af
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 6, 2026
082b355
feat(gemini): refactor function call creation and update test assertions
Aias00 Jan 6, 2026
d5d47ed
feat(gemini): update Gemini SDK integration and enhance documentation
Aias00 Jan 6, 2026
cebe6e9
feat(gemini): rename GeminiNativeProvider to GeminiProvider and refac…
Aias00 Jan 6, 2026
b71070f
refactor(gemini): clean up whitespace in GeminiProvider.java
Aias00 Jan 6, 2026
fd7866e
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Jan 12, 2026
af7d01a
test(genai): update formatter
Aias00 Jan 12, 2026
3122d67
test(genai): update converter
Aias00 Jan 12, 2026
b9cfd45
test(genai): update converter
Aias00 Jan 12, 2026
878c0f9
refactor(genai): simplify message formatting logic in GeminiChatForma…
Aias00 Jan 14, 2026
c4abb2f
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Jan 14, 2026
37785d3
Merge branch 'feat/replace_genai_sdk' of https://github.com/Aias00/ag…
Aias00 Jan 14, 2026
d962a60
refactor(genai): enhance message formatting and improve response parsing
Aias00 Jan 14, 2026
d7e639b
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 16, 2026
5459c70
refactor(genai): streamline message formatting and enhance null handling
Aias00 Jan 16, 2026
e283287
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 16, 2026
d164b77
test(GeminiMessageConverter): add Base64 import for encoding support
Aias00 Jan 16, 2026
4448f47
feat(gemini): implement multi-agent message converter for history mer…
Aias00 Jan 16, 2026
b4aef30
refactor: simplify imports and enhance code readability across multip…
Aias00 Jan 19, 2026
105e142
refactor: replace fully qualified class names with imports for improv…
Aias00 Jan 19, 2026
0702a88
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 21, 2026
1147de4
refactor(tests): simplify imports and enhance readability in test files
Aias00 Jan 21, 2026
66d2531
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 22, 2026
17de421
refactor(ShellCommandTool): remove unused method and clean up code
Aias00 Jan 22, 2026
8b61ee0
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 23, 2026
fad6c3f
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 23, 2026
77b41bc
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Jan 24, 2026
0283275
Merge branch 'main' into feat/replace_genai_sdk
AlbumenJ Jan 26, 2026
bdceb0c
Merge branch 'feat/replace_genai_sdk' of https://github.com/Aias00/ag…
Aias00 Jan 26, 2026
7d0531d
refactor(Gemini API): improve serialization handling and enhance inte…
Aias00 Jan 26, 2026
187c3c6
refactor(Gemini API): improve serialization handling and enhance inte…
Aias00 Jan 26, 2026
97b1269
fix(Gemini API): improve structured output handling and tool call com…
Aias00 Jan 29, 2026
a4ca4c2
feat(Gemini API): align retry logic, finish reason handling, and stru…
Aias00 Jan 29, 2026
e2c3cb1
feat(Gemini API): enhance structured output handling and ensure conve…
Aias00 Feb 3, 2026
79eb366
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Feb 3, 2026
4ac1422
feat(Gemini API): enhance handling of thinking content and tool execu…
Aias00 Feb 6, 2026
87a7854
feat(Gemini API): adjust response schema handling for compatibility w…
Aias00 Feb 7, 2026
ab839af
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Feb 7, 2026
1557c80
feat(Gemini API): adjust response schema handling for compatibility w…
Aias00 Feb 7, 2026
69bf804
feat(AgentBase): improve running state management in reactive chains
Aias00 Feb 9, 2026
d2e9476
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Feb 18, 2026
a2aef24
feat(Gemini API): implement Gemini API error handling and response va…
Aias00 Feb 24, 2026
b8a006b
feat(tests): add unit tests for Gemini API components
Aias00 Feb 24, 2026
9a775b9
feat(tests): add unit tests for Gemini formatter and response parser
Aias00 Feb 24, 2026
36cbb8b
style(tests): format code for improved readability in test files
Aias00 Feb 24, 2026
ac585d9
test(Gemini API): add unit tests for handling null and empty inputs i…
Aias00 Feb 24, 2026
c0b8a0e
test(Gemini API): update tests for response parsing and structured ou…
Aias00 Feb 24, 2026
2f7b62f
test(AnthropicResponseParser): fix assertion for response ID in parsi…
Aias00 Feb 24, 2026
7ac5b95
fix(A2aAgentTest): improve timeout handling and error reporting in as…
Aias00 Feb 24, 2026
29980f9
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Feb 25, 2026
8e109b1
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 2, 2026
9975da6
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Mar 10, 2026
5a91c94
feat(GeminiResponseParser): use UUID for fallback ID generation and i…
Aias00 Mar 10, 2026
0abac60
refactor(GeminiToolsHelper): remove unneeded response schema unwrappi…
Aias00 Mar 10, 2026
5765896
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 11, 2026
d9fd55b
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 13, 2026
4490394
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 13, 2026
d5bcccf
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 13, 2026
62809fb
Merge remote-tracking branch 'origin/main' into feat/replace_genai_sdk
Aias00 Mar 24, 2026
bac9584
refactor(Gemini): improve error handling and response processing in A…
Aias00 Mar 24, 2026
e40c902
refactor(StructuredOutputCapableAgent): enhance resource management a…
Aias00 Mar 24, 2026
968b5ed
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 24, 2026
ffd1fe6
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 24, 2026
330f1c4
Revert "refactor(StructuredOutputCapableAgent): enhance resource mana…
Aias00 Mar 24, 2026
010658d
Revert "refactor(Gemini): improve error handling and response process…
Aias00 Mar 24, 2026
50d9493
Merge branch 'feat/replace_genai_sdk' of https://github.com/Aias00/ag…
Aias00 Mar 24, 2026
fe48f08
feat(Gemini): enhance context preservation with thought signatures an…
Aias00 Mar 26, 2026
e3228b4
Merge branch 'refs/heads/main' into feat/replace_genai_sdk
Aias00 Mar 26, 2026
f9ae0b6
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 27, 2026
77ab451
Merge branch 'main' into feat/replace_genai_sdk
Aias00 Mar 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 0 additions & 5 deletions agentscope-core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -97,11 +97,6 @@
</exclusions>
</dependency>

<!-- Google Gemini Java SDK -->
<dependency>
<groupId>com.google.genai</groupId>
<artifactId>google-genai</artifactId>
</dependency>

<!-- Anthropic Java SDK -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,45 +15,43 @@
*/
package io.agentscope.core.formatter.gemini;

import com.google.genai.types.Content;
import com.google.genai.types.GenerateContentConfig;
import com.google.genai.types.GenerateContentResponse;
import com.google.genai.types.ThinkingConfig;
import com.google.genai.types.Tool;
import com.google.genai.types.ToolConfig;
import io.agentscope.core.formatter.AbstractBaseFormatter;
import io.agentscope.core.formatter.gemini.dto.GeminiContent;
import io.agentscope.core.formatter.gemini.dto.GeminiGenerationConfig;
import io.agentscope.core.formatter.gemini.dto.GeminiGenerationConfig.GeminiThinkingConfig;
import io.agentscope.core.formatter.gemini.dto.GeminiRequest;
import io.agentscope.core.formatter.gemini.dto.GeminiResponse;
import io.agentscope.core.formatter.gemini.dto.GeminiTool;
import io.agentscope.core.formatter.gemini.dto.GeminiToolConfig;
import io.agentscope.core.message.Msg;
import io.agentscope.core.model.ChatResponse;
import io.agentscope.core.model.GenerateOptions;
import io.agentscope.core.model.ToolChoice;
import io.agentscope.core.model.ToolSchema;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;

/**
* Formatter for Gemini Content Generation API.
*
* <p>Converts between AgentScope Msg objects and Gemini SDK types:
* <p>
* Converts between AgentScope Msg objects and Gemini API DTOs:
* <ul>
* <li>Msg → Content (request format)</li>
* <li>GenerateContentResponse → ChatResponse (response parsing)</li>
* <li>ToolSchema → Tool (tool definitions)</li>
* </ul>
*
* <p><b>Important Gemini API Behaviors:</b>
* <ul>
* <li>System messages are converted to "user" role (Gemini doesn't support system role in contents)</li>
* <li>Tool results are independent "user" role Content objects</li>
* <li>Thinking content uses the "thought" flag on Part objects</li>
* <li>Msg → GeminiContent (request format)</li>
* <li>GeminiResponse → ChatResponse (response parsing)</li>
* <li>ToolSchema → GeminiTool (tool definitions)</li>
* </ul>
*/
public class GeminiChatFormatter
extends AbstractBaseFormatter<
Content, GenerateContentResponse, GenerateContentConfig.Builder> {
extends AbstractBaseFormatter<GeminiContent, GeminiResponse, GeminiRequest> {

private final GeminiMessageConverter messageConverter;
private final GeminiResponseParser responseParser;
private final GeminiToolsHelper toolsHelper;
private GeminiContent systemInstruction;

/**
* Creates a new GeminiChatFormatter with default converters and parsers.
Expand All @@ -65,142 +63,194 @@ public GeminiChatFormatter() {
}

@Override
protected List<Content> doFormat(List<Msg> msgs) {
return messageConverter.convertMessages(msgs);
protected List<GeminiContent> doFormat(List<Msg> msgs) {
// Extract and store SYSTEM message separately
systemInstruction = null;
int startIndex = 0;

if (!msgs.isEmpty() && msgs.get(0).getRole() == io.agentscope.core.message.MsgRole.SYSTEM) {
systemInstruction = messageConverter.convertMessages(List.of(msgs.get(0))).get(0);
startIndex = 1;
}

// Gemini API requires contents to start with "user" role
// If first remaining message is ASSISTANT (from another agent), convert it to USER
if (startIndex < msgs.size()
&& msgs.get(startIndex).getRole() == io.agentscope.core.message.MsgRole.ASSISTANT) {
List<GeminiContent> result = new ArrayList<>();

// Convert first ASSISTANT message to USER role for multi-agent compatibility
GeminiContent userContent = new GeminiContent();
userContent.setRole("user");
userContent.setParts(
messageConverter
.convertMessages(List.of(msgs.get(startIndex)))
.get(0)
.getParts());
result.add(userContent);

// Add remaining messages
if (startIndex + 1 < msgs.size()) {
result.addAll(
messageConverter.convertMessages(
msgs.subList(startIndex + 1, msgs.size())));
}

return result;
}

// Return remaining messages (excluding SYSTEM)
if (startIndex > 0 && startIndex < msgs.size()) {
return messageConverter.convertMessages(msgs.subList(startIndex, msgs.size()));
} else if (startIndex == 0) {
return messageConverter.convertMessages(msgs);
}

return new ArrayList<>();
}

/**
* Apply system instruction to the request if present.
*
* @param request The Gemini request to configure
*/
public void applySystemInstruction(GeminiRequest request) {
if (systemInstruction != null) {
request.setSystemInstruction(systemInstruction);
}
}

@Override
public ChatResponse parseResponse(GenerateContentResponse response, Instant startTime) {
public ChatResponse parseResponse(GeminiResponse response, Instant startTime) {
return responseParser.parseResponse(response, startTime);
}

@Override
public void applyOptions(
GenerateContentConfig.Builder configBuilder,
GenerateOptions options,
GenerateOptions defaultOptions) {
GeminiRequest request, GenerateOptions options, GenerateOptions defaultOptions) {

// Ensure generation config exists
if (request.getGenerationConfig() == null) {
request.setGenerationConfig(new GeminiGenerationConfig());
}
GeminiGenerationConfig config = request.getGenerationConfig();

// Apply each option with fallback to defaultOptions
applyFloatOption(
GenerateOptions::getTemperature,
options,
defaultOptions,
configBuilder::temperature);
applyDoubleOption(
GenerateOptions::getTemperature, options, defaultOptions, config::setTemperature);

applyFloatOption(GenerateOptions::getTopP, options, defaultOptions, configBuilder::topP);
applyDoubleOption(GenerateOptions::getTopP, options, defaultOptions, config::setTopP);

// Apply topK (Gemini uses Float for topK)
applyIntegerAsFloatOption(
GenerateOptions::getTopK, options, defaultOptions, configBuilder::topK);
// topK: Integer in GenerateOptions -> Double in GeminiGenerationConfig
applyIntegerAsDoubleOption(
GenerateOptions::getTopK, options, defaultOptions, config::setTopK);

// Apply seed
applyLongAsIntOption(
GenerateOptions::getSeed, options, defaultOptions, configBuilder::seed);
// seed: Long in GenerateOptions -> Integer in GeminiGenerationConfig
applyLongAsIntegerOption(
GenerateOptions::getSeed, options, defaultOptions, config::setSeed);

applyIntegerOption(
GenerateOptions::getMaxTokens,
options,
defaultOptions,
configBuilder::maxOutputTokens);
GenerateOptions::getMaxTokens, options, defaultOptions, config::setMaxOutputTokens);

applyFloatOption(
applyDoubleOption(
GenerateOptions::getFrequencyPenalty,
options,
defaultOptions,
configBuilder::frequencyPenalty);
config::setFrequencyPenalty);

applyFloatOption(
applyDoubleOption(
GenerateOptions::getPresencePenalty,
options,
defaultOptions,
configBuilder::presencePenalty);
config::setPresencePenalty);

// Apply ThinkingConfig if either includeThoughts or thinkingBudget is set
Integer thinkingBudget =
getOptionOrDefault(options, defaultOptions, GenerateOptions::getThinkingBudget);

if (thinkingBudget != null) {
ThinkingConfig.Builder thinkingConfigBuilder = ThinkingConfig.builder();
thinkingConfigBuilder.includeThoughts(true);
thinkingConfigBuilder.thinkingBudget(thinkingBudget);
configBuilder.thinkingConfig(thinkingConfigBuilder.build());
GeminiThinkingConfig thinkingConfig = new GeminiThinkingConfig();
thinkingConfig.setIncludeThoughts(true);
thinkingConfig.setThinkingBudget(thinkingBudget);
config.setThinkingConfig(thinkingConfig);
}
}

/**
* Apply Float option with fallback logic.
* Apply Double option with fallback logic.
*/
private void applyFloatOption(
java.util.function.Function<GenerateOptions, Double> accessor,
private void applyDoubleOption(
Function<GenerateOptions, Double> accessor,
GenerateOptions options,
GenerateOptions defaultOptions,
java.util.function.Consumer<Float> setter) {
Consumer<Double> setter) {

Double value = getOptionOrDefault(options, defaultOptions, accessor);
if (value != null) {
setter.accept(value.floatValue());
setter.accept(value);
}
}

/**
* Apply Integer option with fallback logic.
* Apply Integer option as Double with fallback logic.
*/
private void applyIntegerOption(
java.util.function.Function<GenerateOptions, Integer> accessor,
private void applyIntegerAsDoubleOption(
Function<GenerateOptions, Integer> accessor,
GenerateOptions options,
GenerateOptions defaultOptions,
java.util.function.Consumer<Integer> setter) {
Consumer<Double> setter) {

Integer value = getOptionOrDefault(options, defaultOptions, accessor);
if (value != null) {
setter.accept(value);
setter.accept(value.doubleValue());
}
}

/**
* Apply Integer option as Float with fallback logic (for Gemini topK which requires Float).
* Apply Long option as Integer with fallback logic.
*/
private void applyIntegerAsFloatOption(
java.util.function.Function<GenerateOptions, Integer> accessor,
private void applyLongAsIntegerOption(
Function<GenerateOptions, Long> accessor,
GenerateOptions options,
GenerateOptions defaultOptions,
java.util.function.Consumer<Float> setter) {
Consumer<Integer> setter) {

Integer value = getOptionOrDefault(options, defaultOptions, accessor);
Long value = getOptionOrDefault(options, defaultOptions, accessor);
if (value != null) {
setter.accept(value.floatValue());
setter.accept(value.intValue());
}
}

/**
* Apply Long option as Integer with fallback logic (for Gemini seed which requires Integer).
* Apply Integer option with fallback logic.
*/
private void applyLongAsIntOption(
java.util.function.Function<GenerateOptions, Long> accessor,
private void applyIntegerOption(
Function<GenerateOptions, Integer> accessor,
GenerateOptions options,
GenerateOptions defaultOptions,
java.util.function.Consumer<Integer> setter) {
Consumer<Integer> setter) {

Long value = getOptionOrDefault(options, defaultOptions, accessor);
Integer value = getOptionOrDefault(options, defaultOptions, accessor);
if (value != null) {
setter.accept(value.intValue());
setter.accept(value);
}
}

@Override
public void applyTools(GenerateContentConfig.Builder configBuilder, List<ToolSchema> tools) {
Tool tool = toolsHelper.convertToGeminiTool(tools);
public void applyTools(GeminiRequest request, List<ToolSchema> tools) {
GeminiTool tool = toolsHelper.convertToGeminiTool(tools);
if (tool != null) {
configBuilder.tools(List.of(tool));
// Gemini API expects a list of tools, typically one tool object containing
// function declarations
request.setTools(List.of(tool));
}
}

@Override
public void applyToolChoice(
GenerateContentConfig.Builder configBuilder, ToolChoice toolChoice) {
ToolConfig toolConfig = toolsHelper.convertToolChoice(toolChoice);
public void applyToolChoice(GeminiRequest request, ToolChoice toolChoice) {
GeminiToolConfig toolConfig = toolsHelper.convertToolChoice(toolChoice);
if (toolConfig != null) {
configBuilder.toolConfig(toolConfig);
request.setToolConfig(toolConfig);
}
}
}
Loading
Loading