ai_co_discuss 0.3.60 → 0.3.61
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/web/modern.css +1 -1
- package/web/modern.js +10080 -10064
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 => {
|