dong-ai 0.1.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.
- dong_ai-0.1.0/LICENSE +21 -0
- dong_ai-0.1.0/PKG-INFO +145 -0
- dong_ai-0.1.0/README.md +124 -0
- dong_ai-0.1.0/pyproject.toml +34 -0
- dong_ai-0.1.0/setup.cfg +4 -0
- dong_ai-0.1.0/src/dong_ai/__init__.py +34 -0
- dong_ai-0.1.0/src/dong_ai/api.py +255 -0
- dong_ai-0.1.0/src/dong_ai/browser_tool.py +99 -0
- dong_ai-0.1.0/src/dong_ai/ceo.py +416 -0
- dong_ai-0.1.0/src/dong_ai/ceo_memory.py +279 -0
- dong_ai-0.1.0/src/dong_ai/cli.py +370 -0
- dong_ai-0.1.0/src/dong_ai/codegraph_bridge.py +78 -0
- dong_ai-0.1.0/src/dong_ai/cron.py +141 -0
- dong_ai-0.1.0/src/dong_ai/datastore.py +376 -0
- dong_ai-0.1.0/src/dong_ai/design_engine.py +133 -0
- dong_ai-0.1.0/src/dong_ai/display.py +135 -0
- dong_ai-0.1.0/src/dong_ai/llm.py +145 -0
- dong_ai-0.1.0/src/dong_ai/logger.py +79 -0
- dong_ai-0.1.0/src/dong_ai/mcp_client.py +182 -0
- dong_ai-0.1.0/src/dong_ai/memory.py +364 -0
- dong_ai-0.1.0/src/dong_ai/model_pool.py +336 -0
- dong_ai-0.1.0/src/dong_ai/tool_executor.py +148 -0
- dong_ai-0.1.0/src/dong_ai/tui.py +390 -0
- dong_ai-0.1.0/src/dong_ai/web_search.py +35 -0
- dong_ai-0.1.0/src/dong_ai/worker.py +520 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/PKG-INFO +145 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/SOURCES.txt +33 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/dependency_links.txt +1 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/entry_points.txt +2 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/requires.txt +9 -0
- dong_ai-0.1.0/src/dong_ai.egg-info/top_level.txt +1 -0
- dong_ai-0.1.0/tests/test_ceo_memory.py +234 -0
- dong_ai-0.1.0/tests/test_harness.py +395 -0
- dong_ai-0.1.0/tests/test_model_pool.py +351 -0
- dong_ai-0.1.0/tests/test_worker.py +330 -0
dong_ai-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Dong AI
|
|
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.
|
dong_ai-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: dong-ai
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Dong AI Company — 多智能体 AI 公司框架
|
|
5
|
+
Author-email: Dong AI <dong@dong-ai.dev>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/nousresearch/dong-ai
|
|
8
|
+
Project-URL: Source, https://github.com/nousresearch/dong-ai
|
|
9
|
+
Keywords: ai,agent,multi-agent,llm,framework
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Description-Content-Type: text/markdown
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Provides-Extra: server
|
|
14
|
+
Requires-Dist: fastapi>=0.110; extra == "server"
|
|
15
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == "server"
|
|
16
|
+
Provides-Extra: all
|
|
17
|
+
Requires-Dist: fastapi>=0.110; extra == "all"
|
|
18
|
+
Requires-Dist: uvicorn[standard]>=0.29; extra == "all"
|
|
19
|
+
Requires-Dist: ddgs>=0.5; extra == "all"
|
|
20
|
+
Dynamic: license-file
|
|
21
|
+
|
|
22
|
+
# Dong AI Company
|
|
23
|
+
|
|
24
|
+
<div align="center">
|
|
25
|
+
|
|
26
|
+
**您的私人AI公司 — 一个命令拉起一家AI企业**
|
|
27
|
+
|
|
28
|
+
[](https://python.org)
|
|
29
|
+
[](LICENSE)
|
|
30
|
+
[](.github/workflows/ci.yml)
|
|
31
|
+
[](tests/)
|
|
32
|
+
[](src/dong_ai/model_pool.py)
|
|
33
|
+
[](#)
|
|
34
|
+
|
|
35
|
+
</div>
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
pip install dong-ai
|
|
39
|
+
dong setup
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## 为什么是 AI 公司?
|
|
45
|
+
|
|
46
|
+
现有 AI Agent 是"工具"——你问它答,最多帮你写代码。
|
|
47
|
+
Dong AI 是**一家公司**——有红蓝辩论决策、有工人池执行、有董事会评分质量门。
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
你: "开发配置系统" 工人池 董事会
|
|
51
|
+
│ │ │
|
|
52
|
+
├─ 红队: 方案A(安全但慢) ├─ 代码匠 → 写文件 ├─ 评分8.5
|
|
53
|
+
├─ 蓝队: 方案B(快有风险) ├─ 测试判官 → 测试 ├─ 覆盖检查
|
|
54
|
+
└─ CEO: 采纳方案A └─ 审查 → 通过 └─ 放行下一阶段
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## 特性
|
|
58
|
+
|
|
59
|
+
| 能力 | 说明 |
|
|
60
|
+
|------|------|
|
|
61
|
+
| 🏛️ **治理流水线** | 红蓝辩论 → 依赖拆解 → 工人池(自愈+互审) → 董事会评分 → 需求锁 |
|
|
62
|
+
| 🧠 **图记忆** | 精确符号索引 + 依赖关系,新任务自动注入相关上下文 |
|
|
63
|
+
| 🔌 **开放生态** | Hermes 125+ 技能 / MCP 协议 / OpenAI API 兼容 |
|
|
64
|
+
| 🌐 **20+ Provider** | DeepSeek / OpenAI / Claude / Groq / Together / 本地 / Ollama |
|
|
65
|
+
| ⚙️ **双模式** | API 模式(256K 窗口) / 本地模式(64K 窗口) / 用户自由设置 |
|
|
66
|
+
| 🕐 **定时任务** | `dong cron add --cmd "dong run 审计" --every 1h` |
|
|
67
|
+
| 📡 **Webhook** | `POST /webhook` 触发自动审计 |
|
|
68
|
+
| 🔗 **MCP 客户端** | 发现并调用任何 MCP 服务器工具 |
|
|
69
|
+
|
|
70
|
+
## 快速开始
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
pip install dong-ai
|
|
74
|
+
pip install 'dong-ai[all]' # 全部依赖(含 API 服务)
|
|
75
|
+
|
|
76
|
+
dong setup # 交互式配置向导
|
|
77
|
+
dong chat # 启动对话
|
|
78
|
+
dong run "配置系统" # 一键项目执行
|
|
79
|
+
dong serve # 启动 API 服务 → http://localhost:8648
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 命令一览
|
|
83
|
+
|
|
84
|
+
```
|
|
85
|
+
dong chat 交互式 TUI dong config 配置管理
|
|
86
|
+
dong run "需求" 一键项目执行 dong skill 技能管理
|
|
87
|
+
dong serve API 服务 dong session 会话管理
|
|
88
|
+
dong setup 配置向导 dong mcp MCP 工具发现
|
|
89
|
+
dong detect 模型检测 dong cron 定时任务
|
|
90
|
+
dong version 版本信息 dong webhook Webhook 管理
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## 架构
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
dong chat / dong run / dong serve
|
|
97
|
+
│
|
|
98
|
+
┌────┴────┐
|
|
99
|
+
│ CEO │ ← DesignEngine(红蓝辩论) + WorkerPool(自愈+互审)
|
|
100
|
+
└────┬────┘
|
|
101
|
+
│
|
|
102
|
+
┌────┴────┐
|
|
103
|
+
│ ModelPool│ ← 20+ Provider 自动 failover
|
|
104
|
+
└────┬────┘
|
|
105
|
+
│
|
|
106
|
+
┌────┴────┐
|
|
107
|
+
│ LLMClient│ ← 统一 HTTP + SSE
|
|
108
|
+
└─────────┘
|
|
109
|
+
|
|
110
|
+
存储层:
|
|
111
|
+
Datastore (SQLite)
|
|
112
|
+
├── MemoryRepository 事实 KV
|
|
113
|
+
├── SessionRepository 会话历史
|
|
114
|
+
├── ProjectRepository 决策/模块
|
|
115
|
+
├── LoreRepository 世界观
|
|
116
|
+
└── GraphRepository 代码符号/依赖/需求追溯
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## 双模式配置
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
模式 CEO 上下文 工人上下文 适用场景
|
|
123
|
+
─────────────────────────────────────────────────
|
|
124
|
+
API 256K 128K 云端模型(DeepSeek/GPT/Claude)
|
|
125
|
+
Local 64K 64K 本地模型(Qwen/Llama/Ollama)
|
|
126
|
+
自定义 任意 任意 dong config set ceo_context=999999
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## 测试
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
pip install pytest
|
|
133
|
+
pytest tests/
|
|
134
|
+
# 121 passed in 1.6s
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## 许可证
|
|
138
|
+
|
|
139
|
+
MIT — 随意使用、修改、商用。
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
<p align="center">
|
|
144
|
+
<sub>不是聊天工具——是你的 AI 员工团队</sub>
|
|
145
|
+
</p>
|
dong_ai-0.1.0/README.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Dong AI Company
|
|
2
|
+
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+
**您的私人AI公司 — 一个命令拉起一家AI企业**
|
|
6
|
+
|
|
7
|
+
[](https://python.org)
|
|
8
|
+
[](LICENSE)
|
|
9
|
+
[](.github/workflows/ci.yml)
|
|
10
|
+
[](tests/)
|
|
11
|
+
[](src/dong_ai/model_pool.py)
|
|
12
|
+
[](#)
|
|
13
|
+
|
|
14
|
+
</div>
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
pip install dong-ai
|
|
18
|
+
dong setup
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 为什么是 AI 公司?
|
|
24
|
+
|
|
25
|
+
现有 AI Agent 是"工具"——你问它答,最多帮你写代码。
|
|
26
|
+
Dong AI 是**一家公司**——有红蓝辩论决策、有工人池执行、有董事会评分质量门。
|
|
27
|
+
|
|
28
|
+
```
|
|
29
|
+
你: "开发配置系统" 工人池 董事会
|
|
30
|
+
│ │ │
|
|
31
|
+
├─ 红队: 方案A(安全但慢) ├─ 代码匠 → 写文件 ├─ 评分8.5
|
|
32
|
+
├─ 蓝队: 方案B(快有风险) ├─ 测试判官 → 测试 ├─ 覆盖检查
|
|
33
|
+
└─ CEO: 采纳方案A └─ 审查 → 通过 └─ 放行下一阶段
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 特性
|
|
37
|
+
|
|
38
|
+
| 能力 | 说明 |
|
|
39
|
+
|------|------|
|
|
40
|
+
| 🏛️ **治理流水线** | 红蓝辩论 → 依赖拆解 → 工人池(自愈+互审) → 董事会评分 → 需求锁 |
|
|
41
|
+
| 🧠 **图记忆** | 精确符号索引 + 依赖关系,新任务自动注入相关上下文 |
|
|
42
|
+
| 🔌 **开放生态** | Hermes 125+ 技能 / MCP 协议 / OpenAI API 兼容 |
|
|
43
|
+
| 🌐 **20+ Provider** | DeepSeek / OpenAI / Claude / Groq / Together / 本地 / Ollama |
|
|
44
|
+
| ⚙️ **双模式** | API 模式(256K 窗口) / 本地模式(64K 窗口) / 用户自由设置 |
|
|
45
|
+
| 🕐 **定时任务** | `dong cron add --cmd "dong run 审计" --every 1h` |
|
|
46
|
+
| 📡 **Webhook** | `POST /webhook` 触发自动审计 |
|
|
47
|
+
| 🔗 **MCP 客户端** | 发现并调用任何 MCP 服务器工具 |
|
|
48
|
+
|
|
49
|
+
## 快速开始
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install dong-ai
|
|
53
|
+
pip install 'dong-ai[all]' # 全部依赖(含 API 服务)
|
|
54
|
+
|
|
55
|
+
dong setup # 交互式配置向导
|
|
56
|
+
dong chat # 启动对话
|
|
57
|
+
dong run "配置系统" # 一键项目执行
|
|
58
|
+
dong serve # 启动 API 服务 → http://localhost:8648
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 命令一览
|
|
62
|
+
|
|
63
|
+
```
|
|
64
|
+
dong chat 交互式 TUI dong config 配置管理
|
|
65
|
+
dong run "需求" 一键项目执行 dong skill 技能管理
|
|
66
|
+
dong serve API 服务 dong session 会话管理
|
|
67
|
+
dong setup 配置向导 dong mcp MCP 工具发现
|
|
68
|
+
dong detect 模型检测 dong cron 定时任务
|
|
69
|
+
dong version 版本信息 dong webhook Webhook 管理
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## 架构
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
dong chat / dong run / dong serve
|
|
76
|
+
│
|
|
77
|
+
┌────┴────┐
|
|
78
|
+
│ CEO │ ← DesignEngine(红蓝辩论) + WorkerPool(自愈+互审)
|
|
79
|
+
└────┬────┘
|
|
80
|
+
│
|
|
81
|
+
┌────┴────┐
|
|
82
|
+
│ ModelPool│ ← 20+ Provider 自动 failover
|
|
83
|
+
└────┬────┘
|
|
84
|
+
│
|
|
85
|
+
┌────┴────┐
|
|
86
|
+
│ LLMClient│ ← 统一 HTTP + SSE
|
|
87
|
+
└─────────┘
|
|
88
|
+
|
|
89
|
+
存储层:
|
|
90
|
+
Datastore (SQLite)
|
|
91
|
+
├── MemoryRepository 事实 KV
|
|
92
|
+
├── SessionRepository 会话历史
|
|
93
|
+
├── ProjectRepository 决策/模块
|
|
94
|
+
├── LoreRepository 世界观
|
|
95
|
+
└── GraphRepository 代码符号/依赖/需求追溯
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## 双模式配置
|
|
99
|
+
|
|
100
|
+
```
|
|
101
|
+
模式 CEO 上下文 工人上下文 适用场景
|
|
102
|
+
─────────────────────────────────────────────────
|
|
103
|
+
API 256K 128K 云端模型(DeepSeek/GPT/Claude)
|
|
104
|
+
Local 64K 64K 本地模型(Qwen/Llama/Ollama)
|
|
105
|
+
自定义 任意 任意 dong config set ceo_context=999999
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## 测试
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
pip install pytest
|
|
112
|
+
pytest tests/
|
|
113
|
+
# 121 passed in 1.6s
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## 许可证
|
|
117
|
+
|
|
118
|
+
MIT — 随意使用、修改、商用。
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
<p align="center">
|
|
123
|
+
<sub>不是聊天工具——是你的 AI 员工团队</sub>
|
|
124
|
+
</p>
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "dong-ai"
|
|
7
|
+
version = "0.1.0"
|
|
8
|
+
description = "Dong AI Company — 多智能体 AI 公司框架"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "Dong AI", email = "dong@dong-ai.dev"},
|
|
14
|
+
]
|
|
15
|
+
keywords = ["ai", "agent", "multi-agent", "llm", "framework"]
|
|
16
|
+
|
|
17
|
+
[project.urls]
|
|
18
|
+
Homepage = "https://github.com/nousresearch/dong-ai"
|
|
19
|
+
Source = "https://github.com/nousresearch/dong-ai"
|
|
20
|
+
|
|
21
|
+
[project.optional-dependencies]
|
|
22
|
+
server = ["fastapi>=0.110", "uvicorn[standard]>=0.29"]
|
|
23
|
+
all = [
|
|
24
|
+
"fastapi>=0.110",
|
|
25
|
+
"uvicorn[standard]>=0.29",
|
|
26
|
+
"ddgs>=0.5",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
dong = "dong_ai.cli:main"
|
|
31
|
+
|
|
32
|
+
[tool.setuptools.packages.find]
|
|
33
|
+
where = ["src"]
|
|
34
|
+
include = ["dong_ai*"]
|
dong_ai-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
"""Dong AI Company — 多智能体 AI 公司框架
|
|
2
|
+
|
|
3
|
+
一键安装:
|
|
4
|
+
pip install dong-ai
|
|
5
|
+
|
|
6
|
+
快速开始:
|
|
7
|
+
dong chat # 交互式 TUI
|
|
8
|
+
dong run "需求" # 一键项目执行
|
|
9
|
+
dong serve # API 服务
|
|
10
|
+
dong detect # 检测可用模型
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
__version__ = "0.1.0"
|
|
14
|
+
|
|
15
|
+
from .ceo import CEO
|
|
16
|
+
from .llm import LLMConfig, LLMResponse, OpenAICompatibleClient, create_client
|
|
17
|
+
from .datastore import Datastore, get_repo
|
|
18
|
+
from .design_engine import DesignEngine
|
|
19
|
+
from .display import print_banner, print_assistant, status_line, box_top, box_bottom, sep
|
|
20
|
+
from .tool_executor import ToolExecutor
|
|
21
|
+
from .ceo_memory import CEOMemory
|
|
22
|
+
from .logger import get_logger
|
|
23
|
+
from .model_pool import ModelPool, get_pool, llm_call, PROVIDERS
|
|
24
|
+
from .worker import WorkerPool
|
|
25
|
+
from .web_search import search, search_formatted
|
|
26
|
+
|
|
27
|
+
__all__ = [
|
|
28
|
+
"CEO", "WorkerPool", "ModelPool", "DesignEngine",
|
|
29
|
+
"LLMConfig", "LLMResponse", "OpenAICompatibleClient", "create_client",
|
|
30
|
+
"Datastore", "get_repo", "CEOMemory", "ToolExecutor",
|
|
31
|
+
"print_banner", "print_assistant", "status_line", "box_top", "box_bottom", "sep",
|
|
32
|
+
"get_logger", "get_pool", "llm_call", "PROVIDERS",
|
|
33
|
+
"search", "search_formatted",
|
|
34
|
+
]
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""Dong AI — FastAPI API Server
|
|
2
|
+
|
|
3
|
+
OpenAI 兼容 API,任何 OpenAI 客户端可直接连接。
|
|
4
|
+
|
|
5
|
+
启动:
|
|
6
|
+
dong serve --port 8648
|
|
7
|
+
|
|
8
|
+
端点:
|
|
9
|
+
GET /v1/models → 可用模型列表
|
|
10
|
+
POST /v1/chat/completions → 聊天(含流式)
|
|
11
|
+
POST /v1/run → CEO 项目执行
|
|
12
|
+
GET /health → 健康检查
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import json, time, uuid, os
|
|
16
|
+
from typing import Optional
|
|
17
|
+
|
|
18
|
+
try:
|
|
19
|
+
from fastapi import FastAPI, HTTPException, Request
|
|
20
|
+
from fastapi.responses import StreamingResponse, JSONResponse, HTMLResponse
|
|
21
|
+
from fastapi.staticfiles import StaticFiles
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
except ImportError:
|
|
24
|
+
raise ImportError("需要安装 fastapi: pip install 'dong-ai[server]'")
|
|
25
|
+
|
|
26
|
+
from dong_ai.model_pool import ModelPool
|
|
27
|
+
|
|
28
|
+
app = FastAPI(title="Dong AI API", version="0.1.0")
|
|
29
|
+
pool = ModelPool()
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
# ═══════════════════════════════════════════════════════════
|
|
33
|
+
# Models (OpenAI 兼容)
|
|
34
|
+
# ═══════════════════════════════════════════════════════════
|
|
35
|
+
|
|
36
|
+
@app.get("/v1/models")
|
|
37
|
+
async def list_models():
|
|
38
|
+
"""OpenAI 兼容的模型列表"""
|
|
39
|
+
providers = pool.available()
|
|
40
|
+
models = []
|
|
41
|
+
for p in providers:
|
|
42
|
+
for model_id in p["models"]:
|
|
43
|
+
models.append({
|
|
44
|
+
"id": model_id,
|
|
45
|
+
"object": "model",
|
|
46
|
+
"created": int(time.time()),
|
|
47
|
+
"owned_by": p["name"],
|
|
48
|
+
})
|
|
49
|
+
return {"object": "list", "data": models}
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
# ═══════════════════════════════════════════════════════════
|
|
53
|
+
# Chat Completions (OpenAI 兼容)
|
|
54
|
+
# ═══════════════════════════════════════════════════════════
|
|
55
|
+
|
|
56
|
+
@app.post("/v1/chat/completions")
|
|
57
|
+
async def chat_completions(request: Request):
|
|
58
|
+
"""OpenAI 兼容的聊天补全(支持流式)"""
|
|
59
|
+
body = await request.json()
|
|
60
|
+
messages = body.get("messages", [])
|
|
61
|
+
model = body.get("model", "")
|
|
62
|
+
stream = body.get("stream", False)
|
|
63
|
+
max_tokens = body.get("max_tokens", 8192)
|
|
64
|
+
temperature = body.get("temperature", 0.7)
|
|
65
|
+
|
|
66
|
+
# 从 messages 中提取 system prompt
|
|
67
|
+
system = ""
|
|
68
|
+
filtered = []
|
|
69
|
+
for m in messages:
|
|
70
|
+
if m.get("role") == "system":
|
|
71
|
+
system = m["content"]
|
|
72
|
+
else:
|
|
73
|
+
filtered.append(m)
|
|
74
|
+
messages = filtered
|
|
75
|
+
|
|
76
|
+
# 选择 provider(如果指定 model 则匹配,否则用 best)
|
|
77
|
+
providers = pool.available()
|
|
78
|
+
if model:
|
|
79
|
+
target = next((p for p in providers if model in p["models"]), None)
|
|
80
|
+
if not target:
|
|
81
|
+
raise HTTPException(status_code=404, detail=f"Model {model} not found")
|
|
82
|
+
providers = [target]
|
|
83
|
+
|
|
84
|
+
if not providers:
|
|
85
|
+
raise HTTPException(status_code=503, detail="No available model providers")
|
|
86
|
+
|
|
87
|
+
if stream:
|
|
88
|
+
return _stream_response(providers[0], messages, system, max_tokens, temperature, model)
|
|
89
|
+
else:
|
|
90
|
+
return _json_response(providers[0], messages, system, max_tokens, temperature, model)
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _json_response(provider, messages, system, max_tokens, temperature, model_id):
|
|
94
|
+
"""非流式响应"""
|
|
95
|
+
from dong_ai.llm import LLMConfig, OpenAICompatibleClient
|
|
96
|
+
|
|
97
|
+
client = OpenAICompatibleClient(LLMConfig(
|
|
98
|
+
model=model_id or provider["models"][0],
|
|
99
|
+
base_url=provider["base_url"],
|
|
100
|
+
api_key=provider.get("api_key", ""),
|
|
101
|
+
max_tokens=max_tokens,
|
|
102
|
+
temperature=temperature,
|
|
103
|
+
))
|
|
104
|
+
|
|
105
|
+
try:
|
|
106
|
+
resp = client.chat(messages, system=system if system else None)
|
|
107
|
+
except Exception as e:
|
|
108
|
+
raise HTTPException(status_code=502, detail=str(e))
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
"id": f"chatcmpl-{uuid.uuid4().hex[:12]}",
|
|
112
|
+
"object": "chat.completion",
|
|
113
|
+
"created": int(time.time()),
|
|
114
|
+
"model": model_id or provider["models"][0],
|
|
115
|
+
"choices": [{
|
|
116
|
+
"index": 0,
|
|
117
|
+
"message": {"role": "assistant", "content": resp.text},
|
|
118
|
+
"finish_reason": "stop",
|
|
119
|
+
}],
|
|
120
|
+
"usage": resp.usage,
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def _stream_response(provider, messages, system, max_tokens, temperature, model_id):
|
|
125
|
+
"""流式 SSE 响应"""
|
|
126
|
+
from dong_ai.llm import LLMConfig, OpenAICompatibleClient
|
|
127
|
+
|
|
128
|
+
client = OpenAICompatibleClient(LLMConfig(
|
|
129
|
+
model=model_id or provider["models"][0],
|
|
130
|
+
base_url=provider["base_url"],
|
|
131
|
+
api_key=provider.get("api_key", ""),
|
|
132
|
+
max_tokens=max_tokens,
|
|
133
|
+
temperature=temperature,
|
|
134
|
+
))
|
|
135
|
+
|
|
136
|
+
async def generate():
|
|
137
|
+
completion_id = f"chatcmpl-{uuid.uuid4().hex[:12]}"
|
|
138
|
+
yield f"data: {json.dumps({'id': completion_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': model_id or provider['models'][0], 'choices': [{'index': 0, 'delta': {'role': 'assistant'}, 'finish_reason': None}]})}\n\n"
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
for token in client.chat_stream(messages, system=system if system else "", max_tokens=max_tokens, temperature=temperature):
|
|
142
|
+
yield f"data: {json.dumps({'id': completion_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': model_id or provider['models'][0], 'choices': [{'index': 0, 'delta': {'content': token}, 'finish_reason': None}]})}\n\n"
|
|
143
|
+
|
|
144
|
+
yield f"data: {json.dumps({'id': completion_id, 'object': 'chat.completion.chunk', 'created': int(time.time()), 'model': model_id or provider['models'][0], 'choices': [{'index': 0, 'delta': {}, 'finish_reason': 'stop'}]})}\n\n"
|
|
145
|
+
except Exception as e:
|
|
146
|
+
yield f"data: {json.dumps({'error': {'message': str(e)}})}\n\n"
|
|
147
|
+
|
|
148
|
+
yield "data: [DONE]\n\n"
|
|
149
|
+
|
|
150
|
+
return StreamingResponse(generate(), media_type="text/event-stream",
|
|
151
|
+
headers={"Cache-Control": "no-cache", "Connection": "keep-alive"})
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
# ═══════════════════════════════════════════════════════════
|
|
155
|
+
# CEO 项目执行
|
|
156
|
+
# ═══════════════════════════════════════════════════════════
|
|
157
|
+
|
|
158
|
+
@app.post("/v1/run")
|
|
159
|
+
async def run_project(request: Request):
|
|
160
|
+
"""CEO 一键项目执行"""
|
|
161
|
+
body = await request.json()
|
|
162
|
+
request_text = body.get("request", "")
|
|
163
|
+
if not request_text:
|
|
164
|
+
raise HTTPException(status_code=400, detail="request is required")
|
|
165
|
+
|
|
166
|
+
try:
|
|
167
|
+
from dong_ai.ceo import CEO
|
|
168
|
+
import io, sys
|
|
169
|
+
# 捕获 print 输出作为执行日志
|
|
170
|
+
captured = io.StringIO()
|
|
171
|
+
old_stdout = sys.stdout
|
|
172
|
+
sys.stdout = captured
|
|
173
|
+
ceo = CEO()
|
|
174
|
+
ceo.run(request_text)
|
|
175
|
+
sys.stdout = old_stdout
|
|
176
|
+
log = captured.getvalue()
|
|
177
|
+
except Exception as e:
|
|
178
|
+
raise HTTPException(status_code=500, detail=str(e))
|
|
179
|
+
|
|
180
|
+
return {"status": "done", "log": log, "report_path": str(ceo.report_path)}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
# ═══════════════════════════════════════════════════════════
|
|
184
|
+
# Health
|
|
185
|
+
# ═══════════════════════════════════════════════════════════
|
|
186
|
+
|
|
187
|
+
@app.get("/health")
|
|
188
|
+
async def health():
|
|
189
|
+
providers = pool.available()
|
|
190
|
+
return {
|
|
191
|
+
"status": "ok",
|
|
192
|
+
"version": "0.1.0",
|
|
193
|
+
"providers": len(providers),
|
|
194
|
+
"models": [p["models"][0] for p in providers[:5]],
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
# ═══════════════════════════════════════════════════════════
|
|
199
|
+
# Webhook
|
|
200
|
+
# ═══════════════════════════════════════════════════════════
|
|
201
|
+
|
|
202
|
+
WEBHOOK_SECRET = os.environ.get("DONG_WEBHOOK_SECRET", "")
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
@app.post("/webhook")
|
|
206
|
+
async def webhook(request: Request):
|
|
207
|
+
"""通用 webhook 接收器——接收外部事件并触发动作"""
|
|
208
|
+
body = await request.json()
|
|
209
|
+
event = body.get("event", body.get("type", "unknown"))
|
|
210
|
+
payload = body.get("payload", body)
|
|
211
|
+
|
|
212
|
+
# 验证 secret
|
|
213
|
+
token = request.headers.get("X-Webhook-Token", "")
|
|
214
|
+
if WEBHOOK_SECRET and token != WEBHOOK_SECRET:
|
|
215
|
+
raise HTTPException(status_code=401, detail="invalid token")
|
|
216
|
+
|
|
217
|
+
# 记录 webhook
|
|
218
|
+
try:
|
|
219
|
+
from dong_ai.ceo_memory import CEOMemory
|
|
220
|
+
mem = CEOMemory()
|
|
221
|
+
sid = mem.session_start(f"webhook_{int(time.time())}")
|
|
222
|
+
mem.session_save(sid, "system",
|
|
223
|
+
f"Webhook received: {event}\nPayload: {json.dumps(payload, ensure_ascii=False)[:1000]}")
|
|
224
|
+
except Exception:
|
|
225
|
+
pass
|
|
226
|
+
|
|
227
|
+
# 根据事件类型执行动作
|
|
228
|
+
if event == "deploy" or event == "push":
|
|
229
|
+
# 触发 CEO 审计
|
|
230
|
+
try:
|
|
231
|
+
from dong_ai.ceo import CEO
|
|
232
|
+
ceo = CEO()
|
|
233
|
+
# 后台线程执行
|
|
234
|
+
import threading
|
|
235
|
+
threading.Thread(target=ceo.run,
|
|
236
|
+
args=(f"审计最近的代码变更: {json.dumps(payload, ensure_ascii=False)[:200]}",),
|
|
237
|
+
daemon=True).start()
|
|
238
|
+
return {"status": "accepted", "message": "审计已启动"}
|
|
239
|
+
except Exception as e:
|
|
240
|
+
return {"status": "error", "message": str(e)}
|
|
241
|
+
|
|
242
|
+
return {"status": "received", "event": event}
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
# ═══════════════════════════════════════════════════════════
|
|
246
|
+
# Web UI
|
|
247
|
+
# ═══════════════════════════════════════════════════════════
|
|
248
|
+
|
|
249
|
+
@app.get("/")
|
|
250
|
+
async def chat_ui():
|
|
251
|
+
"""Kimi 风格的聊天界面"""
|
|
252
|
+
html_path = Path(__file__).parent / "chat_ui.html"
|
|
253
|
+
if html_path.exists():
|
|
254
|
+
return HTMLResponse(html_path.read_text(encoding="utf-8"))
|
|
255
|
+
return HTMLResponse("<h1>Dong AI Company</h1><p>Chat UI not found</p>")
|