@@ -24,6 +24,7 @@ public class HermesClient implements AutoCloseable {
2424 private final HermesHttpClient httpClient ;
2525 private final HermesSseClient sseClient ;
2626 private final HermesCli cli ;
27+ private final OkHttpClient ownedHttpClient ;
2728
2829 /**
2930 * 使用组合配置构造客户端(推荐方式)。
@@ -32,7 +33,19 @@ public class HermesClient implements AutoCloseable {
3233 * @param config 组合配置,不得为 null
3334 */
3435 public HermesClient (HermesClientConfig config ) {
35- this (config , new ObjectMapper (), new OkHttpClient ());
36+ this (Objects .requireNonNull (config , "config" ).getHttp (), config .getCli (), new ObjectMapper (),
37+ HermesOkHttpClientFactory .create (config .getHttp ()), true );
38+ }
39+
40+ /**
41+ * 使用组合配置和调用方管理的共享 {@link OkHttpClient}。
42+ * <p>适用于直接注入 Spring 容器中由 okhttp3-extension/starter 配置的客户端。</p>
43+ *
44+ * @param config 组合配置
45+ * @param httpClient 外部共享 OkHttpClient
46+ */
47+ public HermesClient (HermesClientConfig config , OkHttpClient httpClient ) {
48+ this (config , new ObjectMapper (), httpClient );
3649 }
3750
3851 /**
@@ -46,7 +59,8 @@ public HermesClient(HermesClientConfig config, ObjectMapper objectMapper, OkHttp
4659 this (Objects .requireNonNull (config , "config" ).getHttp (),
4760 config .getCli (),
4861 objectMapper ,
49- httpClient );
62+ httpClient ,
63+ false );
5064 }
5165
5266 /**
@@ -99,7 +113,19 @@ public HermesClient(HermesCliConfig cliConfig, ObjectMapper objectMapper, OkHttp
99113 * @param cliConfig CLI 配置,不得为 null
100114 */
101115 public HermesClient (HermesHttpClientConfig httpConfig , HermesCliConfig cliConfig ) {
102- this (httpConfig , cliConfig , new ObjectMapper (), new OkHttpClient ());
116+ this (httpConfig , cliConfig , new ObjectMapper (), HermesOkHttpClientFactory .create (httpConfig ), true );
117+ }
118+
119+ /**
120+ * 使用 HTTP/CLI 配置和调用方管理的共享 {@link OkHttpClient}。
121+ *
122+ * @param httpConfig HTTP 配置
123+ * @param cliConfig CLI 配置
124+ * @param httpClient 外部共享 OkHttpClient
125+ */
126+ public HermesClient (HermesHttpClientConfig httpConfig , HermesCliConfig cliConfig ,
127+ OkHttpClient httpClient ) {
128+ this (httpConfig , cliConfig , new ObjectMapper (), httpClient );
103129 }
104130
105131 /**
@@ -112,10 +138,16 @@ public HermesClient(HermesHttpClientConfig httpConfig, HermesCliConfig cliConfig
112138 */
113139 public HermesClient (HermesHttpClientConfig httpConfig , HermesCliConfig cliConfig ,
114140 ObjectMapper objectMapper , OkHttpClient httpClient ) {
141+ this (httpConfig , cliConfig , objectMapper , httpClient , false );
142+ }
143+
144+ private HermesClient (HermesHttpClientConfig httpConfig , HermesCliConfig cliConfig ,
145+ ObjectMapper objectMapper , OkHttpClient httpClient , boolean ownsHttpClient ) {
115146 Objects .requireNonNull (httpConfig , "httpConfig" );
116147 Objects .requireNonNull (cliConfig , "cliConfig" );
117148 Objects .requireNonNull (objectMapper , "objectMapper" );
118149 Objects .requireNonNull (httpClient , "httpClient" );
150+ this .ownedHttpClient = ownsHttpClient ? httpClient : null ;
119151 this .config = new HermesClientConfig ();
120152 copyHttpConfig (httpConfig );
121153 copyCliConfig (cliConfig );
@@ -171,6 +203,7 @@ public HermesClient(HermesClientConfig config, HermesHttpClient httpClient,
171203 this .httpClient = Objects .requireNonNull (httpClient , "httpClient" );
172204 this .sseClient = Objects .requireNonNull (sseClient , "sseClient" );
173205 this .cli = Objects .requireNonNull (cli , "cli" );
206+ this .ownedHttpClient = null ;
174207 }
175208
176209 private void copyHttpConfig (HermesHttpClientConfig src ) {
@@ -181,6 +214,13 @@ private void copyHttpConfig(HermesHttpClientConfig src) {
181214 this .config .getHttp ().setApiKey (src .getApiKey ());
182215 this .config .getHttp ().setConnectTimeoutMillis (src .getConnectTimeoutMillis ());
183216 this .config .getHttp ().setReadTimeoutMillis (src .getReadTimeoutMillis ());
217+ this .config .getHttp ().setWriteTimeoutMillis (src .getWriteTimeoutMillis ());
218+ this .config .getHttp ().setCallTimeoutMillis (src .getCallTimeoutMillis ());
219+ this .config .getHttp ().setMaxIdleConnections (src .getMaxIdleConnections ());
220+ this .config .getHttp ().setKeepAliveDurationMillis (src .getKeepAliveDurationMillis ());
221+ this .config .getHttp ().setMaxRequests (src .getMaxRequests ());
222+ this .config .getHttp ().setMaxRequestsPerHost (src .getMaxRequestsPerHost ());
223+ this .config .getHttp ().setRetryOnConnectionFailure (src .isRetryOnConnectionFailure ());
184224 this .config .getHttp ().setVerifySsl (src .isVerifySsl ());
185225 this .config .getHttp ().setDefaultModel (src .getDefaultModel ());
186226 this .config .getHttp ().setDefaultInstructions (src .getDefaultInstructions ());
@@ -319,10 +359,9 @@ public ChatStreamingResponse chatCompletionStream(ChatRequest request) {
319359 /** Streaming chat completion with Hermes custom headers. */
320360 public ChatStreamingResponse chatCompletionStream (ChatRequest request ,
321361 Map <String , String > headers ) {
322-
323- request .setStream (true );
362+ Objects .requireNonNull (request , "request" );
324363 ChatStreamingResponse stream = new ChatStreamingResponse ();
325- sseClient .subscribeChat (request , headers , stream ::accept , stream ::finish , stream ::fail );
364+ sseClient .subscribeChat (request . withStream () , headers , stream ::accept , stream ::finish , stream ::fail );
326365 return stream ;
327366 }
328367
@@ -392,9 +431,19 @@ public HermesCli cli() {
392431
393432 public HermesClientConfig getConfig () { return config ; }
394433
434+ /**
435+ * 返回 HTTP 与 SSE 共用的 OkHttpClient;HTTP 未启用时返回 null。
436+ *
437+ * @return 实际使用的 OkHttpClient
438+ */
439+ public OkHttpClient getOkHttpClient () {
440+ return httpClient != null ? httpClient .getOkHttpClient () : null ;
441+ }
442+
395443 @ Override
396444 public void close () {
397445 if (httpClient != null ) httpClient .close ();
398446 if (sseClient != null ) sseClient .close ();
447+ HermesOkHttpClientFactory .shutdown (ownedHttpClient );
399448 }
400449}
0 commit comments