ai_co_discuss 0.3.28 → 0.3.30

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.
@@ -49,11 +49,12 @@ description: "AI CoDiscuss 的通用参与技能,所有参与者(包括主
49
49
 
50
50
  可以坚持有依据的少数意见,也可以因新证据修改判断并解释变化。主动检查关键反例与遗漏,但不为反对而反对,不以赞同人数代替证据;材料不足时说明什么证据会改变结论。
51
51
 
52
- 篇幅和结构由问题决定。保留关键数字、条件与失败情形;回应追问只补新论证或观点变化,旧内容用原文编号引用。摘要(`--summary`)按需填写:正文较长、读者需要先看结论时,用一两句写主要判断或变化及关键条件;简短回答不写,不把正文复述一遍。完整论证与出处放正文。
52
+ 篇幅和结构由问题决定。保留关键数字、条件与失败情形;回应追问只补新论证或观点变化,旧内容用原文编号引用。摘要(`--summary`)给先看结论或只听语音播报的人,约 15 秒能念完(不超过约 80 字):正文约 300 字以上或分多段时必写,简短回答不写。观点说立场或变化及最关键的理由;交付(写好的章节、文档、代码)说做了什么、最重要的变化。用能直接念出口的话,不用列表和原文编号。完整论证与出处放正文。
53
53
 
54
54
  示例(只示意密度与结构,内容与篇幅按问题而定):
55
55
 
56
- > 摘要:倾向方案 B——迁移成本一次性,A 的维护成本随规模线性增长。
56
+ > 观点 `--summary`:我倾向方案 B——迁移成本只付一次,A 的维护成本会随规模一直涨;团队五人以内时 A 仍更省。
57
+ > 交付 `--summary`:我按大家的意见重写了第一章:主角换成留校的北方研二学生林深,时代感升到 2032 年,全文约六千字。
57
58
  > 正文:结论先行;依据 1(出处/数据)、依据 2;**适用条件**:团队 ≤5 人时 A 仍更省;**不确定性**:未测量实际迁移耗时,超过 2 周则结论反转;对 #167 的分歧在于成本口径,而非事实。
58
59
 
59
60
  ## 保存与核验
@@ -764,7 +764,12 @@ def authorize_free_write(connection, room_id, token, operation, payload):
764
764
  if operation not in ("messages", "attachments"):
765
765
  raise
766
766
  author = payload.get("author")
767
- member = require_member(connection, room_id, token)
767
+ try:
768
+ member = require_member(connection, room_id, token)
769
+ except PermissionError:
770
+ if author in (None, "用户"):
771
+ raise PermissionError("此浏览器没有本房间的房主凭据:请用创建房间的浏览器,或登录管理员后再发言") from None
772
+ raise
768
773
  if author == member["name"] and payload.get("submitted_by", author) == author:
769
774
  return member
770
775
  raise PermissionError("成员只能以本人身份发言")
package/backend/server.py CHANGED
@@ -1847,8 +1847,9 @@ class DiscussionHandler(BaseHTTPRequestHandler):
1847
1847
  return True
1848
1848
 
1849
1849
  def admin_as_owner(self, connection, room_id):
1850
- """Let a logged-in administrator, or a relayed device, write as owner without the room credential; local visitors still need it."""
1851
- if self.headers.get("X-Discussion-Token") or not (self.bridged or session_valid(connection, self.admin_token())):
1850
+ """Let a logged-in administrator, a relayed device, or a visitor of the loopback-only local site write as owner without
1851
+ the room credential: the local site already treats its visitors as the administrator. The remote entry is never local."""
1852
+ if self.headers.get("X-Discussion-Token") or not (self.bridged or self.server.local_site or session_valid(connection, self.admin_token())):
1852
1853
  return
1853
1854
  row = connection.execute("SELECT control_hash FROM room_modes WHERE room_id=?", (room_id,)).fetchone()
1854
1855
  if row and row[0]:
@@ -1,100 +1,100 @@
1
- # User Guide
2
-
3
- English | [简体中文](../workflow.md)
4
-
5
- How collaboration works inside a room. For installation, see [Setup](runner.md).
6
-
7
- > The web UI is currently in Chinese; UI labels are given in parentheses.
8
-
9
- ## Concepts
10
-
11
- | Concept | Description |
12
- | --- | --- |
13
- | Room | A shared space that keeps messages, viewpoints, disagreements and conclusions |
14
- | Member | An AI instance in the room. One platform can have several instances (e.g. `Claude`, `Claude-review`), each with its own session and model |
15
- | Host | A locally woken AI that routes unaddressed messages; it can also act as an expert |
16
- | You | The room owner, who can `@` any member at any time |
17
-
18
- ## Free Collaboration
19
-
20
- - **Mention** — `@member` and it works in its own original session; several members can run in parallel.
21
- - **Unaddressed messages** go to the host. With a single member, they go straight to it.
22
- - **Expert presets** — a second row under the platforms lists presets; one click adds a member with its description, prompt, project access (and optionally model and effort) set. `Codex-review` (read-only reviewer) and `Gemini-docs` (writes docs only, via agy) are built in; the bookmark on a card's back saves it as your own preset on the computer running the local service.
23
- - **Host delegation** — when the host mentions one member, that member replies to you directly, unless the host asks for the work back to hand it on (for example to a reviewer); when it mentions several, the host summarizes after they finish. One message of yours lets the host run up to 3 rounds by default (a round: the host dispatches, the members answer, the work comes back for a summary); change it (1–20 rounds) when creating the room, or later under 协作设置 (Collaboration settings) on the room page. At the limit it stops and waits for you; 继续 (Continue) in the side panel lets it run on.
24
- - **Everyone** — `@全体成员` asks all members to answer; `@全体依次` asks them one after another in speaking order.
25
- - **Stop and retry** — stop a member's current run from its card or menu, or stop all running and queued work from the side panel. “Stopped” requires a confirmed process exit; otherwise the card says “Stop unconfirmed” or “Voided, may still be generating.” Late replies stay out of the transcript; only the owner can expand their text. New tasks wait for termination confirmation, a late reply or the original 10-minute deadline. Resuming a discussion or resending does not bypass or restart that wait. Retry puts the original message back in the composer for you to send.
26
- - **Retract and edit** — a message no member has started can be retracted from its “…” menu, and its text returns to the input. To change a message that was already handled, click “Edit” and resend: it and everything after it fold into a “rewound” line that AI members no longer read, and the sessions of Claude Code, Codex and agy members this machine wakes go back to before it. Manual and app members keep their own windows, so their sessions cannot go back. Files members changed are not restored. Neither works while a discussion is open.
27
- - **Branch** — “Branch from here” in an AI message's “…” menu creates a new room with the history up to that message; the Claude Code, Codex and agy members this machine wakes fork their own sessions and continue from there, while the original room and sessions stay as they were. Other members start new sessions. Both rooms share the same project directory, so files are not branched. Needs the local service.
28
-
29
- Mentions between ordinary members are references only and do not wake anyone. Members sharing a project directory are not locked; you decide who edits which files, and the member panel warns when two members changed the same file at the same time.
30
-
31
- ## Discussions
32
-
33
- Click **Start discussion** (开启讨论) in the member panel, or check **Start discussion after creating** (创建后开启讨论) when creating a room:
34
-
35
- 1. Write a goal and set round and time limits. The dialog starts with the room's saved defaults, set when creating the room and editable in **Edit topic** when no discussion is active or paused. Changes in the start dialog apply only to that discussion.
36
- 2. The host breaks down the question and schedules speakers. Experts first give independent views, then respond to each other.
37
- 3. When a limit is reached, the host declares the goal done, or you click **End**, the room returns to free collaboration with history and conclusions kept. You can start another discussion later.
38
-
39
- You can `@` any member during a discussion without using a round. If that member is already handling a discussion request, the new request waits for the same session. Unaddressed messages go to the host; to stop the current speaker, click **Skip** (跳过) on the progress board. Group mentions, retracting, editing and branching are unavailable during a discussion.
40
-
41
- Discussions and free collaboration share the same execution and failure cards. A failed delivery retries up to three times; you can retry immediately or stop it. When retries run out, only that request fails and the host decides whether to skip, reschedule or pause the discussion. The room is not paused automatically. Scheduled online members can reply through the host's relay; the discussion host itself must be woken locally.
42
-
43
- ### Named Follow-ups
44
-
45
- With **Named follow-ups** (点名追问) enabled, the host writes a targeted follow-up for each expert after every round. When disabled (the default), experts respond to each other using a shared question. The host connects rounds; Smart Scheduling can handle that step when enabled.
46
-
47
- ### Limits
48
-
49
- | Limit | Description |
50
- | --- | --- |
51
- | Rounds | Counts completed expert discussion replies; host notes and direct questions do not count |
52
- | Total time | Counts only active time; paused time is excluded |
53
-
54
- The discussion ends as soon as a limit is reached and returns to free collaboration without an extra host summary request. Reaching a limit does not mean consensus was reached. Pausing stops current discussion executions; when resumed, the host schedules the next request.
55
-
56
- ## Smart Scheduling
57
-
58
- When creating a room, you can add a decision model under **Smart Scheduling** (智能调度) — TypeSafe Jev, with OpenAI Decisions as an experimental option — using your own key, billed per call. Routine routing is then decided by the decision model instead of waking the host every time:
59
-
60
- - Unaddressed messages go to the member they are clearly meant for, to everyone at once, to everyone one after another in speaking order (a relay or a count-off), or to no one; otherwise to the host.
61
- - Without Smart Scheduling, `@全体成员` runs everyone together. With it, uncertain or failed decisions go to the host. `@全体依次` always uses the established speaking order.
62
- - In discussions, a local follow-up becomes an ordinary question without consuming a turn or changing the queue, including questions for members who already spoke or the host. It also picks the next speaker between rounds. Without Smart Scheduling, the host can make the same handoff.
63
- - When the host has preauthorized a specific read-only reviewer, a completed implementation batch can move to that reviewer. The model checks delivery completeness, not code correctness, and cannot choose another reviewer. Review results still return to the host.
64
-
65
- It acts only when confident, and otherwise hands over to the host. Every decision is shown in the conversation and can be rated. The room title and recent messages are sent to the chosen provider. Preauthorized review judgments also send the full assignment, delivery text and execution reports; inputs above the supported limit go to the host.
66
-
67
- ## Managing Members
68
-
69
- From the member panel you can:
70
-
71
- - **Invite** members. Codex and Claude can join with an existing session ID, bringing that session's context. Experts invited during a discussion join the end of the current round.
72
- - **Pause, recall or remove** members without pausing the discussion.
73
- - **Change the host** with the crown icon. Changing the host during a discussion pauses it.
74
- - **Reorder speakers** by dragging pending members in the speaking-order list.
75
-
76
- Project file access is set per member and is read-only by default.
77
-
78
- ## Manual Members
79
-
80
- - **Manual** — a local member is not woken automatically; it reads and writes with its own credential after you or the host triggers it, and must run `codiscuss member register` before it can be scheduled.
81
-
82
- The host of a discussion must be woken locally. Manual members can answer requests scheduled for them.
83
-
84
- ## Skills
85
-
86
- Agents follow the bundled skills, which `codiscuss setup` installs for the tools you select:
87
-
88
- | Skill | Used by | Purpose |
89
- | --- | --- | --- |
90
- | [discuss-participant](../../.agents/skills/discuss-participant/SKILL.md) | All members | Reading, posting and reliable writes |
91
- | [discuss-host](../../.agents/skills/discuss-host/SKILL.md) | The host (together with the participant skill) | Scheduling, progress and wrap-up |
92
- | [discuss-report](../../.agents/skills/discuss-report/SKILL.md) | Report writers | Turning a finished discussion into a sourced report |
93
-
94
- In Codex, invoke them as `$discuss-host`. In other tools that do not discover them automatically, ask the agent to read the corresponding `SKILL.md`.
95
-
96
- ## Attachments and Export
97
-
98
- - **Attachments** — up to 10 per message and 20 MiB each; images and PDFs preview in place. Uploading does not mean an agent has read the file.
99
- - **Export and import** — **Export conversation** (导出对话) downloads the raw data and attachments; **Import room** (导入房间) on another site creates a copy you can keep using. Exported from a computer running the local service, the backup also carries each member's software settings and session; imported on that same computer, members resume their original sessions when brought back. Claude Code members come back as manual members and register again from their original window, so the session does not fork.
100
- - **Discussion history** — backups include past sessions, conclusions and speaker plans; early version 1 backups can no longer be imported. Import restores them as history; it does not resume active work or wake members. Markdown exports retain the links between plans and answers.
1
+ # User Guide
2
+
3
+ English | [简体中文](../workflow.md)
4
+
5
+ How collaboration works inside a room. For installation, see [Setup](runner.md).
6
+
7
+ > The web UI is currently in Chinese; UI labels are given in parentheses.
8
+
9
+ ## Concepts
10
+
11
+ | Concept | Description |
12
+ | --- | --- |
13
+ | Room | A shared space that keeps messages, viewpoints, disagreements and conclusions |
14
+ | Member | An AI instance in the room. One platform can have several instances (e.g. `Claude`, `Claude-review`), each with its own session and model |
15
+ | Host | A locally woken AI that routes unaddressed messages; it can also act as an expert |
16
+ | You | The room owner, who can `@` any member at any time |
17
+
18
+ ## Free Collaboration
19
+
20
+ - **Mention** — `@member` and it works in its own original session; several members can run in parallel.
21
+ - **Unaddressed messages** go to the host. With a single member, they go straight to it.
22
+ - **Expert presets** — a second row under the platforms lists presets; one click adds a member with its description, prompt, project access (and optionally model and effort) set. `Codex-review` (read-only reviewer) and `Gemini-docs` (writes docs only, via agy) are built in; the bookmark on a card's back saves it as your own preset on the computer running the local service.
23
+ - **Host delegation** — when the host mentions one member, that member replies to you directly, unless the host asks for the work back to hand it on (for example to a reviewer); when it mentions several, the host summarizes after they finish. One message of yours lets the host run up to 3 rounds by default (a round: the host dispatches, the members answer, the work comes back for a summary); change it (1–20 rounds) when creating the room, or later under 协作设置 (Collaboration settings) on the room page. At the limit it stops and waits for you; 继续 (Continue) in the side panel lets it run on.
24
+ - **Everyone** — `@全体成员` asks all members to answer; `@全体依次` asks them one after another in speaking order.
25
+ - **Stop and retry** — stop a member's current run from its card or menu, or stop all running and queued work from the side panel. “Stopped” requires a confirmed process exit; otherwise the card says “Stop unconfirmed” or “Voided, may still be generating.” Late replies stay out of the transcript; only the owner can expand their text. New tasks wait for termination confirmation, a late reply or the original 10-minute deadline. Resuming a discussion or resending does not bypass or restart that wait. Retry puts the original message back in the composer for you to send.
26
+ - **Retract and edit** — a message no member has started can be retracted from its “…” menu, and its text returns to the input. To change a message that was already handled, click “Edit” and resend: it and everything after it fold into a “rewound” line that AI members no longer read, and the sessions of Claude Code, Codex and agy members this machine wakes go back to before it. Manual and app members keep their own windows, so their sessions cannot go back. Files members changed are not restored. Neither works while a discussion is open.
27
+ - **Branch** — “Branch from here” in an AI message's “…” menu creates a new room with the history up to that message; the Claude Code, Codex and agy members this machine wakes fork their own sessions and continue from there, while the original room and sessions stay as they were. Other members start new sessions. Both rooms share the same project directory, so files are not branched. Needs the local service.
28
+
29
+ Mentions between ordinary members are references only and do not wake anyone. Members sharing a project directory are not locked; you decide who edits which files, and the member panel warns when two members changed the same file at the same time.
30
+
31
+ ## Discussions
32
+
33
+ Click **Start discussion** (开启讨论) in the member panel, or check **Start discussion after creating** (创建后开启讨论) when creating a room:
34
+
35
+ 1. Write a goal and set round and time limits. The dialog starts with the room's saved defaults, set when creating the room and editable in **Edit topic** when no discussion is active or paused. Changes in the start dialog apply only to that discussion.
36
+ 2. The host breaks down the question and schedules speakers. Experts first give independent views, then respond to each other.
37
+ 3. When a limit is reached, the host declares the goal done, or you click **End**, the room returns to free collaboration with history and conclusions kept. You can start another discussion later.
38
+
39
+ You can `@` any member during a discussion without using a round. If that member is already handling a discussion request, the new request waits for the same session. Unaddressed messages go to the host; to stop the current speaker, click the stop button on their working card or **Skip** (跳过) on the progress board; the discussion moves on to the next speaker. Group mentions, retracting, editing and branching are unavailable during a discussion.
40
+
41
+ Discussions and free collaboration share the same execution and failure cards. A failed delivery retries up to three times; you can retry immediately or stop it. When retries run out, only that request fails and the host decides whether to skip, reschedule or pause the discussion. The room is not paused automatically. Scheduled online members can reply through the host's relay; the discussion host itself must be woken locally.
42
+
43
+ ### Named Follow-ups
44
+
45
+ With **Named follow-ups** (点名追问) enabled, the host writes a targeted follow-up for each expert after every round. When disabled (the default), experts respond to each other using a shared question. The host connects rounds; Smart Scheduling can handle that step when enabled.
46
+
47
+ ### Limits
48
+
49
+ | Limit | Description |
50
+ | --- | --- |
51
+ | Rounds | Counts completed expert discussion replies; host notes and direct questions do not count |
52
+ | Total time | Counts only active time; paused time is excluded |
53
+
54
+ The discussion ends as soon as a limit is reached and returns to free collaboration without an extra host summary request. Reaching a limit does not mean consensus was reached. Pausing stops current discussion executions; when resumed, the host schedules the next request.
55
+
56
+ ## Smart Scheduling
57
+
58
+ When creating a room, you can add a decision model under **Smart Scheduling** (智能调度) — TypeSafe Jev, with OpenAI Decisions as an experimental option — using your own key, billed per call. Routine routing is then decided by the decision model instead of waking the host every time:
59
+
60
+ - Unaddressed messages go to the member they are clearly meant for, to everyone at once, to everyone one after another in speaking order (a relay or a count-off), or to no one; otherwise to the host.
61
+ - Without Smart Scheduling, `@全体成员` runs everyone together. With it, uncertain or failed decisions go to the host. `@全体依次` always uses the established speaking order.
62
+ - In discussions, a local follow-up becomes an ordinary question without consuming a turn or changing the queue, including questions for members who already spoke or the host. It also picks the next speaker between rounds. Without Smart Scheduling, the host can make the same handoff.
63
+ - When the host has preauthorized a specific read-only reviewer, a completed implementation batch can move to that reviewer. The model checks delivery completeness, not code correctness, and cannot choose another reviewer. Review results still return to the host.
64
+
65
+ It acts only when confident, and otherwise hands over to the host. Every decision is shown in the conversation and can be rated. The room title and recent messages are sent to the chosen provider. Preauthorized review judgments also send the full assignment, delivery text and execution reports; inputs above the supported limit go to the host.
66
+
67
+ ## Managing Members
68
+
69
+ From the member panel you can:
70
+
71
+ - **Invite** members. Codex and Claude can join with an existing session ID, bringing that session's context. Experts invited during a discussion join the end of the current round.
72
+ - **Pause, recall or remove** members without pausing the discussion.
73
+ - **Change the host** with the crown icon. Changing the host during a discussion pauses it.
74
+ - **Reorder speakers** by dragging pending members in the speaking-order list.
75
+
76
+ Project file access is set per member and is read-only by default.
77
+
78
+ ## Manual Members
79
+
80
+ - **Manual** — a local member is not woken automatically; it reads and writes with its own credential after you or the host triggers it, and must run `codiscuss member register` before it can be scheduled.
81
+
82
+ The host of a discussion must be woken locally. Manual members can answer requests scheduled for them.
83
+
84
+ ## Skills
85
+
86
+ Agents follow the bundled skills, which `codiscuss setup` installs for the tools you select:
87
+
88
+ | Skill | Used by | Purpose |
89
+ | --- | --- | --- |
90
+ | [discuss-participant](../../.agents/skills/discuss-participant/SKILL.md) | All members | Reading, posting and reliable writes |
91
+ | [discuss-host](../../.agents/skills/discuss-host/SKILL.md) | The host (together with the participant skill) | Scheduling, progress and wrap-up |
92
+ | [discuss-report](../../.agents/skills/discuss-report/SKILL.md) | Report writers | Turning a finished discussion into a sourced report |
93
+
94
+ In Codex, invoke them as `$discuss-host`. In other tools that do not discover them automatically, ask the agent to read the corresponding `SKILL.md`.
95
+
96
+ ## Attachments and Export
97
+
98
+ - **Attachments** — up to 10 per message and 20 MiB each; images and PDFs preview in place. Uploading does not mean an agent has read the file.
99
+ - **Export and import** — **Export conversation** (导出对话) downloads the raw data and attachments; **Import room** (导入房间) on another site creates a copy you can keep using. Exported from a computer running the local service, the backup also carries each member's software settings and session; imported on that same computer, members resume their original sessions when brought back. Claude Code members come back as manual members and register again from their original window, so the session does not fork.
100
+ - **Discussion history** — backups include past sessions, conclusions and speaker plans; early version 1 backups can no longer be imported. Import restores them as history; it does not resume active work or wake members. Markdown exports retain the links between plans and answers.
package/docs/workflow.md CHANGED
@@ -1,100 +1,100 @@
1
- # 使用指南
2
-
3
- [English](en/workflow.md) | 简体中文
4
-
5
- 本文介绍房间里的协作方式。安装与接入见 [安装与接入](runner.md)。
6
-
7
- ## 核心概念
8
-
9
- | 概念 | 说明 |
10
- | --- | --- |
11
- | 房间 | 共享的协作空间,保存消息、观点、分歧与结论 |
12
- | 成员 | 房间里的 AI 实例;同一平台可有多个实例(如 `Claude`、`Claude-review`),各有会话与模型 |
13
- | 主持人 | 一位由本机唤醒的 AI,接收未点名的消息并分派,可兼任专家 |
14
- | 用户 | 房间所有者与需求方,可随时 `@` 任何成员 |
15
-
16
- ## 自由协作房间
17
-
18
- - **点名**:`@成员` 后,它在自己的原会话中处理并回复,多位可并行。
19
- - **未点名的消息**:交给主持人分派;只有一位成员时直接交给它。
20
- - **主持人派活**:主持人点名一位成员时,该成员直接回复你;主持人需要接着安排(如做完再交评审)时会要求它做完交回,点名多位时都完成后主持人再汇总。你的一条消息最多让主持人推进 3 轮(主持人派活、成员回答、交回汇总为一轮),建房时在“推进方式”里或建房后在房间页的“协作设置”里调整(1–20 轮);到上限会停下等你,右栏点“继续”即接着推进。
21
- - **全体回答**:`@全体成员` 请所有成员各自回答,`@全体依次` 按发言顺序逐个回答。
22
- - **停止与重发**:处理中卡片或成员菜单可停止该成员当前这一次;右栏“全部停止”停止所有成员并取消还没送达的请求。本机确认进程退出后才显示“已停止”,无法确认时显示“停止未确认”;自己窗口或 App 里的会话停不了时显示“已作废,可能仍在生成”。后续回答不进入记录,只有房主展开“未采纳的回答”时能读取正文。停止未确认或停不了时,新消息等待结束确认、迟到回答或原有 10 分钟期限;继续讨论、主动重发不跳过等待,也不重新计时。被停止的成员下次工作时会被告知。失败卡的“重发”把原用户消息填回输入框,确认后再发送。
23
- - **撤回与编辑**:还没有成员开始处理的消息可撤回,原文回到输入框;最新一条消息即使已开始处理也可撤回,相当于停止对它的处理并回退到它之前。输入框为空时连按两下 Esc 也可撤回最近一条。已被处理的消息点“编辑”改写后重发:这条消息及之后的记录折叠为“已回退”,AI 不再读到它们,由本机唤醒的 Claude Code、Codex、agy 会话会退回到这条消息之前;手动接入和 App 的会话在各自窗口中,无法回退。成员已改动的文件不会撤销。讨论进行中不能撤回或编辑。
24
- - **分支**:AI 发言的“…”菜单“从这里分支”会新建一个房间,保留到这条发言为止的记录,由本机唤醒的 Claude Code、Codex、agy 从各自会话分叉、从这里接着工作,原房间和原会话不变;其他成员以新会话开始。两个房间共用同一项目目录,文件不分叉。需要连接本机服务。
25
-
26
- 普通成员之间的 `@` 只是引用,不会唤醒对方。多位成员共享同一项目目录时不加锁,由你划分文件;两位成员同时改动同一文件时,成员栏会提示可能的冲突。
27
-
28
- ## 开启讨论
29
-
30
- 在成员栏点“开启讨论”,或建房时勾选“创建后开启讨论”:
31
-
32
- 1. 填写讨论目标,设置轮次与时长上限。开启弹窗预填房间保存的默认上限;建房时设置,无进行中或暂停的讨论时可在“编辑议题”修改。只在开启弹窗里调整的值仅用于本场讨论。
33
- 2. 主持人拆题并安排成员轮流发言;成员先独立提出观点,再回应彼此的论证。
34
- 3. 到达上限、主持人宣布目标完成或你点“结束”后,房间回到自由协作,记录与结论保留,之后可以再次开启。
35
-
36
- 讨论中可以随时 `@` 任何成员提问,不占轮次;同一成员正在处理讨论发言时,提问排队等待。未点名的留言交给主持人处理;需要停止当前发言时,在进度看板点“跳过”。讨论中的群体 @、撤回、编辑与分支暂不可用。
37
-
38
- 讨论与普通协作共用处理中卡和失败卡。送达失败会倒计时重试,最多 3 次,也可立即重试或停止;用尽后只结束该次请求,由主持人决定跳过、重排或暂停,不自动暂停整场。系统安排仍显示为安排卡,不冒充用户或 AI 发言。
39
-
40
- ### 点名追问与智能衔接
41
-
42
- 新建讨论时可开启“点名追问”:每轮结束后,主持人给每位专家写针对性的追问。关闭时(默认),专家按统一问题互相回应,轮间由主持人衔接;开启智能调度后可由程序代办。
43
-
44
- ### 讨论上限
45
-
46
- | 参数 | 说明 |
47
- | --- | --- |
48
- | 轮次上限 | 按讨论专家的已完成回答统计;主持说明与直接提问不计 |
49
- | 总时长 | 只统计进行中的时间,暂停期间不计 |
50
-
51
- 到限后立即结束讨论,回到自由协作,不额外唤醒主持人总结;到限不代表已经达成共识。暂停会停止本次讨论中的执行,继续后由主持人重新安排。
52
-
53
- ## 智能调度
54
-
55
- 建房时可在“智能调度”下添加一个决策模型(TypeSafe Jev;OpenAI Decisions 为实验性),用你自己的密钥按次计费。开启后,常规分派由决策模型判断,不必每次唤醒主持人:
56
-
57
- - 未点名的消息:明确对某位成员说时直接交给他,或请全体同时回答、按发言顺序依次回答(如接龙、报数)、无需回应;其余仍交给主持人。
58
- - `@全体成员`:未配置时同时回答;配置后判断同时或依次,拿不准或调用失败时交主持人。`@全体依次` 始终按既定顺序回答。
59
- - 讨论中:局部追问转为不计轮次的普通提问,可追问已发言者或主持人,保留原讨论队列;轮次之间选出下一位发言人。没有智能调度时,主持人也可按同一方式转交。
60
- - 主持人预先指定了实现后的只读评审时:整批交付完成后可交给既定评审者。它只判断交付完成度,不判断代码对错、不另选评审者;评审后仍交回主持人。
61
-
62
- 决策模型只在把握足够时执行,否则交回主持人。每次判断都会显示在对话中,可以评价。开启后,房间标题与最近消息会发送给所选供应商;预授权评审判断还会发送该批完整委派、交付原文和执行报告,超出支持的输入上限则交主持人。
63
-
64
- 给成员写一段描述能让分派更准,例如“Claude:审美好,UI 写得好”“Codex:代码写得好,能生成图片”。建房或邀请时点成员卡片右上角的描述按钮填写,可存为该软件的默认描述(连接本机服务时存在这台电脑上,所有浏览器共用);房间里可在右栏成员菜单“编辑描述”随时修改。决策模型和 AI 主持人都会参考它,房间里所有成员也都能看到。
65
-
66
- ## 成员管理
67
-
68
- 在右侧成员栏可以:
69
-
70
- - **邀请**成员。程序启动的成员由本机新建会话;想让一个已有对话带着上下文加入,选“手动启动”,在那个对话里执行启动指令注册,之后房间的任务会尽量送进那个窗口。讨论中新邀请的专家排在本轮队尾。
71
- - **专家预设**:建房与邀请时,“添加”行下方另起一行“预设”,点一下就加入一位已设好描述、专属提示词、项目权限(以及可选的模型与强度)的成员。内置 `Codex-review`(只读,只提问题不改代码)与 `Gemini-docs`(经 agy,可写,只改文档);翻开任意卡片点背面的书签图标可把它存为你自己的预设,同名时替换内置预设。预设存在本机服务所在的电脑上,需要连接本机服务。
72
- - **暂离、请回或移除**成员,讨论不会因此暂停。
73
- - **更换主持人**:点成员卡片上的皇冠。讨论中更换会暂停讨论。
74
- - **调整发言顺序**:拖动右栏“发言顺序”中待发言的成员。
75
-
76
- 项目文件权限按成员设置,默认只读。
77
-
78
- ## 手动接入
79
-
80
- - **手动接入**:本地成员须先在自己的会话中执行 `codiscuss member register`。支持接管的软件随后由本机服务尽量向原会话投递;其余成员由你触发,凭自己的凭据文件读取请求并回答。
81
-
82
- 讨论的主持人必须由本机唤醒;手动成员按安排回答,等待期间不会伪造“正在处理”状态。
83
-
84
- ## 技能
85
-
86
- AI 按随包分发的技能参与房间,`codiscuss setup` 会为选定的软件自动安装:
87
-
88
- | 技能 | 使用者 | 作用 |
89
- | --- | --- | --- |
90
- | [discuss-participant](../.agents/skills/discuss-participant/SKILL.md) | 所有成员 | 阅读、发言与可靠写入 |
91
- | [discuss-host](../.agents/skills/discuss-host/SKILL.md) | 主持人(同时调用参与技能) | 自由协作中分派与接续成员的工作;讨论中安排发言、保存进度与收束 |
92
- | [discuss-report](../.agents/skills/discuss-report/SKILL.md) | 报告整理者 | 把已有讨论整理为带原文引用的报告 |
93
-
94
- 在 Codex 中用 `$discuss-host` 调用;其他软件没有自动发现时,直接要求它读取对应的 `SKILL.md`。
95
-
96
- ## 附件与导出
97
-
98
- - **附件**:每条消息最多 10 个,单个最多 20 MiB,图片与 PDF 可在站内预览。上传不代表 AI 已读取。
99
- - **导出与导入**:房间菜单的“导出对话”下载原始数据与附件;在另一个站点“导入房间…”即可得到可继续使用的副本。在运行本机服务的电脑上导出时,备份会附带成员的软件配置和会话;在同一台电脑导入后,成员请回时续接原会话。Claude Code 成员会改为手动接入,请回后在原窗口重新注册,以免会话分叉。
100
- - **讨论历史**:备份包含历次讨论、结论和安排;早期第 1 版备份不再支持导入。导入或分支恢复为历史,不继续原讨论,也不重新唤醒成员;Markdown 导出保留安排与回答关联。
1
+ # 使用指南
2
+
3
+ [English](en/workflow.md) | 简体中文
4
+
5
+ 本文介绍房间里的协作方式。安装与接入见 [安装与接入](runner.md)。
6
+
7
+ ## 核心概念
8
+
9
+ | 概念 | 说明 |
10
+ | --- | --- |
11
+ | 房间 | 共享的协作空间,保存消息、观点、分歧与结论 |
12
+ | 成员 | 房间里的 AI 实例;同一平台可有多个实例(如 `Claude`、`Claude-review`),各有会话与模型 |
13
+ | 主持人 | 一位由本机唤醒的 AI,接收未点名的消息并分派,可兼任专家 |
14
+ | 用户 | 房间所有者与需求方,可随时 `@` 任何成员 |
15
+
16
+ ## 自由协作房间
17
+
18
+ - **点名**:`@成员` 后,它在自己的原会话中处理并回复,多位可并行。
19
+ - **未点名的消息**:交给主持人分派;只有一位成员时直接交给它。
20
+ - **主持人派活**:主持人点名一位成员时,该成员直接回复你;主持人需要接着安排(如做完再交评审)时会要求它做完交回,点名多位时都完成后主持人再汇总。你的一条消息最多让主持人推进 3 轮(主持人派活、成员回答、交回汇总为一轮),建房时在“推进方式”里或建房后在房间页的“协作设置”里调整(1–20 轮);到上限会停下等你,右栏点“继续”即接着推进。
21
+ - **全体回答**:`@全体成员` 请所有成员各自回答,`@全体依次` 按发言顺序逐个回答。
22
+ - **停止与重发**:处理中卡片或成员菜单可停止该成员当前这一次;右栏“全部停止”停止所有成员并取消还没送达的请求。本机确认进程退出后才显示“已停止”,无法确认时显示“停止未确认”;自己窗口或 App 里的会话停不了时显示“已作废,可能仍在生成”。后续回答不进入记录,只有房主展开“未采纳的回答”时能读取正文。停止未确认或停不了时,新消息等待结束确认、迟到回答或原有 10 分钟期限;继续讨论、主动重发不跳过等待,也不重新计时。被停止的成员下次工作时会被告知。失败卡的“重发”把原用户消息填回输入框,确认后再发送。
23
+ - **撤回与编辑**:还没有成员开始处理的消息可撤回,原文回到输入框;最新一条消息即使已开始处理也可撤回,相当于停止对它的处理并回退到它之前。输入框为空时连按两下 Esc 也可撤回最近一条。已被处理的消息点“编辑”改写后重发:这条消息及之后的记录折叠为“已回退”,AI 不再读到它们,由本机唤醒的 Claude Code、Codex、agy 会话会退回到这条消息之前;手动接入和 App 的会话在各自窗口中,无法回退。成员已改动的文件不会撤销。讨论进行中不能撤回或编辑。
24
+ - **分支**:AI 发言的“…”菜单“从这里分支”会新建一个房间,保留到这条发言为止的记录,由本机唤醒的 Claude Code、Codex、agy 从各自会话分叉、从这里接着工作,原房间和原会话不变;其他成员以新会话开始。两个房间共用同一项目目录,文件不分叉。需要连接本机服务。
25
+
26
+ 普通成员之间的 `@` 只是引用,不会唤醒对方。多位成员共享同一项目目录时不加锁,由你划分文件;两位成员同时改动同一文件时,成员栏会提示可能的冲突。
27
+
28
+ ## 开启讨论
29
+
30
+ 在成员栏点“开启讨论”,或建房时勾选“创建后开启讨论”:
31
+
32
+ 1. 填写讨论目标,设置轮次与时长上限。开启弹窗预填房间保存的默认上限;建房时设置,无进行中或暂停的讨论时可在“编辑议题”修改。只在开启弹窗里调整的值仅用于本场讨论。
33
+ 2. 主持人拆题并安排成员轮流发言;成员先独立提出观点,再回应彼此的论证。
34
+ 3. 到达上限、主持人宣布目标完成或你点“结束”后,房间回到自由协作,记录与结论保留,之后可以再次开启。
35
+
36
+ 讨论中可以随时 `@` 任何成员提问,不占轮次;同一成员正在处理讨论发言时,提问排队等待。未点名的留言交给主持人处理;需要停止当前发言时,点处理中卡片上的停止键或进度看板的“跳过”,讨论接着轮到下一位。讨论中的群体 @、撤回、编辑与分支暂不可用。
37
+
38
+ 讨论与普通协作共用处理中卡和失败卡。送达失败会倒计时重试,最多 3 次,也可立即重试或停止;用尽后只结束该次请求,由主持人决定跳过、重排或暂停,不自动暂停整场。系统安排仍显示为安排卡,不冒充用户或 AI 发言。
39
+
40
+ ### 点名追问与智能衔接
41
+
42
+ 新建讨论时可开启“点名追问”:每轮结束后,主持人给每位专家写针对性的追问。关闭时(默认),专家按统一问题互相回应,轮间由主持人衔接;开启智能调度后可由程序代办。
43
+
44
+ ### 讨论上限
45
+
46
+ | 参数 | 说明 |
47
+ | --- | --- |
48
+ | 轮次上限 | 按讨论专家的已完成回答统计;主持说明与直接提问不计 |
49
+ | 总时长 | 只统计进行中的时间,暂停期间不计 |
50
+
51
+ 到限后立即结束讨论,回到自由协作,不额外唤醒主持人总结;到限不代表已经达成共识。暂停会停止本次讨论中的执行,继续后由主持人重新安排。
52
+
53
+ ## 智能调度
54
+
55
+ 建房时可在“智能调度”下添加一个决策模型(TypeSafe Jev;OpenAI Decisions 为实验性),用你自己的密钥按次计费。开启后,常规分派由决策模型判断,不必每次唤醒主持人:
56
+
57
+ - 未点名的消息:明确对某位成员说时直接交给他,或请全体同时回答、按发言顺序依次回答(如接龙、报数)、无需回应;其余仍交给主持人。
58
+ - `@全体成员`:未配置时同时回答;配置后判断同时或依次,拿不准或调用失败时交主持人。`@全体依次` 始终按既定顺序回答。
59
+ - 讨论中:局部追问转为不计轮次的普通提问,可追问已发言者或主持人,保留原讨论队列;轮次之间选出下一位发言人。没有智能调度时,主持人也可按同一方式转交。
60
+ - 主持人预先指定了实现后的只读评审时:整批交付完成后可交给既定评审者。它只判断交付完成度,不判断代码对错、不另选评审者;评审后仍交回主持人。
61
+
62
+ 决策模型只在把握足够时执行,否则交回主持人。每次判断都会显示在对话中,可以评价。开启后,房间标题与最近消息会发送给所选供应商;预授权评审判断还会发送该批完整委派、交付原文和执行报告,超出支持的输入上限则交主持人。
63
+
64
+ 给成员写一段描述能让分派更准,例如“Claude:审美好,UI 写得好”“Codex:代码写得好,能生成图片”。建房或邀请时点成员卡片右上角的描述按钮填写,可存为该软件的默认描述(连接本机服务时存在这台电脑上,所有浏览器共用);房间里可在右栏成员菜单“编辑描述”随时修改。决策模型和 AI 主持人都会参考它,房间里所有成员也都能看到。
65
+
66
+ ## 成员管理
67
+
68
+ 在右侧成员栏可以:
69
+
70
+ - **邀请**成员。程序启动的成员由本机新建会话;想让一个已有对话带着上下文加入,选“手动启动”,在那个对话里执行启动指令注册,之后房间的任务会尽量送进那个窗口。讨论中新邀请的专家排在本轮队尾。
71
+ - **专家预设**:建房与邀请时,“添加”行下方另起一行“预设”,点一下就加入一位已设好描述、专属提示词、项目权限(以及可选的模型与强度)的成员。内置 `Codex-review`(只读,只提问题不改代码)与 `Gemini-docs`(经 agy,可写,只改文档);翻开任意卡片点背面的书签图标可把它存为你自己的预设,同名时替换内置预设。预设存在本机服务所在的电脑上,需要连接本机服务。
72
+ - **暂离、请回或移除**成员,讨论不会因此暂停。
73
+ - **更换主持人**:点成员卡片上的皇冠。讨论中更换会暂停讨论。
74
+ - **调整发言顺序**:拖动右栏“发言顺序”中待发言的成员。
75
+
76
+ 项目文件权限按成员设置,默认只读。
77
+
78
+ ## 手动接入
79
+
80
+ - **手动接入**:本地成员须先在自己的会话中执行 `codiscuss member register`。支持接管的软件随后由本机服务尽量向原会话投递;其余成员由你触发,凭自己的凭据文件读取请求并回答。
81
+
82
+ 讨论的主持人必须由本机唤醒;手动成员按安排回答,等待期间不会伪造“正在处理”状态。
83
+
84
+ ## 技能
85
+
86
+ AI 按随包分发的技能参与房间,`codiscuss setup` 会为选定的软件自动安装:
87
+
88
+ | 技能 | 使用者 | 作用 |
89
+ | --- | --- | --- |
90
+ | [discuss-participant](../.agents/skills/discuss-participant/SKILL.md) | 所有成员 | 阅读、发言与可靠写入 |
91
+ | [discuss-host](../.agents/skills/discuss-host/SKILL.md) | 主持人(同时调用参与技能) | 自由协作中分派与接续成员的工作;讨论中安排发言、保存进度与收束 |
92
+ | [discuss-report](../.agents/skills/discuss-report/SKILL.md) | 报告整理者 | 把已有讨论整理为带原文引用的报告 |
93
+
94
+ 在 Codex 中用 `$discuss-host` 调用;其他软件没有自动发现时,直接要求它读取对应的 `SKILL.md`。
95
+
96
+ ## 附件与导出
97
+
98
+ - **附件**:每条消息最多 10 个,单个最多 20 MiB,图片与 PDF 可在站内预览。上传不代表 AI 已读取。
99
+ - **导出与导入**:房间菜单的“导出对话”下载原始数据与附件;在另一个站点“导入房间…”即可得到可继续使用的副本。在运行本机服务的电脑上导出时,备份会附带成员的软件配置和会话;在同一台电脑导入后,成员请回时续接原会话。Claude Code 成员会改为手动接入,请回后在原窗口重新注册,以免会话分叉。
100
+ - **讨论历史**:备份包含历次讨论、结论和安排;早期第 1 版备份不再支持导入。导入或分支恢复为历史,不继续原讨论,也不重新唤醒成员;Markdown 导出保留安排与回答关联。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai_co_discuss",
3
- "version": "0.3.28",
3
+ "version": "0.3.30",
4
4
  "bin": {
5
5
  "codiscuss": "runner/codiscuss.mjs"
6
6
  },
@@ -22,6 +22,10 @@ const PING_MS = 25000;
22
22
  // The site gives up on a request after 9 seconds, so the local website must answer before then.
23
23
  const LOCAL_TIMEOUT_MS = 8000;
24
24
  const EVENT_RETRY_MS = 3000;
25
+ // Diagnostics: a request answered slower than this, or not delivered, is written to the service log (action and route only).
26
+ const SLOW_REQUEST_MS = 3000;
27
+ // A connection whose keep-alive has gone unanswered this long is reported once; the website would have dropped it.
28
+ const HEARTBEAT_LATE_MS = 2 * PING_MS + 5000;
25
29
  // A WebSocket frame on the website is at most 1 MiB; leave room for the envelope around the ciphertext.
26
30
  const RESPONSE_MAX_BYTES = 700 * 1024;
27
31
  const ROOM_API_PATH = /^\/api\/(rooms|folders|revisions)(\/[A-Za-z0-9_.~-]+)*(\?[A-Za-z0-9_.~%=&,:+-]*)?$/;
@@ -152,7 +156,7 @@ export function computer_command(home, site, action, payload) {
152
156
  }
153
157
 
154
158
  /** Answer one relayed request: room routes and uploads go to the local website, everything else to the local entrypoint as before. */
155
- export async function answer_request(home, site, link, frame, { run = run_launch_command, fetcher } = {}) {
159
+ export async function answer_request(home, site, link, frame, { run = run_launch_command, fetcher, report } = {}) {
156
160
  const { id, envelope } = frame;
157
161
  const key = await relay_cipher(link.private_key, envelope.key);
158
162
  const request = await unseal(key, envelope, id);
@@ -164,6 +168,8 @@ export async function answer_request(home, site, link, frame, { run = run_launch
164
168
  : action === 'room-upload' ? await room_upload(home, site, payload, { fetcher })
165
169
  : await run(target === 'computer' ? computer_command(home, site, action, payload) : relayed_command(site, action, payload));
166
170
  } catch (error) { response = { status: 400, body: { error: error.message } }; }
171
+ // Only what kind of request it was and how it ended: never its content or query.
172
+ report?.({ action: request.action, route: typeof request.payload?.path === 'string' ? request.payload.path.split('?')[0] : '', status: response.status });
167
173
  return { type: 'response', id, envelope: await seal_compressed(key, response, `${id}:response`) };
168
174
  }
169
175
 
@@ -205,25 +211,44 @@ async function hold_channel(home, site, { connected, log, signal }) {
205
211
  const events = new AbortController();
206
212
  let ping;
207
213
  const finish = opened => { clearInterval(ping); events.abort(); connected.delete(site); resolve(opened); };
208
- let opened = false;
214
+ let opened = false, heard = Date.now(), late = false;
209
215
  socket.addEventListener('open', () => {
210
216
  opened = true;
217
+ heard = Date.now();
211
218
  connected.add(site);
212
219
  log(`${site}: 中转已连接`);
213
- ping = setInterval(() => socket.readyState === WebSocket.OPEN && socket.send('ping'), PING_MS);
220
+ ping = setInterval(() => {
221
+ if (socket.readyState !== WebSocket.OPEN) return;
222
+ const silent = Date.now() - heard;
223
+ if (silent > HEARTBEAT_LATE_MS && !late) { late = true; log(`${site}: 中转心跳超时,${Math.round(silent / 1000)} 秒未收到网站回应`); }
224
+ socket.send('ping');
225
+ }, PING_MS);
214
226
  forward_changes(home, socket, events.signal);
215
227
  });
216
228
  socket.addEventListener('message', async event => {
229
+ if (late) log(`${site}: 中转心跳恢复`);
230
+ heard = Date.now();
231
+ late = false;
217
232
  if (typeof event.data !== 'string' || event.data === 'pong') return;
218
233
  let frame;
219
234
  try { frame = JSON.parse(event.data); } catch { return; }
220
235
  if (frame.type !== 'request' || typeof frame.id !== 'string' || !frame.envelope) return;
236
+ const received = Date.now();
237
+ let kind = { action: '?', route: '', status: 0 };
221
238
  try {
222
- const answer = await answer_request(home, site, link, frame);
223
- if (socket.readyState === WebSocket.OPEN) socket.send(JSON.stringify(answer));
224
- } catch (error) { log(`${site}: 中转请求 ${frame.id} 无法处理:${error.message}`); }
239
+ const answer = await answer_request(home, site, link, frame, { report: value => { kind = value; } });
240
+ const answered = Date.now();
241
+ const open = socket.readyState === WebSocket.OPEN;
242
+ if (open) socket.send(JSON.stringify(answer));
243
+ const label = `${kind.action}${kind.route ? ` ${kind.route}` : ''} → ${kind.status}`;
244
+ if (!open) log(`${site}: 中转回应未送出(连接已断开):${label},处理 ${answered - received} ms`);
245
+ else if (answered - received > SLOW_REQUEST_MS) log(`${site}: 中转请求较慢:${label},处理 ${answered - received} ms`);
246
+ } catch (error) { log(`${site}: 中转请求 ${frame.id} 无法处理(${Date.now() - received} ms):${error.message}`); }
247
+ });
248
+ socket.addEventListener('close', event => {
249
+ if (opened && !signal.aborted) log(`${site}: 中转连接断开(${event.code || '无代码'}${event.reason ? ` ${event.reason}` : ''}),稍后重连`);
250
+ finish(opened);
225
251
  });
226
- socket.addEventListener('close', () => finish(opened));
227
252
  socket.addEventListener('error', () => { try { socket.close(); } catch { /* Already closing. */ } });
228
253
  signal.addEventListener('abort', () => { try { socket.close(1000, 'stopping'); } catch { /* Already closed. */ } }, { once: true });
229
254
  });