diff --git a/session-mechanism/scripts/collabd.py b/session-mechanism/scripts/collabd.py index 2a0c402..f896586 100644 --- a/session-mechanism/scripts/collabd.py +++ b/session-mechanism/scripts/collabd.py @@ -3758,11 +3758,22 @@ def local_user_id() -> str: return "" -# 🔴🔴 **机制另建会话时,模型该跟谁一致**(2026-10-05 用户点破 P0-80) +# 🔴🔴 **机制另建会话时,模型该跟谁一致**(2026-10-05 用户点破 P0-80;2026-10-12 修严判据) # 症状:常驻新建的 `[执行]`/`[检查]` 会话全是模型 `space-bunny`,而**主会话是 `deepseek-v4.1-flash`** # ⇒ 同一件活在两种模型上跑(能力档、思考开关全不一致)。 -# 真因:`create_check_schedule()` 的 INSERT 里**字面写死** `"space-bunny"`(把一次实测当成了永恒)。 -# ✅ 正解:**跟本区最近一条「人开的」会话取同一档** —— 模型 + 思考档一起继承。 +# 真因(10-05 那次):`create_check_schedule()` 的 INSERT 里**字面写死** `"space-bunny"`。 +# 🔴🔴 真因(2026-10-12 第二次实测):改成"跟本区最近一条**人开的**会话"后**仍然取错** —— +# 取到的是 `hy4-preview-f`,而真主会话是 `deepseek-v4.1-flash`。 +# 病根=**「人开的」(`is_background_automation <> 1`)不等于「主会话」**: +# 本区「人开的」有两条 —— `c9ba8796`「部署 TRENDRADAR 到 Docker」(10-09,`hy4-preview-f`) +# 与 `184c4986`「规划整合营销平台」(10-08,`deepseek-v4.1-flash` = 真主会话)。 +# 按 `created_at desc` 取最近 ⇒ 取到那条**人开的一次性会话** ⇒ 照抄了它的模型。 +# ⚠️ 而 `is_background_automation` 这个判据机制**自己早就注明不可用** +# (见 `_scan_mains()` 文档:接续会话本身就是自动化起的,连主会话都可能是 `bg=1`)。 +# ✅ 正解(10-12 改):**复用机制自己的「主会话候选」判据**(与 `_scan_mains()` 同源)—— +# 本区 + `parse_session_name(标题).role` 不是 `worker` + 不是退役角色标题, +# 按 **`last_activity_at desc`** 取第一条有 model 的。 +# ⇒ 判据只有一份(`_scan_mains()` 怎么认主会话,这里就怎么认),⛔ 不再另立一套。 # ⚠️ 两条建会话的路必须**同源**:常驻直连 SQLite(本函数所服务的路径)/会话侧走 `automation_update`。 # ⛔ 取不到时**必须打日志**(⛔ 不许静默回落 —— 否则又是"看着改了其实没生效")。 FALLBACK_MODEL = "space-bunny" # 兜底常量:仅当**取不到**主会话模型时才用 @@ -3772,33 +3783,41 @@ FALLBACK_THINKING = 0 def preferred_model(cwd: str = "") -> tuple: """**本区主会话用的(模型, 是否开思考)** —— 机制另建会话时照抄这个。 - 取数:`sessions` 里**人开的**(`is_background_automation <> 1`)、**本区**、**最近一条**。 - ⚠️ 排除 `bg=1` 是必须的 —— 否则会取到「机制自己上次建的那条」⇒ **自我强化**, - 永远锁死在历史值上(同 P0-77 那类"错值自我强化")。 + 取数:**复用「主会话候选」判据**(与 `_scan_mains()` 同源)—— + 本区 + 标题解析出的角色不是 `worker` + 不是退役角色标题,按 `last_activity_at desc` 取第一条有 model 的。 + ⚠️ **⛔ 不按 `is_background_automation` 筛**(10-12 实测栽过):**「人开的」≠「主会话」** —— + 人开的一次性会话会把真主会话挤掉;而接续会话本来就是自动化起的,按 bg 排会连真主会话一起排掉。 + ⚠️ **⛔ 不按 `created_at` 排**:主会话可能创建得最早却一直在用 ⇒ 按创建时间会取到别的会话。 ⚠️ `thought_level`:`disabled`/空 ⇒ 0,其余(`high`/`low`/…) ⇒ 1。 """ ws = (str(cwd or WS or os.getcwd())).replace("\\", "/").rstrip("/") try: c = _ro_conn() - r = c.execute( - "select model, thought_level from sessions " - "where (is_background_automation is null or is_background_automation <> 1) " - " and model is not null and model <> '' " - " and replace(cwd,'\\\\','/') like ? " - "order by created_at desc limit 1", ("%" + ws + "%",)).fetchone() + rows = c.execute( + "select id, cwd, coalesce(custom_title, title, ''), model, thought_level from sessions " + "where deleted_at is null order by last_activity_at desc limit 50").fetchall() c.close() except Exception as e: log("⚠️ preferred_model 取数失败(回落 %s):%s" % (FALLBACK_MODEL, e)) return FALLBACK_MODEL, FALLBACK_THINKING - if not r or not (r[0] or "").strip(): - log("⚠️ preferred_model 取不到本区主会话模型(cwd=%s)⇒ 回落 %s" - % (ws, FALLBACK_MODEL)) - return FALLBACK_MODEL, FALLBACK_THINKING - m = str(r[0]).strip() - tl = str(r[1] or "").strip().lower() - th = 0 if tl in ("", "disabled", "off", "none", "0") else 1 - log("preferred_model:本区主会话 model=%s thought=%s ⇒ 机制照抄这个(P0-80)" % (m, tl or "-")) - return m, th + for _sid, _cwd, _title, _model, _thought in (rows or []): + _t = str(_title or "") + _role = str(parse_session_name(_t).get("role") or "") + # 🔴 判据与 `_scan_mains()` 逐字同源:本区 + 非 worker + 非退役角色标题 + if not _same_ws(str(_cwd or "")): + continue + if _role in ("worker",) or is_retired_role_title(_t): + continue + m = str(_model or "").strip() + if not m: + continue # 候选里取第一条**有模型**的 + tl = str(_thought or "").strip().lower() + th = 0 if tl in ("", "disabled", "off", "none", "0") else 1 + log("preferred_model:本区主会话 %s「%s」model=%s thought=%s ⇒ 机制照抄这个(P0-80)" + % (str(_sid)[:8], _t[:24], m, tl or "-")) + return m, th + log("⚠️ preferred_model 取不到本区主会话模型(cwd=%s)⇒ 回落 %s" % (ws, FALLBACK_MODEL)) + return FALLBACK_MODEL, FALLBACK_THINKING def active_schedule_exists(name: str) -> bool: