Skip to content

Commit 1be6194

Browse files
committed
sync: cherry-pick changes from feature/3.0.x
1 parent 332a785 commit 1be6194

78 files changed

Lines changed: 3783 additions & 155 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package io.github.easy4j.opencode;
2+
3+
/**
4+
* Binds a business-layer cancellation signal to a single OpenCode HTTP call.
5+
*
6+
* <p>Implementations allow callers to register a cancellation callback that will be invoked
7+
* when the underlying HTTP call should be aborted. The {@link #onCancel(Runnable)} method
8+
* returns an {@link AutoCloseable} that, when closed, unregisters the callback.</p>
9+
*
10+
* @author [@Loong Wan](https://github.com/loong10k)
11+
* @since 3.0.0
12+
* @see io.github.easy4j.opencode.api.OpenCodeHttpClient
13+
*/
14+
@FunctionalInterface
15+
public interface HttpCallCancellation {
16+
17+
/**
18+
* Registers a cancellation callback and returns a handle to unregister it.
19+
*
20+
* @param callback the runnable to invoke when cancellation is requested
21+
* @return an {@link AutoCloseable} that unregisters the callback when closed
22+
*/
23+
AutoCloseable onCancel(Runnable callback);
24+
25+
/**
26+
* Returns whether this cancellation has been triggered.
27+
*
28+
* @return {@code true} if cancellation has been requested, {@code false} otherwise
29+
*/
30+
default boolean isCancelled() {
31+
return false;
32+
}
33+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package io.github.easy4j.opencode;
2+
3+
/**
4+
* HTTP 对话响应模式。
5+
*/
6+
public enum HttpResponseMode {
7+
8+
/** 等待完整响应后一次性返回。 */
9+
BLOCKING,
10+
11+
/** 消费 Provider SSE 并逐段回调。 */
12+
STREAM,
13+
14+
/** 由调用方根据结构化输出等请求特征选择。 */
15+
AUTO
16+
}

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

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,16 @@
33
import lombok.Data;
44

55
/**
6-
* OpenCode 本地 CLI 客户端配置。
7-
* <p>
8-
* 涵盖本地 {@code opencode} 可执行文件路径、超时、工作目录等 CLI 运行时设置。
9-
* </p>
6+
* Configuration for the local OpenCode CLI subsystem.
7+
*
8+
* <p>Covers local {@code opencode} executable path, timeouts, working directory,
9+
* and other CLI runtime settings. Can be mapped from Spring
10+
* {@code @ConfigurationProperties}.</p>
11+
*
12+
* @author [@Loong Wan](https://github.com/loong10k)
13+
* @since 3.0.0
14+
* @see OpenCodeClient
15+
* @see OpenCodeClientConfig
1016
*/
1117
@Data
1218
public class OpenCodeCliConfig {

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

Lines changed: 125 additions & 36 deletions
Large diffs are not rendered by default.

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,17 @@
33
import lombok.Data;
44

55
/**
6-
* OpenCode 客户端统一配置(纯 POJO,可与 Spring {@code @ConfigurationProperties} 映射)。
7-
* <p>
8-
* 组合 {@link OpenCodeHttpClientConfig}(HTTP/Server 相关)与 {@link OpenCodeCliConfig}(本地 CLI 相关),
9-
* 作为 {@link OpenCodeClient} 等统一入口的配置载体。
10-
* </p>
6+
* Unified configuration POJO for the OpenCode client.
7+
*
8+
* <p>Composes {@link OpenCodeHttpClientConfig} (HTTP/Server settings) and
9+
* {@link OpenCodeCliConfig} (local CLI settings). Compatible with Spring
10+
* {@code @ConfigurationProperties} binding.</p>
11+
*
12+
* @author [@Loong Wan](https://github.com/loong10k)
13+
* @since 3.0.0
14+
* @see OpenCodeHttpClientConfig
15+
* @see OpenCodeCliConfig
16+
* @see OpenCodeClient
1117
*/
1218
@Data
1319
public class OpenCodeClientConfig {

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

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@
33
import lombok.Data;
44

55
/**
6-
* OpenCode HTTP Server 客户端配置。
7-
* <p>
8-
* 涵盖 Server 根地址、Basic Auth、TLS、HTTP 超时及默认模型等网络相关设置。
9-
* </p>
6+
* Configuration for the OpenCode HTTP Server client.
7+
*
8+
* <p>Covers server base URL, Basic Auth, TLS, HTTP timeouts, connection pool sizing,
9+
* streaming thread pool, and default model/agent settings.</p>
10+
*
11+
* @author [@Loong Wan](https://github.com/loong10k)
12+
* @since 3.0.0
13+
* @see OpenCodeHttpClient
14+
* @see OpenCodeOkHttpClientFactory
1015
*/
1116
@Data
1217
public class OpenCodeHttpClientConfig {
1318

19+
/** 对话响应模式,默认保持兼容的完整响应模式。 */
20+
private HttpResponseMode mode = HttpResponseMode.BLOCKING;
21+
1422
/**
1523
* 是否启用 HTTP 子系统。
1624
* <p>为 false 时跳过 HTTP 客户端初始化和检查。</p>
@@ -31,7 +39,7 @@ public class OpenCodeHttpClientConfig {
3139
/**
3240
* OpenCode Server 根地址,例如 {@code http://localhost:4096}。
3341
*/
34-
private String serverUrl = "http://localhost:4096";
42+
private String baseUrl = "http://localhost:4096";
3543

3644
/**
3745
* HTTP Basic Auth 用户名(对应 {@code OPENCODE_SERVER_USERNAME},默认 {@code opencode})。
@@ -55,6 +63,56 @@ public class OpenCodeHttpClientConfig {
5563
*/
5664
private int readTimeoutMillis = 300_000;
5765

66+
/**
67+
* 写入超时(毫秒)。
68+
*/
69+
private int writeTimeoutMillis = 120_000;
70+
71+
/**
72+
* 整个调用超时(毫秒);0 表示不额外限制。
73+
*/
74+
private int callTimeoutMillis;
75+
76+
/**
77+
* 连接池最大空闲连接数。
78+
*/
79+
private int maxIdleConnections = 32;
80+
81+
/**
82+
* 空闲连接保活时间(毫秒)。
83+
*/
84+
private long keepAliveDurationMillis = 300_000L;
85+
86+
/**
87+
* 异步请求最大并发数。
88+
*/
89+
private int maxRequests = 128;
90+
91+
/**
92+
* 单主机异步请求最大并发数。
93+
*/
94+
private int maxRequestsPerHost = 128;
95+
96+
/** 流式事件处理线程数。 */
97+
private int streamCorePoolSize = 32;
98+
99+
/** 流式事件处理最大线程数。 */
100+
private int streamMaxPoolSize = 32;
101+
102+
/** 流式事件处理有界队列容量。 */
103+
private int streamQueueCapacity = 128;
104+
105+
/** 流式事件处理线程空闲保活时间(毫秒)。 */
106+
private long streamKeepAliveMillis = 60_000L;
107+
108+
/** 单个流式订阅的事件缓存上限。 */
109+
private int streamEventQueueCapacity = 1_024;
110+
111+
/**
112+
* 遇到失效连接等传输故障时是否允许 OkHttp 自动恢复。
113+
*/
114+
private boolean retryOnConnectionFailure = true;
115+
58116
/**
59117
* 是否校验 HTTPS 证书;为 false 时关闭校验(仅建议开发环境)。
60118
*/
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
package io.github.easy4j.opencode;
2+
3+
import okhttp3.ConnectionPool;
4+
import okhttp3.Dispatcher;
5+
import okhttp3.OkHttpClient;
6+
7+
import java.util.Objects;
8+
import java.util.concurrent.TimeUnit;
9+
10+
/**
11+
* Factory for creating {@link OkHttpClient} instances used by the OpenCode SDK in standalone mode.
12+
*
13+
* <p>When a Spring container already provides an external {@link OkHttpClient}, the injection
14+
* constructors should be used instead and this factory will not participate.</p>
15+
*
16+
* @author [@Loong Wan](https://github.com/loong10k)
17+
* @since 3.0.0
18+
* @see OpenCodeHttpClientConfig
19+
*/
20+
public final class OpenCodeOkHttpClientFactory {
21+
22+
private OpenCodeOkHttpClientFactory() {
23+
}
24+
25+
/**
26+
* 根据 OpenCode HTTP 配置创建客户端。
27+
*
28+
* @param config HTTP 配置
29+
* @return SDK 自主管理的 OkHttpClient
30+
*/
31+
public static OkHttpClient create(OpenCodeHttpClientConfig config) {
32+
Objects.requireNonNull(config, "config");
33+
Dispatcher dispatcher = new Dispatcher();
34+
dispatcher.setMaxRequests(Math.max(1, config.getMaxRequests()));
35+
dispatcher.setMaxRequestsPerHost(Math.max(1, config.getMaxRequestsPerHost()));
36+
ConnectionPool connectionPool = new ConnectionPool(
37+
Math.max(1, config.getMaxIdleConnections()),
38+
Math.max(1L, config.getKeepAliveDurationMillis()),
39+
TimeUnit.MILLISECONDS);
40+
OkHttpClient.Builder builder = new OkHttpClient.Builder()
41+
.dispatcher(dispatcher)
42+
.connectionPool(connectionPool)
43+
.connectTimeout(Math.max(1, config.getConnectTimeoutMillis()), TimeUnit.MILLISECONDS)
44+
.readTimeout(Math.max(0, config.getReadTimeoutMillis()), TimeUnit.MILLISECONDS)
45+
.writeTimeout(Math.max(1, config.getWriteTimeoutMillis()), TimeUnit.MILLISECONDS)
46+
.callTimeout(Math.max(0, config.getCallTimeoutMillis()), TimeUnit.MILLISECONDS)
47+
.retryOnConnectionFailure(config.isRetryOnConnectionFailure());
48+
if (!config.isVerifySsl()) {
49+
builder.hostnameVerifier((hostname, session) -> true);
50+
}
51+
return builder.build();
52+
}
53+
54+
/**
55+
* 释放 SDK 自建客户端资源。
56+
*
57+
* @param client SDK 自建客户端
58+
*/
59+
public static void shutdown(OkHttpClient client) {
60+
if (Objects.isNull(client)) {
61+
return;
62+
}
63+
client.dispatcher().cancelAll();
64+
client.connectionPool().evictAll();
65+
client.dispatcher().executorService().shutdown();
66+
}
67+
}

0 commit comments

Comments
 (0)