Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 29 additions & 6 deletions agentscope-core/src/main/java/io/agentscope/core/ReActAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ public class ReActAgent extends StructuredOutputCapableAgent {
private final String sysPrompt;
private final Model model;
private final int maxIters;
private final GenerateOptions generateOptions;
private final ExecutionConfig modelExecutionConfig;
private final ExecutionConfig toolExecutionConfig;
private final PlanNotebook planNotebook;
Expand All @@ -157,6 +158,7 @@ private ReActAgent(Builder builder, Toolkit agentToolkit) {
this.sysPrompt = builder.sysPrompt;
this.model = builder.model;
this.maxIters = builder.maxIters;
this.generateOptions = builder.generateOptions;
this.modelExecutionConfig = builder.modelExecutionConfig;
this.toolExecutionConfig = builder.toolExecutionConfig;
this.planNotebook = builder.planNotebook;
Expand Down Expand Up @@ -786,11 +788,14 @@ private List<ToolUseBlock> extractPendingToolCalls() {

@Override
protected GenerateOptions buildGenerateOptions() {
GenerateOptions.Builder builder = GenerateOptions.builder();
if (modelExecutionConfig != null) {
builder.executionConfig(modelExecutionConfig);
}
return builder.build();
// Build options with modelExecutionConfig (timeout, retry, etc.)
GenerateOptions executionOptions =
modelExecutionConfig != null
? GenerateOptions.builder().executionConfig(modelExecutionConfig).build()
: null;
// Merge: user's generateOptions (temperature, topP, maxTokens, etc.) as base,
// executionOptions overrides executionConfig
return GenerateOptions.mergeOptions(executionOptions, generateOptions);
}
Comment on lines 790 to 799

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

当前的实现虽然功能正确,但使用三元运算符使代码略显紧凑,可读性稍差。通过提前处理 modelExecutionConfig == null 的情况,可以使逻辑更清晰:如果没有特定于 agent 的执行配置,就直接使用 generateOptions;否则,将 agent 的配置合并到基础选项之上。

Suggested change
protected GenerateOptions buildGenerateOptions() {
GenerateOptions.Builder builder = GenerateOptions.builder();
if (modelExecutionConfig != null) {
builder.executionConfig(modelExecutionConfig);
}
return builder.build();
// Build options with modelExecutionConfig (timeout, retry, etc.)
GenerateOptions executionOptions =
modelExecutionConfig != null
? GenerateOptions.builder().executionConfig(modelExecutionConfig).build()
: null;
// Merge: user's generateOptions (temperature, topP, maxTokens, etc.) as base,
// executionOptions overrides executionConfig
return GenerateOptions.mergeOptions(executionOptions, generateOptions);
}
protected GenerateOptions buildGenerateOptions() {
if (modelExecutionConfig == null) {
return generateOptions;
}
// The agent's modelExecutionConfig should override any execution config
// within the provided generateOptions.
GenerateOptions executionOptions =
GenerateOptions.builder().executionConfig(modelExecutionConfig).build();
return GenerateOptions.mergeOptions(executionOptions, generateOptions);
}


// ==================== Hook Notification Methods ====================
Expand All @@ -807,7 +812,8 @@ private <T extends HookEvent> Mono<T> notifyHooks(T event) {
}

private Mono<PreReasoningEvent> notifyPreReasoningEvent(List<Msg> msgs) {
return notifyHooks(new PreReasoningEvent(this, model.getModelName(), null, msgs));
return notifyHooks(
new PreReasoningEvent(this, model.getModelName(), buildGenerateOptions(), msgs));
}

private Mono<PostReasoningEvent> notifyPostReasoning(Msg msg) {
Expand Down Expand Up @@ -977,6 +983,7 @@ public static class Builder {
private Toolkit toolkit = new Toolkit();
private Memory memory = new InMemoryMemory();
private int maxIters = 10;
private GenerateOptions generateOptions;
private ExecutionConfig modelExecutionConfig;
private ExecutionConfig toolExecutionConfig;
private final Set<Hook> hooks = new LinkedHashSet<>();
Expand Down Expand Up @@ -1124,6 +1131,22 @@ public Builder enableMetaTool(boolean enableMetaTool) {
return this;
}

/**
* Sets the generation options for model API calls.
*
* <p>This configuration includes generation parameters such as temperature, topP,
* maxTokens, etc. When set, these options will be passed to the model and recorded
* in trace spans (e.g., gen_ai.request.temperature for OpenTelemetry).
*
* @param generateOptions The generation options (temperature, topP, maxTokens, etc.)
* @return This builder instance for method chaining
* @see GenerateOptions
*/
public Builder generateOptions(GenerateOptions generateOptions) {
this.generateOptions = generateOptions;
return this;
}

/**
* Sets the execution configuration for model API calls.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import io.agentscope.core.message.ToolUseBlock;
import io.agentscope.core.model.ChatResponse;
import io.agentscope.core.model.ChatUsage;
import io.agentscope.core.model.GenerateOptions;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.core.util.JsonUtils;
import java.time.Duration;
Expand Down Expand Up @@ -101,6 +102,34 @@ void testInitialization() {
assertTrue(agent.getMemory().getMessages().isEmpty(), "Memory should be empty initially");
}

@Test
@DisplayName("Should pass generateOptions (temperature, topP, maxTokens) to model for tracing")
void testGenerateOptionsPassedToModel() {
GenerateOptions options =
GenerateOptions.builder().temperature(0.7).topP(0.9).maxTokens(1000).build();

ReActAgent agentWithOptions =
ReActAgent.builder()
.name(TestConstants.TEST_REACT_AGENT_NAME)
.sysPrompt(TestConstants.DEFAULT_SYS_PROMPT)
.model(mockModel)
.toolkit(mockToolkit)
.memory(memory)
.generateOptions(options)
.build();

Msg userMsg = TestUtils.createUserMessage("User", TestConstants.TEST_USER_INPUT);
agentWithOptions
.call(userMsg)
.block(Duration.ofMillis(TestConstants.DEFAULT_TEST_TIMEOUT_MS));

GenerateOptions lastOptions = mockModel.getLastOptions();
assertNotNull(lastOptions, "Model should receive GenerateOptions");
assertEquals(0.7, lastOptions.getTemperature(), "Temperature should be passed to model");
assertEquals(0.9, lastOptions.getTopP(), "TopP should be passed to model");
Comment on lines +128 to +129

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在比较浮点数时,使用一个容差(delta)是最佳实践,可以避免因精度问题导致的测试失败。虽然在这里使用字面量比较可能不会出问题,但使用带 delta 的 assertEquals 会使测试更加健壮。

Suggested change
assertEquals(0.7, lastOptions.getTemperature(), "Temperature should be passed to model");
assertEquals(0.9, lastOptions.getTopP(), "TopP should be passed to model");
assertEquals(0.7, lastOptions.getTemperature(), 0.0, "Temperature should be passed to model");
assertEquals(0.9, lastOptions.getTopP(), 0.0, "TopP should be passed to model");

assertEquals(1000, lastOptions.getMaxTokens(), "MaxTokens should be passed to model");
}

@Test
@DisplayName("Should generate simple text response")
void testSimpleReply() {
Expand Down
Loading