ai_co_discuss 0.3.14 → 0.3.16
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 +14 -6
- package/docs/en/workflow.md +1 -1
- package/docs/workflow.md +1 -1
- package/package.json +1 -1
- package/runner/free_runner.mjs +2 -2
- package/runner/scheduler.mjs +7 -4
- package/web/app.js +2 -2
- package/web/modern.css +1 -1
- package/web/modern.js +407 -380
package/backend/free_room.py
CHANGED
|
@@ -1709,7 +1709,8 @@ def route_group(connection, room_id, group, payload):
|
|
|
1709
1709
|
|
|
1710
1710
|
|
|
1711
1711
|
def route_wide(connection, room_id, message_id, payload):
|
|
1712
|
-
"""Smart scheduling answers an unnamed message with everyone (each member once, as if the user named them all
|
|
1712
|
+
"""Smart scheduling answers an unnamed message with everyone (each member once, as if the user named them all, at once
|
|
1713
|
+
or one after another), the few members it names, or no one.
|
|
1713
1714
|
|
|
1714
1715
|
A message naming everyone (a group request) is answered by all at once or, with action sequential, one after another.
|
|
1715
1716
|
Only a host request that has not started changes; a started host already handles the message its own way.
|
|
@@ -1725,16 +1726,23 @@ def route_wide(connection, room_id, message_id, payload):
|
|
|
1725
1726
|
ORDER BY id DESC LIMIT 1""", (room_id, message_id)).fetchone()
|
|
1726
1727
|
if group:
|
|
1727
1728
|
return route_group(connection, room_id, group, payload)
|
|
1728
|
-
if action
|
|
1729
|
-
raise ValueError("
|
|
1730
|
-
if action not in ("all", "none", "some"):
|
|
1731
|
-
raise ValueError("未点名消息只能选 action=all、some 或 none")
|
|
1729
|
+
if action == "host":
|
|
1730
|
+
raise ValueError("只有请全体成员回应的消息可以交回主持人")
|
|
1731
|
+
if action not in ("all", "sequential", "none", "some"):
|
|
1732
|
+
raise ValueError("未点名消息只能选 action=all、sequential、some 或 none")
|
|
1732
1733
|
route = host_route_request(connection, message_id)
|
|
1733
1734
|
if not route or route["room_id"] != room_id:
|
|
1734
1735
|
raise LookupError("只能处理交给主持人的未点名消息")
|
|
1735
1736
|
if route["status"] != "pending":
|
|
1736
1737
|
raise FileExistsError("主持人已开始处理这条消息,不再改派")
|
|
1737
|
-
if action == "
|
|
1738
|
+
if action == "sequential":
|
|
1739
|
+
# Same as a group answered one after another: the host's request gives way to the queue, which includes the host.
|
|
1740
|
+
connection.execute("DELETE FROM member_requests WHERE id=?", (route["id"],))
|
|
1741
|
+
members = connection.execute(f"SELECT id FROM room_members WHERE room_id=? AND status='active' AND {REGISTERED_MEMBER}", (room_id,))
|
|
1742
|
+
queue_in_turn(connection, room_id, message_id, [row["id"] for row in members])
|
|
1743
|
+
connection.execute("INSERT INTO group_routes (message_id,room_id,request_id,action) VALUES (?,?,?,?)",
|
|
1744
|
+
(message_id, room_id, route["id"], action))
|
|
1745
|
+
elif action == "none":
|
|
1738
1746
|
record_cancel_reasons(connection, "id=?", (route["id"],), "no_reply")
|
|
1739
1747
|
connection.execute("UPDATE member_requests SET status='cancelled' WHERE id=?", (route["id"],))
|
|
1740
1748
|
elif action == "some":
|
package/docs/en/workflow.md
CHANGED
|
@@ -57,7 +57,7 @@ The discussion ends as soon as a limit is reached and returns to free collaborat
|
|
|
57
57
|
|
|
58
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
59
|
|
|
60
|
-
- Unaddressed messages go to the member they are clearly meant for, to everyone, or to no one; otherwise to the host.
|
|
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
61
|
- Without Smart Scheduling, `@全体成员` runs everyone together. With it, uncertain or failed decisions go to the host. `@全体依次` always uses the established speaking order.
|
|
62
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
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.
|
package/docs/workflow.md
CHANGED
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
|
|
55
55
|
建房时可在“智能调度”下添加一个决策模型(TypeSafe Jev;OpenAI Decisions 为实验性),用你自己的密钥按次计费。开启后,常规分派由决策模型判断,不必每次唤醒主持人:
|
|
56
56
|
|
|
57
|
-
-
|
|
57
|
+
- 未点名的消息:明确对某位成员说时直接交给他,或请全体同时回答、按发言顺序依次回答(如接龙、报数)、无需回应;其余仍交给主持人。
|
|
58
58
|
- `@全体成员`:未配置时同时回答;配置后判断同时或依次,拿不准或调用失败时交主持人。`@全体依次` 始终按既定顺序回答。
|
|
59
59
|
- 讨论中:局部追问转为不计轮次的普通提问,可追问已发言者或主持人,保留原讨论队列;轮次之间选出下一位发言人。没有智能调度时,主持人也可按同一方式转交。
|
|
60
60
|
- 主持人预先指定了实现后的只读评审时:整批交付完成后可交给既定评审者。它只判断交付完成度,不判断代码对错、不另选评审者;评审后仍交回主持人。
|
package/package.json
CHANGED
package/runner/free_runner.mjs
CHANGED
|
@@ -143,7 +143,7 @@ function member_work(requests, name, message_id) {
|
|
|
143
143
|
function route_host_label(decision, host, members) {
|
|
144
144
|
if (decision.choice === '__host__' || decision.confidence === null) return `交给主持人 ${host}`;
|
|
145
145
|
const group = some_members(decision.choice);
|
|
146
|
-
const lean = decision.choice === '__all__' ? '全体各自回应' : decision.choice === '__none__' ? '无需回应' : group ? `请 ${group.join('、')} 各自回应`
|
|
146
|
+
const lean = decision.choice === '__all__' ? '全体各自回应' : decision.choice === '__all_seq__' ? '全体依次回应' : decision.choice === '__none__' ? '无需回应' : group ? `请 ${group.join('、')} 各自回应`
|
|
147
147
|
: members.some(member => member.name === decision.choice) ? `请 ${decision.choice} 回答` : '';
|
|
148
148
|
return lean ? `倾向${lean},把握不足,交给主持人 ${host}` : `交给主持人 ${host}`;
|
|
149
149
|
}
|
|
@@ -526,7 +526,7 @@ export class FreeRoomRunner {
|
|
|
526
526
|
const applied = await api(this.config, `/recommendations/${message.id}`, { action: decision.action, ...(decision.members ? { members: decision.members } : {}) })
|
|
527
527
|
.then(() => true, error => { this.log(`智能调度 #${message.id} 未能改派:${error.message}`); return false; });
|
|
528
528
|
const names = described.map(member => member.name).join('、');
|
|
529
|
-
const label = decision.action === 'all' ? `请全体各自回应(${names})` : decision.action === 'some' ? `请 ${decision.members.join('、')} 各自回应` : '无需回应,未唤醒任何成员';
|
|
529
|
+
const label = decision.action === 'all' ? `请全体各自回应(${names})` : decision.action === 'sequential' ? '请全体按发言顺序依次回应' : decision.action === 'some' ? `请 ${decision.members.join('、')} 各自回应` : '无需回应,未唤醒任何成员';
|
|
530
530
|
return this.record_route(request, decision, applied ? label : `${label}(未生效,仍由主持人处理)`, applied);
|
|
531
531
|
}
|
|
532
532
|
try {
|
package/runner/scheduler.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export const ROUTE_PROMPT_VERSION = 13;
|
|
|
30
30
|
export const SCHEDULER_MODES = { guided: '引导(试验)', stable: '稳定' };
|
|
31
31
|
export const DEFAULT_SCHEDULER_MODE = 'guided';
|
|
32
32
|
/** The guided wording has its own version, so its ratings are never mixed with the stable checklist's. */
|
|
33
|
-
export const ROUTE_GUIDED_PROMPT_VERSION =
|
|
33
|
+
export const ROUTE_GUIDED_PROMPT_VERSION = 8;
|
|
34
34
|
/** The routing prompt version that a decision in this mode was made with. */
|
|
35
35
|
export function route_prompt_version(mode) {
|
|
36
36
|
return mode === 'stable' ? ROUTE_PROMPT_VERSION : ROUTE_GUIDED_PROMPT_VERSION;
|
|
@@ -50,6 +50,7 @@ export const MAX_REVIEW_INPUT = 60000;
|
|
|
50
50
|
const HOST_CHOICE = '__host__';
|
|
51
51
|
const NOTE_CHOICE = '__note__';
|
|
52
52
|
const ALL_CHOICE = '__all__';
|
|
53
|
+
const ALL_SEQUENTIAL_CHOICE = '__all_seq__';
|
|
53
54
|
const NONE_CHOICE = '__none__';
|
|
54
55
|
/** Prefix of the "only these few" options; the value lists the names after it, joined by SOME_JOINER. */
|
|
55
56
|
export const SOME_PREFIX = '__some__:';
|
|
@@ -220,7 +221,7 @@ const ROUTE_GUIDED_GUIDE = ['这是 AI CoDiscuss 的协作房间。用户是房
|
|
|
220
221
|
'唤醒一位成员要花一次执行,通常几十秒;交给了不对的人,就得打断后重来。'].join('\n');
|
|
221
222
|
const ROUTE_GUIDED_STEM = '用户发来上面这条消息,没有 @ 任何人。请你像熟悉这个房间的成员一样读懂它:用户想让谁来回应?'
|
|
222
223
|
+ '用户心里已经有明确的对象时,直接交给对方,省掉主持人转一手的时间;需要有人先理解、拆分或协调时交给主持人。'
|
|
223
|
-
+ '
|
|
224
|
+
+ '用户想听每个人各自说一句时,交给全体能让大家同时开始,比主持人逐个点名快得多;但大家看不到彼此的回答。每人只需按顺序接着前一位说一次时,交给全体依次回应;需要互相接话、讨论的事仍要主持人安排。用户只是表示收到或感谢时,不必唤醒任何人。'
|
|
224
225
|
+ '两种容易看错的情况:向在场的各位问好,是在等每个人回一声,和只对房间说一句“hi”不同;用户问“谁是……”“谁能……”时是在找符合条件的人,只需要符合的人出来回应(哪怕说“自己说一下”),成员信息里(含主持人)只有一位符合就交给他。';
|
|
225
226
|
|
|
226
227
|
/** The routing question in one mode: option texts, the stem, and what the state adds about the members. */
|
|
@@ -254,13 +255,14 @@ function route_question(mode, host, members, text) {
|
|
|
254
255
|
...named_groups(text, host, members).map(group => ({ value: `${SOME_PREFIX}${group.join(SOME_JOINER)}`,
|
|
255
256
|
description: `只请 ${group.join('、')} 各自回应一次:同时开始,每人都收到这句原话,彼此看不到对方的回答,其他成员不被唤醒` })),
|
|
256
257
|
{ value: ALL_CHOICE, description: '全体成员(含主持人)同时收到这句原话,各自回应一次,彼此看不到对方的回答,也不会被分到不同的任务' },
|
|
258
|
+
{ value: ALL_SEQUENTIAL_CHOICE, description: '全体成员(含主持人)按房间发言顺序逐个回应这句原话,每人一次:前一位答完下一位才开始,后一位能看到前面所有人的回答;比同时回应慢,也不会被分到不同的任务' },
|
|
257
259
|
{ value: NONE_CHOICE, description: '不唤醒任何人,用户这句话不会得到回应' }] };
|
|
258
260
|
}
|
|
259
261
|
|
|
260
262
|
/**
|
|
261
263
|
* Decide who answers one unnamed free-room message: whether its addressee is already settled by the text or the thread.
|
|
262
264
|
* Members are [{name, description}] without the host; host is {name, description}. Returns action member (with member),
|
|
263
|
-
* all, none, or host for anything unsettled or not confident enough.
|
|
265
|
+
* all, sequential (guided only), some, none, or host for anything unsettled or not confident enough.
|
|
264
266
|
*/
|
|
265
267
|
export async function route_free_message(home, scheduler, { title, goal, context, message, host, members }, fetch_impl) {
|
|
266
268
|
const { choices, instructions, extra } = route_question(scheduler.mode || DEFAULT_SCHEDULER_MODE, host, members, message.text);
|
|
@@ -272,10 +274,11 @@ export async function route_free_message(home, scheduler, { title, goal, context
|
|
|
272
274
|
const confidence = certainty(answers.handler);
|
|
273
275
|
// Waking several members, everyone or no one costs more when wrong than moving the message to one member.
|
|
274
276
|
const group = some_members(choice);
|
|
275
|
-
const wide =
|
|
277
|
+
const wide = [ALL_CHOICE, ALL_SEQUENTIAL_CHOICE, NONE_CHOICE].includes(choice) || Boolean(group);
|
|
276
278
|
const limits = scheduler_thresholds(scheduler.mode || DEFAULT_SCHEDULER_MODE);
|
|
277
279
|
const sure = confidence !== null && confidence >= (wide ? limits.wide : limits.member);
|
|
278
280
|
if (sure && choice === ALL_CHOICE) return { action: 'all', choice, confidence, ...judged };
|
|
281
|
+
if (sure && choice === ALL_SEQUENTIAL_CHOICE) return { action: 'sequential', choice, confidence, ...judged };
|
|
279
282
|
if (sure && choice === NONE_CHOICE) return { action: 'none', choice, confidence, ...judged };
|
|
280
283
|
if (sure && group) return { action: 'some', members: group, choice, confidence, ...judged };
|
|
281
284
|
if (sure && members.some(item => item.name === choice)) return { action: 'member', member: choice, choice, confidence, ...judged };
|
package/web/app.js
CHANGED
|
@@ -4112,7 +4112,7 @@ async function execute_view_action(name, value) {
|
|
|
4112
4112
|
export_runtime, download_member_access, copy_member_access_text, copy_member_join, copy_member_launch: name => copy_member_join(name, true), pause_runtime, check_limits, pause_discussion, restart_discussion, conclude_discussion, start_room_discussion, end_room_discussion, reopen_discussion,
|
|
4113
4113
|
save_launch_defaults, launch_current_room, resume_launch, discard_launch, retry_launch_connection, check_launch_connection: load_launch_settings,
|
|
4114
4114
|
load_room_configuration, save_room_configuration, interrupt_member, retry_delivery, retract_message, retract_latest, stop_room, rewind_and_send, fork_room, change_member, reorder_speakers, invite_member, set_proxy, copy_online_notice,
|
|
4115
|
-
prepare_brainstorm, return_conclusion, adopt_recommendation, rate_decision,
|
|
4115
|
+
prepare_brainstorm, return_conclusion, adopt_recommendation, rate_decision,
|
|
4116
4116
|
busy: () => { throw new Error("上一个操作仍在处理中,请稍候;长时间无响应请刷新页面"); },
|
|
4117
4117
|
copy_reading: () => copy_text(`${location.origin}/r/${state.room.id}`), copy: copy_text };
|
|
4118
4118
|
try {
|
|
@@ -4130,7 +4130,7 @@ function change_view_theme(theme) {
|
|
|
4130
4130
|
try { localStorage.setItem(THEME_STORAGE_KEY, document.documentElement.dataset.theme); } catch { /* Keep the session preference. */ }
|
|
4131
4131
|
}
|
|
4132
4132
|
|
|
4133
|
-
window.discuss_view = { snapshot: view_snapshot, write_field: write_view_field, notify,
|
|
4133
|
+
window.discuss_view = { snapshot: view_snapshot, write_field: write_view_field, notify, load_decision_input,
|
|
4134
4134
|
write_launch: write_launch_field, default_launch_entry, description_template, save_description_template, description_draft, write_description_draft, describe_member, set_chain_rounds, continue_chain, expert_presets, apply_expert_preset, unique_instance, member_label, preset_identity, save_expert_preset, delete_expert_preset, write_room_connection, write_room_adapter, launch_clients: LAUNCH_CLIENTS,
|
|
4135
4135
|
launch_model_state, load_launch_models, write_launch_model, save_launch_api_key, write_scheduler, save_scheduler_api_key, check_scheduler, write_named_followup, write_create_discussion, write_create_chain_rounds, check_launch_api, launch_summary, launch_can_set_access, pick_launch_directory, browse_local_directory, save_launch_projects, restore_launch_profile, reset_create_form, empty_discussion_message,
|
|
4136
4136
|
start_drag: start_directory_drag, reconnect: reconnect_live_updates, stop_label,
|