ai_co_discuss 0.2.61 → 0.2.62
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 +1 -1
- package/docs/runner.md +1 -1
- package/package.json +1 -1
- package/runner/free_runner.mjs +2 -2
- package/runner/scheduler.mjs +5 -3
- package/web/modern.css +1 -1
- package/web/modern.js +4 -4
package/backend/free_room.py
CHANGED
|
@@ -691,7 +691,7 @@ def adopt_recommendation(connection, room_id, token, message_id, payload):
|
|
|
691
691
|
mode = payload["mode"]
|
|
692
692
|
if mode == "interrupt" and route["status"] == "delivering":
|
|
693
693
|
# The host's execution may carry other messages too; stopping it voids that whole execution.
|
|
694
|
-
finish_execution(connection, route["execution_id"], "cancelled", "
|
|
694
|
+
finish_execution(connection, route["execution_id"], "cancelled", "智能调度改派,改由其他成员回答", "cancelled")
|
|
695
695
|
elif mode == "interrupt" and route["status"] == "pending":
|
|
696
696
|
connection.execute("UPDATE member_requests SET status='cancelled' WHERE id=?", (route["id"],))
|
|
697
697
|
connection.execute("UPDATE member_recommendations SET status='waiting',mode=? WHERE message_id=?", (mode, message_id))
|
package/docs/runner.md
CHANGED
|
@@ -328,7 +328,7 @@ Codex 要求 CLI 0.163.0 或更新版本,使用 permission profiles 和本地
|
|
|
328
328
|
|
|
329
329
|
新建房间面板始终显示“智能调度”,可选供应商(TypeSafe Jev 的 `POST /v1/systemone`,或 OpenAI Decisions 的 `POST /v1/decisions`)、模型(预设 `jev-latest` / `gpt-6-luna`)并填写密钥。密钥经 `api-key` 保存到服务目录,绑定供应商官方根地址;密钥旁的闪电按钮调用 `scheduler-check`(`codiscuss launch scheduler-check`),向决策模型发一道是非题核对供应商、模型与密钥。启动请求只带 `scheduler: {provider, model, api_key_ref}`,`validate_config` 核对密钥存在后写入私有房间配置。只在本次由本机服务启动时可开启(自由房间至少有一位本机唤醒成员,讨论须勾选“创建后立即启动”),否则选项禁用并说明原因。目前只能在建房时开启,已建房间不能中途开启或关闭。
|
|
330
330
|
|
|
331
|
-
`runner/scheduler.mjs` 用中立的题目(`choice` 带选项,`predicate` 为是非题)组装两家的请求,并把答案统一为 `{choice, confidence, probabilities}` 或 `{probability}`。上下文是房间标题、目标与用户原文、最近 10
|
|
331
|
+
`runner/scheduler.mjs` 用中立的题目(`choice` 带选项,`predicate` 为是非题)组装两家的请求,并把答案统一为 `{choice, confidence, probabilities}` 或 `{probability}`。上下文是房间标题、目标与用户原文、最近 10 条消息(自由房间的路由判断为 20 条;每条截断到 600 字)和待处理的那条用户消息。把握程度取所选项的概率(缺失时才用 `confidence`;Jev 的两项选择 `confidence` 明显低于该概率,实测概率 0.82 时只有 0.64),阈值 0.7。讨论中的判断(留言、下一位发言人、下一轮)另带当前焦点、主持简报(前 1200 字)、主持人最近的安排,下一位发言人还带本轮已发言/未发言名单,并多问一道是非题“是否有明确依据要求候选人发言”(简报分工或流程轮到、或被点名追问;仅“本轮还没发言”不算),低于 0.7 即交回主持人,因为主持人预排的安排用完可能是有意结束;选项描述写明各选项的适用条件,“交给主持人”只在偏离目标、卡住或候选都不合适时选。每次调用计时,毫秒数写入决策记录 detail 的 `duration_ms`,决策卡片显示“耗时”;主持人安排卡片的耗时为上一条回答到安排保存的间隔,两种卡片样式一致。请求 30 秒超时,错误只报 HTTP 状态,不含响应正文或密钥。
|
|
332
332
|
|
|
333
333
|
- **自由房间(推荐,用户决定)**:未点名的消息照常交给主持人,判断在后台进行,不阻塞本次检查和任何投递。每条 `route` 请求只判断一次,选项为各位本机唤醒的非主持成员(描述为软件与项目读写权限)和“交回主持人”;只有选中成员且 `confidence ≥ 0.7` 时,才用 `POST recommendations` 记录推荐,并随即由接入程序以 `adopt` + `interrupt` 自动采纳:打断主持人,改由该成员回答,自动采纳失败时保留原推荐与 60 秒倒计时,用户仍可手动选“打断主持人”或“主持人答完后再回答”。每次判断(含交回主持人)都用房主凭据写入 `POST scheduler-decisions`(`kind` 为 `interjection`,`after_message_id` 为该用户消息),在消息下显示为“智能调度:改由 B 回答 / 交给主持人 A”及置信度;房主可点 👍 / 👎 评价(`POST scheduler-decisions/ID`,`rating` 为 `good` / `bad` / `null` 撤回);评为 👎 时可再选填“应该由谁回答”(`should_be`)和不超过 200 字的说明(`note`)。评价存于 `scheduler_feedback`,每条判断产生时的模型、阈值、提示词版本(`ROUTE_PROMPT_VERSION`,改动题目或选项描述时递增)和包版本存于 `scheduler_decision_context`;两者随房间备份导出与导入,用于日后跨版本校准 0.7 阈值。判断失败、超时或置信度不足时不显示推荐,行为与未开启相同。
|
|
334
334
|
- **讨论房间(有把握即执行)**:投递主持事件前先只读判断,置信度 ≥ 0.7 才执行,否则照常唤醒主持人:
|
package/package.json
CHANGED
package/runner/free_runner.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { appendFileSync, mkdirSync, readFileSync, statSync } from 'node:fs';
|
|
|
5
5
|
import { join, resolve } from 'node:path';
|
|
6
6
|
import { atomic_json, deliver_task, sidecar_receipt, TASK_SUBCOMMANDS } from './discussion_adapters.mjs';
|
|
7
7
|
import { api } from './discussion_runner.mjs';
|
|
8
|
-
import { ROUTE_CONFIDENCE, ROUTE_PROMPT_VERSION, route_free_message } from './scheduler.mjs';
|
|
8
|
+
import { ROUTE_CONFIDENCE, ROUTE_CONTEXT_MESSAGES, ROUTE_PROMPT_VERSION, route_free_message } from './scheduler.mjs';
|
|
9
9
|
|
|
10
10
|
const PACKAGE_VERSION = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf8')).version;
|
|
11
11
|
const RENEW_MS = 30_000;
|
|
@@ -183,7 +183,7 @@ export class FreeRoomRunner {
|
|
|
183
183
|
}
|
|
184
184
|
/** Decide one message; a confident pick is recorded and applied, otherwise the host keeps it. */
|
|
185
185
|
async recommend(request, room, host, members) {
|
|
186
|
-
const page = await api(this.config, `/messages?after=${Math.max(0, request.message_id -
|
|
186
|
+
const page = await api(this.config, `/messages?after=${Math.max(0, request.message_id - ROUTE_CONTEXT_MESSAGES - 1)}`);
|
|
187
187
|
const message = page.messages.find(item => item.id === request.message_id);
|
|
188
188
|
if (!message) return;
|
|
189
189
|
const decision = await route_free_message(this.config.api_home, this.config.scheduler,
|
package/runner/scheduler.mjs
CHANGED
|
@@ -14,6 +14,8 @@ export const ROUTE_PROMPT_VERSION = 2;
|
|
|
14
14
|
const HOST_CHOICE = '__host__';
|
|
15
15
|
const NOTE_CHOICE = '__note__';
|
|
16
16
|
const CONTEXT_MESSAGES = 10;
|
|
17
|
+
/** A free-room route sees a longer stretch, enough to tell who has not spoken for a while. */
|
|
18
|
+
export const ROUTE_CONTEXT_MESSAGES = 20;
|
|
17
19
|
const MAX_MESSAGE_CHARS = 600;
|
|
18
20
|
const MAX_BRIEF_CHARS = 1200;
|
|
19
21
|
|
|
@@ -108,8 +110,8 @@ function topic_lines(title, goal, user_request, { brief, focus, arrangement, pro
|
|
|
108
110
|
}
|
|
109
111
|
|
|
110
112
|
/** State shared by both uses: the room, a few earlier messages, and the message to place. */
|
|
111
|
-
export function scheduler_state(title, context, message, goal = '', user_request = '', extra = {}) {
|
|
112
|
-
const earlier = context.filter(item => item.id < message.id).slice(-
|
|
113
|
+
export function scheduler_state(title, context, message, goal = '', user_request = '', extra = {}, limit = CONTEXT_MESSAGES) {
|
|
114
|
+
const earlier = context.filter(item => item.id < message.id).slice(-limit).map(excerpt);
|
|
113
115
|
return [topic_lines(title, goal, user_request, extra), earlier.length ? `近期消息(旧→新):\n${earlier.join('\n')}` : '近期没有其他消息。', `待处理的用户消息:\n${excerpt(message)}`].join('\n\n');
|
|
114
116
|
}
|
|
115
117
|
|
|
@@ -129,7 +131,7 @@ export function certainty(answer) {
|
|
|
129
131
|
export async function route_free_message(home, scheduler, { title, goal, context, message, host, members }, fetch_impl) {
|
|
130
132
|
const choices = [...members.map(member => ({ value: member.name, description: member.description })),
|
|
131
133
|
{ value: HOST_CHOICE, description: `交回主持人 ${host}:需要拆分任务、多人协作,或消息与任何成员都无关` }];
|
|
132
|
-
const answers = await decide(home, scheduler, scheduler_state(title, context, message, goal), [{ type: 'choice', name: 'handler',
|
|
134
|
+
const answers = await decide(home, scheduler, scheduler_state(title, context, message, goal, '', {}, ROUTE_CONTEXT_MESSAGES), [{ type: 'choice', name: 'handler',
|
|
133
135
|
instructions: '这条用户消息没有用 @ 点名成员,但正文可能直接提到某位成员的名字或在向其提问(如“某某在吗”),此时应选该成员。判断它能否直接交给一位成员独立处理;需要主持人先理解、拆分或协调时选交回主持人。', choices }], fetch_impl);
|
|
134
136
|
const answer = answers.handler || {};
|
|
135
137
|
const confidence = certainty(answer);
|