Metadata-Version: 2.5
Name: cube-agent-harness
Version: 0.1.2
Summary: Open-source Python SDK for embeddable, plugin-extensible agents
Project-URL: Homepage, https://github.com/mindshake-ai/cube
Author: psh
License: MIT License
        
        Copyright (c) 2026 psh
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
License-File: LICENSE
Keywords: agents,llm,plugins,sdk,tools
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Typing :: Typed
Requires-Python: <3.14,>=3.12
Requires-Dist: jsonref>=1.1.0
Requires-Dist: packaging>=24.0
Requires-Dist: pydantic>=2.12.0
Provides-Extra: all
Requires-Dist: aiosqlite<1.0,>=0.21; extra == 'all'
Requires-Dist: asyncmy<1.0,>=0.2.10; extra == 'all'
Requires-Dist: cryptography<49,>=44; extra == 'all'
Requires-Dist: fastmcp-slim[client]==4.0.10; extra == 'all'
Requires-Dist: jsonschema<5,>=4.23.0; extra == 'all'
Requires-Dist: litellm>=1.98.0; extra == 'all'
Requires-Dist: mcp==2.2.0; extra == 'all'
Requires-Dist: openpyxl<4,>=3.1; extra == 'all'
Requires-Dist: pillow<13,>=12.3; extra == 'all'
Requires-Dist: pymupdf<2,>=1.26.0; extra == 'all'
Requires-Dist: pyyaml>=6.0.0; extra == 'all'
Requires-Dist: redis<7.0,>=5.0; extra == 'all'
Requires-Dist: regex>=2024.11.6; extra == 'all'
Requires-Dist: sqlalchemy[asyncio]<2.2,>=2.0.39; extra == 'all'
Requires-Dist: sqlmodel>=0.0.38; extra == 'all'
Provides-Extra: cluster
Requires-Dist: aiosqlite<1.0,>=0.21; extra == 'cluster'
Requires-Dist: asyncmy<1.0,>=0.2.10; extra == 'cluster'
Requires-Dist: cryptography<49,>=44; extra == 'cluster'
Requires-Dist: jsonschema<5,>=4.23.0; extra == 'cluster'
Requires-Dist: openpyxl<4,>=3.1; extra == 'cluster'
Requires-Dist: pyyaml>=6.0.0; extra == 'cluster'
Requires-Dist: redis<7.0,>=5.0; extra == 'cluster'
Requires-Dist: regex>=2024.11.6; extra == 'cluster'
Requires-Dist: sqlalchemy[asyncio]<2.2,>=2.0.39; extra == 'cluster'
Requires-Dist: sqlmodel>=0.0.38; extra == 'cluster'
Provides-Extra: llm
Requires-Dist: litellm>=1.98.0; extra == 'llm'
Provides-Extra: mcp
Requires-Dist: fastmcp-slim[client]==4.0.10; extra == 'mcp'
Requires-Dist: mcp==2.2.0; extra == 'mcp'
Provides-Extra: media
Requires-Dist: pillow<13,>=12.3; extra == 'media'
Requires-Dist: pymupdf<2,>=1.26.0; extra == 'media'
Provides-Extra: platform
Requires-Dist: aiosqlite<1.0,>=0.21; extra == 'platform'
Requires-Dist: cryptography<49,>=44; extra == 'platform'
Requires-Dist: jsonschema<5,>=4.23.0; extra == 'platform'
Requires-Dist: openpyxl<4,>=3.1; extra == 'platform'
Requires-Dist: pyyaml>=6.0.0; extra == 'platform'
Requires-Dist: regex>=2024.11.6; extra == 'platform'
Requires-Dist: sqlalchemy[asyncio]<2.2,>=2.0.39; extra == 'platform'
Requires-Dist: sqlmodel>=0.0.38; extra == 'platform'
Description-Content-Type: text/markdown

# Cube SDK

宿主加载 **Extension**（可信代码扩展）；Agent 装配 **Plugin**（能力插件）。
Plugin 分为 Tool、Package、Skill、MCP、SubAgent 五类；`AgentConfig` 用
`tools/packages/skills/mcps/subagents` 五个独立数组声明。宿主 SPI 位于
`cube.platform.extension`，Agent Plugin 值模型位于 `cube.platform.plugin`。
旧环境升级见 [迁移指南](../docs/extension-plugin-migration.md)。

`cube-agent-harness` 是一个可嵌入、可使用工具、可通过插件扩展的 Python Agent
Harness SDK。安装后使用的 import package 是 `cube`：

```bash
pip install cube-agent-harness
```

```python
import cube
```

这份文档面向通过 PyPI 安装并集成 Cube 的应用开发者，重点说明 SDK 提供什么、各包的
职责边界、主要公共入口以及推荐的应用接入方式。Cube 源码仓库中 Playground、CLI、
部署和本地调试流程不属于 SDK 本身。

## SDK 能力概览

Cube SDK 分成四个公开能力面：

| 包 | 提供的能力 | 典型使用方 |
| --- | --- | --- |
| `cube.core` | Agent loop、消息、LLM contracts、tools、hooks、事件、取消、运行状态。 | 只需要 Agent runtime kernel，或希望自行负责 persistence 和应用层的开发者。 |
| `cube.platform` | 本地应用宿主、durable agency/channel/session、SQLite、workspace、runtime assembly、extension SPI、sandbox。 | 需要快速嵌入一个完整本地 Cube runtime 的应用。 |
| `cube.cluster` | MySQL/Redis 分布式协调、Backend Gateway、Worker lifecycle、owner lease 和 command/event transport。 | 需要把 Backend 与 Agent execution worker 分离部署的应用。 |
| `cube.extensions` | 官方 tools、hooks、channel types、chat/Task sessions 和 SubAgent 能力实现。 | 希望直接使用或参考官方代码扩展的应用。 |

依赖方向保持单向：

```text
cube.cluster -----> cube.platform -----> cube.core
                        ^                   ^
                        |                   |
                   cube.extensions -----------+
```

- `cube.core` 不依赖 platform、database、plugins、CLI 或 Web framework。
- `cube.platform` 提供完整的本地运行能力，不依赖 `cube.cluster`。
- `cube.cluster` 只增加分布式协调，不替代 platform domain services。
- `cube.extensions` 通过 `cube.platform.extension` SPI 注册官方实现。

## SDK 不负责什么

Cube SDK 有意不包含以下产品层能力：

- HTTP/FastAPI routes 和 WebSocket 协议
- 全局账号、密码、JWT、认证和授权系统
- 前端 UI 与前端扩展协议
- CLI 命令和终端交互
- 应用自己的业务数据库与 migration
- 应用默认的 `extensions.toml` / `tables.toml`
- 分布式部署平台、容器编排或共享存储供应商

这些能力由嵌入 Cube 的应用拥有。官方 Playground 和 CLI 是独立应用，只是 SDK 的
参考使用方，不是 `cube-agent-harness` 的 runtime dependency。

## 安装与可选依赖

基础安装只包含轻量 core 和 plugin model contracts：

```bash
pip install cube-agent-harness
```

根据应用需要选择 extras：

```bash
pip install "cube-agent-harness[llm]"       # LiteLLM client/router
pip install "cube-agent-harness[mcp]"       # MCP transports
pip install "cube-agent-harness[media]"     # Pillow 图片处理 + PyMuPDF PDF 渲染
pip install "cube-agent-harness[platform]"  # 本地 platform、SQLite、workspace
pip install "cube-agent-harness[cluster]"   # platform + MySQL/Redis 分布式 runtime
pip install "cube-agent-harness[all]"       # 全部官方 SDK extras
```

Python 版本要求为 3.12 或 3.13。

直接使用 `CubeLocalApp` 时，默认启用 SRT Bash sandbox。嵌入应用需要提供：

- macOS：`srt`、`rg` 和系统自带的 `sandbox-exec`
- Linux：`srt`、`rg`、`bwrap` 和 `socat`

宿主可以显式传入 `sandbox=None`，但 Bash 会保持 fail-closed，除非 runtime 注入了
可用的 `SandboxSpawner`。

## `cube.core`：Agent 运行内核

`cube.core` 是与 platform 无关的运行内核，适合希望自行控制应用生命周期、持久化和
外部 transport 的开发者。

主要能力包括：

- `AgentRuntime`、`AgentRunRequest`、`AgentRunContext` 和 agent loop state
- `BaseMessage`、`AgentMessage`、`QuestionMessage` 等运行时消息模型
- `Tool`、`ToolRuntime`、`ToolRegistry`、tool execution policy、progress 和
  background task lifecycle
- `Hook`、`HookRegistry` 和 hook dispatch/aggregation
- `BaseLLMClient`、LLM messages、tool calls、usage 和 provider adapter contracts
- MCP client/transport adapter
- `EventBus`、`CancellationToken`、runtime events 和公共状态模型
- versioned file write、mount、artifact 和 tool output contracts

稳定的便利入口从 `cube.core` 导入。更细粒度或 provider-specific 的类型从对应子包
导入，例如 `cube.core.runtime`、`cube.core.llm`、`cube.core.tool` 和
`cube.core.hook`。

`cube.core` 不提供 database、session persistence、workspace layout、channel、agency
或应用启动器。需要这些能力时应使用 `cube.platform`。

### 多模态上下文

`ImageContent` 是 `cube.core.llm` 的 provider-neutral 消息契约。对于不能直接在
tool-result message 中携带图片的 OpenAI-compatible 协议，Cube 保留原 tool text，
并在完整 tool-result group 后追加一条只包含来源标记和图片的 user media message。
provider 投影只保留最近 20 个 tool-result images，更早的图片替换为文本标记；直接
用户图片不受这项可再生成媒体策略影响。请求转换和 token 估算使用同一投影。

通用的图片限制和转文本投影位于 `cube.core.llm`，便于不同 compaction hook 复用；
具体图片/PDF 解码压缩仍由 `cube.extensions.tools` 负责，何时触发上下文压缩则由 hook
插件策略决定。完整摘要请求使用文本化媒体投影，避免为待压缩图片再次支付多模态
上下文成本。

### Tool authoring

Cube 提供三种 Tool 构造入口：

- `@tool(...)`：有稳定 Python 定义的普通 Tool。
- `make_tool(...)`：MCP、SubAgent adapter 等运行期才有 schema/callable 的动态 Tool。
- `command_tool(...)`：构建一个 typed `BaseMessage` 并交还所属 runtime 处理的
  message-emitting Tool。

普通 Tool 成功后默认继续 Agent Run。需要在成功提交命令后正常结束当前 Run 时，声明
`success_behavior=ToolSuccessBehavior.END_RUN`；这不同于 cancellation。`END_RUN` Tool
必须 foreground 且 `is_concurrency_safe=False`。Runtime 会先发布 ToolResult 和可选的
`ToolOutput.emitted_message`，再以 `completed` 结束 Run，并为同批被跳过的后续 ToolCall
补齐 ToolResult。

Plugin 注册的 Tool 是进程共享的稳定能力，必须保持无状态。Session 可以通过
`AgentRunSpec.run_tools` 挂载只在当前 Run 可见的动态 Tool；这类 Tool 可以捕获不可变的
Run 上下文，但同样不应在实例上保存每次调用的可变状态。Command Tool 只产出领域
Message，不接收 Session、数据库或 ThreadRuntime 回调。

## `cube.platform`：本地应用与持久化领域

`cube.platform` 把 core runtime 组装成一个 local-first、可嵌入的完整应用宿主。

### 主要公共入口

- `CubeLocalApp`：本地模式 composition root。
- `CubeLocalAppConfig` / `create_cube_local_app(...)`：本地应用配置与构造入口。
- `PlatformServices`：durable agency、channel、session、notification、workspace、
  database 和 health services。
- `PlatformRuntime`：进程内 session activation、Agent execution 和 runtime lifecycle。
- `SessionCommandDispatcher`：与 transport 无关的 live session command boundary。
- `SessionEventSubscriber`：按 session 订阅的 live event boundary。
- `RuntimeAssembly` / `RuntimeAssemblyConfig`：manifest 驱动的 plugin/table 组装。
- `cube.platform.extension`：第三方 extension SPI、entry-point discovery、dependency
  resolution 和 capability registry。

`CubeLocalApp` 向应用暴露四个明确的接入面：

```text
CubeLocalApp
├── services   durable query / management / persistence
├── runtime    process-local session activation and execution
├── commands   transport-neutral live commands
└── events     session-scoped live event streams
```

应用业务代码优先依赖更窄的 `services`、`commands` 和 `events` 协议，不应让完整
`CubeLocalApp` 或 `PlatformRuntime` 类型扩散到所有模块。

### 本地嵌入

安装本地 platform 和常用官方能力：

```bash
pip install "cube-agent-harness[platform,llm]"
```

应用必须先在自己的 `root_dir` 中提供 runtime manifests：

```text
<root_dir>/extensions.toml
<root_dir>/tables.toml
```

应用负责决定启用哪些 plugins、tables、default tool groups 和 hook groups。SDK 不会
自动启用所有已安装插件，也不会自动写入应用默认配置。

完成 manifests 后，可以创建本地应用：

```python
from cube.platform import CubeLocalAppConfig, create_cube_local_app


cube_app = create_cube_local_app(
    CubeLocalAppConfig.from_root_dir("./cube-data"),
)

async with cube_app.lifespan() as app:
    services = app.services
    commands = app.commands
    events = app.events
    # 在应用自己的 service / route / transport 层使用这些窄接口。
```

本地模式默认使用：

```text
<root_dir>/cube.sqlite3
<root_dir>/extensions.toml
<root_dir>/tables.toml
<root_dir>/workspace/
```

`CubeLocalApp` 按 `PlatformServices -> PlatformRuntime` 的顺序启动，关闭顺序相反。
`PlatformServices` 负责 durable state 和 readiness；`PlatformRuntime` 负责 active
sessions、event delivery、Agent execution 和 sandbox lifecycle。

### 持久化领域边界

- `AgencyService` 管理 agency 配置和 agency-scoped human member projections。
- `ChannelService` 管理 plugin-typed Channel 及 channel-mounted session discovery。
- `SessionService` 统一管理 session 创建、manifest、members、transcript 和 history。
- `NotificationService` 提供面向 human decisions/results 的中央 durable inbox。
- `WorkspaceService` 管理长期、人类可编辑的 workspace 文件布局。
- runtime transcript、run/task/background state、notifications 和小型平台记录存入
  SDK database。

Cube 中的人类 member 是 agency-scoped projection，不是全局账号或认证主体。应用把
已认证账号映射到这些 projections。

## `cube.cluster`：分布式后端与工作进程运行时

`cube.cluster` 用于把 durable backend 与 Agent execution worker 分离。它依赖：

- MySQL：Cube durable runtime data
- Redis：worker heartbeat、owner lease、command request/ACK 和 live events
- shared POSIX `root_dir`：所有 backend/worker 可见的同一份 workspace

分布式模式没有统一的 `CubeApp` facade。Backend 和 Worker 的职责有意分开。

### 后端组合

后端组合持久化服务和实时网关：

```python
from pathlib import Path

from cube.cluster import (
    ClusterConfig,
    ClusterGateway,
    ClusterGatewayConfig,
    ClusterPlatformServicesConfig,
    GatewayConfig,
    MySQLConfig,
    RedisConfig,
    create_cluster_platform_services,
)
from cube.platform import RuntimeAssemblyConfig


assembly = RuntimeAssemblyConfig(rollout_tag="v1")
gateway = ClusterGateway(
    config=ClusterGatewayConfig(
        assembly=assembly,
        cluster=ClusterConfig(namespace="cube-prod"),
        redis=RedisConfig(url="redis://:secret@redis:6379/0"),
        gateway=GatewayConfig(),
    )
)
services = create_cluster_platform_services(
    ClusterPlatformServicesConfig(
        root_dir=Path("/cube"),
        assembly=assembly,
        mysql=MySQLConfig(
            url="mysql+asyncmy://cube:secret@mysql:3306/cube?charset=utf8mb4",
        ),
    ),
)

await services.startup()
await gateway.startup()
commands = gateway
events = gateway
```

后端可以查询持久化服务、发送实时命令并订阅事件，但不能创建
`PlatformRuntime`，也不能在同一进程中启动 Worker。

### 工作进程组合

工作进程使用相同的 assembly、MySQL、Redis、namespace、rollout tag 和共享
`root_dir`，由 `ClusterWorker` 持有 `PlatformRuntime` 并执行 sessions：

```bash
CUBE_ROOT_DIR=/cube \
CUBE_CLUSTER_NAMESPACE=cube-prod \
CUBE_ROLLOUT_TAG=v1 \
CUBE_MYSQL_URL='mysql+asyncmy://cube:secret@mysql:3306/cube?charset=utf8mb4' \
CUBE_REDIS_URL='redis://:secret@redis:6379/0' \
CUBE_WORKER_ID=worker-1 \
CUBE_WORKER_SHUTDOWN_GRACE_SECONDS=30 \
python -m cube.cluster.worker
```

滚动期间使用新的 `rollout_tag` 区分新旧服务 cohort；服务健康只检查当前 cohort。
允许 Bash 的 Agent 使用当前 Agency 在 shared root 下的
`.runtime/cli/<agency>/` 作为原生 npm/uv 共享环境。Backend 不管理这个目录；所有
Worker 必须挂载相同绝对路径，并在滚动期间保持 Python、Node 和系统 ABI 兼容。

应用应在自己的 composition root 中隐藏 local/distributed 部署差异，并向业务层暴露
一致的 `services`、`commands` 和 `events` 协议。

## `cube.extensions`：官方能力实现

`cube.extensions` 包含通过公共 extension SPI 注册的官方实现：

- stateless filesystem、shell、user interaction 和辅助 tools
- builtin hooks 和 hook groups
- `dm`、`group_chat`、`project` channel types
- chat session
- 统一的 managed Task；Phase 可选择 Agent direct 或内嵌 Workflow 执行
- SubAgent provider、session 和相关 tools（v1 contract 见
  [`docs/subagent-v1.md`](../docs/subagent-v1.md)）

这些是具体 capability implementations，不是 extension host API。第三方插件应从
`cube.platform.extension` 导入 SPI 类型。

## 插件与运行时组装

插件通过 `cube.extensions` Python entry-point group 暴露 `ExtensionSpec`：

```python
from cube.platform.extension import ExtensionSpec


def register(ctx):
    ctx.tools("finance_controls", my_tool)


plugin = ExtensionSpec(
    name="my.company.finance",
    version="0.1.0",
    requires_tables=("my.company.finance",),
    register=register,
)
```

```toml
[project.entry-points."cube.extensions"]
"my.company.finance" = "my_company_finance.plugin:plugin"
```

Plugin 可以贡献：

- named tool groups
- named hook groups
- hook event / extension point contracts
- session kinds
- channel types
- SubAgent providers

带持久化能力的包独立导出 `TableSpec`，并可在 `ExtensionSpec.requires_tables` 中声明逻辑
table 依赖。`requires_tables` 只是运行前验证元数据；plugin registration 不会自动
import、注册或创建 tables。

运行时从应用 root 中独立加载：

```text
extensions.toml -> ExtensionManager -> frozen ExtensionRegistry
tables.toml  -> TableManager  -> frozen TableRegistry
```

`RuntimeAssembly` 验证 plugin table requirements 后，把 immutable registries 和
capability assembly 注入 `PlatformServices`。应用应在 database 初始化前完成 table
assembly。

## 推荐的应用集成边界

无论 local 还是 distributed，应用都可以定义自己的稳定 wrapper：

```python
from dataclasses import dataclass

from cube.platform import PlatformServices
from cube.platform.command import SessionCommandDispatcher
from cube.platform.event import SessionEventSubscriber


@dataclass(frozen=True)
class CubeComponents:
    services: PlatformServices
    commands: SessionCommandDispatcher
    events: SessionEventSubscriber
```

本地模式从 `CubeLocalApp` 填充这些字段；分布式模式从
`create_cluster_platform_services(...)` 和 `ClusterGateway` 填充相同字段。这样
application services、routes 或其他 transport adapters 不需要知道 session 最终在
本进程还是远端 Worker 中执行。

典型调用边界：

```python
# Durable 查询和管理不会激活 live session。
channel = await cube.services.channels.get(agency_id, channel_id)
history = await cube.services.sessions.get_history(address.session_id)

# Live command 通过 transport-neutral dispatcher。
result = await cube.commands.dispatch(command)

# Live UI/transport 更新通过 session-scoped event stream。
async with cube.events.subscribe(address) as stream:
    async for event in stream:
        ...
```

## 进一步阅读

- `cube.core`：运行时、工具、钩子、LLM 和 MCP 的内核契约
- `cube.platform`：本地宿主、持久化服务、session、workspace 和插件宿主
- `cube.cluster`：后端/工作进程分布式协调协议
- `cube.extensions`：官方能力实现

源码仓库、官方 Playground、CLI、本地调试和部署方式请从
[Cube GitHub 仓库](https://github.com/mindshake-ai/cube) 开始阅读。

### Shell 扩展

`cube.extensions.shell` 提供 Bash、CLI 进程环境与只读安装清单；`agent_base`
只包含基础文件工具与 Plugin 执行器。宿主选择 `shell` 工具组和 `cli-install`
默认 Skill，Task 的 Bash 必需语义由应用清单的 `required_tools = ["shell"]`
保持。安装说明按需加载，不再常驻 system prompt。Platform 只保留通用
`ToolEnvironmentContribution` / `ProcessEnvironment` 和 `AgencyPackageCache`。
参见 [迁移说明](../docs/migrations/shell-extension.md)。
