dmt-agent-api 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.
Files changed (35) hide show
  1. dmt_agent_api-0.3.0/.env.example +3 -0
  2. dmt_agent_api-0.3.0/MANIFEST.in +5 -0
  3. dmt_agent_api-0.3.0/PKG-INFO +166 -0
  4. dmt_agent_api-0.3.0/README.md +153 -0
  5. dmt_agent_api-0.3.0/docs/API.md +27 -0
  6. dmt_agent_api-0.3.0/docs/APPLICATIONS.md +85 -0
  7. dmt_agent_api-0.3.0/docs/TESTING.md +29 -0
  8. dmt_agent_api-0.3.0/examples/async_stream.py +18 -0
  9. dmt_agent_api-0.3.0/examples/quickstart.py +10 -0
  10. dmt_agent_api-0.3.0/examples/skills_and_vaults.py +27 -0
  11. dmt_agent_api-0.3.0/pyproject.toml +25 -0
  12. dmt_agent_api-0.3.0/setup.cfg +4 -0
  13. dmt_agent_api-0.3.0/src/dmt_agent_api.egg-info/PKG-INFO +166 -0
  14. dmt_agent_api-0.3.0/src/dmt_agent_api.egg-info/SOURCES.txt +33 -0
  15. dmt_agent_api-0.3.0/src/dmt_agent_api.egg-info/dependency_links.txt +1 -0
  16. dmt_agent_api-0.3.0/src/dmt_agent_api.egg-info/requires.txt +8 -0
  17. dmt_agent_api-0.3.0/src/dmt_agent_api.egg-info/top_level.txt +1 -0
  18. dmt_agent_api-0.3.0/src/dumate/__init__.py +13 -0
  19. dmt_agent_api-0.3.0/src/dumate/_async_client.py +151 -0
  20. dmt_agent_api-0.3.0/src/dumate/_async_resources.py +217 -0
  21. dmt_agent_api-0.3.0/src/dumate/_async_runs.py +34 -0
  22. dmt_agent_api-0.3.0/src/dumate/_client.py +151 -0
  23. dmt_agent_api-0.3.0/src/dumate/_common.py +65 -0
  24. dmt_agent_api-0.3.0/src/dumate/_downloads.py +85 -0
  25. dmt_agent_api-0.3.0/src/dumate/_sse.py +86 -0
  26. dmt_agent_api-0.3.0/src/dumate/conversation.py +183 -0
  27. dmt_agent_api-0.3.0/src/dumate/errors.py +58 -0
  28. dmt_agent_api-0.3.0/src/dumate/notebook.py +48 -0
  29. dmt_agent_api-0.3.0/src/dumate/py.typed +0 -0
  30. dmt_agent_api-0.3.0/src/dumate/resources.py +206 -0
  31. dmt_agent_api-0.3.0/src/dumate/runs.py +61 -0
  32. dmt_agent_api-0.3.0/src/dumate/types.py +51 -0
  33. dmt_agent_api-0.3.0/tests/test_conversation.py +27 -0
  34. dmt_agent_api-0.3.0/tests/test_sdk.py +253 -0
  35. dmt_agent_api-0.3.0/tools/generate_async.py +102 -0
@@ -0,0 +1,3 @@
1
+ DUMATE_API_KEY=
2
+ DUMATE_BASE_URL=https://api.dumate.cn/api/v1
3
+ DUMATE_AGENT_ID=
@@ -0,0 +1,5 @@
1
+ include README.md .env.example
2
+ recursive-include docs *.md
3
+ recursive-include examples *.py
4
+ recursive-include tests *.py
5
+ recursive-include tools *.py
@@ -0,0 +1,166 @@
1
+ Metadata-Version: 2.4
2
+ Name: dmt-agent-api
3
+ Version: 0.3.0
4
+ Summary: DMT Agent API Python SDK for DuMate
5
+ Requires-Python: >=3.10
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: httpx<1,>=0.27
8
+ Provides-Extra: notebook
9
+ Requires-Dist: ipython>=8; extra == "notebook"
10
+ Provides-Extra: test
11
+ Requires-Dist: pytest>=8; extra == "test"
12
+ Requires-Dist: pytest-asyncio>=0.23; extra == "test"
13
+
14
+ # DuMate Python SDK
15
+
16
+ 面向 DuMate 老版 `/api/v1` 的 Python 客户端。Python 3.10+,提供同步 `DuMate` 和异步 `AsyncDuMate`。当前版本 0.3.0,为独立开发的 SDK。
17
+
18
+ 应用层快速接入与前端数据协议见 [APPLICATIONS.md](docs/APPLICATIONS.md)。提供 `skills.ensure`、`conversations.create/history/stream` 和 `notebook.stream`。
19
+
20
+ ## 安装
21
+
22
+ ```bash
23
+ pip install ./dmt_agent_api-0.3.0-py3-none-any.whl
24
+ ```
25
+
26
+ 源码安装:`pip install .`。配置环境变量 `DUMATE_API_KEY`;可选 `DUMATE_BASE_URL`,默认 `https://api.dumate.cn/api/v1`。Key 仅放在后端。
27
+
28
+ ## 一次调用,等待最终结果
29
+
30
+ ```python
31
+ from dumate import DuMate
32
+
33
+ with DuMate() as client:
34
+ agent = client.agents.create(name="我的助手")
35
+ session = client.sessions.create(agent_id=agent["id"])
36
+ result = client.runs.run_and_wait(
37
+ session_id=session["id"],
38
+ message="介绍你能完成的工作",
39
+ timeout=180,
40
+ )
41
+ print(result.output_text)
42
+ ```
43
+
44
+ `runs.run_and_wait` 在客户端发送一次消息并轮询历史,关联本次用户消息与最终回答;没有对应的服务端 `/runs` 接口。适合网页的一键任务按钮:后端执行调用,完成后返回 `output_text`,前端展示结果即可。较长任务应由应用队列执行并提供任务状态查询。
45
+
46
+ 同一会话串行发送,不同会话可以并发。超时仅停止本地等待,服务端任务可能仍在执行;可查询历史或显式 `sessions.interrupt`。`timeout` 限制轮询等待,单次网络请求还受客户端 `timeout` 约束。默认等待时间无限,建议显式设置。
47
+
48
+ ## 流式事件
49
+
50
+ ```python
51
+ with client.sessions.stream(session_id, message="帮我分析这个问题") as events:
52
+ for event in events:
53
+ if event.type == "message.part.updated":
54
+ part = event.properties.get("part", {})
55
+ print(part.get("type"), part.get("text", ""))
56
+ elif event.type == "session.idle" or (
57
+ event.type == "session.status"
58
+ and event.properties.get("status", {}).get("type") == "idle"
59
+ ):
60
+ break
61
+ ```
62
+
63
+ 流建立后才发送消息。事件保留原始 `type`、`properties` 和 `raw`,未知事件也会返回;SSE `id`、`event` 字段独立保留。应用处理规则:
64
+
65
+ |数据|处理方式|
66
+ |---|---|
67
+ |message.updated 的 info|按消息 ID 更新角色、完成状态和错误|
68
+ |message.part.updated 的 part|按 part ID 替换快照;text 展示文字,reasoning 折叠展示,tool 按真实状态展示|
69
+ |增量事件|仅对明确增量字段追加;快照和增量同时出现时避免重复拼接|
70
+ |工具调用|保留调用 ID、输入、状态和输出;只展示真实事件|
71
+ |session.status / session.idle|更新运行状态;idle 还需核对历史中的最终答案或错误|
72
+ |未知事件|保留原始对象供兼容处理|
73
+
74
+ SDK 提供事件解析,不包含网页组件。断流抛出 `StreamInterruptedError`;应用先恢复 `sessions.history`,再重新订阅,不能自动重发原 query。SDK 不承诺事件重放或 Last-Event-ID 恢复。完整事件字段以服务端实际返回为准。
75
+
76
+ ## Skill
77
+
78
+ ZIP 中包含技能目录和 `SKILL.md`,文件带 YAML `name`、`description`。
79
+
80
+ ```python
81
+ skill = client.skills.upload("my-skill.zip")
82
+ mount = client.skills.mount(skill["id"])
83
+ session = client.sessions.create(agent_id=agent_id, skills=[mount])
84
+
85
+ updated = client.skills.update_zip(skill["id"], "my-skill-v2.zip")
86
+ new_mount = client.skills.mount(skill["id"])
87
+ client.sessions.update(session["id"], skills=[new_mount])
88
+ ```
89
+
90
+ 挂载使用 `skillID`、`releaseID`、`type`;`mount()` 从详情取得 `releaseId`,不能把展示版本号当作发布 ID。URL 导入用 `skills.create(url=...)`,URL 更新用 `skills.update(skill_id, url=...)`。
91
+
92
+ ## Vault、凭据和 MCP
93
+
94
+ ```python
95
+ import os
96
+
97
+ vault = client.vaults.create(name="业务系统")
98
+ credentials = client.vaults.credentials(vault["id"])
99
+ credential = credentials.create(
100
+ name="业务访问令牌",
101
+ auth={
102
+ "type": "environment_variable",
103
+ "secretName": "BUSINESS_TOKEN",
104
+ "secretValue": os.environ["BUSINESS_TOKEN"],
105
+ "networking": {
106
+ "type": "limited",
107
+ "allowedHosts": ["api.your-company.com"],
108
+ },
109
+ },
110
+ )
111
+ session = client.sessions.create(agent_id=agent_id, vault_ids=[vault["id"]])
112
+ ```
113
+
114
+ `auth` 原样传递平台的 `environment_variable`、`static_bearer` 或 `mcp_oauth` 结构,敏感值不要记录到日志。MCP 配置通过 `mcp_servers` 传入 Agent 或 Session,例如 `[{"type":"url","name":"business","url":"https://your-company.com/mcp"}]`;会话配置 MCP 时同时提供对应 `vault_ids`。各 MCP 的认证字段须按官方文档及服务商要求填写;SDK 不代办 OAuth 授权。平台未提供凭据更新接口,轮换需创建新凭据并迁移使用后删除旧凭据。
115
+
116
+ ## 文件与产物
117
+
118
+ ```python
119
+ uploaded = client.files.upload("input.pdf", session_id=session_id)
120
+ result = client.runs.run_and_wait(
121
+ session_id=session_id, message="总结附件", file_ids=[uploaded["fileID"]], timeout=300,
122
+ )
123
+ client.files.download(uploaded["fileID"], "downloaded.pdf")
124
+
125
+ mapping = client.artifacts.path_map(session_id)
126
+ for path, artifact in mapping.items():
127
+ if artifact.get("uploadStatus") == "ready":
128
+ client.artifacts.download(session_id, artifact["artifactID"], "output.bin")
129
+ break
130
+ ```
131
+
132
+ path-map 是整个会话的产物集合,不能全部当作本轮产物。按本轮回答中的文件路径、工具结果或执行前后的映射差异关联。`output.bin` 应由业务层按选中的文件设置名称;不要直接信任远端路径。
133
+
134
+ 下载返回落盘信息,默认禁止覆盖,支持 `max_bytes`。文件先写临时文件,成功后提交;校验响应长度并计算 SHA-256。产物必须 ready;存储返回 403 时刷新一次 URL。存储下载不携带 DuMate Key。URL 校验阻止明显私网地址及不安全跳转;生产环境仍需网络出口策略防止 DNS 重绑定。
135
+
136
+ 预览由应用后端代理文件,前端按 MIME 展示图片、音视频、PDF;HTML 应隔离在 sandbox iframe 中,未知类型提供下载。签名 URL 有时效,不应长期保存为产物身份。
137
+
138
+ ## 异步
139
+
140
+ ```python
141
+ import asyncio
142
+ from dumate import AsyncDuMate
143
+
144
+ async def main():
145
+ async with AsyncDuMate() as client:
146
+ session = await client.sessions.create(agent_id="你的 Agent ID")
147
+ result = await client.runs.run_and_wait(
148
+ session_id=session["id"], message="你好", timeout=180,
149
+ )
150
+ print(result.output_text)
151
+
152
+ asyncio.run(main())
153
+ ```
154
+
155
+ 异步资源方法使用 `await`;列表迭代用 `async for item in client.agents.iter()`;流用 `async with client.sessions.stream(...) as events` 和 `async for`。文件落盘及 DNS 检查仍包含短同步操作,大文件应用可用专门下载工作进程。
156
+
157
+ ## 错误与运行边界
158
+
159
+ - GET 对网络错误、429 和部分 5xx 做有限重试,默认 2 次;写操作不自动重试。
160
+ - 写请求连接失败时 `ConnectionError.outcome_unknown=True`,先核对服务端状态,避免重复创建或执行。
161
+ - `APIError` 包含状态码及请求 ID;异常文本不包含响应正文或 Key。应用不要直接打印凭据查询返回值。
162
+ - `RunTimeoutError`、`RunFailedError`、`ProtocolError` 区分等待超时、运行失败和协议异常。
163
+ - 会话与租户归属校验、鉴权、队列持久化、限流和登录恢复由业务后端负责。
164
+ - 删除 Agent 会级联删除其会话;只清理自己创建且确认不再使用的资源。
165
+
166
+ 完整方法见 [API.md](docs/API.md),验证范围见 [TESTING.md](docs/TESTING.md)。
@@ -0,0 +1,153 @@
1
+ # DuMate Python SDK
2
+
3
+ 面向 DuMate 老版 `/api/v1` 的 Python 客户端。Python 3.10+,提供同步 `DuMate` 和异步 `AsyncDuMate`。当前版本 0.3.0,为独立开发的 SDK。
4
+
5
+ 应用层快速接入与前端数据协议见 [APPLICATIONS.md](docs/APPLICATIONS.md)。提供 `skills.ensure`、`conversations.create/history/stream` 和 `notebook.stream`。
6
+
7
+ ## 安装
8
+
9
+ ```bash
10
+ pip install ./dmt_agent_api-0.3.0-py3-none-any.whl
11
+ ```
12
+
13
+ 源码安装:`pip install .`。配置环境变量 `DUMATE_API_KEY`;可选 `DUMATE_BASE_URL`,默认 `https://api.dumate.cn/api/v1`。Key 仅放在后端。
14
+
15
+ ## 一次调用,等待最终结果
16
+
17
+ ```python
18
+ from dumate import DuMate
19
+
20
+ with DuMate() as client:
21
+ agent = client.agents.create(name="我的助手")
22
+ session = client.sessions.create(agent_id=agent["id"])
23
+ result = client.runs.run_and_wait(
24
+ session_id=session["id"],
25
+ message="介绍你能完成的工作",
26
+ timeout=180,
27
+ )
28
+ print(result.output_text)
29
+ ```
30
+
31
+ `runs.run_and_wait` 在客户端发送一次消息并轮询历史,关联本次用户消息与最终回答;没有对应的服务端 `/runs` 接口。适合网页的一键任务按钮:后端执行调用,完成后返回 `output_text`,前端展示结果即可。较长任务应由应用队列执行并提供任务状态查询。
32
+
33
+ 同一会话串行发送,不同会话可以并发。超时仅停止本地等待,服务端任务可能仍在执行;可查询历史或显式 `sessions.interrupt`。`timeout` 限制轮询等待,单次网络请求还受客户端 `timeout` 约束。默认等待时间无限,建议显式设置。
34
+
35
+ ## 流式事件
36
+
37
+ ```python
38
+ with client.sessions.stream(session_id, message="帮我分析这个问题") as events:
39
+ for event in events:
40
+ if event.type == "message.part.updated":
41
+ part = event.properties.get("part", {})
42
+ print(part.get("type"), part.get("text", ""))
43
+ elif event.type == "session.idle" or (
44
+ event.type == "session.status"
45
+ and event.properties.get("status", {}).get("type") == "idle"
46
+ ):
47
+ break
48
+ ```
49
+
50
+ 流建立后才发送消息。事件保留原始 `type`、`properties` 和 `raw`,未知事件也会返回;SSE `id`、`event` 字段独立保留。应用处理规则:
51
+
52
+ |数据|处理方式|
53
+ |---|---|
54
+ |message.updated 的 info|按消息 ID 更新角色、完成状态和错误|
55
+ |message.part.updated 的 part|按 part ID 替换快照;text 展示文字,reasoning 折叠展示,tool 按真实状态展示|
56
+ |增量事件|仅对明确增量字段追加;快照和增量同时出现时避免重复拼接|
57
+ |工具调用|保留调用 ID、输入、状态和输出;只展示真实事件|
58
+ |session.status / session.idle|更新运行状态;idle 还需核对历史中的最终答案或错误|
59
+ |未知事件|保留原始对象供兼容处理|
60
+
61
+ SDK 提供事件解析,不包含网页组件。断流抛出 `StreamInterruptedError`;应用先恢复 `sessions.history`,再重新订阅,不能自动重发原 query。SDK 不承诺事件重放或 Last-Event-ID 恢复。完整事件字段以服务端实际返回为准。
62
+
63
+ ## Skill
64
+
65
+ ZIP 中包含技能目录和 `SKILL.md`,文件带 YAML `name`、`description`。
66
+
67
+ ```python
68
+ skill = client.skills.upload("my-skill.zip")
69
+ mount = client.skills.mount(skill["id"])
70
+ session = client.sessions.create(agent_id=agent_id, skills=[mount])
71
+
72
+ updated = client.skills.update_zip(skill["id"], "my-skill-v2.zip")
73
+ new_mount = client.skills.mount(skill["id"])
74
+ client.sessions.update(session["id"], skills=[new_mount])
75
+ ```
76
+
77
+ 挂载使用 `skillID`、`releaseID`、`type`;`mount()` 从详情取得 `releaseId`,不能把展示版本号当作发布 ID。URL 导入用 `skills.create(url=...)`,URL 更新用 `skills.update(skill_id, url=...)`。
78
+
79
+ ## Vault、凭据和 MCP
80
+
81
+ ```python
82
+ import os
83
+
84
+ vault = client.vaults.create(name="业务系统")
85
+ credentials = client.vaults.credentials(vault["id"])
86
+ credential = credentials.create(
87
+ name="业务访问令牌",
88
+ auth={
89
+ "type": "environment_variable",
90
+ "secretName": "BUSINESS_TOKEN",
91
+ "secretValue": os.environ["BUSINESS_TOKEN"],
92
+ "networking": {
93
+ "type": "limited",
94
+ "allowedHosts": ["api.your-company.com"],
95
+ },
96
+ },
97
+ )
98
+ session = client.sessions.create(agent_id=agent_id, vault_ids=[vault["id"]])
99
+ ```
100
+
101
+ `auth` 原样传递平台的 `environment_variable`、`static_bearer` 或 `mcp_oauth` 结构,敏感值不要记录到日志。MCP 配置通过 `mcp_servers` 传入 Agent 或 Session,例如 `[{"type":"url","name":"business","url":"https://your-company.com/mcp"}]`;会话配置 MCP 时同时提供对应 `vault_ids`。各 MCP 的认证字段须按官方文档及服务商要求填写;SDK 不代办 OAuth 授权。平台未提供凭据更新接口,轮换需创建新凭据并迁移使用后删除旧凭据。
102
+
103
+ ## 文件与产物
104
+
105
+ ```python
106
+ uploaded = client.files.upload("input.pdf", session_id=session_id)
107
+ result = client.runs.run_and_wait(
108
+ session_id=session_id, message="总结附件", file_ids=[uploaded["fileID"]], timeout=300,
109
+ )
110
+ client.files.download(uploaded["fileID"], "downloaded.pdf")
111
+
112
+ mapping = client.artifacts.path_map(session_id)
113
+ for path, artifact in mapping.items():
114
+ if artifact.get("uploadStatus") == "ready":
115
+ client.artifacts.download(session_id, artifact["artifactID"], "output.bin")
116
+ break
117
+ ```
118
+
119
+ path-map 是整个会话的产物集合,不能全部当作本轮产物。按本轮回答中的文件路径、工具结果或执行前后的映射差异关联。`output.bin` 应由业务层按选中的文件设置名称;不要直接信任远端路径。
120
+
121
+ 下载返回落盘信息,默认禁止覆盖,支持 `max_bytes`。文件先写临时文件,成功后提交;校验响应长度并计算 SHA-256。产物必须 ready;存储返回 403 时刷新一次 URL。存储下载不携带 DuMate Key。URL 校验阻止明显私网地址及不安全跳转;生产环境仍需网络出口策略防止 DNS 重绑定。
122
+
123
+ 预览由应用后端代理文件,前端按 MIME 展示图片、音视频、PDF;HTML 应隔离在 sandbox iframe 中,未知类型提供下载。签名 URL 有时效,不应长期保存为产物身份。
124
+
125
+ ## 异步
126
+
127
+ ```python
128
+ import asyncio
129
+ from dumate import AsyncDuMate
130
+
131
+ async def main():
132
+ async with AsyncDuMate() as client:
133
+ session = await client.sessions.create(agent_id="你的 Agent ID")
134
+ result = await client.runs.run_and_wait(
135
+ session_id=session["id"], message="你好", timeout=180,
136
+ )
137
+ print(result.output_text)
138
+
139
+ asyncio.run(main())
140
+ ```
141
+
142
+ 异步资源方法使用 `await`;列表迭代用 `async for item in client.agents.iter()`;流用 `async with client.sessions.stream(...) as events` 和 `async for`。文件落盘及 DNS 检查仍包含短同步操作,大文件应用可用专门下载工作进程。
143
+
144
+ ## 错误与运行边界
145
+
146
+ - GET 对网络错误、429 和部分 5xx 做有限重试,默认 2 次;写操作不自动重试。
147
+ - 写请求连接失败时 `ConnectionError.outcome_unknown=True`,先核对服务端状态,避免重复创建或执行。
148
+ - `APIError` 包含状态码及请求 ID;异常文本不包含响应正文或 Key。应用不要直接打印凭据查询返回值。
149
+ - `RunTimeoutError`、`RunFailedError`、`ProtocolError` 区分等待超时、运行失败和协议异常。
150
+ - 会话与租户归属校验、鉴权、队列持久化、限流和登录恢复由业务后端负责。
151
+ - 删除 Agent 会级联删除其会话;只清理自己创建且确认不再使用的资源。
152
+
153
+ 完整方法见 [API.md](docs/API.md),验证范围见 [TESTING.md](docs/TESTING.md)。
@@ -0,0 +1,27 @@
1
+ # 方法索引
2
+
3
+ 所有 JSON 响应保留服务端原字段名;可选参数默认省略。除特别说明外,同步与异步参数一致。
4
+
5
+ |资源|方法|
6
+ |---|---|
7
+ |agents|list(keyword,cursor,limit)、iter、create(name,description,system,skills,files,mcp_servers,tools)、get(id,version)、update(id,version,system,skills,files,mcp_servers,tools)、delete(id)|
8
+ |skills|list(page,page_size,skill_id,keyword,order)、iter(page_size)、upload(file)、create(url)、get(id,release_id)、update(id,url)、update_zip(id,file)、mount(id,release_id,type)、delete(id)|
9
+ |vaults|list(cursor,limit)、iter、create(name)、get(id)、delete(id)、credentials(vault_id)|
10
+ |vaults.credentials(id)|list(cursor,limit,auth_type)、iter、create(name,auth)、get(id)、delete(id)|
11
+ |sessions|list(cursor,limit,status)、iter、create(agent_id,metadata,vault_ids,skills,mcp_servers)、get(id)、update(id,metadata,vault_ids,skills,mcp_servers)、delete(id)|
12
+ |sessions 消息|history(id,limit,paginated)、send(id,message,file_ids)、send_event(id,event)、stream(id,message,file_ids)、interrupt(id)、submit_tool_result(id,custom_tool_use_id,content,is_error)、resource_points(id,start_at,end_at)|
13
+ |files|list(cursor,limit,order,file_ids)、iter、upload(file,session_id,mime_type)、update(id,file)、get(id)、delete(id)、download(id,destination,max_bytes,overwrite)|
14
+ |artifacts|path_map(session_id,paths)、download(session_id,artifact_id,destination,max_bytes,overwrite)|
15
+ |runs|run_and_wait(session_id,message,file_ids,timeout,poll_interval)|
16
+
17
+ ID、文件和 destination 为位置参数,其余多数参数为关键字参数;具体签名可用 Python help() 查看。异步的 `credentials(vault_id)` 和 `stream(...)` 是资源及上下文管理器工厂,不加 await。
18
+
19
+ `send()` 返回 `SendReceipt`:session_id、request_id、accepted。accepted 表示接口接受,尚未表示执行成功。
20
+
21
+ `run_and_wait()` 返回 `RunResult`:session_id、user_message_id、request_id、output_text、messages、status。messages 仅包含关联的 assistant 消息。附件请单独查询产物映射。
22
+
23
+ 自定义工具收到真实调用后,后端执行授权业务逻辑,再用 `submit_tool_result` 回传同一个 custom_tool_use_id。工具执行须自行鉴权、限流及去重。
24
+
25
+ 官方入口:https://cloud.baidu.com/doc/Dumate/s/Mmtv8sxf3
26
+
27
+ 对照文档日期:2026-11-11。当前接口版本 `/api/v1`。Skill URL 更新按官方请求示例使用 POST;文档个别标题的方法与示例存在不一致。URL 导入及外部 MCP/OAuth 需按部署环境另行验收。
@@ -0,0 +1,85 @@
1
+ # 应用接入:0.2
2
+
3
+ ## 资源管理与快捷运行
4
+
5
+ 资源仍可独立管理:`client.agents`、`client.skills`、`client.files`、`client.sessions`、`client.vaults`。快捷层只引用已有 ID:
6
+
7
+ ```python
8
+ chat = client.conversations.create(agent_id=agent_id, skills=[skill_mount])
9
+ receipt = client.conversations.send(chat["session_id"], message="你好")
10
+ result = client.conversations.run(chat["session_id"], message="继续处理", timeout=300)
11
+ client.conversations.save(client.conversations.history(chat["session_id"]), "state.json")
12
+ ```
13
+
14
+ `send` 只负责受理;`run` 负责一次发送并等待最终结果;`stream` 负责事件到统一快照;`save` 写入可恢复的 JSON。
15
+
16
+ ## Notebook
17
+
18
+ ```python
19
+ from getpass import getpass
20
+ from dumate import DuMate
21
+
22
+ with DuMate(api_key=getpass("DuMate Key:")) as client:
23
+ skill = client.skills.ensure(name="amount-check", file="amount-check.zip")
24
+ chat = client.conversations.create(
25
+ name="金额分析助手",
26
+ skills=[client.skills.mount(skill["id"])],
27
+ )
28
+ attachment = client.files.upload("amounts.txt", session_id=chat["session_id"])
29
+ result = client.notebook.stream(
30
+ chat["session_id"],
31
+ message="按照技能要求读取附件,计算合计。",
32
+ file_ids=[attachment["fileID"]],
33
+ )
34
+ ```
35
+
36
+ 安装 Notebook 可选依赖:`pip install 'dumate-agent-sdk[notebook]'`;本地 wheel 安装后可单独安装 ipython。使用 Python 3.10+。已有 Agent 时传 `agent_id`,避免每次新建。已有会话直接使用 session_id。
37
+
38
+ `skills.ensure` 按精确名称复用已有 Skill,不更新其内容;新 ZIP 的 YAML name 必须与 name 相同。修改技能用 update_zip。并发首次创建可能发生平台重名冲突,不自动重试写操作。
39
+
40
+ `conversations.create` 同时支持 skills、vault_ids、mcp_servers。只在没有 agent_id 时创建 Agent。会话创建失败时异常上的 created_agent_id 保留新建 Agent ID,可由应用决定清理。
41
+
42
+ ## 前端和后端
43
+
44
+ ```python
45
+ with client.conversations.stream(session_id, message=query, file_ids=file_ids) as updates:
46
+ for snapshot in updates:
47
+ send_to_frontend(snapshot)
48
+ ```
49
+
50
+ `send_to_frontend` 由业务服务实现,可以使用 SSE 或 WebSocket。每个 snapshot 为 JSON 可序列化完整状态,前端整体替换,按 message.id 和 part.id 做组件 key,无需再拼接原始 SSE。
51
+
52
+ |字段|含义|
53
+ |---|---|
54
+ |schema_version|当前为 1|
55
+ |session_id|当前会话|
56
+ |revision|本次订阅内递增版本;重连后重新计数|
57
+ |status|平台运行状态;idle 仅代表空闲,不保证成功|
58
+ |needs_history|出现缺少对应 Part 的增量,需要历史恢复|
59
+ |messages|消息列表,包含 id、role、finish、error、parts|
60
+
61
+ Part 保留平台字段:text 显示正文,reasoning 折叠展示平台提供的内容,tool 显示 tool、state.status、state.input/output/error。未知类型可保留而不渲染。Notebook 对所有内容做 HTML 转义,工具结果默认展开且限制可视高度。返回值保留全部内容。
62
+
63
+ 会话快照包含用户输入和工具结果,业务服务必须鉴权,并根据用户权限脱敏。不要将凭据或任意工具输出发给无权查看的前端。
64
+
65
+ ## 历史、断流和并发
66
+
67
+ `client.conversations.history(session_id)` 返回相同结构,可用于页面刷新。流式接口先读历史、建立 SSE 后发消息;流结束后再以历史校准快照。发生网络异常直接抛出,不自动重发 query。恢复时读取历史,再以 message=None 订阅;不承诺无损事件重放。
68
+
69
+ 同一会话串行发送,不同会话可并行。快照每次深拷贝,调用方修改不会污染 SDK 状态。没有独立事件 ID 时无法识别重复 delta;最终以历史为准。高频长会话可在业务层节流 UI 更新。
70
+
71
+ 同步和异步客户端都有 conversations.create/history/stream。异步使用 await、async with、async for。Notebook 渲染适配器当前仅提供同步接口。
72
+
73
+ ## 一键任务、文件、产物
74
+
75
+ 只要最终答案:`client.runs.run_and_wait(...)`。流式展示:conversations.stream 或 notebook.stream。两者都会发送消息,不能为同一请求同时调用。
76
+
77
+ File 上传、Skill 上传及 Vault 凭据配置属于资源准备阶段;可保存 ID 复用。用户附件通过 file_ids 附到当前 query。SDK 不自动把电脑上的其他文件上传。
78
+
79
+ 产物使用 artifacts.path_map 查询、artifacts.download 下载。映射是整个会话范围,按当前轮工具输出或文件路径关联;不可把历史产物自动算作当前轮。预览组件由前端根据 MIME 选择,HTML 使用隔离 sandbox,下载链接由后端鉴权代理。此版本未提供文件预览组件。
80
+
81
+ ## 生命周期
82
+
83
+ SDK 不自动删除远端资源。保留 agent_id、session_id、skill_id、fileID、vault_id 供恢复及清理。Agent 删除会级联删除会话。Vault 和 Skill 可能被多个会话使用,确认归属后再删除。
84
+
85
+ 生产应用还需持久任务队列、用户与资源映射、限流、审计和幂等管理。SDK 未提供跨进程运行恢复和跨租户权限系统。
@@ -0,0 +1,29 @@
1
+ # 验证范围
2
+
3
+ 版本:0.1.0。验证日期:2026-11-11。
4
+
5
+ ## 真实 API
6
+
7
+ 使用独立测试资源调用 `https://api.dumate.cn/api/v1`:
8
+
9
+ - Agent:列表、创建、详情、删除。
10
+ - Skill:列表、ZIP 上传、详情、ZIP 更新、releaseId 获取与会话挂载。
11
+ - Vault:列表、创建、详情、删除;environment_variable 凭据创建、列表、详情、删除。
12
+ - Session:创建、详情、历史、真实消息执行、资源点查询、删除。
13
+ - SSE:连接后发消息,接收真实 message.updated、message.part.updated、message.part.delta、reasoning-summary、session.status、session.artifact.updated 等事件。
14
+ - 最终答案:同步等待成功;异步调用返回 ASYNC_OK。
15
+ - 产物:真实生成 TXT,查询路径映射、下载,内容包含 SDK artifact verified 及平台生成标识。
16
+ - File:上传、详情、下载、更新、删除;同步与异步下载逐字节比对通过。上传响应字段为 fileID。
17
+ - 测试 Agent、Session、Skill、Vault、凭据及上传文件已清理。
18
+
19
+ ## 自动化测试
20
+
21
+ 21 项通过。包括请求字段、分页、同步与异步调用、SSE 分片/多字节/半帧、先订阅后发送、历史关联、超时不重复发送、错误脱敏、写操作不重试、下载原子提交、私网地址拒绝和产物 URL 刷新。
22
+
23
+ 这些协议与故障测试使用独立测试夹具;真实 API 验证范围列于上节。
24
+
25
+ ## 尚未实测
26
+
27
+ Skill URL 导入/更新、static_bearer 与 MCP OAuth 的真实授权链路、外部 MCP 工具运行、自定义工具完整回传流程、Agent 版本更新、生产规模并发、断网后应用级恢复与跨租户权限控制。
28
+
29
+ SDK 为初始版本。上述能力中,平台接口封装可用范围见 API 索引;未实测项仍需接入方在目标环境验收。SDK 不提供持久任务队列、前端组件或自动断点续跑。
@@ -0,0 +1,18 @@
1
+ import asyncio
2
+ import os
3
+ from dumate import AsyncDuMate
4
+
5
+ async def main():
6
+ async with AsyncDuMate() as client:
7
+ session = await client.sessions.create(agent_id=os.environ["DUMATE_AGENT_ID"])
8
+ async with client.sessions.stream(session["id"], message="你好") as events:
9
+ async for event in events:
10
+ print(event.type)
11
+ if event.type == "session.idle" or (
12
+ event.type == "session.status"
13
+ and event.properties.get("status", {}).get("type") == "idle"
14
+ ):
15
+ break
16
+
17
+ if __name__ == "__main__":
18
+ asyncio.run(main())
@@ -0,0 +1,10 @@
1
+ import os
2
+ from dumate import DuMate
3
+
4
+ if __name__ == "__main__":
5
+ with DuMate() as client:
6
+ session = client.sessions.create(agent_id=os.environ["DUMATE_AGENT_ID"])
7
+ result = client.runs.run_and_wait(
8
+ session_id=session["id"], message="介绍你能完成的工作", timeout=180,
9
+ )
10
+ print(result.output_text)
@@ -0,0 +1,27 @@
1
+ import os
2
+ from dumate import DuMate
3
+
4
+ if __name__ == "__main__":
5
+ with DuMate() as client:
6
+ skill = client.skills.upload(os.environ["DUMATE_SKILL_ZIP"])
7
+ vault = client.vaults.create(name="应用凭据")
8
+ client.vaults.credentials(vault["id"]).create(
9
+ name="业务令牌",
10
+ auth={
11
+ "type": "environment_variable",
12
+ "secretName": "BUSINESS_TOKEN",
13
+ "secretValue": os.environ["BUSINESS_TOKEN"],
14
+ "networking": {
15
+ "type": "limited",
16
+ "allowedHosts": [os.environ["BUSINESS_HOST"]],
17
+ },
18
+ },
19
+ )
20
+ session = client.sessions.create(
21
+ agent_id=os.environ["DUMATE_AGENT_ID"],
22
+ skills=[client.skills.mount(skill["id"])],
23
+ vault_ids=[vault["id"]],
24
+ )
25
+ print("session_id:", session["id"])
26
+ print("skill_id:", skill["id"])
27
+ print("vault_id:", vault["id"])
@@ -0,0 +1,25 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "dmt-agent-api"
7
+ version = "0.3.0"
8
+ description = "DMT Agent API Python SDK for DuMate"
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = ["httpx>=0.27,<1"]
12
+
13
+ [project.optional-dependencies]
14
+ notebook = ["ipython>=8"]
15
+ test = ["pytest>=8", "pytest-asyncio>=0.23"]
16
+
17
+ [tool.setuptools.packages.find]
18
+ where = ["src"]
19
+
20
+ [tool.setuptools.package-data]
21
+ dumate = ["py.typed"]
22
+
23
+ [tool.pytest.ini_options]
24
+ testpaths = ["tests"]
25
+ asyncio_mode = "auto"
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+