ai_co_discuss 0.3.45 → 0.3.47

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.
@@ -1,34 +1,34 @@
1
- # 自由协作主持
2
-
3
- 仅用于自由协作房间的主持人(任务 `role` 为 `host`)。成员的回答与提交方式见参与技能的自由协作一节。
4
-
5
- ## 请求类型
6
-
7
- 任务的 `request_purposes` 说明每条请求为何交给你:
8
-
9
- - `route`:用户未点名的消息,或全体调度交回的原问题,由你回答或分派;全体调度未代办时仍须读取原文,再决定安排。
10
- - `handoff`:你派出并要求交回的成员都已结束,据结果决定下一步。
11
- - `all`:用户请全体成员各自回应一次,其他成员已同时收到;你只回答自己的部分,不加 `--to`。
12
-
13
- 先 `room view` 看成员与状态,再决定由谁处理。
14
-
15
- 任务若有 `scheduler_suggestions`,按其中的 `request_id`、`message_id` 先读原问题;`applied:false` 表示未自动生效,`actual_action:unverified` 表示动作结果尚未核验。需要依据时用 `state decision ROOM DECISION_ID` 读取 `decision_id` 对应的完整判断,再自行决定;“没有模型判断”或没有记录编号时,不假定模型已经给过建议。
16
-
17
- ## 派活
18
-
19
- - 需要他人时在回答中加 `--to 显示名`(可重复,不能点名自己),写明各自负责的文件或模块;不需要他人时不加,本次即结束。
20
- - 只点名一位成员时,它的回答直接面向用户;还要按结果安排下一步(如再交评审)时加 `--handoff`,它做完你会再被唤醒。点名多位时,全部结束后总会回到你汇总。
21
- - 需要预先指定实现后的只读评审时,先读 `review roster ROOM`,再在派实现的 `message post` 中带 `--next-review NAME --review-scope 范围 --review-roster REVISION`;评审者不能是本批实现者。授权与实现任务同时保存,自动要求该批交回主持人。候选目前限程序启动的 Codex CLI;没有合格成员时读取结果给出原因。
22
- - 收到 `review_handoffs` 时,先用 `review ready ROOM --batch ID` 读取完整委派、交付和报告,确认可交既定评审后用 `review advance ROOM --batch ID --revision REV --submission-id UUID --as 本人` 推进。只处理该批交接,其他请求继续完成;状态变化须重读,不能替换评审者或扩大权限。能力失效、额度不足、交付不完整等原因保留在读取结果和任务中。实际投递前本机复核只读权限与能力版本,失败撤销该次评审并交回主持人。
23
- - 收到 `handoff` 后交给其他成员或汇总给用户;成员的回答已完整时只用一两句说明完成,不复述。
24
- - 同一条用户消息最多推进若干轮(`room view` 的 `free.max_rounds`,本链已用见 `free.chain_rounds`,用户可调):你派一次活算一轮,成员做完交回给你汇总不另计。到上限时你的下一次派活会被暂存、任务链停下,由用户决定继续或发新消息;你不能自己加轮。派活前先想清楚需要几位、几轮,最后一轮留给汇总。(上限防止 AI 之间无人值守地来回转交。)
25
-
26
- 用户请成员分工改代码(定计划、实现、评审、整理文档)时,先读 [开发协作](dev-flow.md)。
27
-
28
- ## 工作流
29
-
30
- 本次任务有 `workflow` 字段时,本房间启用了用户的工作流:本地软件读取任务文件 `skills` 末尾的 SKILL.md;API 主持人读取本次系统提示中的工作流正文,不尝试打开该文件路径。按它组织工作,它优先于开发协作参考流程。每次任务都重读一遍,内容变了就重新核对分工。`workflow.members` 列出每张卡片现在由哪位成员担任、是否在场、项目权限;只点名其中在场的成员,名单里缺某个角色时在回答里说明缺谁,不另找成员代替。工作流只带来做法和成员,不扩大你的权限。
31
-
32
- 本次任务(本地任务文件或 API 的 `task`)没有 `workflow` 字段时,不按任何工作流做事,即使会话里读过。
33
-
34
- 用户请你把本房间的做法存成工作流(或要你按某种分工新建一套流程)时,读 [起草工作流](workflow-draft.md)。任务有 `host_workflows: true` 时,房主已允许你自行保存并启用,不必等用户导入。
1
+ # 自由协作主持
2
+
3
+ 仅用于自由协作房间的主持人(任务 `role` 为 `host`)。成员的回答与提交方式见参与技能的自由协作一节。
4
+
5
+ ## 请求类型
6
+
7
+ 任务的 `request_purposes` 说明每条请求为何交给你:
8
+
9
+ - `route`:用户未点名的消息,或全体调度交回的原问题,由你回答或分派;全体调度未代办时仍须读取原文,再决定安排。
10
+ - `handoff`:你派出并要求交回的成员都已结束,据结果决定下一步。
11
+ - `all`:用户请全体成员各自回应一次,其他成员已同时收到;你只回答自己的部分,不加 `--to`。
12
+
13
+ 先 `room view` 看成员与状态,再决定由谁处理。
14
+
15
+ 任务若有 `scheduler_suggestions`,按其中的 `request_id`、`message_id` 先读原问题;`applied:false` 表示未自动生效,`actual_action:unverified` 表示动作结果尚未核验。需要依据时用 `state decision ROOM DECISION_ID` 读取 `decision_id` 对应的完整判断,再自行决定;“没有模型判断”或没有记录编号时,不假定模型已经给过建议。
16
+
17
+ ## 派活
18
+
19
+ - 需要他人时在回答中加 `--to 显示名`(可重复,不能点名自己),写明各自负责的文件或模块;不需要他人时不加,本次即结束。
20
+ - 只点名一位成员时,它的回答直接面向用户;还要按结果安排下一步(如再交评审)时加 `--handoff`,它做完你会再被唤醒。点名多位时,全部结束后总会回到你汇总。
21
+ - 需要预先指定实现后的只读评审时,先读 `review roster ROOM`,再在派实现的 `message post` 中带 `--next-review NAME --review-scope 范围 --review-roster REVISION`;评审者不能是本批实现者。授权与实现任务同时保存,自动要求该批交回主持人。候选目前限程序启动的 Codex CLI;没有合格成员时读取结果给出原因。
22
+ - 收到 `review_handoffs` 时,先用 `review ready ROOM --batch ID` 读取完整委派、交付和报告,确认可交既定评审后用 `review advance ROOM --batch ID --revision REV --submission-id UUID --as 本人` 推进。只处理该批交接,其他请求继续完成;状态变化须重读,不能替换评审者或扩大权限。能力失效、额度不足、交付不完整等原因保留在读取结果和任务中。实际投递前本机复核只读权限与能力版本,失败撤销该次评审并交回主持人。
23
+ - 收到 `handoff` 后交给其他成员或汇总给用户;成员的回答已完整时只用一两句说明完成,不复述。
24
+ - 同一条用户消息最多推进若干轮(`room view` 的 `free.max_rounds`,本链已用见 `free.chain_rounds`,用户可调):你派一次活算一轮,成员做完交回给你汇总不另计。到上限时你的下一次派活会被暂存、任务链停下,由用户决定继续或发新消息;你不能自己加轮。派活前先想清楚需要几位、几轮,最后一轮留给汇总。(上限防止 AI 之间无人值守地来回转交。)
25
+
26
+ 用户请成员分工改代码(定计划、实现、评审、整理文档)时,先读 [开发协作](dev-flow.md)。
27
+
28
+ ## 工作流
29
+
30
+ 本次任务有 `workflow` 字段时,本房间启用了用户的工作流。它像技能一样按需使用:`workflow.description` 是它的用途,请求与用途相符或用户要求按它做时才用,其他请求照常处理。要用时,本会话还没读过、或 `workflow.revision` 与上次读到的不同,才读 `workflow.skill_path`(API 主持人读系统提示中的工作流正文);否则沿用已读内容。按它组织工作时,`workflow.members` 列出每张卡片现在由哪位成员担任、是否在场、项目权限;只点名在场的成员,缺某个角色时在回答里说明缺谁,不另找成员代替。工作流只带来做法和成员,不扩大你的权限。
31
+
32
+ 本次任务(本地任务文件或 API 的 `task`)没有 `workflow` 字段时,不按任何工作流做事,即使会话里读过。
33
+
34
+ 用户请你把本房间的做法存成工作流(或要你按某种分工新建一套流程)时,按 [workflow-creator](../../workflow-creator/SKILL.md) 技能做。任务有 `host_workflows: true` 时,房主已允许你自行保存并启用,不必等用户导入。
@@ -0,0 +1,105 @@
1
+ ---
2
+ name: workflow-creator
3
+ description: AI CoDiscuss 工作流的创建与修改技能。用户要把房间里形成的做法存成工作流、按某种多人分工新建一套流程,或修改、检查已有工作流时使用;产出符合本平台规范的 SKILL.md 与 Agent 卡片,经程序校验后保存。不负责执行工作流本身。
4
+ ---
5
+
6
+ # 创建工作流(workflow-creator)
7
+
8
+ 工作流 = 一份给主持人读的 `SKILL.md` + 一组 Agent 卡片,存在本机服务目录 `workflows/<id>/`,一个文件夹就是一个分享单位。启用后,卡片对应的角色作为成员加入房间,每次执行时收到自己卡片的提示词;主持人像用技能一样按需使用它:每次任务都看到 `description`,请求与它相符时才读 SKILL.md 正文,读过且没改过就不重读。
9
+
10
+ 工作流是“软”的:程序只校验、保存、加载和带来成员,不强制工序。主持人能不能按流程组织、各角色能不能做对,全靠这些文字,所以按 [提示词设计原则](references/prompt-design.md) 写。
11
+
12
+ ## 先判断该不该做成工作流
13
+
14
+ 适合:多人分工、会在不同房间或不同项目里反复用。不适合时直接告诉用户更合适的做法,不硬做:
15
+
16
+ - 单个角色的职责:存成专家预设。
17
+ - 只属于某个项目的事实(设定、路径、进度):写进项目文档。
18
+ - 需要程序强制轮次和发言顺序:用房间的“讨论”。
19
+
20
+ ## 流程
21
+
22
+ 1. **弄清需求**:目标产物;有哪些角色、各自负责什么;交接顺序;谁可以改哪些文件;什么算验收通过;哪些做法已在房间里跑通过。能从房间记录或用户描述得到的不问,只问会改变设计的关键歧义。
23
+ 2. **设计**:按下面“写什么、放哪里”决定 SKILL.md 和每张卡片的内容。
24
+ 3. **按格式写**:见“格式”。
25
+ 4. **校验并保存**:见“校验与保存”,按报错修正,直到通过。
26
+ 5. **修改已有工作流**:先读现有文件,沿用同一 ID,优先局部调整;保存后,启用它的房间从成员下一次执行起读到新内容。
27
+
28
+ ## 写什么、放哪里
29
+
30
+ | 文件 | 读者 | 写什么 |
31
+ |---|---|---|
32
+ | `SKILL.md` | 主持人 | 用途;开工前准备;每一步找哪个角色、交回什么、怎么验收;各角色共同遵守的约束;产物放在哪里(写成“读项目 README 找到……”) |
33
+ | `agents/<卡片ID>.md` | 该角色 | 角色立场、质量标准、本角色特有的做法和常见错误 |
34
+
35
+ - **同一条规则只写一处。** 流程、交接和输出格式写在 SKILL.md,由主持人派活时写进任务;卡片不复述流程。原因:之后用同一 ID 修订时只需改一处,两处都写迟早会对不上。
36
+ - **SKILL.md 自成一体**:只按角色的显示名、描述和产物路径说话,不引用卡片提示词的内容(API 主持人读不到卡片)。
37
+ - **可分享**:不写本项目的具体事实、本机路径或密钥;项目信息写成去哪里读。
38
+ - **只写验证过的做法**:用户直接给了分工、还没跑过的,按用户的分工写,跑过一轮后再用同一 ID 修订。
39
+ - **权限按职责最小**:只有需要改文件的角色给 `write`;同一份文件同一时刻只让一个角色改。
40
+ - 主持人不设卡片;主持人的职责写在 SKILL.md 里。
41
+
42
+ ## 格式
43
+
44
+ ```
45
+ <id>/
46
+ SKILL.md
47
+ agents/
48
+ <卡片ID>.md
49
+ ```
50
+
51
+ `SKILL.md`:
52
+
53
+ ```
54
+ ---
55
+ name: novel-serial
56
+ label: 连载小说
57
+ description: 做什么、什么时候用,一句话,不换行
58
+ ---
59
+ (正文,最多 20,000 字)
60
+ ```
61
+
62
+ `agents/writer.md`:
63
+
64
+ ```
65
+ ---
66
+ name: writer
67
+ platform: Antigravity
68
+ label: 执笔
69
+ description: 一句话说明职责,不换行
70
+ project_access: write
71
+ ---
72
+ (只发给这个角色的专属提示词,最多 4,000 字)
73
+ ```
74
+
75
+ - **工作流 ID**(文件夹名 = SKILL.md 的 `name`):小写英文和数字,可用单个连字符连接(不在首尾),1—40 位。`label` 最多 32 字。
76
+ - **`description`** 最多 500 字:写清做什么、什么时候用。主持人只凭它判断一条请求该不该按这个工作流做,写含糊了,该用时会不用、不该用时会套用。
77
+ - **卡片**:最多 30 张。`name` 是卡片 ID,等于文件名,只用小写英文、数字和下划线,最多 16 位。`platform` 是平台 ID:`Claude`、`Codex`、`Antigravity`、`DeepSeek`、`Qwen`、`Grok`(网页显示的 Gemini 写 `Antigravity`),须是本机已配置的平台。成员名由程序拼成 `平台-卡片ID`。
78
+ - **卡片可选字段**:`label`、`description`、`project_access`(read / write / auto / full)、`model`、`effort`。不用的字段直接省略;模型和强度省略即用本机默认值。接入方式、可执行文件、密钥不写进卡片,由各自电脑的配置决定。
79
+ - 头信息只支持单行 `key: value`;不支持多行值、列表和嵌套。
80
+ - 卡片正文留空时使用该软件的默认提示。
81
+
82
+ ## 校验与保存
83
+
84
+ | 你在哪里 | 怎么保存 |
85
+ |---|---|
86
+ | 房间主持人,任务里有 `host_workflows: true` | 房主已允许你自建:把草稿写成一个文件(下方“草稿格式”,只用一段 `1/1`),放在任务的 `draft_directory` 下,运行 `<cli> launch workflow-adopt --draft <文件> --access-file <本次任务的 access_file>`。程序校验、保存、在本房间启用并邀请缺少的卡片成员(离开的请回),返回 `members`(卡片 ID → 成员名),本次执行里就能点名派活。只能更新本房间绑定的工作流;卡片权限最高 write。 |
87
+ | 房间主持人,任务里没有该字段 | 在回答里发出草稿(草稿格式),由用户在网页“工作流库 → 粘贴导入”保存。可以告诉用户:在“成员与设置 → 协作设置”打开“允许主持人自建工作流”后,你就能自己保存并启用。 |
88
+ | 不在房间里,用户直接让你建 | 先在一个临时文件夹里按“格式”写好,运行 `codiscuss launch workflow-check --dir <文件夹>` 校验;用户确认后运行 `codiscuss launch workflow-save --dir <文件夹>` 保存进工作流库。同 ID 会覆盖原有工作流,覆盖前先告诉用户。 |
89
+
90
+ 不要直接写入本机服务目录的 `workflows/`:那样会跳过校验和写入锁,格式错的文件会让启用它的房间读不到工作流。命令失败时按报错修正,不要绕过。
91
+
92
+ ### 草稿格式
93
+
94
+ 草稿把整个文件夹写进一段文本,用于 `workflow-adopt` 或粘贴导入:
95
+
96
+ ```
97
+ <!-- workflow-part: 1/1 id: novel-serial -->
98
+ <!-- workflow-file: SKILL.md -->
99
+ (SKILL.md 全文,含头信息)
100
+ <!-- workflow-file: agents/writer.md -->
101
+ (卡片全文,含头信息)
102
+ ```
103
+
104
+ - 分隔行必须独占一行、从行首开始。说明文字只能写在第一个 `workflow-file` 分隔行之前;之后的内容都算文件正文,最后一个文件后面不要再加说明。
105
+ - 在回答里发草稿时,不要把整段包在 Markdown 代码围栏里。一条消息装不下(正文上限约 32,000 字)时拆成多条,最多 20 段,每条都带分段头 `序号/总数`,同一个文件不要拆到两条里。写成文件给 `workflow-adopt` 时只用一段。
@@ -0,0 +1,4 @@
1
+ interface:
2
+ display_name: "创建工作流"
3
+ short_description: "把多人协作的做法写成符合 AI CoDiscuss 规范的工作流(SKILL.md + Agent 卡片),校验后保存"
4
+ default_prompt: "使用 $workflow-creator,按我描述的分工创建一个 AI CoDiscuss 工作流。"
@@ -0,0 +1,29 @@
1
+ # 提示词设计原则
2
+
3
+ 写 SKILL.md 和卡片提示词时按这些原则校准:用必要的信息、约束和示例校准 AI 的判断,并有意识地保留自主空间。按需要应用,不要求产物逐项设置对应章节。
4
+
5
+ ## 设计原则
6
+
7
+ - **明确目标与背景**:说明要完成什么、什么结果算合格。利用 AI 已有的通用能力,补充任务特有的信息,避免重复讲解常识或让 AI 猜关键事实。
8
+
9
+ - **保持信噪比**:每条规则都有理解成本。去掉不会影响行为的内容,合并重复要求;关键目标和约束放在容易找到的位置,长提示词尤其注意避免埋在中间。
10
+
11
+ - **按职责组织**:流程、领域知识和输出要求各归其位。同一规则只定义一次。结构用于帮助理解,不为形式增加章节或层级。在工作流里,这就是“流程写 SKILL.md、角色做法写卡片”。
12
+
13
+ - **用 WHY 支持判断**:为影响取舍的关键规则补充简短理由,让 AI 在未覆盖的场景中能够依据目的调整做法。简单明确的要求不必逐条解释。
14
+
15
+ - **用示例校准标准**:难以用文字说清的格式、质量或边界,用少量有代表性的示例表达。示例锚定基准,WHY 帮助处理变化;避免堆积相似示例或将示例中的偶然细节变成规则。
16
+
17
+ - **区分约束层级**:硬约束明确“必须/禁止”;软指导给出默认做法和理由,允许合理取舍;自由区域交由 AI 判断,不补齐每个决策点。提供评估维度,避免不必要地规定具体答案或步骤。
18
+
19
+ - **自主范围与验证相配合**:需要逐步放权时,依据执行和验证结果扩大自主范围;简单任务不额外增加审批或检查流程。
20
+
21
+ ## 修改原则
22
+
23
+ 遵循 KISS,保留已有内容中的有效结构,优先局部调整。
24
+
25
+ 新增规则前检查:解决的是具体问题还是假想情况?现有规则能否覆盖?放在哪里合适?是否重复或冲突?示例是否更清楚?
26
+
27
+ 先理解错误产生的原因,再修改对应内容;问题也可能来自信息缺失或工具能力。尽量一次调整一个影响因素,有实际案例时比较修改效果,避免解决一个问题又破坏原本正确的行为。
28
+
29
+ 按用户要求交付设计内容,无需默认附加原则复述或逐项检查报告。
@@ -39,6 +39,7 @@ REVIEW_STATE_SQL = """SELECT json_object(
39
39
  'withdrawn',(SELECT json_group_array(message_id) FROM message_withdrawals WHERE message_id IN (SELECT id FROM messages WHERE room_id=rooms.id))
40
40
  ) AS state FROM rooms WHERE id=?"""
41
41
  RECENT_REQUESTS = 100
42
+ ADOPT_REASON_LIMIT = 500
42
43
  RECENT_EXECUTIONS = 100
43
44
  # The timeline page reads this many recent executions of each kind; with `after` (?3) only those running or ended since.
44
45
  # Parameters: ?1 room, ?2 limit, ?3 after (0 reads all). Shared verbatim with the Worker.
@@ -753,6 +754,9 @@ def free_view(connection, room_id):
753
754
  member["registered_at"] = registered_at(connection, row)
754
755
  reported = connection.execute("SELECT session_id,client FROM member_sessions WHERE member_id=?", (row["id"],)).fetchone()
755
756
  member["reported_session"], member["reported_client"] = (reported["session_id"], reported["client"]) if reported else ("", "")
757
+ failure = connection.execute("SELECT reason FROM member_adopt_failures WHERE member_id=? AND session_id=?",
758
+ (row["id"], member["reported_session"])).fetchone() if reported else None
759
+ member["adopt_error"] = failure["reason"] if failure else ""
756
760
  latest = connection.execute(f"SELECT e.*,{CAPABILITY_COLUMNS} FROM member_executions e WHERE member_id=? ORDER BY id DESC LIMIT 1",
757
761
  (row["id"],)).fetchone()
758
762
  member["execution"] = public_execution(latest)
@@ -2046,6 +2050,18 @@ def adopt_manual_member(connection, room_id, member, payload):
2046
2050
  connection.execute("UPDATE room_members SET token_hash=? WHERE id=?", (token_hash(payload["token"]), member["id"]))
2047
2051
 
2048
2052
 
2053
+ def record_adopt_failure(connection, room_id, member, payload):
2054
+ """Keep why the local service could not take over the reported session, so the page says why requests stay undelivered."""
2055
+ reason = payload.get("reason")
2056
+ if not isinstance(reason, str) or not reason.strip():
2057
+ raise ValueError("须提供 reason")
2058
+ reported = connection.execute("SELECT session_id FROM member_sessions WHERE member_id=?", (member["id"],)).fetchone()
2059
+ if not reported or reported["session_id"] != payload.get("session_id"):
2060
+ raise ValueError("成员尚未上报与之相符的会话")
2061
+ connection.execute("INSERT OR REPLACE INTO member_adopt_failures (member_id,room_id,session_id,reason) VALUES (?,?,?,?)",
2062
+ (member["id"], room_id, reported["session_id"], reason.strip()[:ADOPT_REASON_LIMIT]))
2063
+
2064
+
2049
2065
  def require_fresh_member_token(connection, room_id, token):
2050
2066
  """Prevent owner or another member's credential from being reused for a new identity."""
2051
2067
  hashed = token_hash(token)
@@ -2088,6 +2104,10 @@ def member_action(connection, room_id, member_id, token, payload):
2088
2104
  queue_invited_expert(connection, room_id, member["name"], int(time.time()))
2089
2105
  elif action == "adopt":
2090
2106
  adopt_manual_member(connection, room_id, member, payload)
2107
+ connection.execute("DELETE FROM member_adopt_failures WHERE member_id=?", (member_id,))
2108
+ elif action == "adopt_failed":
2109
+ record_adopt_failure(connection, room_id, member, payload)
2110
+ return free_view(connection, room_id)
2091
2111
  elif action == "role":
2092
2112
  role = payload.get("role")
2093
2113
  if role not in ("host", "member"):
@@ -2105,7 +2125,7 @@ def member_action(connection, room_id, member_id, token, payload):
2105
2125
  connection.execute("UPDATE room_members SET role='member' WHERE room_id=? AND role='host'", (room_id,))
2106
2126
  connection.execute("UPDATE room_members SET role=? WHERE id=?", (role, member_id))
2107
2127
  else:
2108
- raise ValueError("action 须为 away、active、remove、role 或 adopt")
2128
+ raise ValueError("action 须为 away、active、remove、role、adopt 或 adopt_failed")
2109
2129
  settle_batches(connection, room_id)
2110
2130
  sync_participants(connection, room_id)
2111
2131
  hand_over_routes(connection, room_id, routed, member_id if action in ("away", "remove") else None)
@@ -231,6 +231,13 @@ CREATE TABLE IF NOT EXISTS member_sessions (
231
231
  session_id TEXT NOT NULL,
232
232
  client TEXT NOT NULL
233
233
  );
234
+ -- Why the local service could not take over a manual member's reported session; shown only while that session is still the reported one.
235
+ CREATE TABLE IF NOT EXISTS member_adopt_failures (
236
+ member_id INTEGER PRIMARY KEY REFERENCES room_members(id) ON DELETE CASCADE,
237
+ room_id TEXT NOT NULL,
238
+ session_id TEXT NOT NULL,
239
+ reason TEXT NOT NULL
240
+ );
234
241
  -- A manual member's own registration; it is bound to the credential it used, so a re-issued credential must register again.
235
242
  CREATE TABLE IF NOT EXISTS member_registrations (
236
243
  member_id INTEGER PRIMARY KEY REFERENCES room_members(id) ON DELETE CASCADE,
@@ -968,6 +975,13 @@ BEGIN
968
975
  INSERT INTO room_revisions (room_id,revision) SELECT NEW.room_id,(SELECT COALESCE(MAX(revision),0)+1 FROM room_revisions)
969
976
  WHERE NOT EXISTS (SELECT 1 FROM room_revisions WHERE room_id=NEW.room_id);
970
977
  END;
978
+ DROP TRIGGER IF EXISTS revision_adopt_failure_insert;
979
+ CREATE TRIGGER revision_adopt_failure_insert AFTER INSERT ON member_adopt_failures
980
+ BEGIN
981
+ UPDATE room_revisions SET revision=(SELECT MAX(revision)+1 FROM room_revisions) WHERE room_id=NEW.room_id;
982
+ INSERT INTO room_revisions (room_id,revision) SELECT NEW.room_id,(SELECT COALESCE(MAX(revision),0)+1 FROM room_revisions)
983
+ WHERE NOT EXISTS (SELECT 1 FROM room_revisions WHERE room_id=NEW.room_id);
984
+ END;
971
985
  DROP TRIGGER IF EXISTS revision_session_report_update;
972
986
  CREATE TRIGGER revision_session_report_update AFTER UPDATE ON member_sessions
973
987
  WHEN OLD.session_id IS NOT NEW.session_id OR OLD.client IS NOT NEW.client
package/backend/server.py CHANGED
@@ -842,7 +842,7 @@ def delete_room_records(connection, room_id):
842
842
  """Remove a room's dependent records in the caller's transaction."""
843
843
  connection.execute("DELETE FROM task_message_sources WHERE session_id IN (SELECT id FROM discussion_sessions WHERE room_id=?)", (room_id,))
844
844
  connection.execute("DELETE FROM discussion_sessions WHERE room_id=?", (room_id,))
845
- for table in ("member_recommendations", "free_queue", "queued_messages", "queued_message_pauses", "speaking_orders", "member_requests", "member_descriptions", "member_labels", "execution_notes", "execution_segments", "execution_capabilities", "late_answers", "member_executions", "member_capabilities", "member_sessions", "member_registrations", "room_members", "room_modes", "free_batches", "free_chains", "free_handoffs", "free_round_limits", "free_chain_holds",
845
+ for table in ("member_recommendations", "free_queue", "queued_messages", "queued_message_pauses", "speaking_orders", "member_requests", "member_descriptions", "member_labels", "execution_notes", "execution_segments", "execution_capabilities", "late_answers", "member_executions", "member_capabilities", "member_sessions", "member_adopt_failures", "member_registrations", "room_members", "room_modes", "free_batches", "free_chains", "free_handoffs", "free_round_limits", "free_chain_holds",
846
846
  "scheduler_decisions", "scheduler_routing", "discussion_conclusions", "discussion_sessions"):
847
847
  if table == "scheduler_decisions":
848
848
  for child in ("scheduler_feedback", "scheduler_decision_context", "scheduler_decision_inputs"):
@@ -1883,7 +1883,7 @@ class DiscussionHandler(BaseHTTPRequestHandler):
1883
1883
  if command in ("start", "room-config", "room-models", "room-files", "room-member", "room-member-access", "room-member-allow", "room-member-adapter", "room-member-model", "room-profiles", "room-restore", "room-fork", "room-workflow", "workflows"):
1884
1884
  payload.pop("access_file", None)
1885
1885
  payload.update(site=site, entry="web")
1886
- if command in ("room-files", "room-workflow") and not payload.get("token") and not self.bridge_origin:
1886
+ if command in ("room-files", "room-workflow", "room-member", "room-member-access", "room-member-allow", "room-member-model", "room-member-adapter") and not payload.get("token") and not self.bridge_origin:
1887
1887
  with closing(connect_db(self.server.database)) as connection:
1888
1888
  self.admin_as_owner(connection, payload.get("room_id", ""))
1889
1889
  payload["token"] = self.headers.get("X-Discussion-Token", "")
package/docs/runner.md CHANGED
@@ -101,7 +101,7 @@ API 成员可以担任专家或主持人。房间指定了项目目录时,它
101
101
  - **保存**:点“工作流库”新建或编辑;也可以请房间主持人“把这个房间的做法存成工作流”,复制它起草的消息,在工作流库“粘贴导入”。编辑页可以“从当前房间成员导入”卡片,提示词保持原文。
102
102
  - **让主持人自己建**:建房时(第 3 节“协作方式”)或在“成员与设置 → 协作设置”勾选“允许主持人自建工作流”后,直接对主持人说要什么分工(或“把这个房间的做法存成工作流”),它会自己保存、在本房间启用,并邀请工作流里的成员,接着就按流程派活,不需要你导入或添加成员。之后让它改流程,改动从成员下一次执行起生效。主持人带来的成员项目权限最高为可写;只有本地软件担任的主持人能这样做,API 主持人不行。
103
103
  - **分享**:工作流存在本机服务目录的 `workflows` 文件夹,一个工作流一个文件夹;编辑页可复制路径,复制整个文件夹即可分享。导入时会列出每张卡片的提示词和项目权限;要求写文件的卡片默认按只读导入,逐张勾选后才放开。
104
- - **修改与停用**:修改工作流会作用于所有启用它的房间,成员下一次执行就按新内容;工作流卡片的提示词弹窗提供“去工作流库编辑”。右栏显示工作流状态并可停用:它带来的成员离开(主持人保留),正在进行的工作随之停止;重新启用先打开邀请面板,确认后请回原成员并加入你保留的新增卡片。
104
+ - **修改与结束**:修改工作流会作用于所有启用它的房间,成员下一次执行就按新内容;工作流卡片的提示词弹窗提供“去工作流库编辑”。工作流进行中时,主持人只在请求和它的用途相符(或你说按工作流做)时才用,其他请求照常处理。用完在右栏点“请离成员”:工作流带来的成员离开(主持人保留),正在进行的工作随之停止,工作流结束,右栏这一块消失;成员会话保留,下次在输入框打 `/` 选它就把原成员请回来,接着原来的上下文。换工作流时直接选另一个,原来的成员留作普通成员。
105
105
 
106
106
  ## 朗读与语音输入(可选)
107
107
 
package/package.json CHANGED
@@ -1,86 +1,87 @@
1
- {
2
- "name": "ai_co_discuss",
3
- "version": "0.3.45",
4
- "bin": {
5
- "codiscuss": "runner/codiscuss.mjs"
6
- },
7
- "scripts": {
8
- "dev": "npm run build && wrangler pages dev --ip 127.0.0.1 --port 8787",
9
- "db:local": "wrangler d1 execute DB --local --file backend/schema.sql",
10
- "db:remote": "wrangler d1 execute DB --remote --file backend/schema.sql",
11
- "check": "node --check backend/worker.mjs && node --check web/app.js && node --check runner/admin_account.mjs && node --check runner/codiscuss.mjs && node --check runner/discussion_api.mjs && node --check runner/discussion_launch.mjs && node --check runner/discussion_local.mjs && node --check runner/discussion_runner.mjs && node --check runner/discussion_service.mjs && node --check runner/discussion_setup.mjs && node --check runner/discussion_sidecar.mjs && node --check runner/discussion_skills.mjs && node --check runner/discussion_tui.mjs && node --check runner/execution_progress.mjs && node --check runner/expert_prompts.mjs && node --check runner/files.mjs && node --check runner/free_runner.mjs && node --check runner/remote_launch.mjs && node --check runner/scheduler.mjs && node --check runner/session_driver.mjs && node --check runner/workflows.mjs && node --check runner/adapters/antigravity_app.mjs && node --check runner/adapters/antigravity_cli.mjs && node --check runner/adapters/antigravity_sidecar.mjs && node --check runner/adapters/api.mjs && node --check runner/adapters/claude.mjs && node --check runner/adapters/cli.mjs && node --check runner/adapters/codex_app.mjs && node --check runner/adapters/codex_app_client.mjs && node --check runner/adapters/codex_cli.mjs && node --check runner/adapters/common.mjs && node --check runner/adapters/index.mjs && node --check runner/adapters/profiles.mjs",
12
- "runner": "node runner/discussion_runner.mjs",
13
- "service": "node runner/discussion_service.mjs",
14
- "build:ui": "vite build --config frontend/vite.config.mjs --mode markdown && vite build --config frontend/vite.config.mjs --mode backup && vite build --config frontend/vite.config.mjs",
15
- "test:markdown": "node --test tests/test_markdown.mjs",
16
- "build": "npm run check && npm run build:ui && node scripts/build_pages.mjs",
17
- "test:pages": "node --test tests/test_pages.mjs",
18
- "deploy": "npm run build && wrangler pages deploy --branch main --commit-dirty=true",
19
- "deploy:pages": "npm run deploy",
20
- "test": "npm run test:python && npm run test:js",
21
- "test:python": "python -m unittest discover -s tests -p test_*.py",
22
- "test:js": "node --test tests/test_*.mjs",
23
- "test:install": "node --test tests/test_setup.mjs tests/test_local.mjs tests/test_package.mjs"
24
- },
25
- "devDependencies": {
26
- "@iconify-json/lucide": "1.2.144",
27
- "@mdit/plugin-katex": "1.1.3",
28
- "@nuxt/ui": "4.11.3",
29
- "@tailwindcss/vite": "4.3.3",
30
- "@vitejs/plugin-vue": "6.0.10",
31
- "fflate": "0.8.3",
32
- "katex": "0.18.10",
33
- "markdown-it": "15.0.3",
34
- "markdown-it-cjk-friendly": "3.0.0",
35
- "motion-v": "2.7.0",
36
- "pdfjs-dist": "6.4.299",
37
- "vite": "8.3.4",
38
- "vue": "3.5.44",
39
- "wrangler": "4.151.0"
40
- },
41
- "description": "让不同 AI 在各自软件中协作的共享讨论空间",
42
- "keywords": [
43
- "ai",
44
- "multi-agent",
45
- "discussion",
46
- "cli",
47
- "codex",
48
- "claude",
49
- "gemini"
50
- ],
51
- "homepage": "https://github.com/huyan1458/ai_co_discuss#readme",
52
- "repository": {
53
- "type": "git",
54
- "url": "git+https://github.com/huyan1458/ai_co_discuss.git"
55
- },
56
- "bugs": {
57
- "url": "https://github.com/huyan1458/ai_co_discuss/issues"
58
- },
59
- "author": "huyan1458",
60
- "license": "MIT",
61
- "engines": {
62
- "node": ">=24"
63
- },
64
- "overrides": {
65
- "fontless": {
66
- "esbuild": "0.28.2"
67
- }
68
- },
69
- "files": [
70
- "runner/*.mjs",
71
- "runner/adapters/*.mjs",
72
- "runner/*.py",
73
- "backend/*.py",
74
- "backend/schema.sql",
75
- "backend/migrations/*.sql",
76
- "server.py",
77
- "web/**",
78
- ".agents/skills/discuss-host/**",
79
- ".agents/skills/discuss-participant/**",
80
- ".agents/skills/discuss-report/**",
81
- ".github/SECURITY.md",
82
- "docs/**",
83
- "!**/*.log",
84
- "LICENSE"
85
- ]
86
- }
1
+ {
2
+ "name": "ai_co_discuss",
3
+ "version": "0.3.47",
4
+ "bin": {
5
+ "codiscuss": "runner/codiscuss.mjs"
6
+ },
7
+ "scripts": {
8
+ "dev": "npm run build && wrangler pages dev --ip 127.0.0.1 --port 8787",
9
+ "db:local": "wrangler d1 execute DB --local --file backend/schema.sql",
10
+ "db:remote": "wrangler d1 execute DB --remote --file backend/schema.sql",
11
+ "check": "node --check backend/worker.mjs && node --check web/app.js && node --check runner/admin_account.mjs && node --check runner/codiscuss.mjs && node --check runner/discussion_api.mjs && node --check runner/discussion_launch.mjs && node --check runner/discussion_local.mjs && node --check runner/discussion_runner.mjs && node --check runner/discussion_service.mjs && node --check runner/discussion_setup.mjs && node --check runner/discussion_sidecar.mjs && node --check runner/discussion_skills.mjs && node --check runner/discussion_tui.mjs && node --check runner/execution_progress.mjs && node --check runner/expert_prompts.mjs && node --check runner/files.mjs && node --check runner/free_runner.mjs && node --check runner/remote_launch.mjs && node --check runner/scheduler.mjs && node --check runner/session_driver.mjs && node --check runner/workflows.mjs && node --check runner/adapters/antigravity_app.mjs && node --check runner/adapters/antigravity_cli.mjs && node --check runner/adapters/antigravity_sidecar.mjs && node --check runner/adapters/api.mjs && node --check runner/adapters/claude.mjs && node --check runner/adapters/cli.mjs && node --check runner/adapters/codex_app.mjs && node --check runner/adapters/codex_app_client.mjs && node --check runner/adapters/codex_cli.mjs && node --check runner/adapters/common.mjs && node --check runner/adapters/index.mjs && node --check runner/adapters/profiles.mjs",
12
+ "runner": "node runner/discussion_runner.mjs",
13
+ "service": "node runner/discussion_service.mjs",
14
+ "build:ui": "vite build --config frontend/vite.config.mjs --mode markdown && vite build --config frontend/vite.config.mjs --mode backup && vite build --config frontend/vite.config.mjs",
15
+ "test:markdown": "node --test tests/test_markdown.mjs",
16
+ "build": "npm run check && npm run build:ui && node scripts/build_pages.mjs",
17
+ "test:pages": "node --test tests/test_pages.mjs",
18
+ "deploy": "npm run build && wrangler pages deploy --branch main --commit-dirty=true",
19
+ "deploy:pages": "npm run deploy",
20
+ "test": "npm run test:python && npm run test:js",
21
+ "test:python": "python -m unittest discover -s tests -p test_*.py",
22
+ "test:js": "node --test tests/test_*.mjs",
23
+ "test:install": "node --test tests/test_setup.mjs tests/test_local.mjs tests/test_package.mjs"
24
+ },
25
+ "devDependencies": {
26
+ "@iconify-json/lucide": "1.2.144",
27
+ "@mdit/plugin-katex": "1.1.3",
28
+ "@nuxt/ui": "4.11.3",
29
+ "@tailwindcss/vite": "4.3.3",
30
+ "@vitejs/plugin-vue": "6.0.10",
31
+ "fflate": "0.8.3",
32
+ "katex": "0.18.10",
33
+ "markdown-it": "15.0.3",
34
+ "markdown-it-cjk-friendly": "3.0.0",
35
+ "motion-v": "2.7.0",
36
+ "pdfjs-dist": "6.4.299",
37
+ "vite": "8.3.4",
38
+ "vue": "3.5.44",
39
+ "wrangler": "4.151.0"
40
+ },
41
+ "description": "让不同 AI 在各自软件中协作的共享讨论空间",
42
+ "keywords": [
43
+ "ai",
44
+ "multi-agent",
45
+ "discussion",
46
+ "cli",
47
+ "codex",
48
+ "claude",
49
+ "gemini"
50
+ ],
51
+ "homepage": "https://github.com/huyan1458/ai_co_discuss#readme",
52
+ "repository": {
53
+ "type": "git",
54
+ "url": "git+https://github.com/huyan1458/ai_co_discuss.git"
55
+ },
56
+ "bugs": {
57
+ "url": "https://github.com/huyan1458/ai_co_discuss/issues"
58
+ },
59
+ "author": "huyan1458",
60
+ "license": "MIT",
61
+ "engines": {
62
+ "node": ">=24"
63
+ },
64
+ "overrides": {
65
+ "fontless": {
66
+ "esbuild": "0.28.2"
67
+ }
68
+ },
69
+ "files": [
70
+ "runner/*.mjs",
71
+ "runner/adapters/*.mjs",
72
+ "runner/*.py",
73
+ "backend/*.py",
74
+ "backend/schema.sql",
75
+ "backend/migrations/*.sql",
76
+ "server.py",
77
+ "web/**",
78
+ ".agents/skills/discuss-host/**",
79
+ ".agents/skills/discuss-participant/**",
80
+ ".agents/skills/discuss-report/**",
81
+ ".agents/skills/workflow-creator/**",
82
+ ".github/SECURITY.md",
83
+ "docs/**",
84
+ "!**/*.log",
85
+ "LICENSE"
86
+ ]
87
+ }