fix: 保留流式输出连续重复字符
- 按 AgentScope 增量协议原样保留普通文本分片 - 仅在终态完整快照中去除已发送前缀 - 补充连续端口字符回归测试
This commit is contained in:
@@ -690,6 +690,49 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
Assert.assertTrue(sessionStore.exists("session-1"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证增量模式会保留 URL 中连续出现的相同字符。
|
||||
*/
|
||||
@Test
|
||||
public void shouldPreserveRepeatedIdenticalTextDeltas() {
|
||||
String expectedUrl = "http://127.0.0.1:39000/easyflow/file.docx";
|
||||
AgentScopeReActRuntime runtime = runtimeWithStreamingModel(List.of(
|
||||
ChatResponse.builder()
|
||||
.id("url-response")
|
||||
.content(List.of(TextBlock.builder().text("http://127.0.0.1:39").build()))
|
||||
.build(),
|
||||
ChatResponse.builder()
|
||||
.id("url-response")
|
||||
.content(List.of(TextBlock.builder().text("0").build()))
|
||||
.build(),
|
||||
ChatResponse.builder()
|
||||
.id("url-response")
|
||||
.content(List.of(TextBlock.builder().text("0").build()))
|
||||
.build(),
|
||||
ChatResponse.builder()
|
||||
.id("url-response")
|
||||
.content(List.of(TextBlock.builder().text("0/easyflow/file.docx").build()))
|
||||
.finishReason("stop")
|
||||
.build()));
|
||||
runtime.init(initRequest());
|
||||
|
||||
List<AgentRuntimeEvent> events = runtime.stream(
|
||||
AgentMessage.text(AgentMessageRole.USER, "create file"))
|
||||
.collectList()
|
||||
.block();
|
||||
String streamedText = events.stream()
|
||||
.filter(event -> event.getEventType() == AgentRuntimeEventType.MESSAGE_DELTA)
|
||||
.map(event -> String.valueOf(event.getPayload().getOrDefault("text", "")))
|
||||
.reduce("", String::concat);
|
||||
|
||||
Assert.assertEquals(expectedUrl, streamedText);
|
||||
AgentRuntimeEvent completed = events.stream()
|
||||
.filter(event -> event.getEventType() == AgentRuntimeEventType.COMPLETED)
|
||||
.findFirst()
|
||||
.orElseThrow();
|
||||
Assert.assertEquals(expectedUrl, completed.getPayload().get("text"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldAllowNextStreamAfterPreviousStreamCompleted() {
|
||||
AgentScopeReActRuntime runtime = fakeRuntime();
|
||||
@@ -1370,6 +1413,27 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
new AgentScopeMessageAdapter());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建单次模型调用返回多个增量响应的运行时。
|
||||
*
|
||||
* @param responses 同一次模型调用中的响应增量
|
||||
* @return 测试运行时
|
||||
*/
|
||||
private AgentScopeReActRuntime runtimeWithStreamingModel(List<ChatResponse> responses) {
|
||||
AgentScopeModelFactory modelFactory = new AgentScopeModelFactory() {
|
||||
@Override
|
||||
public Model create(AgentModelSpec modelSpec,
|
||||
com.easyagents.agent.runtime.model.AgentGenerationOptions generationOptions) {
|
||||
return new StreamingScriptedModel(
|
||||
modelSpec == null ? "fake-model" : modelSpec.getModelName(),
|
||||
responses);
|
||||
}
|
||||
};
|
||||
return new AgentScopeReActRuntime(modelFactory, new AgentScopeToolAdapter(),
|
||||
new AgentScopeKnowledgeAdapter(), new AgentScopeMemoryAdapter(), new AgentScopeSkillAdapter(),
|
||||
new AgentScopeMessageAdapter());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据审批事件创建恢复请求。
|
||||
*
|
||||
@@ -1419,6 +1483,51 @@ public class AgentScopeStatefulRuntimeTest {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 单次调用按顺序返回全部响应增量的测试模型。
|
||||
*/
|
||||
private static class StreamingScriptedModel implements Model {
|
||||
|
||||
private final String modelName;
|
||||
private final List<ChatResponse> responses;
|
||||
|
||||
/**
|
||||
* 创建流式测试模型。
|
||||
*
|
||||
* @param modelName 模型名称
|
||||
* @param responses 响应增量
|
||||
*/
|
||||
private StreamingScriptedModel(String modelName, List<ChatResponse> responses) {
|
||||
this.modelName = modelName;
|
||||
this.responses = responses;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回预设的响应增量。
|
||||
*
|
||||
* @param messages 输入消息
|
||||
* @param toolSchemas 工具定义
|
||||
* @param options 生成配置
|
||||
* @return 响应流
|
||||
*/
|
||||
@Override
|
||||
public Flux<ChatResponse> stream(List<Msg> messages,
|
||||
List<ToolSchema> toolSchemas,
|
||||
GenerateOptions options) {
|
||||
return Flux.fromIterable(responses);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取模型名称。
|
||||
*
|
||||
* @return 模型名称
|
||||
*/
|
||||
@Override
|
||||
public String getModelName() {
|
||||
return modelName;
|
||||
}
|
||||
}
|
||||
|
||||
private AgentInitRequest initRequest() {
|
||||
AgentModelSpec modelSpec = new AgentModelSpec();
|
||||
modelSpec.setModelName("fake-model");
|
||||
|
||||
Reference in New Issue
Block a user