mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 04:40:45 +08:00
Remove Manager/comprehensive mode; route everything expert-only.
Keep WhatsApp/Weixin channels intact—only drop manager dispatch UI and force expert normalization end-to-end.
This commit is contained in:
parent
cf31fd104d
commit
ff9ef7279d
11 changed files with 99 additions and 636 deletions
|
|
@ -1665,7 +1665,7 @@ async function renderStack() {
|
|||
]);
|
||||
const status = el("div", { class: "muted", text: `mode=${curMode} specialist=${curSpecialist} lang=${curLang}` });
|
||||
const saveExpertBtn = el("button", {
|
||||
class: "btn",
|
||||
class: "btn btn--primary",
|
||||
text: currentLang === "zh" ? "绑定专家" : "Bind specialist",
|
||||
onclick: async () => {
|
||||
const specialist = String(specialistSel.value || "generalist").trim() || "generalist";
|
||||
|
|
@ -1678,20 +1678,6 @@ async function renderStack() {
|
|||
status.textContent = `mode=${String(resp.interaction_mode || "expert")} specialist=${String(resp.specialist || specialist)} lang=${String(resp.lang || lang)}`;
|
||||
},
|
||||
});
|
||||
const saveComprehensiveBtn = el("button", {
|
||||
class: "btn btn--primary",
|
||||
text: currentLang === "zh" ? "综合" : "Comprehensive",
|
||||
onclick: async () => {
|
||||
const specialist = String(specialistSel.value || "generalist").trim() || "generalist";
|
||||
const lang = String(langSel.value || "auto").trim().toLowerCase() || "auto";
|
||||
const resp = await apiPost(`/admin/api/chat/settings/channel-dispatch/${encodeURIComponent(channel)}`, {
|
||||
interaction_mode: "comprehensive",
|
||||
specialist,
|
||||
lang,
|
||||
});
|
||||
status.textContent = `mode=${String(resp.interaction_mode || "comprehensive")} specialist=${String(resp.specialist || specialist)} lang=${String(resp.lang || lang)}`;
|
||||
},
|
||||
});
|
||||
return el("div", { class: "card" }, [
|
||||
el("div", { class: "card__title", text: title }),
|
||||
el("div", { class: "row" }, [
|
||||
|
|
@ -1700,10 +1686,9 @@ async function renderStack() {
|
|||
el("label", { text: currentLang === "zh" ? "语言" : "Lang" }),
|
||||
langSel,
|
||||
saveExpertBtn,
|
||||
saveComprehensiveBtn,
|
||||
]),
|
||||
status,
|
||||
el("div", { class: "muted", text: currentLang === "zh" ? "默认绑定通用专家;综合模式下由全能者分派。" : "Defaults to generalist; comprehensive mode lets manager dispatch." }),
|
||||
el("div", { class: "muted", text: currentLang === "zh" ? "通道统一走专家模式;选择默认专家即可。" : "Channels are expert-only; pick the default specialist." }),
|
||||
]);
|
||||
};
|
||||
const weixinDispatchCard = createChannelDispatchCard("weixin", "Weixin dispatch", weixinDispatchResp || {});
|
||||
|
|
@ -2320,8 +2305,8 @@ async function renderStack() {
|
|||
class: "muted",
|
||||
text:
|
||||
currentLang === "zh"
|
||||
? "任何 skill/tool/角色/提示词变更后,请立即预热;复杂变更可直接重启。综合模式下:全能者会产出 dispatch.instruction_text,并只把该指令传给专家执行。系统每10分钟自动异步预热一次。"
|
||||
: "After any skill/tool/role/prompt change, run prewarm immediately; restart for complex changes. In comprehensive mode, manager produces dispatch.instruction_text and only this instruction is sent to specialists. System also auto-prewarms every 10 minutes.",
|
||||
? "任何 skill/tool/角色/提示词变更后,请立即预热;复杂变更可直接重启。系统每10分钟自动异步预热一次。"
|
||||
: "After any skill/tool/role/prompt change, run prewarm immediately; restart for complex changes. System also auto-prewarms every 10 minutes.",
|
||||
},
|
||||
),
|
||||
el("div", { class: "row" }, [btnPrewarm]),
|
||||
|
|
@ -2584,12 +2569,10 @@ async function renderUserManagement() {
|
|||
} else {
|
||||
accountActiveInput.checked = true;
|
||||
}
|
||||
const mode = String(((inst && inst.config) || {}).interaction_mode || "expert").trim().toLowerCase();
|
||||
const specialist = String(((inst && inst.config) || {}).specialist || "generalist").trim().toLowerCase() || "generalist";
|
||||
accountSpecialistInput.value = availableAccountSpecialists.includes(specialist) ? specialist : "generalist";
|
||||
if (mode === "comprehensive") {
|
||||
accountStatus.textContent = currentLang === "zh" ? "当前账号模式:综合" : "Current account mode: comprehensive";
|
||||
}
|
||||
accountStatus.textContent =
|
||||
currentLang === "zh" ? `当前账号模式:专家(${specialist})` : `Current account mode: expert (${specialist})`;
|
||||
botSecretInput.value = "";
|
||||
clearBotChk.checked = false;
|
||||
};
|
||||
|
|
@ -2636,7 +2619,7 @@ async function renderUserManagement() {
|
|||
const deleteCell = el("td", {});
|
||||
if (inst) {
|
||||
const btnBindExpert = el("button", {
|
||||
class: "btn",
|
||||
class: "btn btn--primary",
|
||||
text: currentLang === "zh" ? "绑定专家" : "Bind specialist",
|
||||
onclick: async (e) => {
|
||||
e.stopPropagation();
|
||||
|
|
@ -2653,24 +2636,6 @@ async function renderUserManagement() {
|
|||
await loadAccounts();
|
||||
},
|
||||
});
|
||||
const btnComprehensive = el("button", {
|
||||
class: "btn btn--primary",
|
||||
text: currentLang === "zh" ? "综合" : "Comprehensive",
|
||||
onclick: async (e) => {
|
||||
e.stopPropagation();
|
||||
const specialist = String(accountSpecialistInput.value || "generalist").trim() || "generalist";
|
||||
await apiPost("/admin/api/user-channel-accounts/upsert", {
|
||||
tenant_id: tenantId,
|
||||
user_id: selectedUserId,
|
||||
channel: ch,
|
||||
account_id: accountId,
|
||||
name: displayName,
|
||||
is_active: !!inst.is_active,
|
||||
config: { interaction_mode: "comprehensive", specialist },
|
||||
});
|
||||
await loadAccounts();
|
||||
},
|
||||
});
|
||||
const btnDeleteAccount = el("button", { class: "btn btn--danger", text: t("users.accountDelete"), onclick: async (e) => {
|
||||
e.stopPropagation();
|
||||
await apiPost("/admin/api/user-channel-accounts/delete", {
|
||||
|
|
@ -2682,7 +2647,6 @@ async function renderUserManagement() {
|
|||
await loadAccounts();
|
||||
}});
|
||||
deleteCell.appendChild(btnBindExpert);
|
||||
deleteCell.appendChild(btnComprehensive);
|
||||
deleteCell.appendChild(btnDeleteAccount);
|
||||
} else {
|
||||
deleteCell.appendChild(document.createTextNode("—"));
|
||||
|
|
|
|||
|
|
@ -3361,8 +3361,8 @@ async function renderChatUi() {
|
|||
disabled: "disabled",
|
||||
});
|
||||
const composerShell = el("div", { class: "chat-composer-shell" });
|
||||
const MAIN_MODE_VALUE = "comprehensive";
|
||||
const EXCLUDED_SPECIALISTS = new Set(["main", "memory", "manager_self", "pycache", "__pycache__"]);
|
||||
const MAIN_MODE_VALUE = "generalist";
|
||||
const EXCLUDED_SPECIALISTS = new Set(["main", "memory", "manager_self", "pycache", "__pycache__", "comprehensive"]);
|
||||
let specialistCatalog = [];
|
||||
/** Hidden: mode is global-only (⋯ menu). Kept for specialist option list in `publishUserMenuPrefsBridge`. */
|
||||
const modeSelect = el("select", {
|
||||
|
|
@ -3372,6 +3372,7 @@ async function renderChatUi() {
|
|||
tabIndex: -1,
|
||||
});
|
||||
let globalMenuModeValue = String(localStorage.getItem(CHAT_USER_MENU_MODE_KEY) || MAIN_MODE_VALUE).toLowerCase();
|
||||
if (globalMenuModeValue === "comprehensive" || globalMenuModeValue === "main") globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
const modelSelect = el("select", {
|
||||
class: "input",
|
||||
style: "min-width:150px;max-width:240px;padding:6px 8px;",
|
||||
|
|
@ -3424,35 +3425,31 @@ async function renderChatUi() {
|
|||
const execSelectWrap = el("span", { class: "chat-exec-mode-wrap", style: "display:inline-flex;align-items:center;" }, [
|
||||
execSelect,
|
||||
]);
|
||||
const outboundPlanAgentVersion = () => {
|
||||
const modeVal = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
if (modeVal === MAIN_MODE_VALUE) return PLAN_AGENT_V1;
|
||||
return normalizePlanAgentVersion(currentPlanAgentVersion);
|
||||
};
|
||||
const outboundPlanAgentVersion = () => PLAN_AGENT_V1;
|
||||
const refreshExecUi = () => {
|
||||
// Plan mode removed; keep agent execution only.
|
||||
execSelectWrap.style.display = "none";
|
||||
};
|
||||
const modeOptionLabel = (v) => {
|
||||
const key = String(v || "").trim().toLowerCase();
|
||||
if (key === MAIN_MODE_VALUE) return t("chat.modeComprehensive");
|
||||
if (key === "generalist") return t("chat.specialistGeneralist");
|
||||
const row = specialistCatalog.find((x) => String(x.id || "").toLowerCase() === key);
|
||||
if (!row) return key || t("chat.modeComprehensive");
|
||||
if (!row) return key || t("chat.specialistGeneralist");
|
||||
const zh = String(row.display_name_zh || "").trim();
|
||||
const en = String(row.display_name_en || "").trim();
|
||||
return currentLang === "zh" ? (zh || en || key) : (en || zh || key);
|
||||
};
|
||||
const isSelectableSpecialist = (v) => {
|
||||
const key = String(v || "").trim().toLowerCase();
|
||||
if (!key || key === MAIN_MODE_VALUE) return false;
|
||||
if (!key || key === "comprehensive" || key === "main") return false;
|
||||
if (key === "generalist") return true;
|
||||
return specialistCatalog.some((x) => String(x.id || "").toLowerCase() === key);
|
||||
};
|
||||
const persistModeSelection = () => {
|
||||
const v = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
localStorage.setItem(CHAT_INTERACTION_MODE_KEY, v);
|
||||
if (v !== MAIN_MODE_VALUE) localStorage.setItem(CHAT_SPECIALIST_PREF_KEY, v);
|
||||
localStorage.setItem(CHAT_INTERACTION_MODE_KEY, "expert");
|
||||
localStorage.setItem(CHAT_USER_MENU_MODE_KEY, v);
|
||||
localStorage.setItem(CHAT_SPECIALIST_PREF_KEY, v);
|
||||
};
|
||||
const syncHiddenModeSelectFromGlobal = () => {
|
||||
const g = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
|
|
@ -3460,9 +3457,9 @@ async function renderChatUi() {
|
|||
else modeSelect.value = MAIN_MODE_VALUE;
|
||||
};
|
||||
const applyModeOptions = () => {
|
||||
const prev = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
let prev = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
if (prev === "comprehensive" || prev === "main") prev = MAIN_MODE_VALUE;
|
||||
modeSelect.innerHTML = "";
|
||||
modeSelect.appendChild(el("option", { value: MAIN_MODE_VALUE, text: modeOptionLabel(MAIN_MODE_VALUE) }));
|
||||
modeSelect.appendChild(el("option", { value: "generalist", text: modeOptionLabel("generalist") }));
|
||||
specialistCatalog.forEach((x) => {
|
||||
const sid = String(x.id || "").toLowerCase();
|
||||
|
|
@ -3471,6 +3468,7 @@ async function renderChatUi() {
|
|||
});
|
||||
if (Array.from(modeSelect.options).some((o) => String(o.value || "") === prev)) {
|
||||
modeSelect.value = prev;
|
||||
globalMenuModeValue = prev;
|
||||
} else {
|
||||
modeSelect.value = MAIN_MODE_VALUE;
|
||||
globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
|
|
@ -3584,11 +3582,9 @@ async function renderChatUi() {
|
|||
if (gm) {
|
||||
const gIm = String(gm.interaction_mode || "").toLowerCase();
|
||||
const gSp = String(gm.specialist || "").toLowerCase();
|
||||
if (gIm === "comprehensive") globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
else if (gIm === "expert") {
|
||||
if (isSelectableSpecialist(gSp)) globalMenuModeValue = gSp;
|
||||
else globalMenuModeValue = "generalist";
|
||||
} else globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
if (isSelectableSpecialist(gSp)) globalMenuModeValue = gSp;
|
||||
else if (isSelectableSpecialist(gIm)) globalMenuModeValue = gIm;
|
||||
else globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
} else {
|
||||
try {
|
||||
const ur = await apiGet("/admin/api/chat/user-mode");
|
||||
|
|
@ -3602,15 +3598,13 @@ async function renderChatUi() {
|
|||
ur.plan_agent_version || localStorage.getItem(CHAT_PLAN_AGENT_VERSION_KEY),
|
||||
);
|
||||
localStorage.setItem(CHAT_PLAN_AGENT_VERSION_KEY, currentPlanAgentVersion);
|
||||
if (gum === "comprehensive") globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
else if (gum === "expert") {
|
||||
if (isSelectableSpecialist(gus)) globalMenuModeValue = gus;
|
||||
else globalMenuModeValue = "generalist";
|
||||
} else globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
if (isSelectableSpecialist(gus)) globalMenuModeValue = gus;
|
||||
else if (isSelectableSpecialist(gum)) globalMenuModeValue = gum;
|
||||
else globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
}
|
||||
} catch (_) {
|
||||
if (m === "comprehensive") globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
else if (m === "expert" && isSelectableSpecialist(s)) globalMenuModeValue = s;
|
||||
if (m === "expert" && isSelectableSpecialist(s)) globalMenuModeValue = s;
|
||||
else if (isSelectableSpecialist(s)) globalMenuModeValue = s;
|
||||
else globalMenuModeValue = MAIN_MODE_VALUE;
|
||||
}
|
||||
}
|
||||
|
|
@ -3633,17 +3627,18 @@ async function renderChatUi() {
|
|||
const saveUserGlobalModePreference = async () => {
|
||||
try {
|
||||
const modeVal = String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase();
|
||||
const isMain = modeVal === MAIN_MODE_VALUE;
|
||||
const specialist = isSelectableSpecialist(modeVal) ? modeVal : MAIN_MODE_VALUE;
|
||||
const resp = await apiPost("/admin/api/chat/user-mode", {
|
||||
interaction_mode: isMain ? "comprehensive" : "expert",
|
||||
specialist: isMain ? "generalist" : modeVal,
|
||||
interaction_mode: "expert",
|
||||
specialist,
|
||||
confirm_strategy: String(currentConfirmStrategy || CONFIRM_STRATEGY_STRICT),
|
||||
plan_agent_version: String(currentPlanAgentVersion || PLAN_AGENT_V1),
|
||||
});
|
||||
if (resp && typeof resp.plan_agent_v2_globally_enabled === "boolean") {
|
||||
planAgentV2GloballyEnabled = !!resp.plan_agent_v2_globally_enabled;
|
||||
}
|
||||
localStorage.setItem(CHAT_USER_MENU_MODE_KEY, modeVal);
|
||||
localStorage.setItem(CHAT_USER_MENU_MODE_KEY, specialist);
|
||||
globalMenuModeValue = specialist;
|
||||
if (!resp || resp.ok === false) {
|
||||
const detail = String((resp && (resp.error || resp.detail)) || "unknown_error");
|
||||
throw new Error(detail);
|
||||
|
|
@ -3655,13 +3650,11 @@ async function renderChatUi() {
|
|||
if (ur && ur.ok) {
|
||||
const gum = String((ur.interaction_mode || "").toLowerCase());
|
||||
const gus = String((ur.specialist || "").toLowerCase());
|
||||
const expectedIm = isMain ? "comprehensive" : "expert";
|
||||
const expectedSp = isMain ? "generalist" : modeVal;
|
||||
if (gum !== expectedIm || gus !== expectedSp) {
|
||||
if (gum !== "expert" || gus !== specialist) {
|
||||
const msg =
|
||||
currentLang === "zh"
|
||||
? `模式未固化:后端返回 interaction_mode=${gum || "-"} specialist=${gus || "-"}(期望 ${expectedIm}/${expectedSp})`
|
||||
: `Mode not persisted: server returned interaction_mode=${gum || "-"} specialist=${gus || "-"} (expected ${expectedIm}/${expectedSp})`;
|
||||
? `模式未固化:后端返回 interaction_mode=${gum || "-"} specialist=${gus || "-"}(期望 expert/${specialist})`
|
||||
: `Mode not persisted: server returned interaction_mode=${gum || "-"} specialist=${gus || "-"} (expected expert/${specialist})`;
|
||||
showToast(msg, { kind: "error", ttlMs: 8000 });
|
||||
}
|
||||
}
|
||||
|
|
@ -5247,15 +5240,11 @@ ${autoLimit ? `<div style="margin-top:8px;"><span class="muted">auto-added claus
|
|||
sessionId: activeId,
|
||||
text: userText,
|
||||
attachments: attachmentPayload,
|
||||
interactionMode:
|
||||
String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase() === MAIN_MODE_VALUE ? "comprehensive" : "expert",
|
||||
interactionMode: "expert",
|
||||
idempotencyKey: String(turnId || ""),
|
||||
specialist:
|
||||
String(globalMenuModeValue || MAIN_MODE_VALUE).toLowerCase() === MAIN_MODE_VALUE
|
||||
? "generalist"
|
||||
: isSelectableSpecialist(String(globalMenuModeValue || "").toLowerCase())
|
||||
? String(globalMenuModeValue || "generalist").toLowerCase()
|
||||
: "generalist",
|
||||
specialist: isSelectableSpecialist(String(globalMenuModeValue || "").toLowerCase())
|
||||
? String(globalMenuModeValue || "generalist").toLowerCase()
|
||||
: "generalist",
|
||||
memoryMode: String(localStorage.getItem(CHAT_MEMORY_MODE_KEY) || "default"),
|
||||
executionMode: String(currentExecutionMode || EXECUTION_MODE_AGENT),
|
||||
signal: abortController.signal,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue