Skip to content

Commit b6cff84

Browse files
authored
Merge branch 'main' into feat/tool-schema-support
2 parents 8655136 + 198da7f commit b6cff84

13 files changed

Lines changed: 1260 additions & 30 deletions

File tree

agentscope-core/src/main/java/io/agentscope/core/formatter/dashscope/dto/DashScopeRequest.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package io.agentscope.core.formatter.dashscope.dto;
1717

18+
import com.fasterxml.jackson.annotation.JsonIgnore;
1819
import com.fasterxml.jackson.annotation.JsonInclude;
1920
import com.fasterxml.jackson.annotation.JsonProperty;
21+
import io.agentscope.core.model.EndpointType;
2022

2123
/**
2224
* DashScope API request DTO.
@@ -53,12 +55,23 @@ public class DashScopeRequest {
5355
@JsonProperty("parameters")
5456
private DashScopeParameters parameters;
5557

56-
public DashScopeRequest() {}
58+
/**
59+
* The endpoint type for endpoint selection (not serialized to JSON).
60+
*
61+
* <p>This is an internal field used to determine which DashScope API endpoint to use.
62+
* It does not get sent to the API.
63+
*/
64+
@JsonIgnore private EndpointType endpointType;
65+
66+
public DashScopeRequest() {
67+
this.endpointType = EndpointType.AUTO;
68+
}
5769

5870
public DashScopeRequest(String model, DashScopeInput input, DashScopeParameters parameters) {
5971
this.model = model;
6072
this.input = input;
6173
this.parameters = parameters;
74+
this.endpointType = EndpointType.AUTO;
6275
}
6376

6477
public String getModel() {
@@ -85,6 +98,24 @@ public void setParameters(DashScopeParameters parameters) {
8598
this.parameters = parameters;
8699
}
87100

101+
/**
102+
* Gets the endpoint type for endpoint selection.
103+
*
104+
* @return the endpoint type (defaults to AUTO)
105+
*/
106+
public EndpointType getEndpointType() {
107+
return endpointType;
108+
}
109+
110+
/**
111+
* Sets the endpoint type for endpoint selection.
112+
*
113+
* @param endpointType the endpoint type
114+
*/
115+
public void setEndpointType(EndpointType endpointType) {
116+
this.endpointType = endpointType;
117+
}
118+
88119
public static Builder builder() {
89120
return new Builder();
90121
}
@@ -93,6 +124,7 @@ public static class Builder {
93124
private String model;
94125
private DashScopeInput input;
95126
private DashScopeParameters parameters;
127+
private EndpointType endpointType = EndpointType.AUTO;
96128

97129
public Builder model(String model) {
98130
this.model = model;
@@ -109,8 +141,21 @@ public Builder parameters(DashScopeParameters parameters) {
109141
return this;
110142
}
111143

144+
/**
145+
* Sets the endpoint type for endpoint selection.
146+
*
147+
* @param endpointType the endpoint type
148+
* @return this builder
149+
*/
150+
public Builder endpointType(EndpointType endpointType) {
151+
this.endpointType = endpointType;
152+
return this;
153+
}
154+
112155
public DashScopeRequest build() {
113-
return new DashScopeRequest(model, input, parameters);
156+
DashScopeRequest request = new DashScopeRequest(model, input, parameters);
157+
request.setEndpointType(endpointType);
158+
return request;
114159
}
115160
}
116161
}

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

Lines changed: 79 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,8 @@
3737
* <p>This implementation uses direct HTTP calls to DashScope API via OkHttp,
3838
* without depending on the DashScope Java SDK.
3939
*
40-
* <p>Supports both text and vision models through automatic endpoint routing:
41-
* <ul>
42-
* <li>Vision models (names starting with "qvq" or containing "-vl") use MultiModalGeneration API
43-
* <li>Text models use TextGeneration API
44-
* </ul>
40+
* <p>Supports both text and vision models through automatic endpoint routing.
41+
* Use {@link EndpointType} to explicitly control the endpoint selection.
4542
*
4643
* <p>Features:
4744
* <ul>
@@ -60,20 +57,67 @@ public class DashScopeChatModel extends ChatModelBase {
6057
private final boolean stream;
6158
private final Boolean enableThinking; // nullable
6259
private final Boolean enableSearch; // nullable
60+
private final EndpointType endpointType;
6361
private final GenerateOptions defaultOptions;
6462
private final Formatter<DashScopeMessage, DashScopeResponse, DashScopeRequest> formatter;
6563

6664
// HTTP client for API calls
6765
private final DashScopeHttpClient httpClient;
6866

6967
/**
70-
* Creates a new DashScope chat model instance.
68+
* Creates a new DashScope chat model instance with automatic API type detection.
69+
*
70+
* <p>This constructor maintains backward compatibility. API type defaults to AUTO,
71+
* which detects the endpoint based on model name.
72+
*
73+
* @param apiKey the API key for DashScope authentication
74+
* @param modelName the model name (e.g., "qwen-max", "qwen-vl-plus")
75+
* @param stream whether streaming should be enabled (ignored if enableThinking is true)
76+
* @param enableThinking whether thinking mode should be enabled (null for disabled)
77+
* @param enableSearch whether search enhancement should be enabled (null for disabled)
78+
* @param defaultOptions default generation options (null for defaults)
79+
* @param baseUrl custom base URL for DashScope API (null for default)
80+
* @param formatter the message formatter to use (null for default DashScope formatter)
81+
* @param httpTransport custom HTTP transport (null for default from factory)
82+
* @param publicKeyId the RSA public key ID for encryption (null to disable encryption)
83+
* @param publicKey the RSA public key for encryption (Base64-encoded, null to disable encryption)
84+
*/
85+
public DashScopeChatModel(
86+
String apiKey,
87+
String modelName,
88+
boolean stream,
89+
Boolean enableThinking,
90+
Boolean enableSearch,
91+
GenerateOptions defaultOptions,
92+
String baseUrl,
93+
Formatter<DashScopeMessage, DashScopeResponse, DashScopeRequest> formatter,
94+
HttpTransport httpTransport,
95+
String publicKeyId,
96+
String publicKey) {
97+
this(
98+
apiKey,
99+
modelName,
100+
stream,
101+
enableThinking,
102+
enableSearch,
103+
null,
104+
defaultOptions,
105+
baseUrl,
106+
formatter,
107+
httpTransport,
108+
publicKeyId,
109+
publicKey);
110+
}
111+
112+
/**
113+
* Creates a new DashScope chat model instance with explicit API type.
71114
*
72115
* @param apiKey the API key for DashScope authentication
73116
* @param modelName the model name (e.g., "qwen-max", "qwen-vl-plus")
74117
* @param stream whether streaming should be enabled (ignored if enableThinking is true)
75118
* @param enableThinking whether thinking mode should be enabled (null for disabled)
76119
* @param enableSearch whether search enhancement should be enabled (null for disabled)
120+
* @param endpointType the endpoint type to use (null for AUTO detection)
77121
* @param defaultOptions default generation options (null for defaults)
78122
* @param baseUrl custom base URL for DashScope API (null for default)
79123
* @param formatter the message formatter to use (null for default DashScope formatter)
@@ -87,6 +131,7 @@ public DashScopeChatModel(
87131
boolean stream,
88132
Boolean enableThinking,
89133
Boolean enableSearch,
134+
EndpointType endpointType,
90135
GenerateOptions defaultOptions,
91136
String baseUrl,
92137
Formatter<DashScopeMessage, DashScopeResponse, DashScopeRequest> formatter,
@@ -103,6 +148,7 @@ public DashScopeChatModel(
103148
this.stream = enableThinking != null && enableThinking ? true : stream;
104149
this.enableThinking = enableThinking;
105150
this.enableSearch = enableSearch;
151+
this.endpointType = endpointType != null ? endpointType : EndpointType.AUTO;
106152
this.defaultOptions =
107153
defaultOptions != null ? defaultOptions : GenerateOptions.builder().build();
108154
this.formatter = formatter != null ? formatter : new DashScopeChatFormatter();
@@ -150,8 +196,12 @@ protected Flux<ChatResponse> doStream(
150196
List<Msg> messages, List<ToolSchema> tools, GenerateOptions options) {
151197

152198
if (log.isDebugEnabled()) {
153-
boolean useMultimodal = httpClient.requiresMultimodalApi(modelName);
154-
log.debug("DashScope API call: model={}, multimodal={}", modelName, useMultimodal);
199+
boolean useMultimodal = httpClient.requiresMultimodalApi(modelName, endpointType);
200+
log.debug(
201+
"DashScope API call: model={}, endpointType={}, multimodal={}",
202+
modelName,
203+
endpointType,
204+
useMultimodal);
155205
}
156206

157207
Flux<ChatResponse> responseFlux = streamWithHttpClient(messages, tools, options);
@@ -169,7 +219,7 @@ protected Flux<ChatResponse> doStream(
169219
private Flux<ChatResponse> streamWithHttpClient(
170220
List<Msg> messages, List<ToolSchema> tools, GenerateOptions options) {
171221
Instant start = Instant.now();
172-
boolean useMultimodal = httpClient.requiresMultimodalApi(modelName);
222+
boolean useMultimodal = httpClient.requiresMultimodalApi(modelName, endpointType);
173223

174224
// Merge options with defaultOptions (options takes precedence)
175225
GenerateOptions effectiveOptions = GenerateOptions.mergeOptions(options, defaultOptions);
@@ -218,6 +268,9 @@ private Flux<ChatResponse> streamWithHttpClient(
218268
// Apply thinking mode if enabled
219269
applyThinkingMode(request, effectiveOptions);
220270

271+
// Set endpoint type for endpoint selection
272+
request.setEndpointType(endpointType);
273+
221274
if (stream) {
222275
// Streaming mode
223276
return httpClient.stream(
@@ -298,6 +351,7 @@ public static class Builder {
298351
private boolean stream = true;
299352
private Boolean enableThinking;
300353
private Boolean enableSearch;
354+
private EndpointType endpointType;
301355
private GenerateOptions defaultOptions = null;
302356
private String baseUrl;
303357
private Formatter<DashScopeMessage, DashScopeResponse, DashScopeRequest> formatter;
@@ -318,14 +372,11 @@ public Builder apiKey(String apiKey) {
318372
/**
319373
* Sets the model name to use.
320374
*
321-
* <p>The model name determines which API is used:
322-
* <ul>
323-
* <li>Vision models (qvq* or *-vl*) → MultiModal API</li>
324-
* <li>Text models → Text Generation API</li>
325-
* </ul>
375+
* <p>The model name determines which API is used when endpointType is AUTO.
326376
*
327377
* @param modelName the model name (e.g., "qwen-max", "qwen-vl-plus")
328378
* @return this builder instance
379+
* @see DashScopeHttpClient#isMultimodalModel(String)
329380
*/
330381
public Builder modelName(String modelName) {
331382
this.modelName = modelName;
@@ -374,6 +425,19 @@ public Builder enableSearch(Boolean enableSearch) {
374425
return this;
375426
}
376427

428+
/**
429+
* Sets the endpoint type to use for endpoint routing.
430+
*
431+
* @param endpointType the endpoint type to use (null for AUTO)
432+
* @return this builder instance
433+
* @see EndpointType
434+
* @see DashScopeHttpClient#isMultimodalModel(String)
435+
*/
436+
public Builder endpointType(EndpointType endpointType) {
437+
this.endpointType = endpointType;
438+
return this;
439+
}
440+
377441
/**
378442
* Sets the default generation options.
379443
*
@@ -503,6 +567,7 @@ public DashScopeChatModel build() {
503567
stream,
504568
enableThinking,
505569
enableSearch,
570+
endpointType,
506571
effectiveOptions,
507572
baseUrl,
508573
formatter,

0 commit comments

Comments
 (0)