diff --git a/src/Cnblogs.DashScope.Core/ApplicationRequest.cs b/src/Cnblogs.DashScope.Core/ApplicationRequest.cs
index b367d5e..bdafef5 100644
--- a/src/Cnblogs.DashScope.Core/ApplicationRequest.cs
+++ b/src/Cnblogs.DashScope.Core/ApplicationRequest.cs
@@ -1,21 +1,30 @@
-namespace Cnblogs.DashScope.Core;
+using System.Text.Json.Serialization;
+using Cnblogs.DashScope.Core.Internals;
+
+namespace Cnblogs.DashScope.Core;
///
/// Request body for an application all.
///
/// Type of the biz_content
-public class ApplicationRequest
+public class ApplicationRequest : IDashScopeWorkspaceConfig
where TBizParams : class
{
///
/// Content of this call.
///
- public required ApplicationInput Input { get; init; }
+ public required ApplicationInput Input { get; set; }
///
/// Optional configurations.
///
- public ApplicationParameters? Parameters { get; init; }
+ public ApplicationParameters? Parameters { get; set; }
+
+ ///
+ /// Optional workspace id.
+ ///
+ [JsonIgnore]
+ public string? WorkspaceId { get; set; }
}
///
diff --git a/src/Cnblogs.DashScope.Core/DashScopeClientCore.cs b/src/Cnblogs.DashScope.Core/DashScopeClientCore.cs
index 9b917d0..7cca41f 100644
--- a/src/Cnblogs.DashScope.Core/DashScopeClientCore.cs
+++ b/src/Cnblogs.DashScope.Core/DashScopeClientCore.cs
@@ -275,7 +275,9 @@ public async Task ListFilesAsync(CancellationToken cancellati
}
///
- public async Task DeleteFileAsync(DashScopeFileId id, CancellationToken cancellationToken = default)
+ public async Task DeleteFileAsync(
+ DashScopeFileId id,
+ CancellationToken cancellationToken = default)
{
var request = BuildRequest(HttpMethod.Delete, ApiLinks.Files + $"/{id}");
return (await SendCompatibleAsync(request, cancellationToken))!;
@@ -297,8 +299,7 @@ private static HttpRequestMessage BuildRequest(
string url,
TPayload? payload = null,
bool sse = false,
- bool isTask = false,
- string? workspaceId = null)
+ bool isTask = false)
where TPayload : class
{
var message = new HttpRequestMessage(method, url)
@@ -316,9 +317,9 @@ private static HttpRequestMessage BuildRequest(
message.Headers.Add("X-DashScope-Async", "enable");
}
- if (string.IsNullOrWhiteSpace(workspaceId) == false)
+ if (payload is IDashScopeWorkspaceConfig config && string.IsNullOrWhiteSpace(config.WorkspaceId) == false)
{
- message.Headers.Add("X-DashScope-WorkspaceId", workspaceId);
+ message.Headers.Add("X-DashScope-WorkSpace", config.WorkspaceId);
}
return message;
diff --git a/src/Cnblogs.DashScope.Core/Internals/IDashScopeWorkspaceConfig.cs b/src/Cnblogs.DashScope.Core/Internals/IDashScopeWorkspaceConfig.cs
new file mode 100644
index 0000000..752056b
--- /dev/null
+++ b/src/Cnblogs.DashScope.Core/Internals/IDashScopeWorkspaceConfig.cs
@@ -0,0 +1,12 @@
+namespace Cnblogs.DashScope.Core.Internals;
+
+///
+/// Workspace configuration.
+///
+internal interface IDashScopeWorkspaceConfig
+{
+ ///
+ /// Unique id of workspace to use.
+ ///
+ public string? WorkspaceId { get; }
+}
diff --git a/src/Cnblogs.DashScope.Core/TextGenerationTokenDetails.cs b/src/Cnblogs.DashScope.Core/TextGenerationTokenDetails.cs
new file mode 100644
index 0000000..d8e5b18
--- /dev/null
+++ b/src/Cnblogs.DashScope.Core/TextGenerationTokenDetails.cs
@@ -0,0 +1,7 @@
+namespace Cnblogs.DashScope.Core;
+
+///
+/// Token usage details.
+///
+/// Token count of cached input tokens
+public record TextGenerationTokenDetails(int CachedTokens);
diff --git a/src/Cnblogs.DashScope.Core/TextGenerationTokenUsage.cs b/src/Cnblogs.DashScope.Core/TextGenerationTokenUsage.cs
index 8021388..7662d7d 100644
--- a/src/Cnblogs.DashScope.Core/TextGenerationTokenUsage.cs
+++ b/src/Cnblogs.DashScope.Core/TextGenerationTokenUsage.cs
@@ -11,6 +11,11 @@ public class TextGenerationTokenUsage
/// This number may larger than input if internet search is enabled.
public int InputTokens { get; set; }
+ ///
+ /// Input token details.
+ ///
+ public TextGenerationTokenDetails? PromptTokensDetails { get; set; }
+
///
/// The number of output token.
///
diff --git a/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.body.txt b/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.body.txt
index 8d85edb..76cd3dc 100644
--- a/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.body.txt
+++ b/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.body.txt
@@ -1,12 +1 @@
-{
- "output": {
- "finish_reason": "stop",
- "text": "1+1 等于 2。这是最基本的数学加法之一,在十进制计数体系中,任何情况下两个一相加的结果都是二。"
- },
- "usage": {
- "total_tokens": 43,
- "output_tokens": 35,
- "input_tokens": 8
- },
- "request_id": "4ef2ed16-4dc3-9083-a723-fb2e80c84d3b"
-}
+{"output":{"finish_reason":"stop","text":"1+1等于2。这是最基本的数学加法运算之一。"},"usage":{"prompt_tokens_details":{"cached_tokens":0},"total_tokens":30,"output_tokens":14,"input_tokens":16},"request_id":"7e3d5586-cb70-98ce-97bf-8a2ac0091c3f"}
\ No newline at end of file
diff --git a/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.header.txt b/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.header.txt
index 3b4f8a2..ada9654 100644
--- a/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.header.txt
+++ b/test/Cnblogs.DashScope.Sdk.UnitTests/RawHttpData/single-generation-text-nosse.response.header.txt
@@ -1,13 +1,14 @@
-HTTP/1.1 200 OK
-eagleeye-traceid: 5bc840127c9dd7ed1de5586c0865cf01
-content-type: application/json
+HTTP/1.1 200 OK
+Vary: Origin,Access-Control-Request-Method,Access-Control-Request-Headers,Accept-Encoding
+X-Request-ID: 7e3d5586-cb70-98ce-97bf-8a2ac0091c3f
+x-dashscope-timeout: 180
x-dashscope-call-gateway: true
-req-cost-time: 6004
-req-arrive-time: 1708924139239
-resp-start-time: 1708924145244
-x-envoy-upstream-service-time: 5998
-content-encoding: gzip
-vary: Accept-Encoding
-date: Mon, 26 Feb 2024 05:09:05 GMT
-server: istio-envoy
-transfer-encoding: chunked
+x-dashscope-finished: true
+req-cost-time: 974
+req-arrive-time: 1742222245417
+resp-start-time: 1742222246391
+x-envoy-upstream-service-time: 964
+Set-Cookie: acw_tc=7e3d5586-cb70-98ce-97bf-8a2ac0091c3f7d8fa666bbce18dfce67d4b0ced27ae0;path=/;HttpOnly;Max-Age=1800
+Date: Mon, 17 Mar 2025 14:37:26 GMT
+Server: istio-envoy
+Transfer-Encoding: chunked
diff --git a/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.Application.cs b/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.Application.cs
index 6ad5bb1..59cfe01 100644
--- a/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.Application.cs
+++ b/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.Application.cs
@@ -273,6 +273,30 @@ public static readonly RequestSnapshot, ApplicationResponse>
+ WorkflowInDifferentWorkSpaceNoSse =
+ new(
+ "application-workflow",
+ new ApplicationRequest()
+ {
+ Input = new ApplicationInput()
+ {
+ BizParams = new TestApplicationBizParam("code"), Prompt = "请你跟我这样说"
+ },
+ Parameters = new ApplicationParameters()
+ {
+ TopK = 100,
+ TopP = 0.8f,
+ Seed = 1234,
+ Temperature = 0.85f,
+ },
+ WorkspaceId = "workspaceId"
+ },
+ new ApplicationResponse(
+ "10990f51-e2d0-9338-9c52-319af5f4858b",
+ new ApplicationOutput("code", "stop", "5a20b47dac2f43a7b1cbb8924ca66c47", null, null),
+ new ApplicationUsage(null)));
+
public static readonly RequestSnapshot ConversationSessionIdNoSse =
new(
"application-conversation-generation-session-id",
diff --git a/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.TextGeneration.cs b/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.TextGeneration.cs
index 6f8fe94..4a6e30a 100644
--- a/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.TextGeneration.cs
+++ b/test/Cnblogs.DashScope.Sdk.UnitTests/Utils/Snapshots.TextGeneration.cs
@@ -36,14 +36,15 @@ public static class TextFormat
{
Output = new TextGenerationOutput
{
- FinishReason = "stop", Text = "1+1 等于 2。这是最基本的数学加法之一,在十进制计数体系中,任何情况下两个一相加的结果都是二。"
+ FinishReason = "stop", Text = "1+1等于2。这是最基本的数学加法运算之一。"
},
- RequestId = "4ef2ed16-4dc3-9083-a723-fb2e80c84d3b",
+ RequestId = "7e3d5586-cb70-98ce-97bf-8a2ac0091c3f",
Usage = new TextGenerationTokenUsage
{
- InputTokens = 8,
- OutputTokens = 35,
- TotalTokens = 43
+ InputTokens = 16,
+ OutputTokens = 14,
+ TotalTokens = 30,
+ PromptTokensDetails = new TextGenerationTokenDetails(0)
}
});
diff --git a/test/Cnblogs.DashScope.Sdk.UnitTests/WorkspaceIdTests.cs b/test/Cnblogs.DashScope.Sdk.UnitTests/WorkspaceIdTests.cs
new file mode 100644
index 0000000..c6b3a98
--- /dev/null
+++ b/test/Cnblogs.DashScope.Sdk.UnitTests/WorkspaceIdTests.cs
@@ -0,0 +1,25 @@
+using Cnblogs.DashScope.Sdk.UnitTests.Utils;
+using NSubstitute;
+
+namespace Cnblogs.DashScope.Sdk.UnitTests;
+
+public class WorkspaceIdTests
+{
+ [Fact]
+ public async Task ApplicationCall_WithWorkspaceId_ApplyAsync()
+ {
+ // Arrange
+ const bool sse = false;
+ var testCase = Snapshots.Application.WorkflowInDifferentWorkSpaceNoSse;
+ var (client, handler) = await Sut.GetTestClientAsync(sse, testCase);
+
+ // Act
+ await client.GetApplicationResponseAsync("anyId", testCase.RequestModel);
+
+ // Assert
+ handler.Received().MockSend(
+ Arg.Is(
+ m => m.Headers.GetValues("X-DashScope-WorkSpace").First() == testCase.RequestModel.WorkspaceId),
+ Arg.Any());
+ }
+}