Skip to content

Commit a1a81c0

Browse files
committed
refactor: align streaming objects with OpenClaw
1 parent 57af0b5 commit a1a81c0

5 files changed

Lines changed: 60 additions & 50 deletions

File tree

src/main/java/io/github/easy4j/opencode/OpenCodeClient.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public OpenCodeClient(OpenCodeHttpClientConfig httpConfig, OpenCodeCliConfig cli
127127
this.chatClient = null;
128128
this.sseClient = null;
129129
}
130-
this.streamExecutor = this.chatClient == null ? createStreamExecutor(httpConfig) : null;
130+
this.streamExecutor = createStreamExecutor(httpConfig);
131131

132132
// CLI 子系统初始化
133133
if (cliEnabled) {
@@ -166,7 +166,7 @@ public OpenCodeClient(OpenCodeClientConfig config,
166166
this.chatClient = httpClient instanceof OpenCodeChatClient ? (OpenCodeChatClient) httpClient : null;
167167
this.sseClient = sseClient;
168168
this.cli = cli;
169-
this.streamExecutor = this.chatClient == null ? createStreamExecutor(config.getHttp()) : null;
169+
this.streamExecutor = createStreamExecutor(config.getHttp());
170170
}
171171

172172
private static ExecutorService createStreamExecutor(OpenCodeHttpClientConfig config) {
@@ -382,9 +382,6 @@ public ChatStreamingResponse chatCompletionStream(ChatRequest request, String se
382382
public ChatStreamingResponse chatCompletionStream(ChatRequest request, String sessionKey,
383383
OpenCodeRequestContext context,
384384
Consumer<String> deltaConsumer) {
385-
if (chatClient != null) {
386-
return chatClient.chatCompletionStream(request, sessionKey, context, deltaConsumer);
387-
}
388385
String sessionId = httpClient.ensureSession(sessionKey, context);
389386
PromptRequest promptRequest = ChatMessageMapper.toPromptRequest(request);
390387

src/main/java/io/github/easy4j/opencode/api/OpenCodeChatClient.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io.github.easy4j.opencode.api.mapper.ChatMessageMapper;
77
import io.github.easy4j.opencode.api.model.ChatRequest;
88
import io.github.easy4j.opencode.api.model.ChatResponse;
9-
import io.github.easy4j.opencode.api.model.ChatStreamingResponse;
9+
import io.github.easy4j.opencode.api.sse.StreamingChatResponse;
1010
import io.github.easy4j.opencode.api.model.Event;
1111
import io.github.easy4j.opencode.api.model.PromptRequest;
1212
import io.github.easy4j.opencode.api.model.PromptResult;
@@ -78,22 +78,22 @@ public ChatResponse chatCompletionWithSession(ChatRequest request, String sessio
7878
return ChatMessageMapper.toChatResponse(result);
7979
}
8080

81-
public ChatStreamingResponse chatCompletionStream(ChatRequest request, String sessionKey) {
81+
public StreamingChatResponse chatCompletionStream(ChatRequest request, String sessionKey) {
8282
return chatCompletionStream(request, sessionKey, null, null);
8383
}
8484

85-
public ChatStreamingResponse chatCompletionStream(ChatRequest request, String sessionKey,
85+
public StreamingChatResponse chatCompletionStream(ChatRequest request, String sessionKey,
8686
OpenCodeRequestContext context) {
8787
return chatCompletionStream(request, sessionKey, context, null);
8888
}
8989

9090
/** 在事件订阅启动前绑定增量回调,避免丢失首批分片。 */
91-
public ChatStreamingResponse chatCompletionStream(ChatRequest request, String sessionKey,
91+
public StreamingChatResponse chatCompletionStream(ChatRequest request, String sessionKey,
9292
OpenCodeRequestContext context,
9393
Consumer<String> deltaConsumer) {
9494
String sessionId = ensureSession(sessionKey, context);
9595
PromptRequest promptRequest = ChatMessageMapper.toPromptRequest(request);
96-
ChatStreamingResponse stream = new ChatStreamingResponse().onDelta(deltaConsumer);
96+
StreamingChatResponse stream = new StreamingChatResponse().onDelta(deltaConsumer);
9797
OpenCodeSseClient.QueueSubscription subscription = eventClient.subscribeQueueSubscription(context);
9898
BlockingQueue<Event> queue = subscription.getQueue();
9999

@@ -119,7 +119,7 @@ public ChatStreamingResponse chatCompletionStream(ChatRequest request, String se
119119

120120
private void consumeEvents(String sessionId, BlockingQueue<Event> queue,
121121
OpenCodeSseClient.QueueSubscription subscription,
122-
ChatStreamingResponse stream) {
122+
StreamingChatResponse stream) {
123123
try {
124124
long timeoutMillis = Math.max(1L, config.getReadTimeoutMillis());
125125
long deadline = System.currentTimeMillis() + timeoutMillis;
Lines changed: 4 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.easy4j.opencode.api.model;
22

3-
import java.util.concurrent.CompletableFuture;
43
import java.util.function.Consumer;
4+
import java.util.concurrent.CompletableFuture;
55

66
/**
77
* Streaming chat response for OpenCode (aligned with Hermes {@code ChatStreamingResponse}).
@@ -14,49 +14,14 @@
1414
* @see ChatRequest
1515
* @see ChatResponse
1616
*/
17-
public class ChatStreamingResponse extends CompletableFuture<String> {
18-
19-
private final StringBuilder content = new StringBuilder();
20-
private Consumer<String> deltaConsumer;
17+
@Deprecated
18+
public class ChatStreamingResponse extends io.github.easy4j.opencode.api.sse.StreamingChatResponse {
2119

2220
/**
2321
* 注册增量文本回调,每收到一段 delta 触发一次。
2422
*/
2523
public ChatStreamingResponse onDelta(Consumer<String> consumer) {
26-
this.deltaConsumer = consumer;
24+
super.onDelta(consumer);
2725
return this;
2826
}
29-
30-
/**
31-
* 接收一段增量文本。
32-
*/
33-
public void acceptDelta(String delta) {
34-
if (delta != null && !delta.isEmpty()) {
35-
content.append(delta);
36-
if (deltaConsumer != null) {
37-
deltaConsumer.accept(delta);
38-
}
39-
}
40-
}
41-
42-
/**
43-
* 流结束,完成 future。
44-
*/
45-
public void finish() {
46-
complete(content.toString());
47-
}
48-
49-
/**
50-
* 流异常,异常完成 future。
51-
*/
52-
public void fail(Throwable error) {
53-
completeExceptionally(error);
54-
}
55-
56-
/**
57-
* 获取已累积的完整文本。
58-
*/
59-
public String getAccumulatedContent() {
60-
return content.toString();
61-
}
6227
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package io.github.easy4j.opencode.api.sse;
2+
3+
import java.util.concurrent.CompletableFuture;
4+
import java.util.function.Consumer;
5+
6+
/**
7+
* OpenCode 流式聊天响应,逐段回调并在结束时返回累积全文。
8+
*/
9+
public class StreamingChatResponse extends CompletableFuture<String> {
10+
11+
private final StringBuilder content = new StringBuilder();
12+
private Consumer<String> deltaConsumer;
13+
14+
public StreamingChatResponse onDelta(Consumer<String> consumer) {
15+
this.deltaConsumer = consumer;
16+
return this;
17+
}
18+
19+
public void acceptDelta(String delta) {
20+
if (delta != null && !delta.isEmpty()) {
21+
content.append(delta);
22+
if (deltaConsumer != null) {
23+
deltaConsumer.accept(delta);
24+
}
25+
}
26+
}
27+
28+
public void finish() {
29+
complete(content.toString());
30+
}
31+
32+
public void fail(Throwable error) {
33+
completeExceptionally(error);
34+
}
35+
36+
public String getAccumulatedContent() {
37+
return content.toString();
38+
}
39+
}

src/test/java/io/github/easy4j/opencode/OpenCodeChatClientArchitectureTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import io.github.easy4j.opencode.api.OpenCodeChatClient;
44
import io.github.easy4j.opencode.api.OpenCodeHttpClient;
5+
import io.github.easy4j.opencode.api.sse.StreamingChatResponse;
56
import org.junit.jupiter.api.Test;
67

78
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -19,4 +20,12 @@ void shouldExposeUnifiedConfigAndChatScenarioClient() {
1920
assertEquals(OpenCodeHttpClient.class, client.getClass().getSuperclass());
2021
}
2122
}
23+
24+
@Test
25+
void shouldExposeStreamingResponseUnderSsePackage() {
26+
StreamingChatResponse response = new StreamingChatResponse();
27+
response.acceptDelta("hello");
28+
response.finish();
29+
assertEquals("hello", response.join());
30+
}
2231
}

0 commit comments

Comments
 (0)