ai_co_discuss 0.2.71 → 0.2.73
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.
- package/.agents/skills/discuss-host/references/manual.md +1 -1
- package/.agents/skills/discuss-participant/SKILL.md +1 -1
- package/.agents/skills/discuss-participant/references/free.md +2 -0
- package/README.md +128 -185
- package/README.zh-CN.md +122 -0
- package/backend/free_room.py +54 -5
- package/backend/remote_launch.py +175 -0
- package/backend/schema.sql +36 -0
- package/backend/server.py +60 -14
- package/docs/architecture.md +280 -280
- package/docs/deployment.md +225 -225
- package/docs/runner.md +467 -455
- package/docs/skills.md +1 -1
- package/docs/workflow.md +157 -155
- package/package.json +2 -2
- package/runner/api_participant.mjs +235 -230
- package/runner/discussion_adapters.mjs +70 -2
- package/runner/discussion_launch.mjs +54 -5
- package/runner/discussion_local.mjs +3 -2
- package/runner/discussion_service.mjs +8 -0
- package/runner/free_runner.mjs +39 -3
- package/runner/remote_launch.mjs +101 -0
- package/web/app.js +3437 -3384
- package/web/icons/typesafe.png +0 -0
- package/web/modern.css +1 -1
- package/web/modern.js +2526 -2058
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
## 在线专家:协助方式与操作恢复
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
请专家回答时,回答较长的同时提供简述与完整正文;简述的写法、保存与署名遵循 discuss-participant。若长回答缺少简述,主持人可据完整原文另行整理并注明摘要归主持人,专家正文保持原样。
|
|
38
38
|
|
|
39
39
|
选择「用户手动复制协助」时,每轮在当前聊天给出完整、可复制的提问文本和对应安排编号,由用户发到专家原聊天并贴回完整回答;主持人不自行操作该专家网页或发送问题。用户确认送达后再记录通知,收到并核对对应回答后通过 CLI 原文代发。展示提问文本不算送达,等待用户期间不重复催促。
|
|
40
40
|
|
|
@@ -81,7 +81,7 @@ description: "AI CoDiscuss 的通用参与技能,所有参与者(包括主
|
|
|
81
81
|
|
|
82
82
|
可以坚持有依据的少数意见,也可以因新证据修改判断并解释变化。主动检查关键反例与遗漏,但不为反对而反对,不以赞同人数代替证据;材料不足时说明什么证据会改变结论。需要对方回应时直接 `@专家名` 并说明具体问题;@ 只是讨论线索,不会通知。
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
篇幅和结构由问题决定。保留关键数字、条件与失败情形;回应追问只补新论证或观点变化,旧内容用原文编号引用。回答摘要按需填写(讨论与自由协作相同):正文较长、读者需要先看结论时,用一两句写主要判断或变化及关键条件;简短回答不写,不把正文复述一遍。完整论证与出处放正文,不再复制一遍长清单。
|
|
85
85
|
|
|
86
86
|
示例(只示意密度与结构,内容与篇幅按问题而定):
|
|
87
87
|
|
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
没有安排和阶段,不执行 `execution enter`。按任务文件的已读起点 `message list ROOM --after ID` 读取新消息,按时间顺序处理,后面的消息可以修正前面的,以最新指令为准并说明取舍。完成后用 `message post ROOM --as 本人 --kind chat --execution 执行编号 --access-file FILE` 提交一次回答。
|
|
8
8
|
|
|
9
|
+
任务需要多步操作时,在关键转折处(读完材料、改定方案、验证结果)用一两句中文写出进展,不另调命令:本机接入程序会把这些中途说明显示在网页的处理中卡片,让用户知道你在做什么。只写进展与判断,不复述工具输出,不代替最终回答。
|
|
10
|
+
|
|
9
11
|
提交被拒绝说明本次执行已被打断或过期:保留草稿并结束,不要去掉 `--execution` 改作普通发言,因为那会让已失效的执行继续产生可见结果。
|
|
10
12
|
|
|
11
13
|
手动接入的自由成员没有执行编号:从 `room view` 的 `free.requests` 找到自己的待处理请求,回答时用 `--request 请求编号` 关闭。
|
package/README.md
CHANGED
|
@@ -1,185 +1,128 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
[
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
|
108
|
-
|
|
|
109
|
-
|
|
|
110
|
-
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
##
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
发布后核对网页、健康接口和房间读取链接,后续接入使用返回的实际域名。本机 SQLite 与在线 D1 数据独立,不自动同步。Docker 部署及备份方法见 [部署指南](docs/deployment.md)。
|
|
131
|
-
|
|
132
|
-
**网页可以部署在线,全自动接入服务与参与软件仍需在你的电脑运行。** 在线网页 AI 无法访问本机的 `127.0.0.1` 地址。
|
|
133
|
-
|
|
134
|
-
## 使用方式
|
|
135
|
-
|
|
136
|
-
| 方式 | 由谁推进 | 前提 |
|
|
137
|
-
| --- | --- | --- |
|
|
138
|
-
| 讨论 | 本机服务按网站事件唤醒主持人与专家 | 主持人与专家均由本机服务唤醒(CLI / App / API) |
|
|
139
|
-
| 自由协作 · 本机唤醒 | 你或 AI 主持人点名后,本机服务唤醒该成员 | 成员接入为 CLI / App / API |
|
|
140
|
-
| 自由协作 · 手动接入 | 成员自行读取请求,由软件原生定时或人工触发 | 成员持自己的凭据文件 |
|
|
141
|
-
| 自由协作 · 网页代发 | 你把阅读通知交给网页 AI,再代发回答 | 无需本地软件,不能自行发言 |
|
|
142
|
-
|
|
143
|
-
默认上限为 **3 轮、不限时长**,可设置单次执行上限;到限后讨论结束、回到自由协作,需要继续时再次开启讨论。计数和停止规则见 [讨论上限](docs/workflow.md#讨论上限)。
|
|
144
|
-
|
|
145
|
-
消息支持选择文件、拖拽或粘贴截图,每条最多 10 个附件、单个最多 20 MiB。PNG、JPEG、GIF、WebP 可放大查看,PDF 可在站内翻页、缩放,其他文件提供下载(不在线解析 Office 文件)。本地 AI 可通过 CLI 按需下载原文件;实际能否理解图片或文档取决于参与软件,上传不代表 AI 已读取。
|
|
146
|
-
|
|
147
|
-
讨论结束后,可在左上方房间条目的“更多操作 → 导出对话”下载原始数据、全文及已发送附件原文件,窄屏从房间导航进入。房间目录菜单可“导出全部房间”,文件夹菜单可“导出文件夹”。在另一个网站(如本机与线上之间)用房间目录菜单的“导入房间…”选择这些 ZIP,即建成可继续使用的副本:导入者成为房主,成员需“请回”换发凭证,已有同一房间时跳过。两边数据不自动同步,导入是一次性复制。也可用 `discuss-report` 整理带来源的综合报告。备份不下载外链内容。
|
|
148
|
-
|
|
149
|
-
网站目前**没有用户登录和读取权限隔离**;公开部署前请按 [安全说明](.github/SECURITY.md) 配置访问边界。两种房间的用户写入均需要创建时保存的房间控制凭据,未持有凭据的浏览器只能阅读;本地 AI 使用自己的成员凭证或本次自动执行凭据。凭据不能代替软件登录、工具许可或本机启动能力。同一平台可以有多个实例(如 `Claude` 与 `Claude-评审`),各自有独立会话和凭据;自动 CLI 可在卡片背面配置模型与强度,App、网页和手动会话在原软件中设置。讨论安排串行,自由协作的不同成员可并行。在线读取、原生定时和浏览器操作能力取决于参与软件。
|
|
150
|
-
|
|
151
|
-
## 仓库结构
|
|
152
|
-
|
|
153
|
-
```text
|
|
154
|
-
backend/ Python 服务、运行协议、Cloudflare 后端与共用 schema
|
|
155
|
-
frontend/ Vue 界面、Markdown 与备份源码
|
|
156
|
-
web/ 可直接运行的网页、共享控制器、图标及构建产物
|
|
157
|
-
runner/ 统一 CLI、本机常驻服务与软件适配器
|
|
158
|
-
pages/ Cloudflare Pages 路由和静态配置
|
|
159
|
-
deploy/ Docker 构建文件与上下文排除规则
|
|
160
|
-
scripts/ 构建脚本
|
|
161
|
-
tests/ Python 与 JavaScript 测试
|
|
162
|
-
docs/ 使用、部署和架构文档
|
|
163
|
-
.agents/skills/ 主持、参与和报告技能
|
|
164
|
-
.github/ CI、贡献指南与安全说明
|
|
165
|
-
server.py 本地网站启动入口
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
根目录保留项目说明、许可证、工具配置与日常启动入口。前端产物随源码提供,保证 Python 环境可直接运行。修改 `frontend/` 后执行 `npm run build`,开发和验证步骤见 [贡献指南](.github/CONTRIBUTING.md)。
|
|
169
|
-
|
|
170
|
-
## 文档
|
|
171
|
-
|
|
172
|
-
| 任务 | 文档 |
|
|
173
|
-
| --- | --- |
|
|
174
|
-
| 理解主持、阶段、安排与收尾 | [讨论工作流](docs/workflow.md) |
|
|
175
|
-
| 加载主持、参与和报告技能 | [Skill 配置](docs/skills.md) |
|
|
176
|
-
| 配置软件、管理服务和排查自动接入 | [自动接入程序](docs/runner.md) |
|
|
177
|
-
| 从终端创建、读取或操作讨论 | [CLI 使用](docs/cli.md) |
|
|
178
|
-
| 本地、Docker 和 Cloudflare 部署 | [部署指南](docs/deployment.md) |
|
|
179
|
-
| 了解模块与数据模型 | [架构与实现](docs/architecture.md) |
|
|
180
|
-
| 开发、测试和提交变更 | [贡献指南](.github/CONTRIBUTING.md) |
|
|
181
|
-
| 查看仍需验证的能力 | [维护清单](docs/maintainers/TODO.md) |
|
|
182
|
-
|
|
183
|
-
## 许可证
|
|
184
|
-
|
|
185
|
-
[MIT](LICENSE)。第三方组件、字体和图标的许可见 [第三方声明](docs/THIRD_PARTY_NOTICES.md);品牌名称及标志不代表官方合作。
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# AI CoDiscuss
|
|
4
|
+
|
|
5
|
+
**One room for all your AI agents.**
|
|
6
|
+
|
|
7
|
+
Bring Claude Code, Codex, Antigravity and model APIs into a shared room —<br>
|
|
8
|
+
each keeps its own session, tools and account — then delegate by mention or run structured discussions.
|
|
9
|
+
|
|
10
|
+
[Quick Start](#quick-start) · [How It Works](#how-it-works) · [Documentation](#documentation) · [简体中文](README.zh-CN.md)
|
|
11
|
+
|
|
12
|
+
[](https://github.com/huyan1458/ai_co_discuss/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/ai_co_discuss)
|
|
14
|
+
[](package.json)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
|
|
17
|
+
<img src="docs/images/channel-preview.jpg" alt="AI CoDiscuss room: room directory, conversation and member panel" width="900">
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## Why AI CoDiscuss
|
|
22
|
+
|
|
23
|
+
Most multi-agent frameworks spin up fresh agents inside their own runtime. AI CoDiscuss takes the opposite approach: it connects the AI tools you **already use** — with their existing sessions, project context, permissions and subscriptions — and gives them a shared room with a durable record of messages, viewpoints, disagreements and conclusions.
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Delegate by mention** — `@` an agent and it works in its own original session; several can run in parallel. Unaddressed messages go to an AI host that routes the work.
|
|
28
|
+
- **Structured discussions** — set a goal and round / time limits; the host schedules speakers and follow-ups, then the room returns to free collaboration with history and conclusions kept.
|
|
29
|
+
- **Mix any participant** — local CLIs and desktop apps, model APIs, manually connected sessions and web chatbots in one room.
|
|
30
|
+
- **Shared workspace** — point a room at a project directory and grant each local agent read-only or writable access.
|
|
31
|
+
- **Live roster** — invite, pause, recall or remove members at any time, including resuming an existing agent session.
|
|
32
|
+
- **Portable records** — attachments, ZIP export / import between sites, and sourced reports via the `discuss-report` skill.
|
|
33
|
+
- **Local first** — runs entirely on your machine; optionally host the site on Cloudflare or Docker while agents stay local.
|
|
34
|
+
|
|
35
|
+
## Supported Participants
|
|
36
|
+
|
|
37
|
+
| Mode | Participants | Notes |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| **Auto-wake** | Claude Code CLI · Codex App / CLI · Antigravity App / CLI | Woken by the local service, resumes the original session, can host |
|
|
40
|
+
| **Model API** | OpenAI · Claude · Gemini · DeepSeek · Qwen · Grok · OpenAI-compatible | Called by the local service with room tools only, can host |
|
|
41
|
+
| **Manual** | Any local AI that can run `codiscuss` (e.g. Cursor CLI) | Reads and writes with its own member credential |
|
|
42
|
+
| **Web relay** | Online chat products | Read-only; you relay its replies |
|
|
43
|
+
|
|
44
|
+
## Quick Start
|
|
45
|
+
|
|
46
|
+
> [!NOTE]
|
|
47
|
+
> Requires **Node.js 24+** and **Python 3.10+**. Install and sign in to the AI tools you plan to use first; for API-only use, an API key is enough.
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npm install --global ai_co_discuss@latest
|
|
51
|
+
codiscuss setup
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`setup` detects your AI tools, installs the discussion skills and opens the local site at <http://127.0.0.1:8765>. Then:
|
|
55
|
+
|
|
56
|
+
1. Click **New Room** (新建房间) and add AI members.
|
|
57
|
+
2. Pick a host with the crown icon, and optionally set a project directory.
|
|
58
|
+
3. Optionally enable **Start discussion after creating** (创建后开启讨论) and set a goal.
|
|
59
|
+
4. Create the room and start talking — `@` members to assign work.
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
codiscuss local open # open or reuse the local site
|
|
63
|
+
codiscuss local status # show site and service status
|
|
64
|
+
codiscuss local stop # stop the site and its managed service
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
To upgrade, run `codiscuss local stop`, then `npm install --global --prefer-online ai_co_discuss@latest` and `codiscuss setup`. Options, upgrade and uninstall are covered in [Installation](docs/runner.md#npm-安装与本机配置).
|
|
68
|
+
|
|
69
|
+
> [!NOTE]
|
|
70
|
+
> The web UI and detailed documentation are currently available in Chinese.
|
|
71
|
+
|
|
72
|
+
## How It Works
|
|
73
|
+
|
|
74
|
+
```mermaid
|
|
75
|
+
flowchart LR
|
|
76
|
+
U[You · browser] --> S[(Room site<br>local or hosted)]
|
|
77
|
+
S -- events --> R[Local runner<br>codiscuss service]
|
|
78
|
+
R -- wake / resume --> A[Claude Code · Codex · Antigravity]
|
|
79
|
+
R -- API calls --> M[Model APIs]
|
|
80
|
+
A -- codiscuss CLI --> S
|
|
81
|
+
M -- room tools --> S
|
|
82
|
+
W[Web chatbots] -. read-only page .-> S
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- The **site** stores rooms, members and messages, and enforces turn order, revisions and credentials. It never runs models or stores API keys.
|
|
86
|
+
- The **local runner** consumes site events and wakes each agent in its own session, or calls the model API you configured. Keys stay on your machine.
|
|
87
|
+
- **Agents** read and post through the `codiscuss` CLI using per-member credentials, guided by the bundled `discuss-host` and `discuss-participant` skills.
|
|
88
|
+
|
|
89
|
+
Details: [Architecture](docs/architecture.md) · [Runner](docs/runner.md)
|
|
90
|
+
|
|
91
|
+
## More Ways to Start
|
|
92
|
+
|
|
93
|
+
- **Hosted site, local agents** — run `codiscuss local connect https://your-site` once on the machine running your agents. See [Connecting a hosted site](docs/runner.md#线上网页连接本机).
|
|
94
|
+
- **From a phone or tablet** — after connecting once and saving your usual projects on that computer, sign in to the same site as administrator on any device to create rooms whose agents that computer wakes. Folder paths stay on the computer. See [Launching from other devices](docs/runner.md#其他设备经已配对电脑建房).
|
|
95
|
+
- **From an AI chat** — ask a local agent to use the `discuss-host` and `discuss-participant` skills to create and host a room. See [Starting from an AI chat](docs/runner.md#从-ai-对话发起).
|
|
96
|
+
- **Model APIs** — configure provider, base URL, protocol and model per member. See [API access](docs/runner.md#api-接入).
|
|
97
|
+
|
|
98
|
+
## Deployment
|
|
99
|
+
|
|
100
|
+
The site can be self-hosted on **Cloudflare Pages + D1** or **Docker**; agents and the runner still run on your own machine, and local and hosted data are not synced. See [Deployment](docs/deployment.md).
|
|
101
|
+
|
|
102
|
+
> [!WARNING]
|
|
103
|
+
> The site does not yet provide user login or read-access isolation. Anyone who can reach the site can read its rooms. Read the [security policy](.github/SECURITY.md) before exposing it publicly.
|
|
104
|
+
|
|
105
|
+
## Documentation
|
|
106
|
+
|
|
107
|
+
| Topic | Document |
|
|
108
|
+
| --- | --- |
|
|
109
|
+
| Free collaboration, discussions, hosting and limits | [Workflow](docs/workflow.md) |
|
|
110
|
+
| Installation, local service, API access, troubleshooting | [Runner](docs/runner.md) |
|
|
111
|
+
| Host, participant and report skills | [Skills](docs/skills.md) |
|
|
112
|
+
| Command-line reference | [CLI](docs/cli.md) |
|
|
113
|
+
| Local, Docker and Cloudflare deployment | [Deployment](docs/deployment.md) |
|
|
114
|
+
| Modules, data model and protocols | [Architecture](docs/architecture.md) |
|
|
115
|
+
|
|
116
|
+
Documentation is written in Chinese.
|
|
117
|
+
|
|
118
|
+
## Contributing
|
|
119
|
+
|
|
120
|
+
Issues and pull requests are welcome. See the [contributing guide](.github/CONTRIBUTING.md) for development setup, running from source and testing.
|
|
121
|
+
|
|
122
|
+
## Security
|
|
123
|
+
|
|
124
|
+
The [security policy](.github/SECURITY.md) describes the current trust model, credential handling and data boundaries. The project has not undergone an independent security audit.
|
|
125
|
+
|
|
126
|
+
## License
|
|
127
|
+
|
|
128
|
+
Released under the [MIT License](LICENSE). Third-party components are listed in [THIRD_PARTY_NOTICES](docs/THIRD_PARTY_NOTICES.md). Product names and logos belong to their respective owners and do not imply endorsement.
|
package/README.zh-CN.md
ADDED
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
3
|
+
# AI CoDiscuss
|
|
4
|
+
|
|
5
|
+
**让你的 AI 们在同一个房间里协作。**
|
|
6
|
+
|
|
7
|
+
把 Claude Code、Codex、Antigravity 和模型 API 拉进共享房间——<br>
|
|
8
|
+
各自保留原有会话、工具与账号,按点名分工,或围绕目标多轮讨论。
|
|
9
|
+
|
|
10
|
+
[快速开始](#快速开始) · [工作原理](#工作原理) · [文档](#文档) · [English](README.md)
|
|
11
|
+
|
|
12
|
+
[](https://github.com/huyan1458/ai_co_discuss/actions/workflows/ci.yml)
|
|
13
|
+
[](https://www.npmjs.com/package/ai_co_discuss)
|
|
14
|
+
[](package.json)
|
|
15
|
+
[](LICENSE)
|
|
16
|
+
|
|
17
|
+
<img src="docs/images/channel-preview.jpg" alt="AI CoDiscuss 房间:房间目录、对话记录与成员栏" width="900">
|
|
18
|
+
|
|
19
|
+
</div>
|
|
20
|
+
|
|
21
|
+
## 为什么是 AI CoDiscuss
|
|
22
|
+
|
|
23
|
+
多数多智能体框架在自己的运行时里新建 Agent。AI CoDiscuss 反过来:接入你**已经在用**的 AI 软件——连同它们现有的会话、项目上下文、权限和订阅——为它们提供一个共享房间,持久保存消息、观点、分歧与结论。
|
|
24
|
+
|
|
25
|
+
## 特性
|
|
26
|
+
|
|
27
|
+
- **点名分工**:`@` 哪位 AI,它就在自己的原会话中处理,多位可并行;未点名的消息由 AI 主持人分派。
|
|
28
|
+
- **结构化讨论**:设定目标与轮次 / 时长上限,主持人安排发言与追问;结束后回到自由协作,记录与结论保留。
|
|
29
|
+
- **混合接入**:本地 CLI 与桌面 App、模型 API、手动接入的会话和在线网页 AI 可同房协作。
|
|
30
|
+
- **共享项目**:为房间指定项目目录,并为每位本地 AI 设置只读或可写。
|
|
31
|
+
- **随时调整成员**:随时邀请、暂离、请回或移除成员,也可以续接一个已有的 AI 会话。
|
|
32
|
+
- **可迁移记录**:附件、跨站点 ZIP 导出 / 导入,并可用 `discuss-report` 技能生成带来源的报告。
|
|
33
|
+
- **本机优先**:完全在本机运行;也可将网站部署到 Cloudflare 或 Docker,AI 仍在本机执行。
|
|
34
|
+
|
|
35
|
+
## 支持的参与者
|
|
36
|
+
|
|
37
|
+
| 接入方式 | 参与者 | 说明 |
|
|
38
|
+
| --- | --- | --- |
|
|
39
|
+
| **自动唤醒** | Claude Code CLI · Codex App / CLI · Antigravity App / CLI | 由本机服务唤醒并续接原会话,可担任主持人 |
|
|
40
|
+
| **模型 API** | OpenAI · Claude · Gemini · DeepSeek · Qwen · Grok · OpenAI 兼容服务 | 由本机服务调用,仅有房间工具,可担任主持人 |
|
|
41
|
+
| **手动接入** | 任何可运行 `codiscuss` 的本地 AI(如 Cursor CLI) | 凭自己的成员凭证读写 |
|
|
42
|
+
| **网页代发** | 在线聊天产品 | 只读,回答由你代发 |
|
|
43
|
+
|
|
44
|
+
## 快速开始
|
|
45
|
+
|
|
46
|
+
> [!NOTE]
|
|
47
|
+
> 需要 **Node.js 24+** 和 **Python 3.10+**。先安装并登录要使用的 AI 软件;只用 API 时准备 API Key 即可。
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npm install --global ai_co_discuss@latest
|
|
51
|
+
codiscuss setup
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
`setup` 检测本机 AI 软件、安装讨论技能,并打开本机网站 <http://127.0.0.1:8765>。然后:
|
|
55
|
+
|
|
56
|
+
1. 点击 **新建房间**,添加 AI 成员。
|
|
57
|
+
2. 点皇冠指定主持人,按需填写项目目录。
|
|
58
|
+
3. 需要多轮讨论时勾选 **创建后开启讨论** 并写下目标。
|
|
59
|
+
4. 创建房间,用 `@` 点名成员开始协作。
|
|
60
|
+
|
|
61
|
+
```sh
|
|
62
|
+
codiscuss local open # 打开或复用本机网站
|
|
63
|
+
codiscuss local status # 查看网站与服务状态
|
|
64
|
+
codiscuss local stop # 停止网站及其管理的服务
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
升级时先 `codiscuss local stop`,再运行 `npm install --global --prefer-online ai_co_discuss@latest` 和 `codiscuss setup`。安装选项、升级与卸载见 [安装与配置](docs/runner.md#npm-安装与本机配置)。
|
|
68
|
+
|
|
69
|
+
## 工作原理
|
|
70
|
+
|
|
71
|
+
```mermaid
|
|
72
|
+
flowchart LR
|
|
73
|
+
U[你 · 浏览器] --> S[(房间网站<br>本机或线上)]
|
|
74
|
+
S -- 事件 --> R[本机接入服务<br>codiscuss service]
|
|
75
|
+
R -- 唤醒 / 续接 --> A[Claude Code · Codex · Antigravity]
|
|
76
|
+
R -- API 调用 --> M[模型 API]
|
|
77
|
+
A -- codiscuss CLI --> S
|
|
78
|
+
M -- 房间工具 --> S
|
|
79
|
+
W[网页 AI] -. 只读阅读页 .-> S
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
- **网站**保存房间、成员与消息,校验发言安排、版本与凭据;不运行模型,也不保存 API 密钥。
|
|
83
|
+
- **本机接入服务**消费网站事件,在各 AI 的原会话中唤醒它,或调用你配置的模型 API;密钥只留在本机。
|
|
84
|
+
- **AI 成员**按随包提供的 `discuss-host`、`discuss-participant` 技能,凭各自的成员凭证通过 `codiscuss` CLI 读写房间。
|
|
85
|
+
|
|
86
|
+
详见 [架构与实现](docs/architecture.md) · [自动接入程序](docs/runner.md)
|
|
87
|
+
|
|
88
|
+
## 更多入口
|
|
89
|
+
|
|
90
|
+
- **线上网站 + 本机 AI**:在运行 AI 的电脑上执行一次 `codiscuss local connect https://你的站点`。见 [线上网页连接本机](docs/runner.md#线上网页连接本机)。
|
|
91
|
+
- **从 AI 对话发起**:让本地 AI 使用 `discuss-host` 和 `discuss-participant` 技能建房并主持。见 [从 AI 对话发起](docs/runner.md#从-ai-对话发起)。
|
|
92
|
+
- **模型 API**:按成员配置供应商、Base URL、请求协议与模型。见 [API 接入](docs/runner.md#api-接入)。
|
|
93
|
+
|
|
94
|
+
## 部署
|
|
95
|
+
|
|
96
|
+
网站支持自托管于 **Cloudflare Pages + D1** 或 **Docker**;AI 与接入服务仍在你的电脑运行,本机与线上数据互不同步。见 [部署指南](docs/deployment.md)。
|
|
97
|
+
|
|
98
|
+
> [!WARNING]
|
|
99
|
+
> 网站暂无用户登录与读取权限隔离,能访问站点的人即可阅读其中的房间。公开部署前请阅读 [安全说明](.github/SECURITY.md)。
|
|
100
|
+
|
|
101
|
+
## 文档
|
|
102
|
+
|
|
103
|
+
| 主题 | 文档 |
|
|
104
|
+
| --- | --- |
|
|
105
|
+
| 自由协作、讨论、主持与上限 | [讨论工作流](docs/workflow.md) |
|
|
106
|
+
| 安装、本机服务、API 接入与故障排查 | [自动接入程序](docs/runner.md) |
|
|
107
|
+
| 主持、参与与报告技能 | [Skill 配置](docs/skills.md) |
|
|
108
|
+
| 命令行参考 | [CLI 使用](docs/cli.md) |
|
|
109
|
+
| 本地、Docker 与 Cloudflare 部署 | [部署指南](docs/deployment.md) |
|
|
110
|
+
| 模块、数据模型与协议 | [架构与实现](docs/architecture.md) |
|
|
111
|
+
|
|
112
|
+
## 参与贡献
|
|
113
|
+
|
|
114
|
+
欢迎提交 Issue 与 Pull Request。开发环境、源码运行与测试见 [贡献指南](.github/CONTRIBUTING.md)。
|
|
115
|
+
|
|
116
|
+
## 安全
|
|
117
|
+
|
|
118
|
+
[安全说明](.github/SECURITY.md) 介绍当前的信任模型、凭据处理与数据边界。项目尚未经过独立安全审计。
|
|
119
|
+
|
|
120
|
+
## 许可证
|
|
121
|
+
|
|
122
|
+
基于 [MIT 许可证](LICENSE) 发布。第三方组件见 [第三方声明](docs/THIRD_PARTY_NOTICES.md)。文中产品名称及标志归各自所有者,不代表官方合作。
|
package/backend/free_room.py
CHANGED
|
@@ -24,6 +24,12 @@ RECENT_REQUESTS = 100
|
|
|
24
24
|
RECENT_EXECUTIONS = 100
|
|
25
25
|
RECENT_CHANGES = 50
|
|
26
26
|
MAX_CHANGED_FILES = 200
|
|
27
|
+
# What a member's software last showed it doing, as reported by the runner with each renewal.
|
|
28
|
+
ACTIVITY_PHASES = ("", "thinking", "command", "tool", "editing", "writing")
|
|
29
|
+
# Progress notes per execution, their length, and how many one renewal may carry.
|
|
30
|
+
MAX_EXECUTION_NOTES = 50
|
|
31
|
+
MAX_NOTE_LENGTH = 500
|
|
32
|
+
MAX_NOTES_PER_RENEW = 10
|
|
27
33
|
MAX_PATH_LENGTH = 500
|
|
28
34
|
ACTIVE = ("dispatched", "started")
|
|
29
35
|
ACCESS_MODES = ("runner", "manual", "online")
|
|
@@ -44,10 +50,12 @@ QUEUE_ASKED = "EXISTS(SELECT 1 FROM member_requests r WHERE r.message_id={row}.m
|
|
|
44
50
|
SESSION_MODES = ("new", "borrowed")
|
|
45
51
|
FREE_OPERATIONS = ("messages", "attachments", "move", "folder", "archive", "restore", "delete")
|
|
46
52
|
MEMBER_FIELDS = ("id", "name", "adapter", "role", "status", "access", "session_mode", "read_until")
|
|
47
|
-
EXECUTION_FIELDS = ("id", "member_id", "status", "session_id", "lease_until", "created_at", "finished_at", "result"
|
|
53
|
+
EXECUTION_FIELDS = ("id", "member_id", "status", "session_id", "lease_until", "created_at", "finished_at", "result",
|
|
54
|
+
"activity", "activity_at")
|
|
48
55
|
# Columns added after the first free-room tables; Python databases created by that build gain them here.
|
|
49
56
|
LATER_COLUMNS = {"room_members": {"access": "TEXT NOT NULL DEFAULT 'runner'", "session_mode": "TEXT NOT NULL DEFAULT 'new'"},
|
|
50
|
-
"member_executions": {"changes": "TEXT NOT NULL DEFAULT ''", "cwd": "TEXT NOT NULL DEFAULT ''"
|
|
57
|
+
"member_executions": {"changes": "TEXT NOT NULL DEFAULT ''", "cwd": "TEXT NOT NULL DEFAULT ''",
|
|
58
|
+
"activity": "TEXT NOT NULL DEFAULT ''", "activity_at": "INTEGER NOT NULL DEFAULT 0"},
|
|
51
59
|
"member_requests": {"chain_id": "INTEGER NOT NULL DEFAULT 0", "batch_id": "INTEGER NOT NULL DEFAULT 0",
|
|
52
60
|
"purpose": "TEXT NOT NULL DEFAULT 'ask'", "created_by": "TEXT NOT NULL DEFAULT 'user'"}}
|
|
53
61
|
|
|
@@ -187,16 +195,30 @@ def public_execution(row):
|
|
|
187
195
|
return {key: row[key] for key in EXECUTION_FIELDS} if row else None
|
|
188
196
|
|
|
189
197
|
|
|
198
|
+
def note_count(connection, execution_id):
|
|
199
|
+
"""How many progress notes an execution has; the texts are read separately so room views stay small."""
|
|
200
|
+
return connection.execute("SELECT COUNT(*) FROM execution_notes WHERE execution_id=?", (execution_id,)).fetchone()[0]
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def execution_notes(connection, room_id, execution_id):
|
|
204
|
+
"""Read one execution's progress notes in order, with the same access as the room view."""
|
|
205
|
+
if not connection.execute("SELECT 1 FROM member_executions WHERE room_id=? AND id=?", (room_id, execution_id)).fetchone():
|
|
206
|
+
raise LookupError("执行不存在")
|
|
207
|
+
return {"notes": [dict(row) for row in connection.execute(
|
|
208
|
+
"SELECT seq,text,created_at FROM execution_notes WHERE execution_id=? ORDER BY seq", (execution_id,))]}
|
|
209
|
+
|
|
210
|
+
|
|
190
211
|
def recent_executions(connection, room_id):
|
|
191
212
|
"""Return bounded public reports, including requests no longer in the recent request list."""
|
|
192
213
|
rows = connection.execute("""SELECT e.*,
|
|
193
214
|
(SELECT json_group_array(id) FROM member_requests WHERE execution_id=e.id) AS request_ids,
|
|
194
215
|
(SELECT MAX(answer_id) FROM member_requests WHERE execution_id=e.id) AS answer_id,
|
|
195
|
-
(SELECT MIN(message_id) FROM member_requests WHERE execution_id=e.id) AS request_message_id
|
|
216
|
+
(SELECT MIN(message_id) FROM member_requests WHERE execution_id=e.id) AS request_message_id,
|
|
217
|
+
(SELECT COUNT(*) FROM execution_notes WHERE execution_id=e.id) AS note_count
|
|
196
218
|
FROM member_executions e WHERE room_id=? ORDER BY id DESC LIMIT ?""", (room_id, RECENT_EXECUTIONS))
|
|
197
219
|
return [{**public_execution(row), "cwd": row["cwd"], "changes": json.loads(row["changes"] or "[]"),
|
|
198
220
|
"changes_recorded": bool(row["changes"]), "request_ids": json.loads(row["request_ids"]),
|
|
199
|
-
"answer_id": row["answer_id"], "request_message_id": row["request_message_id"]} for row in rows]
|
|
221
|
+
"answer_id": row["answer_id"], "request_message_id": row["request_message_id"], "notes": row["note_count"]} for row in rows]
|
|
200
222
|
|
|
201
223
|
|
|
202
224
|
def possible_conflicts(connection, room_id, names):
|
|
@@ -245,6 +267,7 @@ def free_view(connection, room_id):
|
|
|
245
267
|
member["execution"] = public_execution(latest)
|
|
246
268
|
if latest and latest["status"] in ACTIVE:
|
|
247
269
|
member["execution"]["stale"] = latest["lease_until"] <= now
|
|
270
|
+
member["execution"]["notes"] = note_count(connection, latest["id"])
|
|
248
271
|
member["pending"] = connection.execute("SELECT COUNT(*) FROM member_requests WHERE member_id=? AND status='pending'",
|
|
249
272
|
(row["id"],)).fetchone()[0]
|
|
250
273
|
members.append(member)
|
|
@@ -1037,6 +1060,26 @@ def changed_files(payload):
|
|
|
1037
1060
|
return sorted(set(files))
|
|
1038
1061
|
|
|
1039
1062
|
|
|
1063
|
+
def renewed_activity(payload, row, now):
|
|
1064
|
+
"""Validate the runner's reported phase; its output time is kept within the execution, since the runner's clock may differ."""
|
|
1065
|
+
activity, activity_at = payload.get("activity"), payload.get("activity_at")
|
|
1066
|
+
if activity not in ACTIVITY_PHASES:
|
|
1067
|
+
raise ValueError(f"activity 须为 {'、'.join(item for item in ACTIVITY_PHASES if item)} 或空")
|
|
1068
|
+
if type(activity_at) is not int:
|
|
1069
|
+
raise ValueError("activity_at 须为秒级时间戳")
|
|
1070
|
+
return activity, min(max(activity_at, row["created_at"]), now)
|
|
1071
|
+
|
|
1072
|
+
|
|
1073
|
+
def renewed_notes(payload):
|
|
1074
|
+
"""Validate progress notes carried by a renewal; a repeated sequence number is the same note resent."""
|
|
1075
|
+
notes = payload.get("notes", [])
|
|
1076
|
+
if (not isinstance(notes, list) or len(notes) > MAX_NOTES_PER_RENEW or any(
|
|
1077
|
+
not isinstance(note, dict) or type(note.get("seq")) is not int or not 1 <= note["seq"] <= MAX_EXECUTION_NOTES
|
|
1078
|
+
or not isinstance(note.get("text"), str) or not 0 < len(note["text"]) <= MAX_NOTE_LENGTH for note in notes)):
|
|
1079
|
+
raise ValueError(f"notes 须为最多 {MAX_NOTES_PER_RENEW} 条 {{seq: 1–{MAX_EXECUTION_NOTES}, text: 1–{MAX_NOTE_LENGTH} 字}}")
|
|
1080
|
+
return notes
|
|
1081
|
+
|
|
1082
|
+
|
|
1040
1083
|
def execution_action(connection, room_id, execution_id, token, payload):
|
|
1041
1084
|
"""Runner-side lifecycle: renew, fail, release undelivered work, or report observed file changes."""
|
|
1042
1085
|
require_owner(connection, room_id, token)
|
|
@@ -1057,7 +1100,13 @@ def execution_action(connection, room_id, execution_id, token, payload):
|
|
|
1057
1100
|
limit = row["created_at"] + execution_minutes(connection, room_id) * 60
|
|
1058
1101
|
if row["lease_until"] <= now or limit <= now:
|
|
1059
1102
|
raise FileExistsError("执行租约或单次时限已到,不能续租")
|
|
1060
|
-
|
|
1103
|
+
# Older runners renew without activity; the last reported one is kept.
|
|
1104
|
+
activity, activity_at = renewed_activity(payload, row, now) if "activity" in payload else (row["activity"], row["activity_at"])
|
|
1105
|
+
notes = renewed_notes(payload)
|
|
1106
|
+
connection.execute("UPDATE member_executions SET lease_until=?,activity=?,activity_at=? WHERE id=?",
|
|
1107
|
+
(min(now + LEASE_SECONDS, limit), activity, activity_at, execution_id))
|
|
1108
|
+
connection.executemany("INSERT OR IGNORE INTO execution_notes (execution_id,seq,room_id,text,created_at) VALUES (?,?,?,?,?)",
|
|
1109
|
+
[(execution_id, note["seq"], room_id, note["text"], now) for note in notes])
|
|
1061
1110
|
elif action == "fail":
|
|
1062
1111
|
finish_execution(connection, execution_id, "failed", str(payload.get("reason") or "执行失败"), "failed")
|
|
1063
1112
|
settle_batches(connection, room_id)
|