ai_co_discuss 0.2.32 → 0.2.34
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/SKILL.md +2 -1
- package/backend/free_room.py +86 -20
- package/backend/room_import.py +11 -2
- package/backend/schema.sql +35 -4
- package/backend/server.py +66 -10
- package/docs/architecture.md +8 -2
- package/docs/cli.md +1 -1
- package/docs/runner.md +11 -6
- package/docs/workflow.md +157 -150
- package/package.json +1 -1
- package/runner/api_participant.mjs +4 -2
- package/runner/discuss.py +5 -0
- package/runner/discussion_launch.mjs +22 -2
- package/runner/discussion_runner.mjs +149 -36
- package/runner/discussion_service.mjs +19 -0
- package/runner/free_runner.mjs +24 -28
- package/runner/scheduler.mjs +67 -15
- package/web/app.js +29 -9
- package/web/modern.css +1 -1
- package/web/modern.js +1229 -988
package/web/app.js
CHANGED
|
@@ -38,7 +38,7 @@ const PLATFORM_IDENTITIES = {
|
|
|
38
38
|
};
|
|
39
39
|
const IDENTITIES = by_platform(PLATFORM_IDENTITIES, (identity, name) => ({ ...identity, label: name, description: "AI 实例" }));
|
|
40
40
|
const state = { rooms: [], folders: [], room: null, page: 1, pages: 1, query: "", mention_only: false, free_notice: "", free_error: "",
|
|
41
|
-
free_proxy: "", create_parent: null,
|
|
41
|
+
free_proxy: "", create_parent: null, named_followup: false,
|
|
42
42
|
archive_view: false, directory_sort: "manual", management: null, dragged_room: null, folder_moves: new Map(), folder_version: 0,
|
|
43
43
|
reply_to: null, turn_reply_to: null, tab: "topic", refresh_version: 0, context_dirty: false, topic_dirty: false,
|
|
44
44
|
snapshot_id: 0, pending_submission: null, pending_turn: null, pending_room: null, toast_timer: null,
|
|
@@ -841,6 +841,7 @@ function reset_create_form() {
|
|
|
841
841
|
state.launch.create = true;
|
|
842
842
|
state.launch.workspace = {};
|
|
843
843
|
state.launch.scheduler = {};
|
|
844
|
+
state.named_followup = false;
|
|
844
845
|
state.launch.profiles = JSON.parse(JSON.stringify(state.launch.saved_profiles || {}));
|
|
845
846
|
Object.values(state.launch.profiles).forEach(fill_api_key);
|
|
846
847
|
state.launch.notice = "";
|
|
@@ -945,7 +946,7 @@ async function invite_member({ name, access, project_access = "read", session_id
|
|
|
945
946
|
finish_member_request(room_id, token, record, result);
|
|
946
947
|
if (state.room?.id === room_id) {
|
|
947
948
|
state.free_notice = access === "online" ? `${record.member.name} 已加入,阅读通知与真实回答由你或授权主持人转交。`
|
|
948
|
-
: access === "manual" ? `${record.member.name}
|
|
949
|
+
: access === "manual" ? `${record.member.name} 已加入;点它的“复制启动指令”,粘贴到你要用的 AI 会话即可。`
|
|
949
950
|
: record.options?.session_id ? `${record.member.name} 已接入原会话;它工作时请不要在原窗口继续操作。`
|
|
950
951
|
: state.room.mode === "free" ? `${record.member.name} 已加入,之后点名它即会由本机服务唤醒。`
|
|
951
952
|
: `${record.member.name} 已加入讨论,主持人会重新安排发言。`;
|
|
@@ -1342,7 +1343,7 @@ function room_creation_payload(folder_id) {
|
|
|
1342
1343
|
// Free rooms carry their task in the conversation, so no opening brief is sent even if one was typed for a discussion.
|
|
1343
1344
|
if (element("new-room-kind").value === "free") return { ...common, user_request: "", mode: "free", host: common.host || "用户" };
|
|
1344
1345
|
return { ...common, mode: "brainstorm", background: element("new-room-background").value,
|
|
1345
|
-
boundaries: element("new-room-boundaries").value, runtime_mode: "automatic", limits: read_limits("new-room"),
|
|
1346
|
+
boundaries: element("new-room-boundaries").value, runtime_mode: "automatic", limits: read_limits("new-room"), named_followup: state.named_followup,
|
|
1346
1347
|
...(state.create_parent ? { parent_room_id: state.create_parent } : {}) };
|
|
1347
1348
|
}
|
|
1348
1349
|
|
|
@@ -1436,8 +1437,8 @@ async function local_launch_request(action, payload) {
|
|
|
1436
1437
|
response = await fetch(`${local_connection?.endpoint || ""}/api/local/${action}`, {
|
|
1437
1438
|
method: payload === undefined ? "GET" : "POST", headers, credentials: "omit", redirect: "error",
|
|
1438
1439
|
body: payload === undefined ? undefined : JSON.stringify(payload),
|
|
1439
|
-
...(payload === undefined || ["room-models", "models", "api-check"].includes(action)
|
|
1440
|
-
? { signal: AbortSignal.timeout(["models", "api-check"].includes(action) ? MODEL_CATALOG_TIMEOUT_MS : LOCAL_CONNECTION_TIMEOUT_MS) } : {}) });
|
|
1440
|
+
...(payload === undefined || ["room-models", "models", "api-check", "scheduler-check"].includes(action)
|
|
1441
|
+
? { signal: AbortSignal.timeout(["models", "api-check", "scheduler-check"].includes(action) ? MODEL_CATALOG_TIMEOUT_MS : LOCAL_CONNECTION_TIMEOUT_MS) } : {}) });
|
|
1441
1442
|
} catch (error) {
|
|
1442
1443
|
if (!local_connection) throw error;
|
|
1443
1444
|
throw new Error("无法连接本机服务:请在这台电脑运行 codiscuss local open,并允许浏览器访问本机网络,再重试原请求");
|
|
@@ -1758,6 +1759,12 @@ function creation_launch_options() {
|
|
|
1758
1759
|
return { ...launch_options(), ...(enabled && provider && model && api_key_ref ? { scheduler: { provider, model, api_key_ref } } : {}) };
|
|
1759
1760
|
}
|
|
1760
1761
|
|
|
1762
|
+
/** Choose whether the new discussion's host writes named follow-ups for each expert between rounds. */
|
|
1763
|
+
function write_named_followup(value) {
|
|
1764
|
+
state.named_followup = Boolean(value);
|
|
1765
|
+
publish_view();
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1761
1768
|
/** Change the smart scheduling draft; a new provider starts from its preset model and any key saved for its root. */
|
|
1762
1769
|
function write_scheduler(field, value) {
|
|
1763
1770
|
const scheduler = state.launch.scheduler;
|
|
@@ -1771,6 +1778,12 @@ function write_scheduler(field, value) {
|
|
|
1771
1778
|
publish_view();
|
|
1772
1779
|
}
|
|
1773
1780
|
|
|
1781
|
+
/** Ask the local service to send the decision model one tiny question; throws its reason on failure. */
|
|
1782
|
+
async function check_scheduler() {
|
|
1783
|
+
const { provider, model, api_key_ref } = state.launch.scheduler;
|
|
1784
|
+
await local_launch_request("scheduler-check", { provider, model, api_key_ref });
|
|
1785
|
+
}
|
|
1786
|
+
|
|
1774
1787
|
/** Save the scheduling provider's key to the local private store, under that provider's official root. */
|
|
1775
1788
|
async function save_scheduler_api_key(api_key) {
|
|
1776
1789
|
const scheduler = state.launch.scheduler;
|
|
@@ -2193,7 +2206,7 @@ ${instruction}
|
|
|
2193
2206
|
/** How a manual member learns it is its turn: free rooms are pulled by the member, discussions only on the host's assignment. */
|
|
2194
2207
|
function manual_trigger_instruction(room) {
|
|
2195
2208
|
return room.mode === "free" ? "首次复制后,可由人工或软件原生定时触发;自行提交,不必每轮复制回答。"
|
|
2196
|
-
: "这是全自动讨论:只在主持人给你安排发言时才参与,先核对 turn current
|
|
2209
|
+
: "这是全自动讨论:只在主持人给你安排发言时才参与,先核对 turn current 是否轮到你,再按参与技能认领发言权并提交;没有安排就结束本次检查。首次提交后,若你运行在 Claude Code 中,本机服务会自动接管你的会话并在后续轮次唤醒你;未被接管时才需要你或软件原生定时触发。";
|
|
2197
2210
|
}
|
|
2198
2211
|
|
|
2199
2212
|
/** Download a private per-room setup file for the independent local runner. */
|
|
@@ -2260,6 +2273,13 @@ async function convert_suggestion({ message_id, member_id }) {
|
|
|
2260
2273
|
await refresh_room();
|
|
2261
2274
|
}
|
|
2262
2275
|
|
|
2276
|
+
/** Adopt smart scheduling's recommendation: interrupt the host now, or ask the member once the host is done. */
|
|
2277
|
+
async function adopt_recommendation({ message_id, mode }) {
|
|
2278
|
+
const room_id = state.room.id;
|
|
2279
|
+
await request_json(`/api/rooms/${room_id}/recommendations/${message_id}`, { action: "adopt", mode });
|
|
2280
|
+
if (state.room?.id === room_id) await refresh_room();
|
|
2281
|
+
}
|
|
2282
|
+
|
|
2263
2283
|
/** A completed creation starts the next form with fresh mode defaults. */
|
|
2264
2284
|
function reset_creation_mode() {
|
|
2265
2285
|
state.creation_mode = "brainstorm";
|
|
@@ -2869,7 +2889,7 @@ function view_snapshot() {
|
|
|
2869
2889
|
free_notice: state.free_notice, free_error: state.free_error, free_proxy: state.free_proxy,
|
|
2870
2890
|
create_parent: state.create_parent, access: access_snapshot(),
|
|
2871
2891
|
tab: state.tab, snapshot_id: state.snapshot_id, context_dirty: state.context_dirty,
|
|
2872
|
-
theme: document.documentElement.dataset.theme, fields, experts, launch: structuredClone(state.launch) };
|
|
2892
|
+
theme: document.documentElement.dataset.theme, fields, experts, launch: structuredClone(state.launch), named_followup: state.named_followup };
|
|
2873
2893
|
}
|
|
2874
2894
|
|
|
2875
2895
|
/** Update a shared draft using the same input events as the original controls. */
|
|
@@ -3041,7 +3061,7 @@ async function execute_view_action(name, value) {
|
|
|
3041
3061
|
choose_runtime, 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, force_close, conclude_discussion,
|
|
3042
3062
|
save_launch_defaults, launch_current_room, resume_launch, discard_launch, retry_launch_connection, check_launch_connection: load_launch_settings,
|
|
3043
3063
|
load_room_configuration, save_room_configuration, interrupt_member, change_member, invite_member, interrupt_free, set_proxy, copy_online_notice,
|
|
3044
|
-
prepare_brainstorm, return_conclusion, convert_suggestion,
|
|
3064
|
+
prepare_brainstorm, return_conclusion, convert_suggestion, adopt_recommendation,
|
|
3045
3065
|
busy: () => { throw new Error("上一个操作仍在处理中,请稍候;长时间无响应请刷新页面"); },
|
|
3046
3066
|
copy_reading: () => copy_text(`${location.origin}/r/${state.room.id}`), copy: copy_text };
|
|
3047
3067
|
if (!["refresh", "busy"].includes(name)) state.free_error = "";
|
|
@@ -3064,7 +3084,7 @@ function change_view_theme(theme) {
|
|
|
3064
3084
|
|
|
3065
3085
|
window.discuss_view = { snapshot: view_snapshot, write_field: write_view_field,
|
|
3066
3086
|
write_launch: write_launch_field, write_room_connection, write_room_adapter, launch_clients: LAUNCH_CLIENTS,
|
|
3067
|
-
launch_model_state, load_launch_models, write_launch_model, save_launch_api_key, write_scheduler, save_scheduler_api_key, check_launch_api, launch_summary, launch_can_set_access, launch_can_bind_session, pick_launch_directory, restore_launch_profile, reset_create_form, empty_discussion_message,
|
|
3087
|
+
launch_model_state, load_launch_models, write_launch_model, save_launch_api_key, write_scheduler, save_scheduler_api_key, check_scheduler, write_named_followup, check_launch_api, launch_summary, launch_can_set_access, launch_can_bind_session, pick_launch_directory, restore_launch_profile, reset_create_form, empty_discussion_message,
|
|
3068
3088
|
start_drag: start_directory_drag,
|
|
3069
3089
|
attachment_markup, attachment_size, attachment_file_icon, drop_attachments, paste_attachments,
|
|
3070
3090
|
write_expert: write_view_expert, add_instance: add_view_instance, platform_of, execute: execute_view_action, theme: change_view_theme,
|