Skip to content

Commit 68e7fb1

Browse files
guanxucyaohuitc
authored andcommitted
fix(dashscope): Missing additional headers and params for DashScopeHttpClient (agentscope-ai#481)
1 parent 6f9c013 commit 68e7fb1

File tree

4 files changed

+172
-31
lines changed

4 files changed

+172
-31
lines changed

agentscope-core/src/main/java/io/agentscope/core/model/DashScopeChatModel.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,14 +230,23 @@ private Flux<ChatResponse> streamWithHttpClient(
230230

231231
if (stream) {
232232
// Streaming mode
233-
return httpClient.stream(request)
233+
return httpClient.stream(
234+
request,
235+
effectiveOptions.getAdditionalHeaders(),
236+
effectiveOptions.getAdditionalBodyParams(),
237+
effectiveOptions.getAdditionalQueryParams())
234238
.map(response -> formatter.parseResponse(response, start));
235239
} else {
236240
// Non-streaming mode
237241
return Flux.defer(
238242
() -> {
239243
try {
240-
DashScopeResponse response = httpClient.call(request);
244+
DashScopeResponse response =
245+
httpClient.call(
246+
request,
247+
effectiveOptions.getAdditionalHeaders(),
248+
effectiveOptions.getAdditionalBodyParams(),
249+
effectiveOptions.getAdditionalQueryParams());
241250
ChatResponse chatResponse = formatter.parseResponse(response, start);
242251
return Flux.just(chatResponse);
243252
} catch (Exception e) {

agentscope-core/src/main/java/io/agentscope/core/model/DashScopeHttpClient.java

Lines changed: 0 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -109,17 +109,6 @@ public DashScopeHttpClient(String apiKey) {
109109
this(apiKey, null);
110110
}
111111

112-
/**
113-
* Make a synchronous API call.
114-
*
115-
* @param request the DashScope request
116-
* @return the DashScope response
117-
* @throws DashScopeHttpException if the request fails
118-
*/
119-
public DashScopeResponse call(DashScopeRequest request) {
120-
return call(request, null, null, null);
121-
}
122-
123112
/**
124113
* Make a synchronous API call with additional HTTP parameters.
125114
*
@@ -180,16 +169,6 @@ public DashScopeResponse call(
180169
}
181170
}
182171

183-
/**
184-
* Make a streaming API call.
185-
*
186-
* @param request the DashScope request
187-
* @return a Flux of DashScope responses (one per SSE event)
188-
*/
189-
public Flux<DashScopeResponse> stream(DashScopeRequest request) {
190-
return stream(request, null, null, null);
191-
}
192-
193172
/**
194173
* Make a streaming API call with additional HTTP parameters.
195174
*

agentscope-core/src/test/java/io/agentscope/core/model/DashScopeChatModelTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,18 @@
2828
import io.agentscope.core.formatter.dashscope.dto.DashScopeParameters;
2929
import io.agentscope.core.formatter.dashscope.dto.DashScopeRequest;
3030
import io.agentscope.core.message.Msg;
31+
import io.agentscope.core.message.MsgRole;
32+
import io.agentscope.core.message.TextBlock;
3133
import io.agentscope.core.model.test.ModelTestUtils;
34+
import io.agentscope.core.model.transport.OkHttpTransport;
3235
import java.lang.reflect.InvocationTargetException;
3336
import java.lang.reflect.Method;
3437
import java.util.ArrayList;
3538
import java.util.List;
39+
import java.util.Map;
40+
import okhttp3.mockwebserver.MockResponse;
41+
import okhttp3.mockwebserver.MockWebServer;
42+
import okhttp3.mockwebserver.RecordedRequest;
3643
import org.junit.jupiter.api.BeforeEach;
3744
import org.junit.jupiter.api.DisplayName;
3845
import org.junit.jupiter.api.Tag;
@@ -420,6 +427,95 @@ void testWithThinkingMode() {
420427
assertNotNull(thinkingModel);
421428
}
422429

430+
@Test
431+
@DisplayName("DashScope chat model stream with additional headers and params")
432+
void testDoStreamWithAdditionHeadersAndParams() throws Exception {
433+
MockWebServer mockServer = new MockWebServer();
434+
mockServer.start();
435+
436+
mockServer.enqueue(
437+
new MockResponse()
438+
.setResponseCode(200)
439+
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
440+
.setHeader("Content-Type", "application/json"));
441+
442+
DashScopeChatModel chatModel =
443+
DashScopeChatModel.builder().apiKey(mockApiKey).modelName("qwen-plus").stream(true)
444+
.enableThinking(true)
445+
.enableSearch(true)
446+
.baseUrl(mockServer.url("/").toString().replaceAll("/$", ""))
447+
.httpTransport(OkHttpTransport.builder().build())
448+
.build();
449+
450+
chatModel
451+
.doStream(
452+
List.of(
453+
Msg.builder()
454+
.role(MsgRole.USER)
455+
.content(TextBlock.builder().text("test").build())
456+
.build()),
457+
List.of(),
458+
GenerateOptions.builder()
459+
.additionalHeaders(Map.of("custom", "custom-header"))
460+
.additionalBodyParams(Map.of("custom", "custom-body"))
461+
.additionalQueryParams(Map.of("custom", "custom-query"))
462+
.build())
463+
.blockLast();
464+
465+
RecordedRequest recorded = mockServer.takeRequest();
466+
assertEquals("custom-header", recorded.getHeader("custom"));
467+
assertEquals(
468+
DashScopeHttpClient.TEXT_GENERATION_ENDPOINT + "?custom=custom-query",
469+
recorded.getPath());
470+
assertTrue(recorded.getBody().readUtf8().contains("\"custom\":\"custom-body\""));
471+
472+
mockServer.close();
473+
}
474+
475+
@Test
476+
@DisplayName("DashScope chat model non-stream with additional headers and params")
477+
void testDoNonStreamWithAdditionHeadersAndParams() throws Exception {
478+
MockWebServer mockServer = new MockWebServer();
479+
mockServer.start();
480+
481+
mockServer.enqueue(
482+
new MockResponse()
483+
.setResponseCode(200)
484+
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
485+
.setHeader("Content-Type", "application/json"));
486+
487+
DashScopeChatModel chatModel =
488+
DashScopeChatModel.builder().apiKey(mockApiKey).modelName("qwen-plus").stream(true)
489+
.stream(false)
490+
.baseUrl(mockServer.url("/").toString().replaceAll("/$", ""))
491+
.httpTransport(OkHttpTransport.builder().build())
492+
.build();
493+
494+
chatModel
495+
.doStream(
496+
List.of(
497+
Msg.builder()
498+
.role(MsgRole.USER)
499+
.content(TextBlock.builder().text("test").build())
500+
.build()),
501+
List.of(),
502+
GenerateOptions.builder()
503+
.additionalHeaders(Map.of("custom", "custom-header"))
504+
.additionalBodyParams(Map.of("custom", "custom-body"))
505+
.additionalQueryParams(Map.of("custom", "custom-query"))
506+
.build())
507+
.blockLast();
508+
509+
RecordedRequest recorded = mockServer.takeRequest();
510+
assertEquals("custom-header", recorded.getHeader("custom"));
511+
assertEquals(
512+
DashScopeHttpClient.TEXT_GENERATION_ENDPOINT + "?custom=custom-query",
513+
recorded.getPath());
514+
assertTrue(recorded.getBody().readUtf8().contains("\"custom\":\"custom-body\""));
515+
516+
mockServer.close();
517+
}
518+
423519
@Test
424520
@DisplayName("DashScope chat model apply thinking mode")
425521
void testApplyThinkingMode() {

agentscope-core/src/test/java/io/agentscope/core/model/DashScopeHttpClientTest.java

Lines changed: 65 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@
2828
import io.agentscope.core.formatter.dashscope.dto.DashScopeRequest;
2929
import io.agentscope.core.formatter.dashscope.dto.DashScopeResponse;
3030
import java.util.ArrayList;
31+
import java.util.HashMap;
3132
import java.util.List;
33+
import java.util.Map;
3234
import okhttp3.mockwebserver.MockResponse;
3335
import okhttp3.mockwebserver.MockWebServer;
3436
import okhttp3.mockwebserver.RecordedRequest;
@@ -137,7 +139,7 @@ void testCallTextGenerationApi() throws Exception {
137139

138140
DashScopeRequest request = createTestRequest("qwen-plus", "Hello");
139141

140-
DashScopeResponse response = client.call(request);
142+
DashScopeResponse response = client.call(request, null, null, null);
141143

142144
assertNotNull(response);
143145
assertEquals("test-request-id", response.getRequestId());
@@ -181,7 +183,7 @@ void testCallMultimodalApi() throws Exception {
181183

182184
DashScopeRequest request = createTestRequest("qwen-vl-max", "What's in this image?");
183185

184-
DashScopeResponse response = client.call(request);
186+
DashScopeResponse response = client.call(request, null, null, null);
185187

186188
assertNotNull(response);
187189
assertEquals("multimodal-request-id", response.getRequestId());
@@ -209,7 +211,7 @@ void testStreamTextGenerationApi() {
209211
DashScopeRequest request = createTestRequest("qwen-plus", "Hi");
210212

211213
List<DashScopeResponse> responses = new ArrayList<>();
212-
StepVerifier.create(client.stream(request))
214+
StepVerifier.create(client.stream(request, null, null, null))
213215
.recordWith(() -> responses)
214216
.expectNextCount(2)
215217
.verifyComplete();
@@ -239,7 +241,7 @@ void testStreamMultimodalApi() {
239241

240242
DashScopeRequest request = createTestRequest("qwen-vl-max", "Describe image");
241243

242-
StepVerifier.create(client.stream(request))
244+
StepVerifier.create(client.stream(request, null, null, null))
243245
.expectNextMatches(
244246
r ->
245247
"I see"
@@ -273,7 +275,7 @@ void testApiErrorHandling() {
273275
DashScopeHttpClient.DashScopeHttpException exception =
274276
assertThrows(
275277
DashScopeHttpClient.DashScopeHttpException.class,
276-
() -> client.call(request));
278+
() -> client.call(request, null, null, null));
277279

278280
assertTrue(exception.getMessage().contains("Invalid API key"));
279281
}
@@ -291,7 +293,7 @@ void testHttpErrorHandling() {
291293
DashScopeHttpClient.DashScopeHttpException exception =
292294
assertThrows(
293295
DashScopeHttpClient.DashScopeHttpException.class,
294-
() -> client.call(request));
296+
() -> client.call(request, null, null, null));
295297

296298
assertEquals(500, exception.getStatusCode());
297299
}
@@ -322,7 +324,7 @@ void testRequestHeaders() throws Exception {
322324
.setHeader("Content-Type", "application/json"));
323325

324326
DashScopeRequest request = createTestRequest("qwen-plus", "test");
325-
client.call(request);
327+
client.call(request, null, null, null);
326328

327329
RecordedRequest recorded = mockServer.takeRequest();
328330
assertEquals("Bearer test-api-key", recorded.getHeader("Authorization"));
@@ -339,7 +341,7 @@ void testStreamingRequestHeaders() throws Exception {
339341
.setHeader("Content-Type", "text/event-stream"));
340342

341343
DashScopeRequest request = createTestRequest("qwen-plus", "test");
342-
client.stream(request).blockLast();
344+
client.stream(request, null, null, null).blockLast();
343345

344346
RecordedRequest recorded = mockServer.takeRequest();
345347
assertEquals("enable", recorded.getHeader("X-DashScope-SSE"));
@@ -482,6 +484,61 @@ void testHeaderOverride() throws Exception {
482484
assertEquals("application/json; charset=utf-8", recorded.getHeader("Content-Type"));
483485
}
484486

487+
@Test
488+
void testCallAdditionalHeadersAndParams() throws Exception {
489+
mockServer.enqueue(
490+
new MockResponse()
491+
.setResponseCode(200)
492+
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
493+
.setHeader("Content-Type", "application/json"));
494+
495+
DashScopeRequest request = createTestRequest("qwen-plus", "test");
496+
// Override the Content-Type header
497+
Map<String, String> additionalHeaders = new HashMap<>();
498+
additionalHeaders.put("custom", "custom-header");
499+
Map<String, Object> additionalBodyParams = new HashMap<>();
500+
additionalBodyParams.put("custom", "custom-body");
501+
Map<String, String> additionalQueryParams = new HashMap<>();
502+
additionalQueryParams.put("custom", "custom-query");
503+
504+
client.call(request, additionalHeaders, additionalBodyParams, additionalQueryParams);
505+
506+
RecordedRequest recorded = mockServer.takeRequest();
507+
assertEquals("custom-header", recorded.getHeader("custom"));
508+
assertEquals(
509+
DashScopeHttpClient.TEXT_GENERATION_ENDPOINT + "?custom=custom-query",
510+
recorded.getPath());
511+
assertTrue(recorded.getBody().readUtf8().contains("\"custom\":\"custom-body\""));
512+
}
513+
514+
@Test
515+
void testStreamAdditionalHeadersAndParams() throws Exception {
516+
mockServer.enqueue(
517+
new MockResponse()
518+
.setResponseCode(200)
519+
.setBody("{\"request_id\":\"test\",\"output\":{\"choices\":[]}}")
520+
.setHeader("Content-Type", "application/json"));
521+
522+
DashScopeRequest request = createTestRequest("qwen-plus", "test");
523+
// Override the Content-Type header
524+
Map<String, String> additionalHeaders = new HashMap<>();
525+
additionalHeaders.put("custom", "custom-header");
526+
Map<String, Object> additionalBodyParams = new HashMap<>();
527+
additionalBodyParams.put("custom", "custom-value");
528+
Map<String, String> additionalQueryParams = new HashMap<>();
529+
additionalQueryParams.put("custom", "custom-value");
530+
531+
client.stream(request, additionalHeaders, additionalBodyParams, additionalQueryParams)
532+
.blockLast();
533+
534+
RecordedRequest recorded = mockServer.takeRequest();
535+
assertEquals("custom-header", recorded.getHeader("custom"));
536+
assertEquals(
537+
DashScopeHttpClient.TEXT_GENERATION_ENDPOINT + "?custom=custom-value",
538+
recorded.getPath());
539+
assertTrue(recorded.getBody().readUtf8().contains("\"custom\":\"custom-value\""));
540+
}
541+
485542
// ==================== DashScopeHttpException Tests ====================
486543

487544
@Test

0 commit comments

Comments
 (0)