agent-builder-gateway-sdk 0.2.0__tar.gz → 0.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of agent-builder-gateway-sdk might be problematic. Click here for more details.
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/PKG-INFO +1 -1
- agent_builder_gateway_sdk-0.3.0/SDK_IMPROVEMENTS.md +253 -0
- agent_builder_gateway_sdk-0.3.0/examples/response_parsing.py +195 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/pyproject.toml +1 -1
- agent_builder_gateway_sdk-0.3.0/src/gateway_sdk/models.py +213 -0
- agent_builder_gateway_sdk-0.3.0/test_sdk_video_processing.py +243 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/uv.lock +1 -1
- agent_builder_gateway_sdk-0.2.0/src/gateway_sdk/models.py +0 -114
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/.github/workflows/publish.yml +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/.github/workflows/test.yml +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/.gitignore +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/LICENSE +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/README.md +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/RELEASE_GUIDE.md +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/examples/basic_usage.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/examples/streaming.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/__init__.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/auth.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/client.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/exceptions.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/streaming.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/tests/__init__.py +0 -0
- {agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/tests/test_models.py +0 -0
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
# SDK 改进说明
|
|
2
|
+
|
|
3
|
+
## 🎯 改进目标
|
|
4
|
+
|
|
5
|
+
解决 AI 编码助手在解析预制件响应时频繁出错的问题。
|
|
6
|
+
|
|
7
|
+
## 📊 问题诊断
|
|
8
|
+
|
|
9
|
+
### **根本原因**
|
|
10
|
+
|
|
11
|
+
预制件响应是**双层嵌套结构**,容易混淆:
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
result.output = {
|
|
15
|
+
'status': 'SUCCESS', # Gateway 层状态
|
|
16
|
+
'output': { # ← 预制件函数的返回值
|
|
17
|
+
'success': True,
|
|
18
|
+
'message': '处理成功',
|
|
19
|
+
# ...
|
|
20
|
+
},
|
|
21
|
+
'files': { # ← 输出文件
|
|
22
|
+
'output': ['s3://...']
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
### **常见错误**
|
|
28
|
+
|
|
29
|
+
1. 直接访问 `result.output.get('success')` - 错误层级
|
|
30
|
+
2. 没有检查 `result.output` 是否存在 - KeyError
|
|
31
|
+
3. 混淆两个 `output` 的含义 - 语义不清
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## ✅ 改进方案
|
|
36
|
+
|
|
37
|
+
### **新增 5 个便捷方法**
|
|
38
|
+
|
|
39
|
+
在 `src/gateway_sdk/models.py` 的 `PrefabResult` 类中添加:
|
|
40
|
+
|
|
41
|
+
#### 1. `get_function_result() -> Dict[str, Any]`
|
|
42
|
+
|
|
43
|
+
获取预制件函数的返回值(自动处理双层嵌套)
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# ✅ 之前(容易出错)
|
|
47
|
+
function_result = result.output.get('output', {}) if result.output else {}
|
|
48
|
+
|
|
49
|
+
# ✅ 现在(简洁安全)
|
|
50
|
+
function_result = result.get_function_result()
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### 2. `get_business_success() -> bool`
|
|
54
|
+
|
|
55
|
+
判断业务是否成功
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# ✅ 之前
|
|
59
|
+
function_result = result.output.get('output', {}) if result.output else {}
|
|
60
|
+
success = function_result.get('success', False)
|
|
61
|
+
|
|
62
|
+
# ✅ 现在
|
|
63
|
+
success = result.get_business_success()
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### 3. `get_business_message() -> str`
|
|
67
|
+
|
|
68
|
+
获取业务消息
|
|
69
|
+
|
|
70
|
+
```python
|
|
71
|
+
# ✅ 现在
|
|
72
|
+
message = result.get_business_message()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
#### 4. `get_business_error() -> Optional[str]`
|
|
76
|
+
|
|
77
|
+
获取业务错误信息
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# ✅ 现在
|
|
81
|
+
error = result.get_business_error()
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
#### 5. `get_business_error_code() -> Optional[str]`
|
|
85
|
+
|
|
86
|
+
获取业务错误代码
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# ✅ 现在
|
|
90
|
+
error_code = result.get_business_error_code()
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## 📝 使用示例
|
|
96
|
+
|
|
97
|
+
### **之前的代码(容易出错)**
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
result = client.run(...)
|
|
101
|
+
|
|
102
|
+
if result.is_success():
|
|
103
|
+
# 手动处理双层嵌套,容易出错
|
|
104
|
+
function_result = result.output.get('output', {}) if result.output else {}
|
|
105
|
+
|
|
106
|
+
if function_result.get('success'):
|
|
107
|
+
message = function_result.get('message', '')
|
|
108
|
+
data = function_result.get('data')
|
|
109
|
+
|
|
110
|
+
files = result.output.get('files', {}) if result.output else {}
|
|
111
|
+
output_s3_url = files.get('output', [])[0] if files.get('output') else None
|
|
112
|
+
|
|
113
|
+
print(f"消息: {message}")
|
|
114
|
+
print(f"输出文件: {output_s3_url}")
|
|
115
|
+
else:
|
|
116
|
+
error = function_result.get('error', '未知错误')
|
|
117
|
+
print(f"错误: {error}")
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### **现在的代码(简洁清晰)**
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
result = client.run(...)
|
|
124
|
+
|
|
125
|
+
if result.is_success():
|
|
126
|
+
# ✅ 使用便捷方法
|
|
127
|
+
if result.get_business_success():
|
|
128
|
+
message = result.get_business_message()
|
|
129
|
+
|
|
130
|
+
function_result = result.get_function_result()
|
|
131
|
+
data = function_result.get('data')
|
|
132
|
+
|
|
133
|
+
output_files = result.get_files()
|
|
134
|
+
output_s3_url = output_files.get('output', [])[0] if output_files.get('output') else None
|
|
135
|
+
|
|
136
|
+
print(f"消息: {message}")
|
|
137
|
+
print(f"输出文件: {output_s3_url}")
|
|
138
|
+
else:
|
|
139
|
+
error = result.get_business_error()
|
|
140
|
+
print(f"错误: {error}")
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 🎯 在 PocketFlow Node 中使用
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
class MyNode(AsyncNode):
|
|
149
|
+
def __init__(self, gateway_client: GatewayClient):
|
|
150
|
+
super().__init__()
|
|
151
|
+
self.client = gateway_client
|
|
152
|
+
|
|
153
|
+
async def exec_async(self, prep_res: dict) -> dict:
|
|
154
|
+
"""执行阶段:调用预制件"""
|
|
155
|
+
try:
|
|
156
|
+
result = self.client.run(
|
|
157
|
+
prefab_id="file-processing-prefab",
|
|
158
|
+
version="0.1.5",
|
|
159
|
+
function_name="parse_file",
|
|
160
|
+
files={"input": [prep_res["file_s3_url"]]}
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
# ✅ 使用便捷方法,代码更清晰
|
|
164
|
+
if result.is_success():
|
|
165
|
+
if result.get_business_success():
|
|
166
|
+
function_result = result.get_function_result()
|
|
167
|
+
output_files = result.get_files()
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
"success": True,
|
|
171
|
+
"message": result.get_business_message(),
|
|
172
|
+
"content": function_result.get('content'),
|
|
173
|
+
"output_file": output_files.get('output', [])[0] if output_files.get('output') else None
|
|
174
|
+
}
|
|
175
|
+
else:
|
|
176
|
+
return {
|
|
177
|
+
"success": False,
|
|
178
|
+
"error": result.get_business_error(),
|
|
179
|
+
"error_code": result.get_business_error_code()
|
|
180
|
+
}
|
|
181
|
+
else:
|
|
182
|
+
return {
|
|
183
|
+
"success": False,
|
|
184
|
+
"error": result.error
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
except Exception as e:
|
|
188
|
+
return {
|
|
189
|
+
"success": False,
|
|
190
|
+
"error": str(e)
|
|
191
|
+
}
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 📊 对比分析
|
|
197
|
+
|
|
198
|
+
| 项目 | 之前 | 现在 |
|
|
199
|
+
|-----|------|------|
|
|
200
|
+
| **代码行数** | ~8 行 | ~3 行 |
|
|
201
|
+
| **空指针安全** | ⚠️ 需要手动检查 | ✅ 自动处理 |
|
|
202
|
+
| **易读性** | ⚠️ 嵌套复杂 | ✅ 语义清晰 |
|
|
203
|
+
| **出错率** | ⚠️ 高(容易混淆) | ✅ 低 |
|
|
204
|
+
|
|
205
|
+
---
|
|
206
|
+
|
|
207
|
+
## 🚀 测试验证
|
|
208
|
+
|
|
209
|
+
运行测试脚本验证新 API:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
cd /Users/ketd/code-ganyi/agent-builder-gateway-adk
|
|
213
|
+
python3 test_sdk_video_processing.py 1
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
**测试结果**:
|
|
217
|
+
```
|
|
218
|
+
✅ SDK 调用成功!
|
|
219
|
+
🎉 业务执行成功!
|
|
220
|
+
📝 消息: 文件解析成功
|
|
221
|
+
📄 函数返回值:
|
|
222
|
+
success: True
|
|
223
|
+
message: 文件解析成功
|
|
224
|
+
content: GF—2025—1301...
|
|
225
|
+
📁 输出文件:
|
|
226
|
+
output:
|
|
227
|
+
- s3://cubeflow-dev/prefab-gateway/prefab-outputs/.../result.md
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## 📚 相关文档
|
|
233
|
+
|
|
234
|
+
- **SDK 使用指南**: `agent-builder-gateway-sdk-guide.md`
|
|
235
|
+
- **响应解析示例**: `examples/response_parsing.py`
|
|
236
|
+
- **开发提示词**: `StartTaskPrompt.md`(已更新)
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## ✨ 优势总结
|
|
241
|
+
|
|
242
|
+
1. **降低出错率** - 自动处理双层嵌套,避免手动解析错误
|
|
243
|
+
2. **提高可读性** - 方法名语义清晰,一看就懂
|
|
244
|
+
3. **简化代码** - 减少 60% 的响应解析代码
|
|
245
|
+
4. **向后兼容** - 保留原有方法,不影响现有代码
|
|
246
|
+
5. **类型安全** - 返回类型明确,IDE 智能提示友好
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
## 🎉 结论
|
|
251
|
+
|
|
252
|
+
通过添加便捷方法,SDK 的易用性大幅提升,AI 编码助手在解析响应时不会再出错!
|
|
253
|
+
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SDK 响应解析示例
|
|
4
|
+
|
|
5
|
+
展示如何使用 SDK 的便捷方法正确解析预制件响应
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from gateway_sdk import GatewayClient
|
|
9
|
+
|
|
10
|
+
# 初始化客户端
|
|
11
|
+
client = GatewayClient(api_key="your-api-key")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ============================================
|
|
15
|
+
# 示例 1:使用新的便捷方法(推荐)
|
|
16
|
+
# ============================================
|
|
17
|
+
|
|
18
|
+
def example_with_convenience_methods():
|
|
19
|
+
"""使用便捷方法解析响应(推荐)"""
|
|
20
|
+
|
|
21
|
+
result = client.run(
|
|
22
|
+
prefab_id="file-processing-prefab",
|
|
23
|
+
version="0.1.5",
|
|
24
|
+
function_name="parse_file",
|
|
25
|
+
parameters={},
|
|
26
|
+
files={"input": ["s3://bucket/document.pdf"]}
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
# ✅ 第 1 步:检查 SDK 调用是否成功
|
|
30
|
+
if result.is_success():
|
|
31
|
+
print("✅ SDK 调用成功")
|
|
32
|
+
|
|
33
|
+
# ✅ 第 2 步:检查业务是否成功(使用便捷方法)
|
|
34
|
+
if result.get_business_success():
|
|
35
|
+
print("🎉 业务执行成功")
|
|
36
|
+
|
|
37
|
+
# ✅ 第 3 步:获取业务数据
|
|
38
|
+
message = result.get_business_message()
|
|
39
|
+
print(f"消息: {message}")
|
|
40
|
+
|
|
41
|
+
# ✅ 第 4 步:获取完整的函数返回值
|
|
42
|
+
function_result = result.get_function_result()
|
|
43
|
+
content = function_result.get('content')
|
|
44
|
+
print(f"内容长度: {len(content) if content else 0}")
|
|
45
|
+
|
|
46
|
+
# ✅ 第 5 步:获取输出文件
|
|
47
|
+
output_files = result.get_files()
|
|
48
|
+
if 'output' in output_files:
|
|
49
|
+
s3_url = output_files['output'][0]
|
|
50
|
+
print(f"输出文件: {s3_url}")
|
|
51
|
+
|
|
52
|
+
else:
|
|
53
|
+
# 业务失败(使用便捷方法)
|
|
54
|
+
print("❌ 业务执行失败")
|
|
55
|
+
error = result.get_business_error()
|
|
56
|
+
error_code = result.get_business_error_code()
|
|
57
|
+
print(f"错误: {error}")
|
|
58
|
+
print(f"错误码: {error_code}")
|
|
59
|
+
|
|
60
|
+
else:
|
|
61
|
+
# SDK 调用失败
|
|
62
|
+
print("❌ SDK 调用失败")
|
|
63
|
+
print(f"错误: {result.error}")
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# ============================================
|
|
67
|
+
# 示例 2:手动解析(不推荐,但也可以工作)
|
|
68
|
+
# ============================================
|
|
69
|
+
|
|
70
|
+
def example_with_manual_parsing():
|
|
71
|
+
"""手动解析响应(不推荐,容易出错)"""
|
|
72
|
+
|
|
73
|
+
result = client.run(
|
|
74
|
+
prefab_id="file-processing-prefab",
|
|
75
|
+
version="0.1.5",
|
|
76
|
+
function_name="parse_file",
|
|
77
|
+
parameters={},
|
|
78
|
+
files={"input": ["s3://bucket/document.pdf"]}
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
if result.is_success():
|
|
82
|
+
# ⚠️ 手动处理双层嵌套(容易出错)
|
|
83
|
+
function_result = result.output.get('output', {}) if result.output else {}
|
|
84
|
+
|
|
85
|
+
if function_result.get('success'):
|
|
86
|
+
message = function_result.get('message', '')
|
|
87
|
+
content = function_result.get('content')
|
|
88
|
+
|
|
89
|
+
# 获取输出文件
|
|
90
|
+
files = result.output.get('files', {}) if result.output else {}
|
|
91
|
+
output_s3_url = files.get('output', [])[0] if files.get('output') else None
|
|
92
|
+
|
|
93
|
+
print(f"消息: {message}")
|
|
94
|
+
print(f"输出文件: {output_s3_url}")
|
|
95
|
+
else:
|
|
96
|
+
error = function_result.get('error')
|
|
97
|
+
print(f"错误: {error}")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
# ============================================
|
|
101
|
+
# 示例 3:在 PocketFlow Node 中使用
|
|
102
|
+
# ============================================
|
|
103
|
+
|
|
104
|
+
class FileParsingNode:
|
|
105
|
+
"""文件解析节点示例"""
|
|
106
|
+
|
|
107
|
+
def __init__(self, gateway_client):
|
|
108
|
+
self.client = gateway_client
|
|
109
|
+
|
|
110
|
+
async def exec_async(self, prep_res: dict) -> dict:
|
|
111
|
+
"""执行阶段:调用预制件"""
|
|
112
|
+
try:
|
|
113
|
+
file_s3_url = prep_res.get('file_s3_url')
|
|
114
|
+
|
|
115
|
+
# 调用预制件
|
|
116
|
+
result = self.client.run(
|
|
117
|
+
prefab_id="file-processing-prefab",
|
|
118
|
+
version="0.1.5",
|
|
119
|
+
function_name="parse_file",
|
|
120
|
+
parameters={},
|
|
121
|
+
files={"input": [file_s3_url]}
|
|
122
|
+
)
|
|
123
|
+
|
|
124
|
+
# ✅ 使用便捷方法解析响应
|
|
125
|
+
if result.is_success():
|
|
126
|
+
if result.get_business_success():
|
|
127
|
+
# 业务成功
|
|
128
|
+
function_result = result.get_function_result()
|
|
129
|
+
output_files = result.get_files()
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
"success": True,
|
|
133
|
+
"message": result.get_business_message(),
|
|
134
|
+
"content": function_result.get('content'),
|
|
135
|
+
"output_file": output_files.get('output', [])[0] if output_files.get('output') else None
|
|
136
|
+
}
|
|
137
|
+
else:
|
|
138
|
+
# 业务失败
|
|
139
|
+
return {
|
|
140
|
+
"success": False,
|
|
141
|
+
"error": result.get_business_error(),
|
|
142
|
+
"error_code": result.get_business_error_code()
|
|
143
|
+
}
|
|
144
|
+
else:
|
|
145
|
+
# SDK 调用失败
|
|
146
|
+
return {
|
|
147
|
+
"success": False,
|
|
148
|
+
"error": result.error
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
except Exception as e:
|
|
152
|
+
return {
|
|
153
|
+
"success": False,
|
|
154
|
+
"error": str(e)
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# ============================================
|
|
159
|
+
# 示例 4:常见错误(避免)
|
|
160
|
+
# ============================================
|
|
161
|
+
|
|
162
|
+
def common_mistakes():
|
|
163
|
+
"""常见错误示例(不要这样做)"""
|
|
164
|
+
|
|
165
|
+
result = client.run(...)
|
|
166
|
+
|
|
167
|
+
# ❌ 错误 1:直接访问 result.output,没有处理嵌套
|
|
168
|
+
# data = result.output.get('data') # 错误!data 不在这一层
|
|
169
|
+
|
|
170
|
+
# ❌ 错误 2:没有检查 result.output 是否存在
|
|
171
|
+
# function_result = result.output['output'] # 可能 KeyError
|
|
172
|
+
|
|
173
|
+
# ❌ 错误 3:混淆两层 output
|
|
174
|
+
# success = result.output.get('success') # 错误!success 在 output['output'] 中
|
|
175
|
+
|
|
176
|
+
# ✅ 正确:使用便捷方法
|
|
177
|
+
if result.is_success() and result.get_business_success():
|
|
178
|
+
function_result = result.get_function_result()
|
|
179
|
+
success = function_result.get('success')
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
if __name__ == "__main__":
|
|
183
|
+
print("SDK 响应解析示例")
|
|
184
|
+
print("=" * 60)
|
|
185
|
+
print()
|
|
186
|
+
print("推荐使用便捷方法,避免手动处理响应嵌套!")
|
|
187
|
+
print()
|
|
188
|
+
print("便捷方法列表:")
|
|
189
|
+
print("- result.get_function_result() # 获取函数返回值")
|
|
190
|
+
print("- result.get_business_success() # 判断业务成功")
|
|
191
|
+
print("- result.get_business_message() # 获取业务消息")
|
|
192
|
+
print("- result.get_business_error() # 获取业务错误")
|
|
193
|
+
print("- result.get_business_error_code() # 获取错误代码")
|
|
194
|
+
print("- result.get_files() # 获取输出文件")
|
|
195
|
+
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
"""数据模型"""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Dict, List, Optional
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from enum import Enum
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class CallStatus(str, Enum):
|
|
9
|
+
"""调用状态"""
|
|
10
|
+
|
|
11
|
+
SUCCESS = "SUCCESS"
|
|
12
|
+
FAILED = "FAILED"
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class StreamEventType(str, Enum):
|
|
16
|
+
"""流式事件类型"""
|
|
17
|
+
|
|
18
|
+
START = "start"
|
|
19
|
+
CONTENT = "content"
|
|
20
|
+
PROGRESS = "progress"
|
|
21
|
+
DONE = "done"
|
|
22
|
+
ERROR = "error"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
@dataclass
|
|
26
|
+
class PrefabCall:
|
|
27
|
+
"""预制件调用请求"""
|
|
28
|
+
|
|
29
|
+
prefab_id: str
|
|
30
|
+
version: str
|
|
31
|
+
function_name: str
|
|
32
|
+
parameters: Dict[str, Any]
|
|
33
|
+
files: Optional[Dict[str, List[str]]] = None
|
|
34
|
+
|
|
35
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
36
|
+
"""转换为字典格式"""
|
|
37
|
+
inputs: Dict[str, Any] = {"parameters": self.parameters}
|
|
38
|
+
if self.files:
|
|
39
|
+
inputs["files"] = self.files
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
"prefab_id": self.prefab_id,
|
|
43
|
+
"version": self.version,
|
|
44
|
+
"function_name": self.function_name,
|
|
45
|
+
"inputs": inputs,
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass
|
|
50
|
+
class PrefabResult:
|
|
51
|
+
"""预制件执行结果"""
|
|
52
|
+
|
|
53
|
+
status: CallStatus
|
|
54
|
+
output: Optional[Dict[str, Any]] = None
|
|
55
|
+
error: Optional[Dict[str, Any]] = None
|
|
56
|
+
job_id: Optional[str] = None
|
|
57
|
+
|
|
58
|
+
def is_success(self) -> bool:
|
|
59
|
+
"""判断是否成功"""
|
|
60
|
+
return self.status == CallStatus.SUCCESS
|
|
61
|
+
|
|
62
|
+
def get(self, key: str, default: Any = None) -> Any:
|
|
63
|
+
"""便捷获取输出字段"""
|
|
64
|
+
if self.output:
|
|
65
|
+
return self.output.get(key, default)
|
|
66
|
+
return default
|
|
67
|
+
|
|
68
|
+
def get_result(self) -> Any:
|
|
69
|
+
"""
|
|
70
|
+
获取完整的 output 字典(保持向后兼容)
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
完整的 output 字典,包含 status, output, files 等
|
|
74
|
+
"""
|
|
75
|
+
return self.output
|
|
76
|
+
|
|
77
|
+
def get_function_result(self) -> Dict[str, Any]:
|
|
78
|
+
"""
|
|
79
|
+
获取预制件函数的返回值(对应 manifest.returns)
|
|
80
|
+
|
|
81
|
+
这是响应的嵌套结构:
|
|
82
|
+
- result.output 是 Gateway 的响应
|
|
83
|
+
- result.output['output'] 是预制件函数的实际返回值
|
|
84
|
+
|
|
85
|
+
Returns:
|
|
86
|
+
预制件函数的返回值字典
|
|
87
|
+
|
|
88
|
+
Example:
|
|
89
|
+
>>> result = client.run(...)
|
|
90
|
+
>>> function_result = result.get_function_result()
|
|
91
|
+
>>> if function_result.get('success'):
|
|
92
|
+
... print(function_result.get('message'))
|
|
93
|
+
"""
|
|
94
|
+
if self.output and isinstance(self.output, dict):
|
|
95
|
+
return self.output.get('output', {})
|
|
96
|
+
return {}
|
|
97
|
+
|
|
98
|
+
def get_business_success(self) -> bool:
|
|
99
|
+
"""
|
|
100
|
+
判断业务是否成功(检查函数返回值中的 success 字段)
|
|
101
|
+
|
|
102
|
+
注意:
|
|
103
|
+
- result.is_success() 表示 SDK 调用成功
|
|
104
|
+
- result.get_business_success() 表示业务逻辑成功
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
业务是否成功
|
|
108
|
+
|
|
109
|
+
Example:
|
|
110
|
+
>>> result = client.run(...)
|
|
111
|
+
>>> if result.is_success() and result.get_business_success():
|
|
112
|
+
... print("调用成功且业务成功")
|
|
113
|
+
"""
|
|
114
|
+
function_result = self.get_function_result()
|
|
115
|
+
return function_result.get('success', False)
|
|
116
|
+
|
|
117
|
+
def get_business_message(self) -> str:
|
|
118
|
+
"""
|
|
119
|
+
获取业务消息
|
|
120
|
+
|
|
121
|
+
Returns:
|
|
122
|
+
业务消息字符串,如果没有消息则返回空字符串
|
|
123
|
+
|
|
124
|
+
Example:
|
|
125
|
+
>>> result = client.run(...)
|
|
126
|
+
>>> print(f"消息: {result.get_business_message()}")
|
|
127
|
+
"""
|
|
128
|
+
function_result = self.get_function_result()
|
|
129
|
+
return function_result.get('message', '')
|
|
130
|
+
|
|
131
|
+
def get_business_error(self) -> Optional[str]:
|
|
132
|
+
"""
|
|
133
|
+
获取业务错误信息
|
|
134
|
+
|
|
135
|
+
Returns:
|
|
136
|
+
错误信息字符串,如果没有错误则返回 None
|
|
137
|
+
|
|
138
|
+
Example:
|
|
139
|
+
>>> result = client.run(...)
|
|
140
|
+
>>> if not result.get_business_success():
|
|
141
|
+
... print(f"错误: {result.get_business_error()}")
|
|
142
|
+
"""
|
|
143
|
+
function_result = self.get_function_result()
|
|
144
|
+
return function_result.get('error')
|
|
145
|
+
|
|
146
|
+
def get_business_error_code(self) -> Optional[str]:
|
|
147
|
+
"""
|
|
148
|
+
获取业务错误代码
|
|
149
|
+
|
|
150
|
+
Returns:
|
|
151
|
+
错误代码字符串,如果没有错误码则返回 None
|
|
152
|
+
|
|
153
|
+
Example:
|
|
154
|
+
>>> result = client.run(...)
|
|
155
|
+
>>> if not result.get_business_success():
|
|
156
|
+
... print(f"错误码: {result.get_business_error_code()}")
|
|
157
|
+
"""
|
|
158
|
+
function_result = self.get_function_result()
|
|
159
|
+
return function_result.get('error_code')
|
|
160
|
+
|
|
161
|
+
def get_files(self) -> Dict[str, List[str]]:
|
|
162
|
+
"""
|
|
163
|
+
获取输出文件(S3 URL 列表)
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
文件字典,key 对应 manifest.files 中定义的 key
|
|
167
|
+
|
|
168
|
+
Example:
|
|
169
|
+
>>> result = client.run(...)
|
|
170
|
+
>>> output_files = result.get_files()
|
|
171
|
+
>>> # 获取特定 key 的输出文件
|
|
172
|
+
>>> if 'output' in output_files:
|
|
173
|
+
... s3_url = output_files['output'][0]
|
|
174
|
+
"""
|
|
175
|
+
if self.output:
|
|
176
|
+
return self.output.get("files", {})
|
|
177
|
+
return {}
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
@dataclass
|
|
181
|
+
class BatchResult:
|
|
182
|
+
"""批量执行结果"""
|
|
183
|
+
|
|
184
|
+
job_id: str
|
|
185
|
+
status: str
|
|
186
|
+
results: List[PrefabResult]
|
|
187
|
+
|
|
188
|
+
def all_success(self) -> bool:
|
|
189
|
+
"""判断是否全部成功"""
|
|
190
|
+
return all(r.is_success() for r in self.results)
|
|
191
|
+
|
|
192
|
+
def get_failed(self) -> List[PrefabResult]:
|
|
193
|
+
"""获取失败的结果"""
|
|
194
|
+
return [r for r in self.results if not r.is_success()]
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
@dataclass
|
|
198
|
+
class StreamEvent:
|
|
199
|
+
"""流式事件"""
|
|
200
|
+
|
|
201
|
+
type: StreamEventType
|
|
202
|
+
data: Any
|
|
203
|
+
|
|
204
|
+
@classmethod
|
|
205
|
+
def from_dict(cls, data: Dict[str, Any]) -> "StreamEvent":
|
|
206
|
+
"""从字典创建"""
|
|
207
|
+
event_type = data.get("type", "content")
|
|
208
|
+
try:
|
|
209
|
+
event_type_enum = StreamEventType(event_type)
|
|
210
|
+
except ValueError:
|
|
211
|
+
event_type_enum = StreamEventType.CONTENT
|
|
212
|
+
|
|
213
|
+
return cls(type=event_type_enum, data=data.get("data"))
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
SDK 测试脚本 - 调用 video-processing-prefab
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import sys
|
|
7
|
+
from pathlib import Path
|
|
8
|
+
|
|
9
|
+
# 添加 src 到路径以便本地测试
|
|
10
|
+
sys.path.insert(0, str(Path(__file__).parent / "src"))
|
|
11
|
+
|
|
12
|
+
from gateway_sdk import GatewayClient
|
|
13
|
+
from gateway_sdk.exceptions import GatewayError
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def test_parse_file():
|
|
17
|
+
"""测试文件解析功能"""
|
|
18
|
+
|
|
19
|
+
# ============================================
|
|
20
|
+
# 配置部分 - 使用 API Key
|
|
21
|
+
# ============================================
|
|
22
|
+
API_KEY = "sk-RblEJO35N0WBq1KIj0zF7Vm4g6LKzI68xWle2WgxrZE"
|
|
23
|
+
BASE_URL = "http://nodeport.sensedeal.vip:30566"
|
|
24
|
+
|
|
25
|
+
# 测试参数
|
|
26
|
+
PREFAB_ID = "file-processing-prefab"
|
|
27
|
+
VERSION = "0.1.5"
|
|
28
|
+
FUNCTION_NAME = "parse_file"
|
|
29
|
+
INPUT_FILE = "s3://cubeflow-dev/prefab-gateway/prefab-inputs/f94d31c2-154d-4363-8450-cc907117cbcb/2025/10/28/1761659981781-_____________GF_2025_1301_.pdf"
|
|
30
|
+
|
|
31
|
+
# ============================================
|
|
32
|
+
# 初始化客户端
|
|
33
|
+
# ============================================
|
|
34
|
+
print("🔧 初始化 Gateway SDK 客户端...")
|
|
35
|
+
print(f" Base URL: {BASE_URL}")
|
|
36
|
+
print(f" Prefab: {PREFAB_ID} v{VERSION}")
|
|
37
|
+
print()
|
|
38
|
+
|
|
39
|
+
try:
|
|
40
|
+
client = GatewayClient(
|
|
41
|
+
base_url=BASE_URL,
|
|
42
|
+
api_key=API_KEY,
|
|
43
|
+
timeout=120 # 视频处理可能需要较长时间
|
|
44
|
+
)
|
|
45
|
+
print("✅ 客户端初始化成功")
|
|
46
|
+
print()
|
|
47
|
+
|
|
48
|
+
except Exception as e:
|
|
49
|
+
print(f"❌ 客户端初始化失败: {e}")
|
|
50
|
+
return False
|
|
51
|
+
|
|
52
|
+
# ============================================
|
|
53
|
+
# 调用预制件
|
|
54
|
+
# ============================================
|
|
55
|
+
print(f"🚀 调用预制件: {FUNCTION_NAME}")
|
|
56
|
+
print(f" 输入文件: {INPUT_FILE}")
|
|
57
|
+
print()
|
|
58
|
+
|
|
59
|
+
try:
|
|
60
|
+
result = client.run(
|
|
61
|
+
prefab_id=PREFAB_ID,
|
|
62
|
+
version=VERSION,
|
|
63
|
+
function_name=FUNCTION_NAME,
|
|
64
|
+
parameters={}, # parse_file 不需要额外参数
|
|
65
|
+
files={
|
|
66
|
+
"input": [INPUT_FILE] # PDF 文件输入
|
|
67
|
+
}
|
|
68
|
+
)
|
|
69
|
+
|
|
70
|
+
# ============================================
|
|
71
|
+
# 处理结果
|
|
72
|
+
# ============================================
|
|
73
|
+
print("📊 调用结果:")
|
|
74
|
+
print(f" 状态: {result.status}")
|
|
75
|
+
print(f" Job ID: {result.job_id}")
|
|
76
|
+
print()
|
|
77
|
+
|
|
78
|
+
if result.is_success():
|
|
79
|
+
print("✅ SDK 调用成功!")
|
|
80
|
+
print()
|
|
81
|
+
|
|
82
|
+
# ========================================
|
|
83
|
+
# 使用新的便捷方法
|
|
84
|
+
# ========================================
|
|
85
|
+
|
|
86
|
+
# 检查业务是否成功
|
|
87
|
+
if result.get_business_success():
|
|
88
|
+
print("🎉 业务执行成功!")
|
|
89
|
+
print()
|
|
90
|
+
|
|
91
|
+
# 获取业务消息
|
|
92
|
+
message = result.get_business_message()
|
|
93
|
+
if message:
|
|
94
|
+
print(f"📝 消息: {message}")
|
|
95
|
+
print()
|
|
96
|
+
|
|
97
|
+
# 获取函数返回值(完整的业务数据)
|
|
98
|
+
function_result = result.get_function_result()
|
|
99
|
+
print("📄 函数返回值:")
|
|
100
|
+
for key, value in function_result.items():
|
|
101
|
+
if key == 'content':
|
|
102
|
+
# 内容太长,只显示前100个字符
|
|
103
|
+
print(f" {key}: {str(value)[:100]}...")
|
|
104
|
+
else:
|
|
105
|
+
print(f" {key}: {value}")
|
|
106
|
+
print()
|
|
107
|
+
|
|
108
|
+
# 获取输出文件
|
|
109
|
+
output_files = result.get_files()
|
|
110
|
+
if output_files:
|
|
111
|
+
print("📁 输出文件:")
|
|
112
|
+
for key, files in output_files.items():
|
|
113
|
+
print(f" {key}:")
|
|
114
|
+
for file_url in files:
|
|
115
|
+
print(f" - {file_url}")
|
|
116
|
+
print()
|
|
117
|
+
|
|
118
|
+
return True
|
|
119
|
+
|
|
120
|
+
else:
|
|
121
|
+
# 业务失败
|
|
122
|
+
print("❌ 业务执行失败")
|
|
123
|
+
error = result.get_business_error()
|
|
124
|
+
error_code = result.get_business_error_code()
|
|
125
|
+
if error:
|
|
126
|
+
print(f" 错误信息: {error}")
|
|
127
|
+
if error_code:
|
|
128
|
+
print(f" 错误代码: {error_code}")
|
|
129
|
+
print()
|
|
130
|
+
return False
|
|
131
|
+
|
|
132
|
+
else:
|
|
133
|
+
print("❌ 调用失败")
|
|
134
|
+
print(f" 错误信息: {result.error}")
|
|
135
|
+
print()
|
|
136
|
+
return False
|
|
137
|
+
|
|
138
|
+
except GatewayError as e:
|
|
139
|
+
print(f"❌ Gateway 错误: {e}")
|
|
140
|
+
print(f" 错误类型: {type(e).__name__}")
|
|
141
|
+
if hasattr(e, 'status_code'):
|
|
142
|
+
print(f" 状态码: {e.status_code}")
|
|
143
|
+
return False
|
|
144
|
+
|
|
145
|
+
except Exception as e:
|
|
146
|
+
print(f"❌ 未知错误: {e}")
|
|
147
|
+
print(f" 错误类型: {type(e).__name__}")
|
|
148
|
+
import traceback
|
|
149
|
+
traceback.print_exc()
|
|
150
|
+
return False
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_list_prefabs():
|
|
154
|
+
"""测试列出预制件功能"""
|
|
155
|
+
|
|
156
|
+
API_KEY = "sk-RblEJO35N0WBq1KIj0zF7Vm4g6LKzI68xWle2WgxrZE"
|
|
157
|
+
BASE_URL = "http://nodeport.sensedeal.vip:30566"
|
|
158
|
+
|
|
159
|
+
print("📋 测试列出预制件...")
|
|
160
|
+
print()
|
|
161
|
+
|
|
162
|
+
try:
|
|
163
|
+
client = GatewayClient(
|
|
164
|
+
base_url=BASE_URL,
|
|
165
|
+
api_key=API_KEY,
|
|
166
|
+
timeout=30
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
prefabs = client.list_prefabs()
|
|
170
|
+
print(f"✅ 找到 {len(prefabs)} 个预制件:")
|
|
171
|
+
print()
|
|
172
|
+
|
|
173
|
+
for prefab in prefabs[:5]: # 只显示前 5 个
|
|
174
|
+
print(f" • {prefab.prefab_id} v{prefab.version}")
|
|
175
|
+
if hasattr(prefab, 'description'):
|
|
176
|
+
print(f" {prefab.description}")
|
|
177
|
+
|
|
178
|
+
if len(prefabs) > 5:
|
|
179
|
+
print(f" ... 还有 {len(prefabs) - 5} 个")
|
|
180
|
+
|
|
181
|
+
print()
|
|
182
|
+
return True
|
|
183
|
+
|
|
184
|
+
except Exception as e:
|
|
185
|
+
print(f"❌ 失败: {e}")
|
|
186
|
+
return False
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def main():
|
|
190
|
+
"""主函数"""
|
|
191
|
+
import sys
|
|
192
|
+
|
|
193
|
+
print("=" * 60)
|
|
194
|
+
print(" Gateway SDK 测试脚本")
|
|
195
|
+
print("=" * 60)
|
|
196
|
+
print()
|
|
197
|
+
|
|
198
|
+
# 支持命令行参数
|
|
199
|
+
if len(sys.argv) > 1:
|
|
200
|
+
choice = sys.argv[1]
|
|
201
|
+
else:
|
|
202
|
+
print("⚠️ 使用 API Key 进行测试")
|
|
203
|
+
print()
|
|
204
|
+
|
|
205
|
+
print("选择测试项目:")
|
|
206
|
+
print(" 1. 测试文件解析 (parse_file)")
|
|
207
|
+
print(" 2. 测试列出预制件 (list_prefabs)")
|
|
208
|
+
print(" 3. 运行所有测试")
|
|
209
|
+
print()
|
|
210
|
+
print("💡 命令行用法: python test_sdk_video_processing.py [1|2|3]")
|
|
211
|
+
print()
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
choice = input("请选择 (1-3, 默认 1): ").strip() or "1"
|
|
215
|
+
except (EOFError, KeyboardInterrupt):
|
|
216
|
+
print("\n使用默认选项: 1")
|
|
217
|
+
choice = "1"
|
|
218
|
+
print()
|
|
219
|
+
|
|
220
|
+
success = True
|
|
221
|
+
|
|
222
|
+
if choice == "1":
|
|
223
|
+
success = test_parse_file()
|
|
224
|
+
elif choice == "2":
|
|
225
|
+
success = test_list_prefabs()
|
|
226
|
+
elif choice == "3":
|
|
227
|
+
success = test_parse_file() and test_list_prefabs()
|
|
228
|
+
else:
|
|
229
|
+
print("❌ 无效选择")
|
|
230
|
+
success = False
|
|
231
|
+
|
|
232
|
+
print()
|
|
233
|
+
print("=" * 60)
|
|
234
|
+
if success:
|
|
235
|
+
print(" ✅ 测试完成")
|
|
236
|
+
else:
|
|
237
|
+
print(" ❌ 测试失败")
|
|
238
|
+
print("=" * 60)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
if __name__ == "__main__":
|
|
242
|
+
main()
|
|
243
|
+
|
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
"""数据模型"""
|
|
2
|
-
|
|
3
|
-
from typing import Any, Dict, List, Optional
|
|
4
|
-
from dataclasses import dataclass
|
|
5
|
-
from enum import Enum
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class CallStatus(str, Enum):
|
|
9
|
-
"""调用状态"""
|
|
10
|
-
|
|
11
|
-
SUCCESS = "SUCCESS"
|
|
12
|
-
FAILED = "FAILED"
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class StreamEventType(str, Enum):
|
|
16
|
-
"""流式事件类型"""
|
|
17
|
-
|
|
18
|
-
START = "start"
|
|
19
|
-
CONTENT = "content"
|
|
20
|
-
PROGRESS = "progress"
|
|
21
|
-
DONE = "done"
|
|
22
|
-
ERROR = "error"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclass
|
|
26
|
-
class PrefabCall:
|
|
27
|
-
"""预制件调用请求"""
|
|
28
|
-
|
|
29
|
-
prefab_id: str
|
|
30
|
-
version: str
|
|
31
|
-
function_name: str
|
|
32
|
-
parameters: Dict[str, Any]
|
|
33
|
-
files: Optional[Dict[str, List[str]]] = None
|
|
34
|
-
|
|
35
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
36
|
-
"""转换为字典格式"""
|
|
37
|
-
inputs: Dict[str, Any] = {"parameters": self.parameters}
|
|
38
|
-
if self.files:
|
|
39
|
-
inputs["files"] = self.files
|
|
40
|
-
|
|
41
|
-
return {
|
|
42
|
-
"prefab_id": self.prefab_id,
|
|
43
|
-
"version": self.version,
|
|
44
|
-
"function_name": self.function_name,
|
|
45
|
-
"inputs": inputs,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
@dataclass
|
|
50
|
-
class PrefabResult:
|
|
51
|
-
"""预制件执行结果"""
|
|
52
|
-
|
|
53
|
-
status: CallStatus
|
|
54
|
-
output: Optional[Dict[str, Any]] = None
|
|
55
|
-
error: Optional[Dict[str, Any]] = None
|
|
56
|
-
job_id: Optional[str] = None
|
|
57
|
-
|
|
58
|
-
def is_success(self) -> bool:
|
|
59
|
-
"""判断是否成功"""
|
|
60
|
-
return self.status == CallStatus.SUCCESS
|
|
61
|
-
|
|
62
|
-
def get(self, key: str, default: Any = None) -> Any:
|
|
63
|
-
"""便捷获取输出字段"""
|
|
64
|
-
if self.output:
|
|
65
|
-
return self.output.get(key, default)
|
|
66
|
-
return default
|
|
67
|
-
|
|
68
|
-
def get_result(self) -> Any:
|
|
69
|
-
"""获取业务结果"""
|
|
70
|
-
if self.output:
|
|
71
|
-
return self.output.get("result", self.output)
|
|
72
|
-
return None
|
|
73
|
-
|
|
74
|
-
def get_files(self) -> Dict[str, List[str]]:
|
|
75
|
-
"""获取输出文件"""
|
|
76
|
-
if self.output:
|
|
77
|
-
return self.output.get("files", {})
|
|
78
|
-
return {}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
@dataclass
|
|
82
|
-
class BatchResult:
|
|
83
|
-
"""批量执行结果"""
|
|
84
|
-
|
|
85
|
-
job_id: str
|
|
86
|
-
status: str
|
|
87
|
-
results: List[PrefabResult]
|
|
88
|
-
|
|
89
|
-
def all_success(self) -> bool:
|
|
90
|
-
"""判断是否全部成功"""
|
|
91
|
-
return all(r.is_success() for r in self.results)
|
|
92
|
-
|
|
93
|
-
def get_failed(self) -> List[PrefabResult]:
|
|
94
|
-
"""获取失败的结果"""
|
|
95
|
-
return [r for r in self.results if not r.is_success()]
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
@dataclass
|
|
99
|
-
class StreamEvent:
|
|
100
|
-
"""流式事件"""
|
|
101
|
-
|
|
102
|
-
type: StreamEventType
|
|
103
|
-
data: Any
|
|
104
|
-
|
|
105
|
-
@classmethod
|
|
106
|
-
def from_dict(cls, data: Dict[str, Any]) -> "StreamEvent":
|
|
107
|
-
"""从字典创建"""
|
|
108
|
-
event_type = data.get("type", "content")
|
|
109
|
-
try:
|
|
110
|
-
event_type_enum = StreamEventType(event_type)
|
|
111
|
-
except ValueError:
|
|
112
|
-
event_type_enum = StreamEventType.CONTENT
|
|
113
|
-
|
|
114
|
-
return cls(type=event_type_enum, data=data.get("data"))
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/.github/workflows/publish.yml
RENAMED
|
File without changes
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/.github/workflows/test.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/client.py
RENAMED
|
File without changes
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/exceptions.py
RENAMED
|
File without changes
|
{agent_builder_gateway_sdk-0.2.0 → agent_builder_gateway_sdk-0.3.0}/src/gateway_sdk/streaming.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|