Metadata-Version: 2.4
Name: symphony-platform
Version: 0.2.0
Summary: 现代化 agent 协作平台：单/多 agent 编排、Skill 能力包、多租户、可持久化
Project-URL: Homepage, https://github.com/aitoys/symphony
Project-URL: Repository, https://github.com/aitoys/symphony
Project-URL: Issues, https://github.com/aitoys/symphony/issues
Project-URL: Changelog, https://github.com/aitoys/symphony/blob/main/CHANGELOG.md
Author: Symphony Contributors
License: MIT
License-File: LICENSE
Keywords: agent,fastapi,langgraph,llm,multi-agent,orchestration,saas
Classifier: Development Status :: 4 - Beta
Classifier: Framework :: FastAPI
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: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: aiosqlite>=0.20
Requires-Dist: asyncpg>=0.29
Requires-Dist: bcrypt>=4.0
Requires-Dist: fastapi>=0.115
Requires-Dist: httpx>=0.27
Requires-Dist: langchain-anthropic>=0.2
Requires-Dist: langchain-core>=0.3
Requires-Dist: langchain-mcp-adapters>=0.3.0
Requires-Dist: langchain-openai>=0.2
Requires-Dist: langgraph>=0.2.50
Requires-Dist: pydantic-settings>=2.5
Requires-Dist: pydantic>=2.9
Requires-Dist: sqlalchemy[asyncio]>=2.0
Requires-Dist: uvicorn[standard]>=0.30
Description-Content-Type: text/markdown

# Symphony

现代化 agent 协作平台（SaaS 版）：单 agent ReAct 闭环、多模式 multi-agent 协作（supervisor / pipeline / fan-out）、**Skill 能力包**、多 LLM provider、可持久化（SQLite/Postgres）、可认证、带内置控制台。

[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![Python 3.12+](https://img.shields.io/badge/python-3.12+-blue.svg)](https://www.python.org/downloads/)
[![CI](https://github.com/aitoys/symphony/actions/workflows/ci.yml/badge.svg)](https://github.com/aitoys/symphony/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/symphony-platform.svg)](https://pypi.org/project/symphony-platform/)

## 控制台预览

内置 Web 控制台（`/ui`，纯 HTML/JS 无构建）：登录 → 总览 → 租户/用户/成员管理（按角色门控）。

| 总览 Dashboard | 租户管理（超管） | 用户管理（超管） |
|---|---|---|
| ![Dashboard](docs/img/dashboard.png) | ![Tenants](docs/img/tenants.png) | ![Users](docs/img/users.png) |

| 成员管理（owner） | 个人中心（改密） |
|---|---|
| ![Members](docs/img/members.png) | ![Profile](docs/img/profile.png) |

## 特性

- **单 agent ReAct 闭环**：LangGraph 驱动，感知 -> 决策 -> 工具调用 -> 观察 -> 循环
- **multi-agent 协作（三种模式）**：
  - `supervisor`：编排多 worker，子任务委派与汇总（agent-as-tool）
  - `pipeline`：串行链式，前一个输出作为后一个输入
  - `fan-out`：并行分发同一输入，聚合各输出
- **Skill 能力包**：比工具更高层的抽象，可包含工具集合、prompt 片段、参数、子工作流
  - 代码内置 skill（启动时自动注册，全局可见）
  - 动态 skill（API/控制台创建，同租户隔离）
  - 多 skill 挂载，namespace 冲突隔离，priority 合并
- **多 LLM provider**：mock（零配置）/ OpenAI / Anthropic / OpenAI 兼容网关，惰性加载
- **持久化**：SQLite（文件级，重启不丢，默认）/ 内存（开发）/ Postgres（生产），可配置切换
- **多租户隔离**：`X-Tenant-ID` 行级隔离 + 严格准入（未注册租户 404）
- **认证与权限**：人类登录（邮箱+密码，opaque session token，即时吊销）+ 机器 API key（绑定租户）；三级角色（platform_admin / owner / member），登录限流防爆破
- **同步 / 异步执行**：sync 阻塞返回 / async 入队轮询
- **工具生态（三层）**：内置工具 + 自定义 webhook 工具（HTTP 接口包装为 agent 工具，JSON Schema 描述参数）+ MCP server 接入（动态加载，复用整个 MCP 生态：github / filesystem / 向量检索…）
- **多轮会话**：`thread_id` 跨 run 共享历史（checkpointer 单例）；`GET /runs?thread_id=` 按会话聚合
- **可观测与治理**：运行取消（`POST /runs/{id}/cancel`）、就绪探活（`/health/ready`）、token 用量统计（成本归因）、结构化日志（JSON + request_id 贯穿请求链路）
- **内置 Web 控制台**：`/ui` 可视化管理，纯 HTML/JS 无构建步骤

## 架构

```mermaid
flowchart TB
  UI[Web 控制台 /ui] --> Routes
  CLIENT[REST / SSE 客户端] --> Routes
  subgraph API[API 层 · FastAPI]
    Routes[Agents / Runs / Skills / Teams / Orchestration 路由]
    Auth[认证中间件 + 多租户隔离]
    Routes --> Auth
  end
  subgraph Core[核心编排层]
    Exec[Executor 限流 / 调度 / 取消]
    Agent[Agent 构建 · LangGraph ReAct]
    Orch[pipeline / fanout / team]
    Skills[Skill 加载 · namespace 隔离]
    Tools[内置 + Webhook + MCP 工具]
  end
  subgraph Store[存储层 · Protocol]
    SQLite[(SQLite)]
    PG[(Postgres)]
    MEM[(InMemory)]
  end
  LLM[LLM Provider · mock / OpenAI / Anthropic / 兼容网关]
  Auth --> Exec
  Exec --> Agent
  Agent --> Orch
  Agent --> Skills --> Tools
  Agent --> LLM
  Exec --> Store
```

分层 `API → Core → Store`，依赖倒置（Store / Executor 均为 Protocol 抽象）。每个 Agent 可挂载 Skill、内置/Webhook/MCP 工具，经 Executor 限流调度后调用 LLM；Store 可在内存 / SQLite / Postgres 间切换而不影响上层。

## 快速开始

> 需先安装 [uv](https://docs.astral.sh/uv/)（Python 包与项目管理器）：
> `curl -LsSf https://astral.sh/uv/install.sh | sh`

```bash
uv sync
uv run uvicorn symphony.main:app --reload
```

- 控制台：http://localhost:8000/ui
- API 文档：http://localhost:8000/docs

或从 PyPI 安装后直接起服务：

```bash
pip install symphony-platform
symphony                 # = uvicorn symphony.main:app（读 HOST/PORT 环境变量）
```

或 Docker 一键启动：

```bash
docker build -t symphony . && docker run -p 8000:8000 --env-file .env symphony
# 或带 Postgres 后端：docker compose up -d
```

可运行示例见 [`examples/`](examples/)（单 agent / pipeline / SSE 消费，均零配置可跑）。

默认 mock LLM + SQLite 存储，零配置即可跑通完整闭环（含工具调用、多模式协作与 skill 挂载），重启数据不丢失。

### 开箱即演示

服务启动时会自动为 `demo-tenant` 播种一套演示数据（幂等，可由 `SEED_DEMO_DATA=false` 关闭）：

- **7 个 agent**：数学计算、数据分析师（内置 skill）、中文写作（动态 skill）、翻译官、摘要助手、supervisor 编排主管、内容流水线入口（workflow skill）
- **3 个 skill**：内置 `data_analysis` + 动态 `zh_writer` + 带 pipeline 子工作流的 `content_pipeline`
- **3 条历史 Run**：单 agent / pipeline / fan-out 各一条，控制台 Dashboard 打开即有数据

控制台顶部 Tenant 填 `demo-tenant`，即可在 Agents / Skills / Runs / 协作 各页面直接演示全部场景。

### 真实 LLM 多 Agent 协作（`real-demo` 租户）

切换到真实 LLM（如 `LLM_MODE=openai_compatible` 并配置网关）后，启动时额外为 `real-demo` 租户播种 3 个业务 agent：

- **行业研究员** → **商业分析师** → **策略撰稿人**（pipeline 串行协作）
- 输入一个商业问题，产出「结论 / 三大机会 / 关键风险 / 建议下一步」结构化策略报告
- 单 agent 无法达到这种分工深度——这是 Symphony 相比单个数字员工的核心价值

控制台切到 `real-demo` 租户，到「协作」页选 pipeline 模式勾选三个 agent 提交，或：

```bash
curl -X POST http://localhost:8000/orchestration/pipeline \
  -H "Content-Type: application/json" -H "X-Tenant-ID: real-demo" \
  -d '{"agent_ids":["rd-researcher","rd-analyst","rd-writer"],"input":"AI 编程助手赛道的市场机会","mode":"sync"}'
```

mock 模式下此租户不播种（避免无意义输出误导验收）。

## 配置（`.env`）

参考 `.env.example`：

```dotenv
LLM_MODE=mock               # mock | openai | anthropic | openai_compatible
OPENAI_API_KEY=
OPENAI_MODEL=gpt-4o-mini
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=claude-3-5-sonnet-latest

# OpenAI 兼容服务（内部路由网关 / 中转服务）
OPENAI_COMPATIBLE_BASE_URL=
OPENAI_COMPATIBLE_API_KEY=
OPENAI_COMPATIBLE_MODEL=

STORAGE_BACKEND=sqlite      # memory | sqlite | postgres
SQLITE_PATH=symphony.db
DATABASE_URL=postgresql+asyncpg://user:pass@localhost:5432/symphony

# 认证（任一非空即开启认证；均为空=开发模式免认证）
API_KEYS=                   # 租户级 key，支持 key:tenant 绑定（key 仅限指定租户）
ADMIN_API_KEYS=             # 管理 key（保护 /tenants /users，不绑租户；与 API_KEYS 物理隔离）
ALLOW_UNBOUND_KEY=false     # 裸 key（无 :tenant）默认拒绝；置 true 才放行（兼容旧模式）
EXPOSE_DOCS=true            # 是否暴露 /docs /redoc /openapi.json；生产建议 false

# 用户体系（人类登录）
ADMIN_EMAIL=                # 启动 upsert 首个平台超管（配合 ADMIN_PASSWORD）
ADMIN_PASSWORD=
SESSION_TTL_DAYS=7          # session token 有效期
LOGIN_MAX_ATTEMPTS=10       # 登录失败限流：窗口内上限
LOGIN_WINDOW_SECS=600       # 登录失败限流：窗口秒数

TENANTS=                    # 启动 bootstrap 租户清单，如 acme,globex:Globex Ltd.
```

## 用户与权限

Symphony 同时支持「机器」与「人」两条凭证通道：

- **机器通道**：租户级 `API_KEY`（`X-API-Key` 头，绑定租户）与管理 `ADMIN_API_KEY`（服务间凭证）。原样保留。
- **人类通道**：邮箱 + 密码登录，签发 opaque session token（`Authorization: Bearer`），存 store 可即时吊销。

### 三级角色

| 角色 | 范围 | 能力 |
|---|---|---|
| `platform_admin` | 全局 | 管理 `/tenants`、`/users`（建/禁用/重置密码） |
| `owner` | 本租户 | 管理本租户成员（邀请/改角色/移除） |
| `member` | 本租户 | 访问本租户业务数据（agents/runs/…） |

### 登录与 demo 凭据

开箱即演示模式下，`demo-tenant` 预置一个 owner 用户：

```
邮箱：demo@symphony.local
密码：demo12345
```

首个平台超管可用 env 引导（幂等 upsert，已存在则跳过）：

```dotenv
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=change-me-on-first-login
```

### 安全要点

- 登录恒定时间校验，用户不存在与密码错均返回 401（不泄漏账号存在性）
- 登录失败按 email 滑窗限流（`LOGIN_MAX_ATTEMPTS` / `LOGIN_WINDOW_SECS`），达上限 429
- 改密 / 禁用用户 → 该用户全部存量 session 立即失效（无需等过期）
- 自助改密（`POST /auth/password`）成功后续发新 token，当前会话无感续期，其他设备被踢下线

## API

所有业务请求需带 `X-Tenant-ID`；启用认证时还需 `X-API-Key`。

| 方法 | 路径 | 说明 |
|---|---|---|
| GET | `/health` | 健康检查（liveness，免认证） |
| GET | `/health/ready` | 就绪探活（探测 store/llm，不就绪 503） |
| POST | `/auth/login` | 邮箱+密码登录，签发 session token |
| POST | `/auth/logout` | 吊销当前 token |
| POST | `/auth/password` | 自助改密（旧密码→新密码，续发新 token） |
| GET | `/auth/me` | 当前用户与所属租户（memberships） |
| GET/POST/PATCH | `/users[/{id}]` | 用户管理（platform_admin：建/禁用/重置密码） |
| GET/POST/GET/PATCH | `/tenants[/{id}]` | 租户管理（platform_admin：建/查询/改状态） |
| GET/POST/PATCH/DELETE | `/tenants/{tid}/memberships[/{uid}]` | 成员管理（owner：邀请/改角色/移除） |
| POST | `/agents` | 创建 agent（name + system_prompt + tools + skill_ids + model） |
| GET | `/agents` | 列出当前租户的 agents |
| GET | `/agents/{id}` | 查询 agent 配置 |
| PATCH | `/agents/{id}` | 更新 agent 配置（name/prompt/tools/skill_ids/model） |
| DELETE | `/agents/{id}` | 删除 agent（幂等 204） |
| GET | `/tools` | 列出内置工具（只读） |
| GET/POST/GET/PATCH/DELETE | `/mcp-servers[/{id}]` | MCP server 资源 CRUD（多 agent 引用，集中管理 token） |
| GET/POST/GET/PATCH/DELETE | `/webhook-tools[/{id}]` | webhook 工具资源 CRUD（HTTP 接口包装为工具） |
| POST | `/agents/{id}/runs` | 提交单 agent 任务（`mode=sync\|async`） |
| POST | `/agents/{id}/runs/stream` | 流式执行（SSE 逐 token 推送） |
| POST | `/teams/runs` | supervisor 协作（supervisor + workers） |
| POST | `/orchestration/pipeline` | 串行链式编排（agent_ids） |
| POST | `/orchestration/fanout` | 并行聚合编排（agent_ids） |
| GET | `/skills` | 列出当前租户 skills（含代码内置） |
| POST | `/skills` | 创建动态 skill |
| GET | `/skills/{id}` | 查询 skill |
| PATCH | `/skills/{id}` | 更新动态 skill（内置不可改） |
| DELETE | `/skills/{id}` | 删除动态 skill（内置不可删） |
| GET | `/runs` | 列出当前租户的 runs |
| GET | `/runs/{run_id}` | 查询运行状态与步骤 |
| POST | `/runs/{run_id}/cancel` | 取消运行中任务（已终态 409） |
| GET | `/ui` | 内置 Web 控制台 |

## Skill

Skill 是比单个工具更高层的能力抽象，一个 Skill 可包含：

- `tools`：工具名列表（引用 `core.tools` 中预置工具）
- `prompt_fragment`：追加到 agent system_prompt 的片段
- `params`：预置参数（JSON）
- `workflow`：可选子工作流（pipeline / fanout / team）
- `namespace`：命名空间，用于多 skill 工具名隔离（`<namespace>__<tool>`）
- `priority`：合并优先级（高优先级覆盖低优先级的 params）

### 代码内置 Skill

在 `src/symphony/core/skills/builtins.py` 添加，启动时自动注册，所有租户可用：

```python
from symphony.core.skills import Skill

class DataAnalysisSkill(Skill):
    name = "Data Analysis"
    description = "Analyze data using calculator and echo tools."
    tools = ["calculator", "echo"]
    prompt_fragment = "You are a data analysis assistant. Use calculator for computations."
    params = {"default_lang": "zh"}
```

### 动态 Skill

通过 API 或控制台创建，仅同租户可见，修改后立即对所有挂载它的 agent 生效。

## 关键抽象与可替换实现

```
Web 控制台 / API (FastAPI + 认证中间件)
    │  依赖注入
Core 抽象：LLMProvider / Store / Executor / Checkpointer / Skill
    │  可切换实现
LangGraph ReAct Agent（单 agent / supervisor / pipeline / fan-out）
```

**关键抽象（SOLID / DIP）**：API 与 Core 只依赖 Protocol，实现可替换：

| 抽象 | 当前实现 | 生产升级方向 |
|---|---|---|
| `LLMProvider` | MockChatModel / ChatOpenAI / ChatAnthropic / OpenAI 兼容网关 | 本地模型、更多 provider |
| `Store` | InMemoryStore / SQLiteStore / PostgresStore | - |
| `Executor` | InMemoryExecutor（asyncio） | ArqExecutor + Redis（跨进程可恢复） |
| `Checkpointer` | MemorySaver | PostgresSaver（任务可恢复） |
| `Skill` | 代码内置 + 动态配置 | skill 市场、跨租户共享 |

## 部署

**生产**推荐 Docker + Postgres：

```bash
docker compose up -d            # Postgres 后端，见 docker-compose.yml
```

**本地一键 Demo**（零账号、零费用、零配置 mock LLM，体验与在线版完全一致）：

```bash
pip install symphony-platform
symphony                        # 起 http://localhost:8000
```

浏览器开 http://localhost:8000/ui ，用 `demo@symphony.local` / `demo12345` 登录（Tenant 填 `demo-tenant`）即可。

> 仓库另附 `fly.toml`，作为**可选**的公网托管方案（Fly.io 需绑卡，按 auto-stop 计费）。无强制云依赖，本地即可完整演示。

部署要点：
- 生产置 `EXPOSE_DOCS=false` 收敛攻击面；至少配 `API_KEYS`（租户级）或 `ADMIN_API_KEYS`（管理面）
- 多 worker 部署需用 Postgres 后端 + 外部登录限流（Redis），进程内限流仅单 worker 有效
- SQLite 后端适合单机/Demo；Postgres 适合生产与水平扩展

## 测试

```bash
uv run pytest -v
```

覆盖：健康检查、Agent CRUD、租户隔离、认证、同步/异步闭环、executor 背压与优雅关闭、SQLite 持久化（重启不丢）、supervisor / pipeline / fan-out 协作、多 LLM provider、存储后端配置、skill 加载与 namespace 隔离、动态 skill 实时生效、子工作流工具生成、演示数据播种（幂等 + 租户隔离）、输入校验与多租户越权防御。运行 `uv run pytest -v` 查看全部用例。

**CI 质量门禁**：ruff（lint + format）+ **mypy 类型检查**（src 全量）+ **覆盖率 ≥ 85%**（当前 91%）+ **Postgres 后端方言无关性验证**（postgres service job）。

## 项目结构

```
src/symphony/
├── main.py            # FastAPI 装配 + 认证中间件 + lifespan
├── config.py          # pydantic-settings
├── utils.py           # 通用工具（utc_now / uuid_hex / slugify / BUILTIN_TENANT / RunMode）
├── api/               # schemas / deps / routes(agents, runs, teams, orchestration, skills, tools, mcp_servers, webhook_tools, ui)
├── core/              # agent / tools / llm / executor / team / orchestration / skill_loader / skills / seed
├── models/            # AgentConfig / Run / RunStep / SkillConfig / SkillWorkflow
└── store/             # Store Protocol + InMemory / SQLite / Postgres
```

## 设计取舍

- **零外部服务默认**：默认 SQLite + mock，`uv run` 即跑通且重启不丢数据；Postgres 为可选生产后端（需服务）。
- **零配置可跑**：含工具调用、supervisor / pipeline / fan-out 协作、skill 挂载的完整演示，无需任何 key 或外部服务。
- **Postgres 复用 SQLite 逻辑**：`PostgresStore` 继承 `SQLiteStore`，仅重写连接构造（SQLAlchemy 方言无关）；JSON 以 Text+序列化存储，两端通用。
- **YAGNI**：未引入 langchain 全包（`create_react_agent` 用 langgraph.prebuilt，V2.0 前迁移）；ArqExecutor / PostgresSaver 需对应外部服务，未实现（InMemoryExecutor 单机生产可用）。

## 贡献

欢迎贡献！请阅读 [CONTRIBUTING.md](CONTRIBUTING.md)。行为准则见 [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)，安全漏洞报告见 [SECURITY.md](SECURITY.md)。

## 许可证

[MIT](LICENSE)
