ai_co_discuss 0.3.60 → 0.3.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/docs/runner.md +3 -3
- package/package.json +1 -1
- package/runner/discussion_launch.mjs +30 -5
- package/runner/scheduler.mjs +2 -2
- package/web/modern.css +1 -1
- package/web/modern.js +10083 -10067
package/docs/runner.md
CHANGED
|
@@ -75,11 +75,11 @@ codiscuss local connect https://你的站点
|
|
|
75
75
|
之后:
|
|
76
76
|
- 设备在浏览器里保存一把不可导出的设备密钥,之后打开网站直接可用。网站只认电脑签过名的设备名单,没有能被盗用的账号密码。
|
|
77
77
|
- 每台设备授权 30 天,到期前用通行密钥续期。勾选“临时设备”的只授权 1 天,用于借来的电脑。
|
|
78
|
-
-
|
|
79
|
-
-
|
|
78
|
+
- 新设备只能在电脑前添加,已配对设备不能远程添加。设备丢失时,在其他已配对设备或电脑上解绑它;只有一台外出设备时,回到电脑前解绑并重新配对。
|
|
79
|
+
- 每台设备的记录按钮(时钟图标)列出电脑为它记下的配对、解绑、每日确认和远程操作(不含内容);已解绑设备的记录汇总在列表末尾。看到不是你做的操作,立即解绑对应设备。
|
|
80
80
|
- 清除浏览器数据会删掉设备密钥,需要回到电脑前重新配对。
|
|
81
81
|
|
|
82
|
-
**每日确认**:每台设备每天第一次打开网页时,用面容、指纹或设备密码确认一次,之后 24
|
|
82
|
+
**每日确认**:每台设备每天第一次打开网页时,用面容、指纹或设备密码确认一次,之后 24 小时内建房、发消息、设置任意权限档(含可写、全放开)都不再询问。配对和续期本身也算一次确认。解绑设备只阻止之后的远程操作,已经在运行的工作和已改动的文件不会因此撤回。
|
|
83
83
|
|
|
84
84
|
配对后目录“协作房间”直接列出电脑上的房间,与在电脑上看到的一致,可以发消息、上传附件、管理成员、导出备份,并实时更新。对话只保存在电脑上,网站只转交加密内容。
|
|
85
85
|
|
package/package.json
CHANGED
|
@@ -251,19 +251,44 @@ export function pick_directory({ platform = process.platform, spawn_process = sp
|
|
|
251
251
|
/** Some CLIs take seconds to list models; reuse a good list for a day unless the executable changes or the user retries. */
|
|
252
252
|
const MODEL_CACHE_MS = 24 * 60 * 60 * 1000;
|
|
253
253
|
|
|
254
|
+
/** The executable's size and modification time, so a reinstalled or updated CLI is read again. */
|
|
255
|
+
function executable_stamp(profile) {
|
|
256
|
+
try { const file = statSync(profile.executable); return `${file.size}:${file.mtimeMs}`; } catch { return ''; }
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* The model and effort a software runs with when the card leaves them empty. One read from its own settings is
|
|
261
|
+
* cheap and always fresh; one that must run the CLI (agy) is kept for a day, because each run may refresh the
|
|
262
|
+
* software's login and, when that refresh fails, it opens a browser sign-in. `refresh` reads it again.
|
|
263
|
+
*/
|
|
264
|
+
export async function cached_software_defaults(home, profile, { refresh = false, query = software_defaults } = {}) {
|
|
265
|
+
if (!adapter_profile(profile.adapter)?.defaults_by_query) return query(profile);
|
|
266
|
+
const path = join(home, 'model-catalogs.json');
|
|
267
|
+
const key = JSON.stringify([profile.adapter, profile.executable || '', executable_stamp(profile), 'defaults']);
|
|
268
|
+
let cache = {};
|
|
269
|
+
try { cache = JSON.parse(readFileSync(path, 'utf8')); } catch {}
|
|
270
|
+
const entry = cache[key];
|
|
271
|
+
if (!refresh && entry && Date.now() - entry.at < MODEL_CACHE_MS) return entry.result;
|
|
272
|
+
const result = await query(profile);
|
|
273
|
+
if (result?.model) {
|
|
274
|
+
try { cache = JSON.parse(readFileSync(path, 'utf8')); } catch {}
|
|
275
|
+
atomic_json(path, { ...cache, [key]: { at: Date.now(), result } });
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
|
|
254
280
|
/** Return the software catalog, served from the private service home when still valid. */
|
|
255
281
|
export async function cached_software_models(home, profile, { refresh = false, query = software_models, query_effort = software_effort, query_defaults = software_defaults } = {}) {
|
|
256
282
|
const path = join(home, 'model-catalogs.json');
|
|
257
|
-
|
|
258
|
-
try { const file = statSync(profile.executable); stamp = `${file.size}:${file.mtimeMs}`; } catch {}
|
|
283
|
+
const stamp = executable_stamp(profile);
|
|
259
284
|
const key = JSON.stringify([profile.adapter, profile.executable || '', stamp]);
|
|
260
285
|
const effort_key = JSON.stringify([profile.adapter, profile.executable || '', stamp, 'effort', profile.model || '']);
|
|
261
286
|
let cache = {};
|
|
262
287
|
try { cache = JSON.parse(readFileSync(path, 'utf8')); } catch {}
|
|
263
288
|
const cached = entry => !refresh && entry && Date.now() - entry.at < MODEL_CACHE_MS ? entry.result : null;
|
|
264
|
-
// Defaults are read on every request, so a changed software setting shows without waiting out the cache.
|
|
265
289
|
const [result, effort, defaults] = await Promise.all([cached(cache[key]) || query(profile),
|
|
266
|
-
adapter_profile(profile.adapter)?.efforts_per_model ? cached(cache[effort_key]) || query_effort(profile) : null,
|
|
290
|
+
adapter_profile(profile.adapter)?.efforts_per_model ? cached(cache[effort_key]) || query_effort(profile) : null,
|
|
291
|
+
cached_software_defaults(home, profile, { refresh, query: query_defaults })]);
|
|
267
292
|
const updates = {};
|
|
268
293
|
if (!cached(cache[key]) && !result.error && result.models.length) {
|
|
269
294
|
updates[key] = { at: Date.now(), result };
|
|
@@ -291,7 +316,7 @@ export function launch_settings(home) {
|
|
|
291
316
|
* `actual_model` / `actual_effort` (present only when known) are what each member's session last ran with, read from the software's own session log.
|
|
292
317
|
* With `quick`, agy's default model is not queried and its entry is marked `defaults_pending`.
|
|
293
318
|
*/
|
|
294
|
-
export async function room_models(home, raw, { read_defaults =
|
|
319
|
+
export async function room_models(home, raw, { read_defaults = profile => cached_software_defaults(home, profile), read_session = session_settings } = {}) {
|
|
295
320
|
const input = launch_input({ ...raw, entry: 'web' });
|
|
296
321
|
if (!input.room_id) throw new Error('读取本场模型须提供 room_id');
|
|
297
322
|
const paths = read_registry(home).filter(path => {
|
package/runner/scheduler.mjs
CHANGED
|
@@ -30,7 +30,7 @@ export const ROUTE_PROMPT_VERSION = 14;
|
|
|
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 = 10;
|
|
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;
|
|
@@ -225,7 +225,7 @@ const ROUTE_GUIDED_GUIDE = ['这是 AI CoDiscuss 的协作房间。用户是房
|
|
|
225
225
|
const ROUTE_GUIDED_STEM = '用户发来上面这条消息,没有 @ 任何人。请你像熟悉这个房间的成员一样读懂它:用户想让谁来回应?'
|
|
226
226
|
+ '用户心里已经有明确的对象时,直接交给对方,省掉主持人转一手的时间;需要有人先理解、拆分或协调时交给主持人。'
|
|
227
227
|
+ '用户想听每个人各自说一句时,交给全体能让大家同时开始,比主持人逐个点名快得多;但大家看不到彼此的回答。每人只需按顺序接着前一位说一次时,交给全体依次回应;需要互相接话、讨论的事仍要主持人安排。用户只是表示收到或感谢时,不必唤醒任何人。'
|
|
228
|
-
+ '
|
|
228
|
+
+ '两种容易看错的情况:用“你们”“大家”“各位”这类指所有人的称呼问好,是在等每个人回一声,和不带称呼地对房间说一句“hi”“你好”不同;用户问“谁是……”“谁能……”时是在找符合条件的人,只需要符合的人出来回应(哪怕说“自己说一下”),成员信息里(含主持人)只有一位符合就交给他。';
|
|
229
229
|
|
|
230
230
|
/** The routing question in one mode: option texts, the stem, and what the state adds about the members. */
|
|
231
231
|
/** Every group of two or more among the members the text names, so "these few each answer" is one choice. */
|