Metadata-Version: 2.5
Name: managed-agent-sdk
Version: 0.0.5
Summary: Managed Agent SDK (Python) — 控制面支持腾讯云 API 与 WorkBuddy OpenAPI，数据面使用 ACP
Project-URL: Homepage, https://cnb.cool/codebuddy/managed-agent-doc/-/tree/main/python
Project-URL: Documentation, https://cnb.cool/codebuddy/managed-agent-doc/-/blob/main/python/README.md
Project-URL: Repository, https://cnb.cool/codebuddy/managed-agent-doc
Project-URL: Issues, https://cnb.cool/codebuddy/managed-agent-doc/-/issues
Project-URL: Changelog, https://cnb.cool/codebuddy/managed-agent-doc/-/blob/main/python/CHANGELOG.md
Author-email: Tencent CodeBuddy <codebuddy@tencent.com>
License: MIT
License-File: LICENSE
Keywords: acp,agent,llm,managed-agent,sandbox
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: <3.15,>=3.10
Requires-Dist: agent-client-protocol<0.13,>=0.12
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.6
Requires-Dist: tencentcloud-sdk-python-common>=3.0.1000
Provides-Extra: dev
Requires-Dist: mypy>=1.10; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.5; extra == 'dev'
Requires-Dist: uvicorn>=0.30; extra == 'dev'
Description-Content-Type: text/markdown

# managed-agent-sdk（Python）

腾讯云 **WorkBuddy 企业版 Managed Agent** 的 Python SDK。

控制面支持腾讯云 API（TC3 签名）与 WorkBuddy OpenAPI（OAuth2），数据面使用 ACP 协议；SDK 自动获取并缓存数据面凭证。

```bash
pip install managed-agent-sdk
```

要求 Python 3.10 ~ 3.14。Node 版见 [`@tencent-ai/managed-agent-sdk`](https://www.npmjs.com/package/@tencent-ai/managed-agent-sdk)，两侧 API 语义一致。

## 凭证

SecretId / SecretKey 在 [腾讯云访问管理控制台的 API 密钥管理](https://console.cloud.tencent.com/cam/capi) 获取。

从环境变量读取，或在构造时显式传入：

```bash
export TENCENTCLOUD_SECRET_ID=你的SecretId
export TENCENTCLOUD_SECRET_KEY=你的SecretKey
```

腾讯云 API 支持长期密钥。数据面（ACP）的凭证由 SDK 通过控制面自动换取并缓存，无需单独配置。

### WorkBuddy OpenAPI

API key 有两种，按需选择其一：

- 开放平台 API key：在 [WorkBuddy 管理后台的开放平台应用列表](https://workbuddy.cn/admin/integration/oauth/list) 获取
- 企业个人 API key：在 [WorkBuddy 个人中心的 API key 页面](https://www.workbuddy.cn/profile/keys) 获取

配置企业 ID 与 API key：

```bash
export WORKBUDDY_ENTERPRISE_ID=你的企业ID
export WORKBUDDY_API_KEY=你的APIKey
```

传入 `ClientOpts(openapi=OpenApiOpts())` 选择 OpenAPI：

```python
import asyncio

from managed_agent_sdk import ClientOpts, ManagedAgentClient, OpenApiOpts


async def main() -> None:
    async with ManagedAgentClient(ClientOpts(openapi=OpenApiOpts())) as client:
        print((await client.models.list()).items)


asyncio.run(main())
```

`OpenApiOpts` 的字段均可显式传入；省略时读取对应环境变量。服务地址默认用 SDK 内置
值，可用 `OpenApiOpts(endpoint=...)` 传入覆盖（含协议、不含路径的 http(s) 根地址）；
每个控制面请求带 `X-Api-Key` 头，缺企业 ID 或 API key 时构造抛出异常。

领域方法及 PascalCase 出参与腾讯云 API 相同；新建 Agent 默认不下发到 WorkBuddy 客户端。

`capi` 与 `openapi` 只能传其一，同时传入时构造抛出 `ValidationError`。`transport` 可配置 OpenAPI 与 ACP 的 HTTP 传输层。

## 快速开始

```python
import asyncio

from managed_agent_sdk import (
    CreateAgentOpts,
    CreateSessionOpts,
    ManagedAgentClient,
    ManifestBuilder,
    PromptOpts,
)


async def main() -> None:
    async with ManagedAgentClient() as client:
        # 1. 创建 Agent —— 服务端顺带建好承载 manifest 的 default 版本
        agent = await client.agents.create(
            CreateAgentOpts(
                agent_name="日志分析助手",
                model="deepseek-v3",
                manifest=ManifestBuilder().system_prompt("你是日志分析专家").build(),
            )
        )

        # 2. 创建会话（拉起真实沙箱，不会自动回收 —— 尽量复用）
        session = await agent.sessions.create(CreateSessionOpts())

        # 3. 对话。回复文本走 on_chunk，见下方说明
        def on_chunk(n) -> None:
            u = n.update
            if u.sessionUpdate == "agent_message_chunk" and u.content.type == "text":
                print(u.content.text, end="", flush=True)

        res = await session.prompt("分析这份日志", PromptOpts(on_chunk=on_chunk))
        print(f"\nstop_reason: {res.stop_reason}")

        await session.disconnect()


asyncio.run(main())
```

### 回复文本怎么拿

`prompt()` 的返回值只携带 `stop_reason` 与 `refusal`，**不含回复正文** ——
流式内容与终局结果分两条通道，这是 ACP 的协议设计。两条路都能拿到正文：

- **`on_chunk`**（上面的写法）：实时增量，适合边生成边展示
- **`session.messages()`**：轮次结束后按 `EventType == "ASSISTANT"` 取 `Message["Content"]`，
  适合只要最终结果、不关心过程

### 版本要不要自己建

入门不需要。`agents.create()` 传了 `manifest` / `model` 时，服务端会建好一个
`default` 版本承载它们；`sessions.create()` 不传 `version_id` 时按 Agent 的
routing 配置分流，也会落到它。

要灰度多个配置（A/B、逐步放量）时才用 `agent.versions.create()` 显式建版本，
再配合 `agent.update_routing()` 分流。

## 配置连接器 / 技能 / 专家

三类资源的**配置入口不统一**，这是最容易配错的地方：

| 资源 | 查询 | 配置入口 | 最终落点 |
| --- | --- | --- | --- |
| 连接器（MCP） | `client.connectors.list()` | `connector_ids`（Action 入参） | 服务端物化成 manifest 的 `mcp_servers` |
| 技能 | `client.skills.list()` | `ManifestBuilder.skills()` | manifest 的 `skills` |
| 专家 | `client.experts.list()` | `ManifestBuilder.experts()` | manifest 的 `experts` |

技能与专家进 manifest，连接器**不进** —— 只把 ID 交给服务端，由它查网关地址后物化。
自己往 manifest 里写 `mcp_servers` 会与之重复。

```python
skills = await client.skills.list("BUILTIN", ListSkillsOpts(limit=50))
connectors = await client.connectors.list_active()

agent = await client.agents.create(
    CreateAgentOpts(
        agent_name="运维助手",
        manifest=(
            ManifestBuilder()
            .system_prompt("你是运维专家")
            .skills([{"type": "builtin", "id": s["SkillId"]} for s in skills.items])
            .build()
        ),
        connector_ids=[c["ConnectorId"] for c in connectors.items],  # 独立入参
    )
)
```

`connector_ids` 是该版本最终要绑的完整集合，服务端按它做全量覆盖 ——
改绑定直接传新集合，解绑从列表里去掉即可，传 `[]` 解绑全部。

## 两条约定

**入参 snake_case，出参 PascalCase。** 出参原样透传云 API 字段名，便于对照官方文档排查。

**控制面重试。** 控制面失败直接抛出异常，不做自动重试。`Create*` 类接口非幂等且服务端不提供 `ClientToken`，重试 `sessions.create()` 会重复拉起沙箱并产生真实费用。ACP 支持断线重连（`Last-Event-ID` 断点续传，不重放 prompt）。

**会话即沙箱，且不会自动回收。** `sessions.create()` 每次调用都拉起一个真实沙箱。注意 `disconnect()` **只断 ACP 连接，不释放沙箱** —— 服务端既没有销毁会话的接口，也没有空闲超时回收（`IDLE` 只是「上一轮对话结束」的轮次状态，沙箱照常运行）。要复用会话，别在循环里反复新建。

## 文档

完整 API 参考、错误码表、已知问题见
[Managed Agent SDK 文档](https://cnb.cool/codebuddy/managed-agent-doc/-/blob/main/python/README.md)。
