ai_co_discuss 0.2.66 → 0.2.68
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/backend/free_room.py +4 -0
- package/docs/workflow.md +1 -1
- package/package.json +1 -1
- package/runner/discussion_launch.mjs +3 -5
- package/runner/discussion_service.mjs +3 -2
- package/web/modern.css +1 -1
- package/web/modern.js +10 -10
package/backend/free_room.py
CHANGED
|
@@ -994,6 +994,10 @@ def adopt_manual_member(connection, room_id, member, payload):
|
|
|
994
994
|
raise ValueError("只有自由协作或全自动讨论中在场的手动专家可以转为托管")
|
|
995
995
|
connection.execute("UPDATE room_members SET access='runner',adapter=?,session_mode='borrowed' WHERE id=?", (payload["adapter"], member["id"]))
|
|
996
996
|
connection.execute("DELETE FROM member_sessions WHERE member_id=?", (member["id"],))
|
|
997
|
+
# A free room's service answers as the member, so it takes over with a credential the owner's side generated.
|
|
998
|
+
if payload.get("token") is not None:
|
|
999
|
+
require_fresh_member_token(connection, room_id, payload["token"])
|
|
1000
|
+
connection.execute("UPDATE room_members SET token_hash=? WHERE id=?", (token_hash(payload["token"]), member["id"]))
|
|
997
1001
|
|
|
998
1002
|
|
|
999
1003
|
def require_fresh_member_token(connection, room_id, token):
|
package/docs/workflow.md
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
自由协作房间从同一角色库选择一位或多位成员。用户是需求方而不是主持人:只要有能自行发言的成员(本机唤醒或手动接入),房间就始终有一位 AI 主持人,默认是第一位本机唤醒的成员,可点皇冠或在成员菜单中更换;主持人不能直接卸任,离开或被移出时由下一位成员接任,原先由用户主持的旧房间在下一条消息时自动指定。只有一位成员时,每条消息都交给它;有多位时,你的消息默认发给主持人;在正文中 `@成员` 才让其他成员发言(代码和引用中的 @ 不算,输入框中会生效的 @ 显示为蓝色),被点名的成员各自处理,主持人也可以 @ 其他成员派活。输入框下方的备注行显示这条消息会发给谁。只有网页 AI 成员时没有主持人,未点名的消息只作留言。输入 `@` 后,输入框上方弹出在场成员菜单,继续输入可筛选;用方向键与 Enter / Tab 或点击补全,Esc 关闭。选择只修改草稿。输入框 Enter 发送、Shift + Enter 换行;发送按钮始终用于发言,无正文或附件时禁用,成员处理中也不切换为停止按钮。自动成员空闲时,服务把它名下所有未处理的消息打包成一次执行交给原会话;执行期间再发的消息排队,下一次一起投递。手动成员自行读取自己的请求,在线成员由用户转交。成员按时间顺序处理,后面的消息可以修正前面的。
|
|
27
27
|
|
|
28
|
-
运行中可在右侧成员栏邀请 AI(沿用本机软件配置和本房间工作目录),也可让成员离开、请回或移除。自动成员的项目文件权限默认只读;需要它修改项目时,在邀请前选择“项目文件可写”,权限只应用于这位成员;App 与手动成员的文件权限由其软件设置,API 与网页成员不访问项目文件。填写已有会话 ID 时续接该原会话,不新建。离开会立即停止它的工作;请回时换发新凭证并续接它原来的会话。邀请时可选“手动接入”:成员不会被自动唤醒,而是得到一份私有凭据文件,由你在它的会话中按参与技能读写。自由协作房间里,手动成员执行 `member register` 之前视为不存在:不能被点名,不收请求,不进“全体各自回应”和智能调度候选;注册后与其他成员一样可被点名,其 CLI 上报会话后本机服务按软件转为托管(Claude Code、Codex、agy
|
|
28
|
+
运行中可在右侧成员栏邀请 AI(沿用本机软件配置和本房间工作目录),也可让成员离开、请回或移除。自动成员的项目文件权限默认只读;需要它修改项目时,在邀请前选择“项目文件可写”,权限只应用于这位成员;App 与手动成员的文件权限由其软件设置,API 与网页成员不访问项目文件。填写已有会话 ID 时续接该原会话,不新建。离开会立即停止它的工作;请回时换发新凭证并续接它原来的会话。邀请时可选“手动接入”:成员不会被自动唤醒,而是得到一份私有凭据文件,由你在它的会话中按参与技能读写。自由协作房间里,手动成员执行 `member register` 之前视为不存在:不能被点名,不收请求,不进“全体各自回应”和智能调度候选;注册后与其他成员一样可被点名,其 CLI 上报会话后本机服务按软件转为托管(Claude Code、Codex、agy),此后与自动成员无异;转托管时本机服务为该成员生成新凭证并由网站替换,浏览器生成的原凭证随即失效(本机不保存原凭证)。绑定你正在使用的会话的成员会标注“借用会话”:它工作时不要在原窗口继续操作。
|
|
29
29
|
|
|
30
30
|
输入 `@全体成员`(或 `@all`)等同于点名当前所有可点名成员(含主持人,不含未注册的手动成员),各自回答,主持人不汇总;成员不止一位时 @ 菜单首项提供该选项。
|
|
31
31
|
|
package/package.json
CHANGED
|
@@ -453,18 +453,16 @@ function codex_session_adapter(session_id, env = process.env) {
|
|
|
453
453
|
* Register a manual Claude or Codex expert's own session as a hosted participant, so the service resumes it for later turns.
|
|
454
454
|
* Returns the adapter used. Throws when the local software is not configured or the session is not found on this machine; the member then stays manual.
|
|
455
455
|
*/
|
|
456
|
-
export function adopt_member_profile(home, path, name, session_id, client = 'claude') {
|
|
456
|
+
export function adopt_member_profile(home, path, name, session_id, client = 'claude', member_token = '') {
|
|
457
457
|
const release = acquire_lock(join(dirname(path), 'configuration-edit'));
|
|
458
458
|
try {
|
|
459
459
|
const config = configuration_snapshot(path).config;
|
|
460
460
|
const adapter = client === 'codex' ? codex_session_adapter(session_id) : client === 'antigravity' ? 'antigravity_cli' : 'claude';
|
|
461
461
|
const input = { cwd: config.cwd, adopt: true, participants: { [name]: { adapter, session_id } } };
|
|
462
462
|
const profile = borrowed_session(name, participant_profile(name, launch_settings(home).participants, input, false), config.cwd);
|
|
463
|
-
// A free room delivers with each member's own credential;
|
|
464
|
-
const access_path = join(dirname(path), `manual-${name}.access.json`);
|
|
465
|
-
const manual_token = config.mode === 'free' && existsSync(access_path) ? JSON.parse(readFileSync(access_path, 'utf8')).token : '';
|
|
463
|
+
// A free room delivers with each member's own credential; the browser-made one is not kept locally, so the owner issues a new one.
|
|
466
464
|
const next = { ...config, participants: { ...config.participants, [name]: profile },
|
|
467
|
-
...(
|
|
465
|
+
...(member_token ? { members: { ...config.members, [name]: { token: member_token, pending: '' } } } : {}) };
|
|
468
466
|
validate_config(next, dirname(path));
|
|
469
467
|
atomic_json(path, next);
|
|
470
468
|
return adapter;
|
|
@@ -273,8 +273,9 @@ class RoomWorker {
|
|
|
273
273
|
if (member.access !== 'manual' || member.status !== 'active' || !member.registered_at || !member.reported_session || this.adopt_failed.has(key)) continue;
|
|
274
274
|
try {
|
|
275
275
|
const { adopt_member_profile } = await import('./discussion_launch.mjs');
|
|
276
|
-
const
|
|
277
|
-
|
|
276
|
+
const member_token = this.config.mode === 'free' ? `${randomUUID()}${randomUUID()}` : '';
|
|
277
|
+
const adapter = adopt_member_profile(this.home, this.path, member.name, member.reported_session, member.reported_client, member_token);
|
|
278
|
+
await api(this.config, `/members/${member.id}`, { action: 'adopt', adapter, session_id: member.reported_session, ...(member_token ? { token: member_token } : {}) });
|
|
278
279
|
this.log(`${this.config.room}: ${member.name} 已转为本机托管`);
|
|
279
280
|
} catch (error) {
|
|
280
281
|
this.adopt_failed.add(key);
|