Skip to content

Commit 10c24b7

Browse files
committed
feat: Add usage field support to workflow interfaces
- Add usage field to workflow run interface (RunWorkflowResp, WorkflowRunResult) - Add usage field to workflow stream_run interface (WorkflowEventMessage) - Add usage field to workflow get history interface (WorkflowRunHistory) - Update test cases to verify usage field functionality - Follow same pattern as existing ChatUsage class - Align with Python and Go SDK implementations Usage field provides token consumption information: - token_count: Total tokens used - input_count: Tokens used for input - output_count: Tokens used for output Fixes: Support for usage field in workflow APIs as per API documentation
1 parent 03314ae commit 10c24b7

8 files changed

Lines changed: 184 additions & 5 deletions

File tree

.gitignore

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,8 @@ replay_pid*
3939

4040
# BlueJ files
4141
*.ctxt
42-
**/target
42+
**/target
43+
44+
# ai
45+
.serena/
46+
CLAUDE.md

CLAUDE.md

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
# CLAUDE.md
2+
3+
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4+
5+
## Build and Development Commands
6+
7+
### Prerequisites
8+
- Java 8+ (tested with Temurin 8)
9+
- Maven 3.9+
10+
- Environment variables for testing: `COZE_API_TOKEN`, `COZE_API_BASE`, etc.
11+
12+
### Build Commands
13+
```bash
14+
# Build the entire project
15+
mvn clean compile
16+
17+
# Run tests for specific module
18+
mvn test -pl api
19+
mvn test -pl example
20+
21+
# Run specific test class
22+
mvn test -Dtest=com.coze.openapi.service.service.chat.ChatServiceTest -pl api
23+
24+
# Run tests with Java 8 (required for compatibility)
25+
JAVA_HOME=/Library/Java/JavaVirtualMachines/temurin-8.jdk/Contents/Home mvn test
26+
27+
# Package the SDK
28+
mvn clean package -DskipTests
29+
30+
# Install to local Maven repository
31+
mvn clean install -DskipTests
32+
33+
# Code formatting and linting
34+
mvn spotless:check
35+
mvn spotless:apply
36+
37+
# Generate coverage report
38+
mvn jacoco:report
39+
```
40+
41+
## Architecture Overview
42+
43+
### Project Structure
44+
This is a multi-module Maven project with two main modules:
45+
- **api**: The core Coze Java SDK containing all API implementations
46+
- **example**: Comprehensive examples demonstrating SDK usage
47+
48+
### Core Architecture
49+
The SDK follows a service-oriented architecture with these key components:
50+
51+
#### 1. Main Entry Point (`CozeAPI`)
52+
- Central client class providing access to all Coze services
53+
- Built using Retrofit for HTTP communication
54+
- Supports both sync and async operations
55+
- Configurable via fluent builder pattern
56+
57+
#### 2. Service Layer
58+
Services are organized by functional domain:
59+
- **ChatService**: Bot conversations and streaming chat
60+
- **BotService**: Bot creation, management, and publishing
61+
- **WorkflowService**: Workflow execution and streaming
62+
- **ConversationService**: Conversation management and messages
63+
- **DatasetService**: Knowledge base and document management
64+
- **FileService**: File upload and management
65+
- **AudioService**: Speech synthesis and transcription
66+
- **WorkspaceService**: Workspace operations
67+
- **CommerceService**: Benefit and billing management
68+
- **WebsocketsClient**: Real-time WebSocket communication
69+
70+
#### 3. Authentication
71+
Multiple authentication methods supported:
72+
- **TokenAuth**: Personal access token authentication
73+
- **WebOAuthClient**: Web OAuth 2.0 flow
74+
- **JWTOAuthClient**: JWT-based OAuth for service accounts
75+
- **PKCEOAuthClient**: PKCE OAuth for public clients
76+
- **DeviceOAuthClient**: Device flow for limited-input devices
77+
78+
#### 4. API Design Patterns
79+
- **Request/Response**: All API calls use strongly-typed request/response objects
80+
- **Pagination**: List operations return paginated results with iterator support
81+
- **Streaming**: Real-time streaming via RxJava Flowable
82+
- **WebSocket**: Real-time communication for chat, audio, and transcription
83+
- **Error Handling**: Custom exceptions with detailed error information
84+
85+
### Key Technologies
86+
- **HTTP Client**: Retrofit 2.9.0 with OkHttp 3.14.9
87+
- **JSON**: Jackson 2.14.2 for serialization/deserialization
88+
- **Async**: RxJava2 for reactive programming
89+
- **JWT**: JJWT 0.11.5 for JWT token handling
90+
- **OAuth**: ScribeJava 8.3.1 for OAuth flows
91+
- **Testing**: JUnit 5.10.2 with Mockito 4.11.0
92+
- **Build**: Maven with Spotless for code formatting
93+
94+
### Environment Configuration
95+
Required environment variables for testing:
96+
```bash
97+
# Basic API access
98+
export COZE_API_TOKEN="your_personal_access_token"
99+
export COZE_API_BASE="https://api.coze.com" # or https://api.coze.cn for CN
100+
101+
# Bot and workspace IDs
102+
export PUBLISHED_BOT_ID="your_bot_id"
103+
export WORKSPACE_ID="your_workspace_id"
104+
export USER_ID="your_user_id"
105+
106+
# OAuth configurations (as needed)
107+
export COZE_WEB_OAUTH_CLIENT_ID="..."
108+
export COZE_WEB_OAUTH_CLIENT_SECRET="..."
109+
export COZE_WEB_OAUTH_REDIRECT_URI="..."
110+
```
111+
112+
### Development Workflow
113+
1. **Setup**: Configure Java 8 and Maven
114+
2. **Build**: Run `mvn clean compile` to build the project
115+
3. **Test**: Use existing test classes as templates for new features
116+
4. **Format**: Run `mvn spotless:apply` before committing
117+
5. **Examples**: Use `/example` module for testing new features
118+
6. **Documentation**: Update README.md and examples for new APIs
119+
120+
### Testing Strategy
121+
- Unit tests in `api/src/test/java/`
122+
- Integration tests use mock Retrofit services
123+
- Examples in `example/src/main/java/` demonstrate real usage
124+
- Test classes mirror service structure (e.g., `ChatServiceTest` tests `ChatService`)
125+
126+
### Code Style
127+
- Google Java Format (via Spotless Maven plugin)
128+
- Lombok for boilerplate reduction
129+
- Builder pattern for complex objects
130+
- Fluent interfaces for service configuration

api/src/main/java/com/coze/openapi/client/workflows/run/RunWorkflowResp.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.coze.openapi.client.workflows.run;
22

3+
import com.coze.openapi.client.chat.model.ChatUsage;
34
import com.coze.openapi.client.common.BaseResponse;
45
import com.fasterxml.jackson.annotation.JsonProperty;
56

@@ -36,4 +37,8 @@ public class RunWorkflowResp extends BaseResponse<String> {
3637

3738
@JsonProperty("cost")
3839
private String cost;
40+
41+
/** Token usage information for the workflow execution. */
42+
@JsonProperty("usage")
43+
private ChatUsage usage;
3944
}

api/src/main/java/com/coze/openapi/client/workflows/run/model/WorkflowEventMessage.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Map;
44

5+
import com.coze.openapi.client.chat.model.ChatUsage;
56
import com.coze.openapi.service.utils.Utils;
67
import com.fasterxml.jackson.annotation.JsonProperty;
78

@@ -41,6 +42,10 @@ public class WorkflowEventMessage {
4142
@JsonProperty("ext")
4243
private Map<String, Object> ext;
4344

45+
/** Token usage information for the workflow execution. */
46+
@JsonProperty("usage")
47+
private ChatUsage usage;
48+
4449
public static WorkflowEventMessage fromJson(String data) {
4550
return Utils.fromJson(data, WorkflowEventMessage.class);
4651
}

api/src/main/java/com/coze/openapi/client/workflows/run/model/WorkflowRunHistory.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.coze.openapi.client.workflows.run.model;
22

3+
import com.coze.openapi.client.chat.model.ChatUsage;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import lombok.AllArgsConstructor;
@@ -87,4 +88,8 @@ public class WorkflowRunHistory {
8788
*/
8889
@JsonProperty("debug_url")
8990
private String debugUrl;
91+
92+
/** Token usage information for the workflow execution. */
93+
@JsonProperty("usage")
94+
private ChatUsage usage;
9095
}

api/src/main/java/com/coze/openapi/client/workflows/run/model/WorkflowRunResult.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.coze.openapi.client.workflows.run.model;
22

3+
import com.coze.openapi.client.chat.model.ChatUsage;
34
import com.fasterxml.jackson.annotation.JsonProperty;
45

56
import lombok.AllArgsConstructor;
@@ -29,4 +30,8 @@ public class WorkflowRunResult {
2930
*/
3031
@JsonProperty("execute_id")
3132
private String executeID;
33+
34+
/** Token usage information for the workflow execution. */
35+
@JsonProperty("usage")
36+
private ChatUsage usage;
3237
}

api/src/test/java/com/coze/openapi/service/service/workflow/WorkFlowRunServiceTest.java

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import com.coze.openapi.api.WorkflowRunAPI;
1717
import com.coze.openapi.api.WorkflowRunHistoryAPI;
18+
import com.coze.openapi.client.chat.model.ChatUsage;
1819
import com.coze.openapi.client.workflows.run.RunWorkflowReq;
1920
import com.coze.openapi.client.workflows.run.RunWorkflowResp;
2021
import com.coze.openapi.client.workflows.run.model.WorkflowEvent;
@@ -53,7 +54,7 @@ public class WorkFlowRunServiceTest {
5354
+ "\n"
5455
+ "id: 5\n"
5556
+ "event: Message\n"
56-
+ "data: {\"content\":\"{\\\"output\\\":\\\"为什么小明要带一把尺子去看电影?因为他听说电影很长,怕坐不下!\\\"}\",\"cost\":\"0.00\",\"node_is_finish\":true,\"node_seq_id\":\"0\",\"node_title\":\"\",\"token\":1230}\n"
57+
+ "data: {\"content\":\"{\\\"output\\\":\\\"为什么小明要带一把尺子去看电影?因为他听说电影很长,怕坐不下!\\\"}\",\"cost\":\"0.00\",\"node_is_finish\":true,\"node_seq_id\":\"0\",\"node_title\":\"\",\"token\":1230,\"usage\":{\"token_count\":1230,\"input_count\":615,\"output_count\":615}}\n"
5758
+ "\n"
5859
+ "id: 0\n"
5960
+ "event: Error\n"
@@ -104,7 +105,11 @@ void parseStreamEventTest() {
104105
5,
105106
event ->
106107
event.getEvent().equals(WorkflowEventType.MESSAGE)
107-
&& event.getMessage().getToken().equals(1230))
108+
&& event.getMessage().getToken().equals(1230)
109+
&& event.getMessage().getUsage() != null
110+
&& event.getMessage().getUsage().getTokenCount() == 1230
111+
&& event.getMessage().getUsage().getInputCount() == 615
112+
&& event.getMessage().getUsage().getOutputCount() == 615)
108113
.assertValueAt(
109114
9,
110115
event ->
@@ -123,13 +128,16 @@ void testCreate() throws Exception {
123128

124129
RunWorkflowReq req = RunWorkflowReq.builder().workflowID(workflowID).build();
125130

131+
ChatUsage usage = ChatUsage.builder().tokenCount(100).inputCount(50).outputCount(50).build();
132+
126133
RunWorkflowResp baseResponse =
127134
RunWorkflowResp.builder()
128135
.code(0)
129136
.msg("success")
130137
.executeID(executeID)
131138
.logID(Utils.TEST_LOG_ID)
132139
.data("data")
140+
.usage(usage)
133141
.build();
134142

135143
// 创建 mock Call 对象
@@ -143,6 +151,10 @@ void testCreate() throws Exception {
143151
// 验证结果
144152
assertNotNull(result);
145153
assertEquals(executeID, result.getExecuteID());
154+
assertNotNull(result.getUsage());
155+
assertEquals(100, result.getUsage().getTokenCount());
156+
assertEquals(50, result.getUsage().getInputCount());
157+
assertEquals(50, result.getUsage().getOutputCount());
146158
}
147159

148160
@Test

api/src/test/java/com/coze/openapi/service/service/workflow/WorkflowRunHistoryServiceTest.java

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.mockito.MockitoAnnotations;
1616

1717
import com.coze.openapi.api.WorkflowRunHistoryAPI;
18+
import com.coze.openapi.client.chat.model.ChatUsage;
1819
import com.coze.openapi.client.common.BaseResponse;
1920
import com.coze.openapi.client.workflows.run.RetrieveRunHistoryReq;
2021
import com.coze.openapi.client.workflows.run.RetrieveRunHistoryResp;
@@ -44,10 +45,14 @@ void testRetrieve() throws Exception {
4445
RetrieveRunHistoryReq req =
4546
RetrieveRunHistoryReq.builder().workflowID(workflowId).executeID(executeId).build();
4647

48+
ChatUsage usage1 = ChatUsage.builder().tokenCount(150).inputCount(75).outputCount(75).build();
49+
50+
ChatUsage usage2 = ChatUsage.builder().tokenCount(200).inputCount(100).outputCount(100).build();
51+
4752
List<WorkflowRunHistory> histories =
4853
Arrays.asList(
49-
WorkflowRunHistory.builder().executeID("node1").build(),
50-
WorkflowRunHistory.builder().executeID("node2").build());
54+
WorkflowRunHistory.builder().executeID("node1").usage(usage1).build(),
55+
WorkflowRunHistory.builder().executeID("node2").usage(usage2).build());
5156

5257
BaseResponse<List<WorkflowRunHistory>> baseResponse =
5358
BaseResponse.<List<WorkflowRunHistory>>builder()
@@ -71,5 +76,13 @@ void testRetrieve() throws Exception {
7176
assertEquals(2, result.getHistories().size());
7277
assertEquals("node1", result.getHistories().get(0).getExecuteID());
7378
assertEquals(Utils.TEST_LOG_ID, result.getLogID());
79+
assertNotNull(result.getHistories().get(0).getUsage());
80+
assertEquals(150, result.getHistories().get(0).getUsage().getTokenCount());
81+
assertEquals(75, result.getHistories().get(0).getUsage().getInputCount());
82+
assertEquals(75, result.getHistories().get(0).getUsage().getOutputCount());
83+
assertNotNull(result.getHistories().get(1).getUsage());
84+
assertEquals(200, result.getHistories().get(1).getUsage().getTokenCount());
85+
assertEquals(100, result.getHistories().get(1).getUsage().getInputCount());
86+
assertEquals(100, result.getHistories().get(1).getUsage().getOutputCount());
7487
}
7588
}

0 commit comments

Comments
 (0)