managed-agent-sdk 0.0.1__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.
- managed_agent_sdk-0.0.1/.gitignore +43 -0
- managed_agent_sdk-0.0.1/CHANGELOG.md +90 -0
- managed_agent_sdk-0.0.1/LICENSE +21 -0
- managed_agent_sdk-0.0.1/PKG-INFO +155 -0
- managed_agent_sdk-0.0.1/README.md +118 -0
- managed_agent_sdk-0.0.1/pyproject.toml +140 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/__init__.py +325 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_generated/__init__.py +8 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_generated/actions.py +815 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_generated/defaults.py +112 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_generated/enums.py +103 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_generated/types.py +440 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/_version.py +19 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/acp/__init__.py +18 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/acp/client.py +691 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/acp/compat.py +104 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/acp/transport.py +755 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/acp_types.py +93 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/agent.py +496 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/auth.py +115 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/capi.py +331 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/catalog.py +317 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/client.py +325 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/errors.py +278 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/external_agent.py +306 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/manifest.py +249 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/opts.py +299 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/py.typed +0 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/session.py +462 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/types.py +110 -0
- managed_agent_sdk-0.0.1/src/managed_agent_sdk/version.py +229 -0
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# ── Node ────────────────────────────────
|
|
2
|
+
node_modules/
|
|
3
|
+
dist/
|
|
4
|
+
lib/
|
|
5
|
+
*.tsbuildinfo
|
|
6
|
+
.pnpm-store/
|
|
7
|
+
|
|
8
|
+
# ── Python ──────────────────────────────
|
|
9
|
+
__pycache__/
|
|
10
|
+
*.py[cod]
|
|
11
|
+
*.egg-info/
|
|
12
|
+
build/
|
|
13
|
+
.venv/
|
|
14
|
+
venv/
|
|
15
|
+
.pytest_cache/
|
|
16
|
+
.mypy_cache/
|
|
17
|
+
.ruff_cache/
|
|
18
|
+
|
|
19
|
+
# ── 测试覆盖率报告 ──────────────────────
|
|
20
|
+
coverage/
|
|
21
|
+
.coverage
|
|
22
|
+
|
|
23
|
+
# ── 中间结果(脚本临时产物统一落这里)──────
|
|
24
|
+
.scratch/
|
|
25
|
+
|
|
26
|
+
# ── 本地环境(含真实凭证,永不入仓)──────
|
|
27
|
+
# 两行都需要:`.env.*` 不匹配无后缀的 `.env`
|
|
28
|
+
.env
|
|
29
|
+
.env.*
|
|
30
|
+
# 模板例外 —— 不含真实值,新人靠它起步。
|
|
31
|
+
# 没有这条负例时 .env.example 会被上面一行盖住,
|
|
32
|
+
# 当前它只因「已被跟踪」才幸免,换个仓库或重新 add 就会失效。
|
|
33
|
+
!.env.example
|
|
34
|
+
|
|
35
|
+
# 发布时注入 npm token 的鉴权文件。
|
|
36
|
+
# 根 .npmrc 只配镜像源、需入库共享,故这里只忽略包目录下的。
|
|
37
|
+
packages/*/.npmrc
|
|
38
|
+
|
|
39
|
+
# 交付给测试的打包产物(pnpm pack / uv build 的输出)
|
|
40
|
+
dist-release/
|
|
41
|
+
packages/*/*.tgz
|
|
42
|
+
|
|
43
|
+
.DS_Store
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
managed-agent-sdk(Python)的所有重要更新都会记录在这里。
|
|
4
|
+
|
|
5
|
+
遵循 [语义化版本](https://semver.org/spec/v2.0.0.html)。
|
|
6
|
+
|
|
7
|
+
## [0.0.1] - 2026-09-22
|
|
8
|
+
|
|
9
|
+
首个版本。行为与 Node 版对齐,两侧由一份共享用例(`spec/cases/`)保证一致。
|
|
10
|
+
|
|
11
|
+
### 运行环境
|
|
12
|
+
|
|
13
|
+
要求 Python >= 3.10, < 3.15。全异步 API(`async`/`await`),基于 httpx。
|
|
14
|
+
|
|
15
|
+
### 🎉 新功能
|
|
16
|
+
|
|
17
|
+
**控制面**(走腾讯云 API,官方 SDK 签名)
|
|
18
|
+
|
|
19
|
+
- `client.agents` —— Agent 的增删改查、路由权重灰度(`update_routing`)、
|
|
20
|
+
A2A Inbound 配置
|
|
21
|
+
- `agent.versions` —— 版本创建(含从源版本派生)、查询、修改。
|
|
22
|
+
`create` / `create_from_source` 恒发 `IsTest: true`,不把「建出 prod 版本」
|
|
23
|
+
这个选择交给调用方
|
|
24
|
+
- `agent.sessions` / `client.sessions` —— 会话创建、查询、跨版本迁移
|
|
25
|
+
- `agent.external_agents` —— A2A Outbound 的绑定与解绑
|
|
26
|
+
- `client.models` —— 内置模型列表
|
|
27
|
+
|
|
28
|
+
**数据面**(走 ACP 协议)
|
|
29
|
+
|
|
30
|
+
- `session.prompt()` 流式对话,支持多模态 image block。返回值是 SDK 收窄过的
|
|
31
|
+
`PromptResponse`(`managed_agent_sdk.acp_types`),**只有 `stop_reason`** ——
|
|
32
|
+
上游 `acp.schema.PromptResponse` 还带 `usage` / `_meta`,但服务端实测恒为
|
|
33
|
+
`None`,透出去会让人以为能从这里读用量。要读用量走 `session.messages()` 的
|
|
34
|
+
`Message["TokenUsage"]`(与 Node 版 `Pick<…, 'stopReason'>` 对齐)
|
|
35
|
+
- `session.subscribe()` 订阅上游通知、`cancel()` 取消进行中的回合
|
|
36
|
+
- SSE 断线自动重连(连接层状态恢复,**不重放 prompt**)
|
|
37
|
+
- 两段凭证(云 API 密钥 + OneID 换票)由 SDK 内部缝合,调用方无需感知
|
|
38
|
+
- 建连只发 `Authorization: Bearer` + `X-Agent-Session-Id`。网关的 oneid-auth
|
|
39
|
+
插件按 Bearer 令牌本身本地验签,**不能再带 `X-Auth-Method: oneid`** ——
|
|
40
|
+
带上会走旧的鉴权分支并被拒(401 `oneid token invalid: not_oneid`)
|
|
41
|
+
- 数据面每次请求(建连 / 重连 / POST / DELETE)前取新鲜 token。OneID token
|
|
42
|
+
有效期 30 天,长连接会跨过它 —— 只在建连时取一次的话,过期后所有请求都
|
|
43
|
+
带着废票发。取票走 client 级缓存(提前 5 分钟换新、并发合并),每次调用
|
|
44
|
+
的开销只是一次判时间
|
|
45
|
+
- 建连遇到 401 / 403 立即失败并抛 `AcpAuthError`,不进重连循环 ——
|
|
46
|
+
鉴权失败重试改变不了结果,只会把失败拖到握手超时,报出「网络超时」
|
|
47
|
+
掩盖真实原因。异常带服务端原文与 `request_id`(`x-request-id`),
|
|
48
|
+
可直接交给服务端排查;其余状态码仍按原重连策略走
|
|
49
|
+
|
|
50
|
+
**目录资源**
|
|
51
|
+
|
|
52
|
+
- 连接器(`client.connectors`)、技能(`client.skills`)、专家(`client.experts`)
|
|
53
|
+
- 连接器绑定用 `connector_ids` 声明最终集合,服务端按它全量覆盖;
|
|
54
|
+
传空列表即解绑全部
|
|
55
|
+
- `ManifestBuilder` —— 类型化构建 manifest,本地校验对齐服务端 v2 白名单
|
|
56
|
+
|
|
57
|
+
**类型与配置**
|
|
58
|
+
|
|
59
|
+
- 随包附带 `py.typed`,mypy / pyright 可直接吃到类型
|
|
60
|
+
- `ClientOpts.transport` 可注入自定义 httpx transport(链路追踪 / 代理 /
|
|
61
|
+
测试替身),只影响数据面;控制面由官方 SDK 发请求,用 `proxy` 配置
|
|
62
|
+
|
|
63
|
+
### ⚠️ 需要注意的行为
|
|
64
|
+
|
|
65
|
+
**分页 `limit` 上限统一为 100**,各列表方法一致。超限本地抛
|
|
66
|
+
`ValidationError`,不发请求。
|
|
67
|
+
|
|
68
|
+
**`offset` 必须是 `limit` 的整数倍**,全部列表方法一致,否则抛
|
|
69
|
+
`ValidationError`:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
await client.agents.list(PageOpts(offset=30, limit=20)) # ValidationError
|
|
73
|
+
await client.agents.list(PageOpts(offset=40, limit=20)) # 正常
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
省略 `limit` 时按默认的 20 校验边界。
|
|
77
|
+
|
|
78
|
+
**不做控制面自动重试。** `create_*` 类接口非幂等且服务端不提供 `ClientToken`,
|
|
79
|
+
重试 `create_session` 会重复拉起沙箱并产生真实费用。`CapiError.retryable`
|
|
80
|
+
仅作信息提示,由调用方决定是否重试。
|
|
81
|
+
|
|
82
|
+
**出参保持云 API 原样**(PascalCase、不翻译枚举、不过滤零值),抓包所见即
|
|
83
|
+
所得,拿着云 API 文档就能对照。入参则提供 snake_case 便利层。
|
|
84
|
+
|
|
85
|
+
**会话沙箱不会自动回收**,用完请 `await session.disconnect()`。
|
|
86
|
+
|
|
87
|
+
### 🔧 协议兼容
|
|
88
|
+
|
|
89
|
+
`Usage.total_tokens` 按 ACP 协议声明是必填字段。本侧走 pydantic 运行时校验,
|
|
90
|
+
已在 `acp/compat.py` 放宽该约束以兼容实际返回(Node 侧无运行时校验,不受影响)。
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Tencent CodeBuddy
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: managed-agent-sdk
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Managed Agent SDK (Python) — 控制面走腾讯云 API,数据面走 ACP
|
|
5
|
+
Project-URL: Homepage, https://cnb.cool/codebuddy/managed-agent-sdk
|
|
6
|
+
Project-URL: Repository, https://cnb.cool/codebuddy/managed-agent-sdk
|
|
7
|
+
Project-URL: Issues, https://cnb.cool/codebuddy/managed-agent-sdk/-/issues
|
|
8
|
+
Project-URL: Changelog, https://cnb.cool/codebuddy/managed-agent-sdk/-/blob/main/packages/python/CHANGELOG.md
|
|
9
|
+
Author-email: Tencent CodeBuddy <codebuddy@tencent.com>
|
|
10
|
+
License: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Keywords: acp,agent,llm,managed-agent,sandbox
|
|
13
|
+
Classifier: Development Status :: 3 - Alpha
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Python: <3.15,>=3.10
|
|
25
|
+
Requires-Dist: agent-client-protocol<0.13,>=0.12
|
|
26
|
+
Requires-Dist: httpx>=0.27
|
|
27
|
+
Requires-Dist: pydantic>=2.6
|
|
28
|
+
Requires-Dist: tencentcloud-sdk-python-common>=3.0.1000
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: mypy>=1.10; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8; extra == 'dev'
|
|
33
|
+
Requires-Dist: respx>=0.21; extra == 'dev'
|
|
34
|
+
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
35
|
+
Requires-Dist: uvicorn>=0.30; extra == 'dev'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
# managed-agent-sdk(Python)
|
|
39
|
+
|
|
40
|
+
腾讯云 **WorkBuddy 企业版 Managed Agent** 的 Python SDK。
|
|
41
|
+
|
|
42
|
+
控制面走腾讯云 API(TC3 签名),数据面走 ACP 协议,两段凭证由 SDK 内部缝合。
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install managed-agent-sdk
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
要求 Python 3.10 ~ 3.14。Node 版见 [`@tencent-ai/managed-agent-sdk`](https://www.npmjs.com/package/@tencent-ai/managed-agent-sdk),两侧 API 语义一致。
|
|
49
|
+
|
|
50
|
+
## 凭证
|
|
51
|
+
|
|
52
|
+
从环境变量读取,或在构造时显式传入:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
export TENCENTCLOUD_SECRET_ID=你的SecretId
|
|
56
|
+
export TENCENTCLOUD_SECRET_KEY=你的SecretKey
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
只支持长期密钥,不支持 STS 临时密钥。数据面(ACP)的凭证由 SDK 用这套密钥自动换取并缓存,无需单独配置。
|
|
60
|
+
|
|
61
|
+
## 快速开始
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import asyncio
|
|
65
|
+
|
|
66
|
+
from managed_agent_sdk import (
|
|
67
|
+
CreateAgentOpts,
|
|
68
|
+
CreateSessionOpts,
|
|
69
|
+
CreateVersionOpts,
|
|
70
|
+
ManagedAgentClient,
|
|
71
|
+
ManifestBuilder,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
async def main() -> None:
|
|
76
|
+
async with ManagedAgentClient() as client:
|
|
77
|
+
# 创建 Agent
|
|
78
|
+
agent = await client.agents.create(
|
|
79
|
+
CreateAgentOpts(
|
|
80
|
+
agent_name="日志分析助手",
|
|
81
|
+
model="deepseek-v3",
|
|
82
|
+
manifest=ManifestBuilder().system_prompt("你是日志分析专家").build(),
|
|
83
|
+
)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# 创建版本(manifest 服务端必填)
|
|
87
|
+
version = await agent.versions.create(
|
|
88
|
+
CreateVersionOpts(
|
|
89
|
+
manifest=ManifestBuilder().system_prompt("你是日志分析专家").build(),
|
|
90
|
+
)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# 创建会话(拉起真实沙箱,不会自动回收 —— 尽量复用)
|
|
94
|
+
session = await agent.sessions.create(
|
|
95
|
+
CreateSessionOpts(version_id=version.version_id)
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# 对话
|
|
99
|
+
res = await session.prompt("分析这份日志")
|
|
100
|
+
print(res.stop_reason)
|
|
101
|
+
|
|
102
|
+
await session.disconnect()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
asyncio.run(main())
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`prompt()` 的返回值只携带 `stop_reason`,回复文本从 `on_chunk` 取 —— 流式内容与终局结果分两条通道,这是 ACP 的协议设计。
|
|
109
|
+
|
|
110
|
+
## 配置连接器 / 技能 / 专家
|
|
111
|
+
|
|
112
|
+
三类资源的**配置入口不统一**,这是最容易配错的地方:
|
|
113
|
+
|
|
114
|
+
| 资源 | 查询 | 配置入口 | 最终落点 |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| 连接器(MCP) | `client.connectors.list()` | `connector_ids`(Action 入参) | 服务端物化成 manifest 的 `mcp_servers` |
|
|
117
|
+
| 技能 | `client.skills.list()` | `ManifestBuilder.skills()` | manifest 的 `skills` |
|
|
118
|
+
| 专家 | `client.experts.list()` | `ManifestBuilder.experts()` | manifest 的 `experts` |
|
|
119
|
+
|
|
120
|
+
技能与专家进 manifest,连接器**不进** —— 只把 ID 交给服务端,由它查网关地址后物化。
|
|
121
|
+
自己往 manifest 里写 `mcp_servers` 会与之重复。
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
skills = await client.skills.list("BUILTIN", ListSkillsOpts(limit=50))
|
|
125
|
+
connectors = await client.connectors.list_active()
|
|
126
|
+
|
|
127
|
+
agent = await client.agents.create(
|
|
128
|
+
CreateAgentOpts(
|
|
129
|
+
agent_name="运维助手",
|
|
130
|
+
manifest=(
|
|
131
|
+
ManifestBuilder()
|
|
132
|
+
.system_prompt("你是运维专家")
|
|
133
|
+
.skills([{"type": "builtin", "id": s["SkillId"]} for s in skills.items])
|
|
134
|
+
.build()
|
|
135
|
+
),
|
|
136
|
+
connector_ids=[c["ConnectorId"] for c in connectors.items], # 独立入参
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
`connector_ids` 是该版本最终要绑的完整集合,服务端按它做全量覆盖 ——
|
|
142
|
+
改绑定直接传新集合,解绑从列表里去掉即可,传 `[]` 解绑全部。
|
|
143
|
+
|
|
144
|
+
## 两条约定
|
|
145
|
+
|
|
146
|
+
**入参 snake_case,出参 PascalCase。** 出参原样透传云 API 字段名,便于对照官方文档排查。
|
|
147
|
+
|
|
148
|
+
**不做控制面自动重试。** `Create*` 类接口非幂等且服务端不提供 `ClientToken`,重试 `sessions.create()` 会重复拉起沙箱并产生真实费用。唯一例外是 ACP 断线重连(`Last-Event-ID` 断点续传,不重放 prompt)。
|
|
149
|
+
|
|
150
|
+
**会话即沙箱,且不会自动回收。** `sessions.create()` 每次调用都拉起一个真实沙箱。注意 `disconnect()` **只断 ACP 连接,不释放沙箱** —— 服务端既没有销毁会话的接口,也没有空闲超时回收(`IDLE` 只是「上一轮对话结束」的轮次状态,沙箱照常运行)。要复用会话,别在循环里反复新建。
|
|
151
|
+
|
|
152
|
+
## 文档
|
|
153
|
+
|
|
154
|
+
完整 API 参考、错误码表、已知问题见
|
|
155
|
+
[Managed Agent SDK 文档](https://cnb.cool/codebuddy/managed-agent-doc/-/blob/main/python/README.md)。
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# managed-agent-sdk(Python)
|
|
2
|
+
|
|
3
|
+
腾讯云 **WorkBuddy 企业版 Managed Agent** 的 Python SDK。
|
|
4
|
+
|
|
5
|
+
控制面走腾讯云 API(TC3 签名),数据面走 ACP 协议,两段凭证由 SDK 内部缝合。
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install managed-agent-sdk
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
要求 Python 3.10 ~ 3.14。Node 版见 [`@tencent-ai/managed-agent-sdk`](https://www.npmjs.com/package/@tencent-ai/managed-agent-sdk),两侧 API 语义一致。
|
|
12
|
+
|
|
13
|
+
## 凭证
|
|
14
|
+
|
|
15
|
+
从环境变量读取,或在构造时显式传入:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
export TENCENTCLOUD_SECRET_ID=你的SecretId
|
|
19
|
+
export TENCENTCLOUD_SECRET_KEY=你的SecretKey
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
只支持长期密钥,不支持 STS 临时密钥。数据面(ACP)的凭证由 SDK 用这套密钥自动换取并缓存,无需单独配置。
|
|
23
|
+
|
|
24
|
+
## 快速开始
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import asyncio
|
|
28
|
+
|
|
29
|
+
from managed_agent_sdk import (
|
|
30
|
+
CreateAgentOpts,
|
|
31
|
+
CreateSessionOpts,
|
|
32
|
+
CreateVersionOpts,
|
|
33
|
+
ManagedAgentClient,
|
|
34
|
+
ManifestBuilder,
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def main() -> None:
|
|
39
|
+
async with ManagedAgentClient() as client:
|
|
40
|
+
# 创建 Agent
|
|
41
|
+
agent = await client.agents.create(
|
|
42
|
+
CreateAgentOpts(
|
|
43
|
+
agent_name="日志分析助手",
|
|
44
|
+
model="deepseek-v3",
|
|
45
|
+
manifest=ManifestBuilder().system_prompt("你是日志分析专家").build(),
|
|
46
|
+
)
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# 创建版本(manifest 服务端必填)
|
|
50
|
+
version = await agent.versions.create(
|
|
51
|
+
CreateVersionOpts(
|
|
52
|
+
manifest=ManifestBuilder().system_prompt("你是日志分析专家").build(),
|
|
53
|
+
)
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# 创建会话(拉起真实沙箱,不会自动回收 —— 尽量复用)
|
|
57
|
+
session = await agent.sessions.create(
|
|
58
|
+
CreateSessionOpts(version_id=version.version_id)
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
# 对话
|
|
62
|
+
res = await session.prompt("分析这份日志")
|
|
63
|
+
print(res.stop_reason)
|
|
64
|
+
|
|
65
|
+
await session.disconnect()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
asyncio.run(main())
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`prompt()` 的返回值只携带 `stop_reason`,回复文本从 `on_chunk` 取 —— 流式内容与终局结果分两条通道,这是 ACP 的协议设计。
|
|
72
|
+
|
|
73
|
+
## 配置连接器 / 技能 / 专家
|
|
74
|
+
|
|
75
|
+
三类资源的**配置入口不统一**,这是最容易配错的地方:
|
|
76
|
+
|
|
77
|
+
| 资源 | 查询 | 配置入口 | 最终落点 |
|
|
78
|
+
| --- | --- | --- | --- |
|
|
79
|
+
| 连接器(MCP) | `client.connectors.list()` | `connector_ids`(Action 入参) | 服务端物化成 manifest 的 `mcp_servers` |
|
|
80
|
+
| 技能 | `client.skills.list()` | `ManifestBuilder.skills()` | manifest 的 `skills` |
|
|
81
|
+
| 专家 | `client.experts.list()` | `ManifestBuilder.experts()` | manifest 的 `experts` |
|
|
82
|
+
|
|
83
|
+
技能与专家进 manifest,连接器**不进** —— 只把 ID 交给服务端,由它查网关地址后物化。
|
|
84
|
+
自己往 manifest 里写 `mcp_servers` 会与之重复。
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
skills = await client.skills.list("BUILTIN", ListSkillsOpts(limit=50))
|
|
88
|
+
connectors = await client.connectors.list_active()
|
|
89
|
+
|
|
90
|
+
agent = await client.agents.create(
|
|
91
|
+
CreateAgentOpts(
|
|
92
|
+
agent_name="运维助手",
|
|
93
|
+
manifest=(
|
|
94
|
+
ManifestBuilder()
|
|
95
|
+
.system_prompt("你是运维专家")
|
|
96
|
+
.skills([{"type": "builtin", "id": s["SkillId"]} for s in skills.items])
|
|
97
|
+
.build()
|
|
98
|
+
),
|
|
99
|
+
connector_ids=[c["ConnectorId"] for c in connectors.items], # 独立入参
|
|
100
|
+
)
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
`connector_ids` 是该版本最终要绑的完整集合,服务端按它做全量覆盖 ——
|
|
105
|
+
改绑定直接传新集合,解绑从列表里去掉即可,传 `[]` 解绑全部。
|
|
106
|
+
|
|
107
|
+
## 两条约定
|
|
108
|
+
|
|
109
|
+
**入参 snake_case,出参 PascalCase。** 出参原样透传云 API 字段名,便于对照官方文档排查。
|
|
110
|
+
|
|
111
|
+
**不做控制面自动重试。** `Create*` 类接口非幂等且服务端不提供 `ClientToken`,重试 `sessions.create()` 会重复拉起沙箱并产生真实费用。唯一例外是 ACP 断线重连(`Last-Event-ID` 断点续传,不重放 prompt)。
|
|
112
|
+
|
|
113
|
+
**会话即沙箱,且不会自动回收。** `sessions.create()` 每次调用都拉起一个真实沙箱。注意 `disconnect()` **只断 ACP 连接,不释放沙箱** —— 服务端既没有销毁会话的接口,也没有空闲超时回收(`IDLE` 只是「上一轮对话结束」的轮次状态,沙箱照常运行)。要复用会话,别在循环里反复新建。
|
|
114
|
+
|
|
115
|
+
## 文档
|
|
116
|
+
|
|
117
|
+
完整 API 参考、错误码表、已知问题见
|
|
118
|
+
[Managed Agent SDK 文档](https://cnb.cool/codebuddy/managed-agent-doc/-/blob/main/python/README.md)。
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["hatchling"]
|
|
3
|
+
build-backend = "hatchling.build"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "managed-agent-sdk"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
description = "Managed Agent SDK (Python) — 控制面走腾讯云 API,数据面走 ACP"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10,<3.15"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [{ name = "Tencent CodeBuddy", email = "codebuddy@tencent.com" }]
|
|
13
|
+
keywords = [
|
|
14
|
+
"agent",
|
|
15
|
+
"acp",
|
|
16
|
+
"managed-agent",
|
|
17
|
+
"llm",
|
|
18
|
+
"sandbox",
|
|
19
|
+
]
|
|
20
|
+
classifiers = [
|
|
21
|
+
"Development Status :: 3 - Alpha",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Programming Language :: Python :: 3",
|
|
25
|
+
"Programming Language :: Python :: 3.10",
|
|
26
|
+
"Programming Language :: Python :: 3.11",
|
|
27
|
+
"Programming Language :: Python :: 3.12",
|
|
28
|
+
"Programming Language :: Python :: 3.13",
|
|
29
|
+
"Programming Language :: Python :: 3.14",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
"Typing :: Typed",
|
|
32
|
+
]
|
|
33
|
+
dependencies = [
|
|
34
|
+
"httpx>=0.27",
|
|
35
|
+
"pydantic>=2.6",
|
|
36
|
+
# 锁到次版本:本 SDK 依赖上游的内部结构 —— acp/compat.py 给 pydantic 模型
|
|
37
|
+
# 打补丁放宽必填字段,set_session_model 直连私有属性
|
|
38
|
+
# ClientSideConnection._conn 发不带下划线前缀的方法名。0.x 阶段每个次版本
|
|
39
|
+
# 都可能改这些,放到 <1.0 等于让新用户装到未验证过的组合。
|
|
40
|
+
# 升级上游时连同 compat.py 一起验证,再手工放宽这里。
|
|
41
|
+
"agent-client-protocol>=0.12,<0.13",
|
|
42
|
+
# Managed Agent 控制面走云 API,签名与信封拆解交给官方 SDK
|
|
43
|
+
"tencentcloud-sdk-python-common>=3.0.1000",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=8",
|
|
49
|
+
"pytest-asyncio>=0.23",
|
|
50
|
+
"respx>=0.21",
|
|
51
|
+
"uvicorn>=0.30",
|
|
52
|
+
"mypy>=1.10",
|
|
53
|
+
"ruff>=0.5",
|
|
54
|
+
]
|
|
55
|
+
|
|
56
|
+
[project.urls]
|
|
57
|
+
Homepage = "https://cnb.cool/codebuddy/managed-agent-sdk"
|
|
58
|
+
Repository = "https://cnb.cool/codebuddy/managed-agent-sdk"
|
|
59
|
+
Issues = "https://cnb.cool/codebuddy/managed-agent-sdk/-/issues"
|
|
60
|
+
Changelog = "https://cnb.cool/codebuddy/managed-agent-sdk/-/blob/main/packages/python/CHANGELOG.md"
|
|
61
|
+
|
|
62
|
+
# ─── Hatchling ────────────────────────────────
|
|
63
|
+
|
|
64
|
+
[tool.hatch.version]
|
|
65
|
+
path = "src/managed_agent_sdk/_version.py"
|
|
66
|
+
|
|
67
|
+
[tool.hatch.build.targets.wheel]
|
|
68
|
+
packages = ["src/managed_agent_sdk"]
|
|
69
|
+
|
|
70
|
+
[tool.hatch.build.targets.sdist]
|
|
71
|
+
include = [
|
|
72
|
+
"src/managed_agent_sdk",
|
|
73
|
+
"README.md",
|
|
74
|
+
"CHANGELOG.md",
|
|
75
|
+
"LICENSE",
|
|
76
|
+
"pyproject.toml",
|
|
77
|
+
]
|
|
78
|
+
|
|
79
|
+
# ─── Ruff ────────────────────────────────────
|
|
80
|
+
|
|
81
|
+
[tool.ruff]
|
|
82
|
+
line-length = 100
|
|
83
|
+
target-version = "py310"
|
|
84
|
+
src = ["src", "e2e"]
|
|
85
|
+
|
|
86
|
+
[tool.ruff.lint]
|
|
87
|
+
select = [
|
|
88
|
+
"E", # pycodestyle errors
|
|
89
|
+
"W", # pycodestyle warnings
|
|
90
|
+
"F", # pyflakes
|
|
91
|
+
"I", # isort
|
|
92
|
+
"B", # flake8-bugbear
|
|
93
|
+
"UP", # pyupgrade
|
|
94
|
+
"SIM", # flake8-simplify
|
|
95
|
+
"RUF", # ruff-specific
|
|
96
|
+
]
|
|
97
|
+
ignore = [
|
|
98
|
+
"E501", # line too long — 交给 ruff format
|
|
99
|
+
"B008", # function call in default arg — dataclass 经常需要
|
|
100
|
+
"RUF001", # ambiguous chars in string — 中文文档正常
|
|
101
|
+
"RUF002", # ambiguous chars in docstring — 中文文档正常
|
|
102
|
+
"RUF003", # ambiguous chars in comment — 中文注释正常
|
|
103
|
+
"RUF012", # mutable class attr default — pydantic 模型会为每实例深拷贝默认值,无共享引用风险
|
|
104
|
+
"RUF022", # `__all__` is not sorted — 语义分组优先
|
|
105
|
+
"SIM105", # contextlib.suppress — try/except/pass 对热路径更直观
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
[tool.ruff.lint.per-file-ignores]
|
|
109
|
+
"e2e/**" = ["E402"] # 联调脚本需在 import 前注入 sys.path
|
|
110
|
+
|
|
111
|
+
# ─── Mypy ────────────────────────────────────
|
|
112
|
+
|
|
113
|
+
[tool.mypy]
|
|
114
|
+
python_version = "3.10"
|
|
115
|
+
strict = true
|
|
116
|
+
warn_unused_ignores = true
|
|
117
|
+
warn_redundant_casts = true
|
|
118
|
+
warn_return_any = true
|
|
119
|
+
no_implicit_reexport = false # __init__.py 里的 re-export 是明确的
|
|
120
|
+
files = ["src/managed_agent_sdk"]
|
|
121
|
+
|
|
122
|
+
[[tool.mypy.overrides]]
|
|
123
|
+
module = [
|
|
124
|
+
"acp.*",
|
|
125
|
+
"agent_client_protocol.*",
|
|
126
|
+
"httpx",
|
|
127
|
+
"httpx.*",
|
|
128
|
+
# 腾讯云官方 SDK 未提供 py.typed
|
|
129
|
+
"tencentcloud.*",
|
|
130
|
+
]
|
|
131
|
+
ignore_missing_imports = true
|
|
132
|
+
|
|
133
|
+
# ─── Pytest ──────────────────────────────────
|
|
134
|
+
|
|
135
|
+
[tool.pytest.ini_options]
|
|
136
|
+
asyncio_mode = "auto"
|
|
137
|
+
testpaths = ["tests"]
|
|
138
|
+
python_files = ["*_test.py"]
|
|
139
|
+
pythonpath = ["src"]
|
|
140
|
+
addopts = "-ra -q"
|