diff --git a/pom.xml b/pom.xml
index 4b1b1274..f672ae5b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -40,7 +40,7 @@
DashScope Java SDK
com.alibaba
dashscope-sdk-java
- 2.22.26
+ 2.22.27
8
diff --git a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java
index ad71ae6d..2e58dce7 100644
--- a/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java
+++ b/src/main/java/com/alibaba/dashscope/common/DashScopeResult.java
@@ -9,6 +9,7 @@
import com.alibaba.dashscope.utils.ApiKeywords;
import com.alibaba.dashscope.utils.EncryptionUtils;
import com.alibaba.dashscope.utils.JsonUtils;
+import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.nio.ByteBuffer;
import java.util.List;
@@ -16,7 +17,9 @@
import java.util.stream.Collectors;
import lombok.Data;
import lombok.EqualsAndHashCode;
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
@Data
@EqualsAndHashCode(callSuper = true)
public class DashScopeResult extends Result {
@@ -34,110 +37,37 @@ protected T fromResponse(Protocol protocol, NetworkResponse r
this.setHeaders(changeHeaders(response.getHeaders()));
if (protocol == Protocol.WEBSOCKET) {
if (response.getBinary() == null) {
- JsonObject jsonObject = JsonUtils.parse(response.getMessage());
- if (jsonObject.has(ApiKeywords.HEADER)) {
- JsonObject headers = jsonObject.get(ApiKeywords.HEADER).getAsJsonObject();
- if (headers.has(ApiKeywords.TASKID)) {
- this.setRequestId(headers.get(ApiKeywords.TASKID).getAsString());
- }
- // Extract status_code, code and message from header
- if (headers.has(ApiKeywords.STATUS_CODE)) {
- this.setStatusCode(
- headers.get(ApiKeywords.STATUS_CODE).isJsonNull()
- ? null
- : headers.get(ApiKeywords.STATUS_CODE).getAsInt());
- } else {
- // Set default status code
- this.setStatusCode(200);
- }
- if (headers.has(ApiKeywords.ERROR_CODE)) {
- this.setCode(
- headers.get(ApiKeywords.ERROR_CODE).isJsonNull()
- ? ""
- : headers.get(ApiKeywords.ERROR_CODE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setCode("");
- }
- if (headers.has(ApiKeywords.ERROR_MESSAGE)) {
- this.setMessage(
- headers.get(ApiKeywords.ERROR_MESSAGE).isJsonNull()
- ? ""
- : headers.get(ApiKeywords.ERROR_MESSAGE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setMessage("");
- }
- }
- if (jsonObject.has(ApiKeywords.PAYLOAD)) {
- JsonObject payload = jsonObject.getAsJsonObject(ApiKeywords.PAYLOAD);
- if (payload.has(ApiKeywords.OUTPUT)) {
- this.output =
- payload.get(ApiKeywords.OUTPUT).isJsonNull()
- ? null
- : payload.get(ApiKeywords.OUTPUT);
- }
- if (payload.has(ApiKeywords.USAGE)) {
- this.setUsage(
- payload.get(ApiKeywords.USAGE).isJsonNull()
- ? null
- : payload.get(ApiKeywords.USAGE));
- }
+ String message = response.getMessage();
+ if (message == null || message.isEmpty()) {
+ log.warn(
+ "WebSocket response message is null or empty, httpStatusCode: {}",
+ response.getHttpStatusCode());
+ setInternalError();
+ return (T) this;
}
+ fromWebSocketMessage(message);
} else {
this.output = response.getBinary();
}
} else {
- JsonObject jsonObject = JsonUtils.parse(response.getMessage());
- // Set HTTP status code if available
+ String message = response.getMessage();
+ if (message == null || message.isEmpty()) {
+ log.warn(
+ "HTTP response message is null or empty, httpStatusCode: {}",
+ response.getHttpStatusCode());
+ setInternalError();
+ return (T) this;
+ }
+ JsonObject jsonObject = parseJson(message, "Failed to parse HTTP response as JSON: {}");
+ if (jsonObject == null) {
+ return (T) this;
+ }
if (response.getHttpStatusCode() != null) {
this.setStatusCode(response.getHttpStatusCode());
}
- if (jsonObject.has(ApiKeywords.OUTPUT)) {
- this.output =
- jsonObject.get(ApiKeywords.OUTPUT).isJsonNull()
- ? null
- : jsonObject.get(ApiKeywords.OUTPUT).getAsJsonObject();
- }
- if (jsonObject.has(ApiKeywords.USAGE)) {
- this.setUsage(
- jsonObject.get(ApiKeywords.USAGE).isJsonNull()
- ? null
- : jsonObject.get(ApiKeywords.USAGE).getAsJsonObject());
- }
- if (jsonObject.has(ApiKeywords.REQUEST_ID)) {
- this.setRequestId(jsonObject.get(ApiKeywords.REQUEST_ID).getAsString());
- }
- if (jsonObject.has(ApiKeywords.STATUS_CODE)) {
- this.setStatusCode(
- jsonObject.get(ApiKeywords.STATUS_CODE).isJsonNull()
- ? null
- : jsonObject.get(ApiKeywords.STATUS_CODE).getAsInt());
- }
- if (jsonObject.has(ApiKeywords.CODE)) {
- this.setCode(
- jsonObject.get(ApiKeywords.CODE).isJsonNull()
- ? ""
- : jsonObject.get(ApiKeywords.CODE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setCode("");
- }
- if (jsonObject.has(ApiKeywords.MESSAGE)) {
- this.setMessage(
- jsonObject.get(ApiKeywords.MESSAGE).isJsonNull()
- ? ""
- : jsonObject.get(ApiKeywords.MESSAGE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setMessage("");
- }
- if (jsonObject.has(ApiKeywords.DATA)) {
- if (jsonObject.has(ApiKeywords.REQUEST_ID)) {
- jsonObject.remove(ApiKeywords.REQUEST_ID);
- }
- this.output = jsonObject;
- }
+ handleOutputField(jsonObject);
+ populateFromHttpJson(jsonObject);
+ handleDataField(jsonObject);
}
return (T) this;
}
@@ -148,24 +78,19 @@ public T fromResponse(
Protocol protocol, NetworkResponse response, boolean isFlattenResult) throws ApiException {
if (!isFlattenResult) {
return fromResponse(protocol, response);
- } else {
- this.setHeaders(changeHeaders(response.getHeaders()));
- // flatten not support websocket.
- if (protocol == Protocol.WEBSOCKET) {
- if (response.getBinary() == null) {
- JsonObject jsonObject = JsonUtils.parse(response.getMessage());
- this.output = jsonObject;
- // convert to the result
- } else {
- this.output = response.getBinary();
- }
- } else { // HTTP
- JsonObject jsonObject = JsonUtils.parse(response.getMessage());
- this.output = jsonObject;
- this.event = response.getEvent();
+ }
+ this.setHeaders(changeHeaders(response.getHeaders()));
+ if (protocol == Protocol.WEBSOCKET) {
+ if (response.getBinary() == null) {
+ this.output = parseJson(response.getMessage(), "Failed to parse WebSocket message");
+ } else {
+ this.output = response.getBinary();
}
- return (T) this;
+ } else {
+ this.output = parseJson(response.getMessage(), "Failed to parse HTTP response message");
+ this.event = response.getEvent();
}
+ return (T) this;
}
@Override
@@ -174,15 +99,25 @@ public T fromResponse(
Protocol protocol, NetworkResponse response, boolean isFlattenResult, HalfDuplexRequest req)
throws ApiException {
this.setHeaders(changeHeaders(response.getHeaders()));
- // check it's encrypted output
if ((response.getHeaders().containsKey("X-DashScope-OutputEncrypted".toLowerCase())
|| req.isEncryptRequest())
&& protocol == Protocol.HTTP) {
- // Set HTTP status code if available
if (response.getHttpStatusCode() != null) {
this.setStatusCode(response.getHttpStatusCode());
}
- JsonObject jsonObject = JsonUtils.parse(response.getMessage());
+ String encryptedMessage = response.getMessage();
+ if (encryptedMessage == null || encryptedMessage.isEmpty()) {
+ log.warn(
+ "Encrypted HTTP response message is null or empty, httpStatusCode: {}",
+ response.getHttpStatusCode());
+ setInternalError();
+ return (T) this;
+ }
+ JsonObject jsonObject =
+ parseJson(encryptedMessage, "Failed to parse encrypted HTTP response message");
+ if (jsonObject == null) {
+ return (T) this;
+ }
String encryptedOutput =
jsonObject.get(ApiKeywords.OUTPUT).isJsonNull()
? null
@@ -193,53 +128,112 @@ public T fromResponse(
encryptedOutput,
req.getEncryptionConfig().getAESEncryptKey(),
req.getEncryptionConfig().getIv());
- this.output = JsonUtils.parse(plainOutput);
+ this.output = parseJson(plainOutput, "Failed to parse decrypted output");
} else {
this.output = null;
}
- if (jsonObject.has(ApiKeywords.USAGE)) {
- this.setUsage(
- jsonObject.get(ApiKeywords.USAGE).isJsonNull()
- ? null
- : jsonObject.get(ApiKeywords.USAGE).getAsJsonObject());
- }
- if (jsonObject.has(ApiKeywords.REQUEST_ID)) {
- this.setRequestId(jsonObject.get(ApiKeywords.REQUEST_ID).getAsString());
- }
- if (jsonObject.has(ApiKeywords.STATUS_CODE)) {
- this.setStatusCode(
- jsonObject.get(ApiKeywords.STATUS_CODE).isJsonNull()
- ? null
- : jsonObject.get(ApiKeywords.STATUS_CODE).getAsInt());
- }
- if (jsonObject.has(ApiKeywords.CODE)) {
- this.setCode(
- jsonObject.get(ApiKeywords.CODE).isJsonNull()
- ? ""
- : jsonObject.get(ApiKeywords.CODE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setCode("");
- }
- if (jsonObject.has(ApiKeywords.MESSAGE)) {
- this.setMessage(
- jsonObject.get(ApiKeywords.MESSAGE).isJsonNull()
- ? ""
- : jsonObject.get(ApiKeywords.MESSAGE).getAsString());
- } else {
- // Set default empty string for successful responses
- this.setMessage("");
- }
- if (jsonObject.has(ApiKeywords.DATA)) {
- if (jsonObject.has(ApiKeywords.REQUEST_ID)) {
- jsonObject.remove(ApiKeywords.REQUEST_ID);
- }
- }
+ populateFromHttpJson(jsonObject);
return (T) this;
}
return fromResponse(protocol, response, isFlattenResult);
}
+ private void fromWebSocketMessage(String message) {
+ JsonObject jsonObject = parseJson(message, "Failed to parse WebSocket message");
+ if (jsonObject == null) {
+ return;
+ }
+ if (jsonObject.has(ApiKeywords.HEADER)) {
+ JsonObject headers = jsonObject.get(ApiKeywords.HEADER).getAsJsonObject();
+ if (headers.has(ApiKeywords.TASKID)) {
+ this.setRequestId(headers.get(ApiKeywords.TASKID).getAsString());
+ }
+ this.setStatusCode(
+ headers.has(ApiKeywords.STATUS_CODE) && !headers.get(ApiKeywords.STATUS_CODE).isJsonNull()
+ ? headers.get(ApiKeywords.STATUS_CODE).getAsInt()
+ : 200);
+ this.setCode(
+ headers.has(ApiKeywords.ERROR_CODE) && !headers.get(ApiKeywords.ERROR_CODE).isJsonNull()
+ ? headers.get(ApiKeywords.ERROR_CODE).getAsString()
+ : "");
+ this.setMessage(
+ headers.has(ApiKeywords.ERROR_MESSAGE)
+ && !headers.get(ApiKeywords.ERROR_MESSAGE).isJsonNull()
+ ? headers.get(ApiKeywords.ERROR_MESSAGE).getAsString()
+ : "");
+ }
+ if (jsonObject.has(ApiKeywords.PAYLOAD)) {
+ JsonObject payload = jsonObject.getAsJsonObject(ApiKeywords.PAYLOAD);
+ if (payload.has(ApiKeywords.OUTPUT)) {
+ this.output =
+ payload.get(ApiKeywords.OUTPUT).isJsonNull() ? null : payload.get(ApiKeywords.OUTPUT);
+ }
+ if (payload.has(ApiKeywords.USAGE)) {
+ this.setUsage(
+ payload.get(ApiKeywords.USAGE).isJsonNull() ? null : payload.get(ApiKeywords.USAGE));
+ }
+ }
+ }
+
+ private void handleOutputField(JsonObject jsonObject) {
+ // Handle OUTPUT field first
+ if (this.output == null && jsonObject.has(ApiKeywords.OUTPUT)) {
+ JsonElement outputElement = jsonObject.get(ApiKeywords.OUTPUT);
+ this.output = (outputElement == null || outputElement.isJsonNull()) ? null : outputElement;
+ }
+ }
+
+ private void handleDataField(JsonObject jsonObject) {
+ // Handle DATA field only if OUTPUT was not present
+ if (this.output == null && jsonObject.has(ApiKeywords.DATA)) {
+ jsonObject.remove(ApiKeywords.REQUEST_ID);
+ this.output = jsonObject;
+ }
+ }
+
+ private void populateFromHttpJson(JsonObject jsonObject) {
+ if (jsonObject.has(ApiKeywords.USAGE)) {
+ this.setUsage(
+ jsonObject.get(ApiKeywords.USAGE).isJsonNull()
+ ? null
+ : jsonObject.get(ApiKeywords.USAGE).getAsJsonObject());
+ }
+ if (jsonObject.has(ApiKeywords.REQUEST_ID)) {
+ this.setRequestId(jsonObject.get(ApiKeywords.REQUEST_ID).getAsString());
+ }
+ if (jsonObject.has(ApiKeywords.STATUS_CODE)) {
+ this.setStatusCode(
+ jsonObject.get(ApiKeywords.STATUS_CODE).isJsonNull()
+ ? null
+ : jsonObject.get(ApiKeywords.STATUS_CODE).getAsInt());
+ }
+ this.setCode(
+ jsonObject.has(ApiKeywords.CODE) && !jsonObject.get(ApiKeywords.CODE).isJsonNull()
+ ? jsonObject.get(ApiKeywords.CODE).getAsString()
+ : "");
+ this.setMessage(
+ jsonObject.has(ApiKeywords.MESSAGE) && !jsonObject.get(ApiKeywords.MESSAGE).isJsonNull()
+ ? jsonObject.get(ApiKeywords.MESSAGE).getAsString()
+ : "");
+ }
+
+ private JsonObject parseJson(String raw, String logMsg) {
+ try {
+ return JsonUtils.parse(raw);
+ } catch (Exception e) {
+ log.error(logMsg, e);
+ setInternalError();
+ return null;
+ }
+ }
+
+ private void setInternalError() {
+ this.output = null;
+ this.setStatusCode(PublicErrorDef.INTERNAL_ERROR.getStatusCode());
+ this.setCode(PublicErrorDef.INTERNAL_ERROR.getErrorCode());
+ this.setMessage(PublicErrorDef.INTERNAL_ERROR.getErrorMsg());
+ }
+
private Map changeHeaders(Map> headers) {
if (headers == null || headers.isEmpty()) {
return null;
diff --git a/src/main/java/com/alibaba/dashscope/common/PublicErrorDef.java b/src/main/java/com/alibaba/dashscope/common/PublicErrorDef.java
new file mode 100644
index 00000000..e8be4fa5
--- /dev/null
+++ b/src/main/java/com/alibaba/dashscope/common/PublicErrorDef.java
@@ -0,0 +1,112 @@
+// Copied from com.alibaba.dashscope:error:1.0.0
+package com.alibaba.dashscope.common;
+
+// Auto-generated by tools/generate.py -- DO NOT EDIT.
+import java.util.Map;
+
+/** Customer-facing error definitions. */
+public enum PublicErrorDef {
+ INVALID_REQUEST(
+ 400,
+ "BadRequestError",
+ "The request is invalid. Please check the request and try again.",
+ "invalid_request_error"),
+ MISSING_PARAMETER(
+ 400, "BadRequestError", "Missing required parameter: {parameter}.", "invalid_request_error"),
+ CONTENT_POLICY_VIOLATION(
+ 400,
+ "BadRequestError",
+ "The request was rejected by content policy.",
+ "invalid_request_error"),
+ INVALID_URL(
+ 400,
+ "BadRequestError",
+ "The provided URL is invalid or cannot be accessed.",
+ "invalid_request_error"),
+ INVALID_FILE(400, "BadRequestError", "The provided file is invalid.", "invalid_request_error"),
+ AUTH_FAILED(
+ 401,
+ "AuthenticationError",
+ "Authentication failed. Please provide valid authentication credentials.",
+ "authentication_error"),
+ INVALID_API_KEY(
+ 401, "AuthenticationError", "Incorrect API key provided.", "authentication_error"),
+ PERMISSION_DENIED(
+ 403,
+ "PermissionDeniedError",
+ "You do not have permission to access this resource.",
+ "permission_error"),
+ RESOURCE_NOT_FOUND(
+ 404, "NotFoundError", "The requested resource was not found: {resource}.", "not_found_error"),
+ REQUEST_TOO_LARGE(
+ 413,
+ "RequestTooLargeError",
+ "The request exceeds the maximum allowed size of {limit}.",
+ "request_too_large"),
+ RATE_LIMIT_EXCEEDED(
+ 429,
+ "RateLimitError",
+ "Rate limit exceeded. Please slow down your requests.",
+ "rate_limit_error"),
+ CONCURRENCY_LIMIT_EXCEEDED(
+ 429,
+ "RateLimitError",
+ "Too many concurrent requests. Please reduce concurrency and try again.",
+ "rate_limit_error"),
+ INSUFFICIENT_QUOTA(
+ 429,
+ "RateLimitError",
+ "You exceeded your current quota. Please check your plan and billing details.",
+ "billing_error"),
+ INTERNAL_ERROR(
+ 500,
+ "InternalServerError",
+ "The server encountered an internal error. Please try again later.",
+ "api_error"),
+ SERVICE_UNAVAILABLE(
+ 503,
+ "ServiceUnavailableError",
+ "The service is temporarily unavailable. Please try again later.",
+ "overloaded_error"),
+ REQUEST_TIMEOUT(
+ 504,
+ "GatewayTimeoutError",
+ "The request timed out. Please try again later.",
+ "timeout_error");
+
+ private final int statusCode;
+ private final String errorCode;
+ private final String errorMsg;
+ private final String anthropicErrorCode;
+
+ PublicErrorDef(int statusCode, String errorCode, String errorMsg, String anthropicErrorCode) {
+ this.statusCode = statusCode;
+ this.errorCode = errorCode;
+ this.errorMsg = errorMsg;
+ this.anthropicErrorCode = anthropicErrorCode;
+ }
+
+ public int getStatusCode() {
+ return statusCode;
+ }
+
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ public String getErrorMsg() {
+ return errorMsg;
+ }
+
+ public String getAnthropicErrorCode() {
+ return anthropicErrorCode;
+ }
+
+ public String formatMsg(Map vars) {
+ String msg = errorMsg;
+ for (Map.Entry entry : vars.entrySet()) {
+ msg = msg.replace("{" + entry.getKey() + "}", entry.getValue());
+ }
+ return msg;
+ }
+}
diff --git a/src/main/java/com/alibaba/dashscope/threads/runs/DefaultAssistantEventHandler.java b/src/main/java/com/alibaba/dashscope/threads/runs/DefaultAssistantEventHandler.java
index 80333e5d..d0bda500 100644
--- a/src/main/java/com/alibaba/dashscope/threads/runs/DefaultAssistantEventHandler.java
+++ b/src/main/java/com/alibaba/dashscope/threads/runs/DefaultAssistantEventHandler.java
@@ -188,7 +188,7 @@ public void onError(String errorMsg) {
@Override
public void onUnknown(String msg) {
- System.out.println(msg);
+ // Ignored
}
@Override