mirror of
https://github.com/hansjone/oclaw.git
synced 2026-10-09 01:50:44 +08:00
feat: plan agent v2, global chat mode, and user-mode v2 flag sync
- Add runtime/plan_agent_v2 package and shims; gateway/direct_loop/WS wiring - Admin chat: interaction mode and specialist only in user menu; session API stores memory_mode and execution_mode only - POST /admin/api/chat/user-mode mirrors plan_agent_version to AIA_EXPERT_PLAN_AGENT_V2_ENABLED (v2 to 1, v1 to 0) - Composer cleanup (hidden mode select, no reasoning toggle in meta bar); tests and _local/system.env.example Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
ae44cbcad5
commit
37522f492a
49 changed files with 4146 additions and 238 deletions
|
|
@ -33,6 +33,7 @@ from oclaw.platform.files.file_attachments import (
|
|||
from oclaw.platform.files.session_export import export_session_json, export_session_markdown
|
||||
from oclaw.platform.persistence.sqlite_store import SqliteStore
|
||||
from oclaw.runtime.gateway import OclawGateway
|
||||
from oclaw.runtime.plan_agent_v2.switch import v2_feature_enabled
|
||||
from oclaw.runtime.types import StandardMessage, normalize_interaction_mode, normalize_requested_specialist
|
||||
from oclaw.runtime.chat.history_tool_result_compact import compact_tool_results_in_session_history
|
||||
|
||||
|
|
@ -65,7 +66,7 @@ def _wiki_root_from_config() -> Path | None:
|
|||
root = (Path(__file__).resolve().parents[2] / root).resolve()
|
||||
return root
|
||||
|
||||
_CHAT_MSG_LIMIT = 256
|
||||
_CHAT_MSG_LIMIT = 5000
|
||||
_SESSION_TITLE_MAX_LEN = 120
|
||||
_AVATAR_UPLOAD_MAX_BYTES = 2 * 1024 * 1024
|
||||
_AVATAR_MIMES = frozenset({"image/png", "image/jpeg", "image/jpg", "image/webp", "image/gif"})
|
||||
|
|
@ -698,66 +699,149 @@ def _chat_user_mode_setting_key(*, tenant_id: str, user_id: str, field: str) ->
|
|||
return f"chat.user.mode.{tenant_id}.{user_id}.{field}"
|
||||
|
||||
|
||||
def _normalize_execution_mode(payload: dict[str, Any] | None) -> str:
|
||||
body = payload or {}
|
||||
raw = str(body.get("execution_mode") or "").strip().lower()
|
||||
return raw if raw in {"agent", "plan"} else "agent"
|
||||
|
||||
|
||||
def _normalize_confirm_strategy(payload: dict[str, Any] | None) -> str:
|
||||
body = payload or {}
|
||||
raw = str(body.get("confirm_strategy") or "").strip().lower()
|
||||
return raw if raw in {"auto", "strict", "off"} else "strict"
|
||||
|
||||
|
||||
def _normalize_plan_agent_version(payload: dict[str, Any] | None) -> str:
|
||||
body = payload or {}
|
||||
raw = str(body.get("plan_agent_version") or "").strip().lower()
|
||||
return raw if raw in {"v1", "v2"} else "v1"
|
||||
|
||||
|
||||
def _resolve_user_menu_chat_settings(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
) -> tuple[str, str, str, str]:
|
||||
"""User-wide settings (⋯ menu): mode + confirm + plan/agent version — all sessions share these keys."""
|
||||
user_mode_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="interaction_mode")
|
||||
user_specialist_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="specialist")
|
||||
user_confirm_strategy_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="confirm_strategy")
|
||||
user_plan_agent_version_key = _chat_user_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, field="plan_agent_version"
|
||||
)
|
||||
mode_raw = str(store.get_setting(user_mode_key) or "").strip()
|
||||
specialist_raw = str(store.get_setting(user_specialist_key) or "").strip()
|
||||
confirm_raw = str(store.get_setting(user_confirm_strategy_key) or "").strip()
|
||||
plan_agent_raw = str(store.get_setting(user_plan_agent_version_key) or "").strip()
|
||||
interaction_mode = normalize_interaction_mode(mode_raw or "expert")
|
||||
specialist = normalize_requested_specialist(specialist_raw or "generalist")
|
||||
specialist = _apply_specialist_flags(store, specialist)
|
||||
confirm_strategy = _normalize_confirm_strategy({"confirm_strategy": (confirm_raw or "strict")})
|
||||
plan_agent_version = _normalize_plan_agent_version({"plan_agent_version": (plan_agent_raw or "v1")})
|
||||
return interaction_mode, specialist, confirm_strategy, plan_agent_version
|
||||
|
||||
|
||||
def _persist_user_menu_chat_settings(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
interaction_mode: str,
|
||||
specialist: str,
|
||||
confirm_strategy: str,
|
||||
plan_agent_version: str,
|
||||
) -> None:
|
||||
store.set_setting(
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="interaction_mode"),
|
||||
interaction_mode,
|
||||
)
|
||||
store.set_setting(
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="specialist"),
|
||||
specialist,
|
||||
)
|
||||
store.set_setting(
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="confirm_strategy"),
|
||||
confirm_strategy,
|
||||
)
|
||||
store.set_setting(
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="plan_agent_version"),
|
||||
plan_agent_version,
|
||||
)
|
||||
store.set_setting("AIA_EXPERT_PLAN_CONFIRM_STRATEGY", confirm_strategy)
|
||||
|
||||
|
||||
def _resolve_session_dialog_chat_settings(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
) -> tuple[str, str]:
|
||||
"""Per-session dialog only: memory_mode + execution_mode (session keys). Mode/specialist are user-global."""
|
||||
session_memory_mode_key = _chat_session_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="memory_mode"
|
||||
)
|
||||
session_execution_mode_key = _chat_session_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="execution_mode"
|
||||
)
|
||||
memory_raw = str(store.get_setting(session_memory_mode_key) or "").strip()
|
||||
execution_raw = str(store.get_setting(session_execution_mode_key) or "").strip()
|
||||
memory_mode = _normalize_memory_mode({"memory_mode": (memory_raw or "default")})
|
||||
execution_mode = _normalize_execution_mode({"execution_mode": (execution_raw or "agent")})
|
||||
return memory_mode, execution_mode
|
||||
|
||||
|
||||
def _persist_session_dialog_chat_settings(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
memory_mode: str,
|
||||
execution_mode: str,
|
||||
) -> None:
|
||||
store.set_setting(
|
||||
_chat_session_mode_setting_key(tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="memory_mode"),
|
||||
memory_mode,
|
||||
)
|
||||
store.set_setting(
|
||||
_chat_session_mode_setting_key(tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="execution_mode"),
|
||||
execution_mode,
|
||||
)
|
||||
|
||||
|
||||
def _resolve_mode_settings(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
) -> tuple[str, str, str]:
|
||||
"""Resolve chat mode with global-user preference first, then session fallback."""
|
||||
user_mode_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="interaction_mode")
|
||||
user_specialist_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="specialist")
|
||||
user_memory_mode_key = _chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="memory_mode")
|
||||
session_mode_key = _chat_session_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="interaction_mode"
|
||||
) -> tuple[str, str, str, str, str, str]:
|
||||
"""User-wide mode/specialist + session memory/exec + user confirm/plan_agent for gateway + REST send."""
|
||||
u_im, u_sp, u_cs, u_pav = _resolve_user_menu_chat_settings(store=store, tenant_id=tenant_id, user_id=user_id)
|
||||
s_mm, s_em = _resolve_session_dialog_chat_settings(
|
||||
store=store, tenant_id=tenant_id, user_id=user_id, session_id=str(session_id)
|
||||
)
|
||||
session_specialist_key = _chat_session_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="specialist"
|
||||
)
|
||||
session_memory_mode_key = _chat_session_mode_setting_key(
|
||||
tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="memory_mode"
|
||||
)
|
||||
|
||||
mode_raw = str(store.get_setting(user_mode_key) or "").strip() or str(store.get_setting(session_mode_key) or "").strip()
|
||||
specialist_raw = str(store.get_setting(user_specialist_key) or "").strip() or str(
|
||||
store.get_setting(session_specialist_key) or ""
|
||||
).strip()
|
||||
memory_raw = str(store.get_setting(user_memory_mode_key) or "").strip() or str(store.get_setting(session_memory_mode_key) or "").strip()
|
||||
|
||||
interaction_mode = normalize_interaction_mode(mode_raw or "expert")
|
||||
specialist = normalize_requested_specialist(specialist_raw or "generalist")
|
||||
specialist = _apply_specialist_flags(store, specialist)
|
||||
memory_mode = _normalize_memory_mode({"memory_mode": (memory_raw or "default")})
|
||||
return interaction_mode, specialist, memory_mode
|
||||
return u_im, u_sp, s_mm, s_em, u_cs, u_pav
|
||||
|
||||
|
||||
def _persist_mode_settings(
|
||||
def _seed_new_session_dialog_from_user_defaults(
|
||||
*,
|
||||
store: SqliteStore,
|
||||
tenant_id: str,
|
||||
user_id: str,
|
||||
session_id: str,
|
||||
interaction_mode: str,
|
||||
specialist: str,
|
||||
memory_mode: str,
|
||||
) -> None:
|
||||
"""Persist as global user default and current-session compatibility snapshot."""
|
||||
for key in (
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="interaction_mode"),
|
||||
_chat_session_mode_setting_key(tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="interaction_mode"),
|
||||
):
|
||||
store.set_setting(key, interaction_mode)
|
||||
for key in (
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="specialist"),
|
||||
_chat_session_mode_setting_key(tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="specialist"),
|
||||
):
|
||||
store.set_setting(key, specialist)
|
||||
for key in (
|
||||
_chat_user_mode_setting_key(tenant_id=tenant_id, user_id=user_id, field="memory_mode"),
|
||||
_chat_session_mode_setting_key(tenant_id=tenant_id, user_id=user_id, session_id=str(session_id), field="memory_mode"),
|
||||
):
|
||||
store.set_setting(key, memory_mode)
|
||||
"""New session: default memory + execution only (mode/specialist come from user menu at resolve time)."""
|
||||
_persist_session_dialog_chat_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
memory_mode=_normalize_memory_mode({"memory_mode": "default"}),
|
||||
execution_mode=_normalize_execution_mode({"execution_mode": "agent"}),
|
||||
)
|
||||
|
||||
|
||||
def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStore, str | None], dict[str, Any]]) -> None:
|
||||
|
|
@ -805,20 +889,8 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
user_id = str(ctx.get("user_id") or "")
|
||||
title = str(payload.get("title") or "").strip() or ("新会话" if _api_lang(store) == "zh" else "New Chat")
|
||||
s = store.create_session_for_user(title=title, tenant_id=tenant_id, user_id=user_id)
|
||||
interaction_mode, specialist, memory_mode = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(s.id),
|
||||
)
|
||||
_persist_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(s.id),
|
||||
interaction_mode=interaction_mode,
|
||||
specialist=specialist,
|
||||
memory_mode=memory_mode,
|
||||
_seed_new_session_dialog_from_user_defaults(
|
||||
store=store, tenant_id=tenant_id, user_id=user_id, session_id=str(s.id)
|
||||
)
|
||||
return {
|
||||
"ok": True,
|
||||
|
|
@ -885,20 +957,8 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
title=("新会话" if lang == "zh" else "New Chat"), tenant_id=tenant_id, user_id=user_id
|
||||
)
|
||||
next_id = str(ns.id)
|
||||
interaction_mode, specialist, memory_mode = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=next_id,
|
||||
)
|
||||
_persist_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=next_id,
|
||||
interaction_mode=interaction_mode,
|
||||
specialist=specialist,
|
||||
memory_mode=memory_mode,
|
||||
_seed_new_session_dialog_from_user_defaults(
|
||||
store=store, tenant_id=tenant_id, user_id=user_id, session_id=next_id
|
||||
)
|
||||
return {"ok": True, "next_session_id": next_id}
|
||||
|
||||
|
|
@ -971,6 +1031,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
@chat.get("/sessions/{session_id}/messages")
|
||||
def api_chat_messages(
|
||||
session_id: str,
|
||||
limit: int = Query(default=_CHAT_MSG_LIMIT, ge=1, le=20000),
|
||||
authorization: str | None = Header(default=None),
|
||||
) -> dict[str, Any]:
|
||||
store = SqliteStore(db_path())
|
||||
|
|
@ -981,7 +1042,7 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
if not sess:
|
||||
raise HTTPException(status_code=404, detail="session_not_found")
|
||||
meta = store.get_session_messages_meta(session_id)
|
||||
msgs = store.get_messages(session_id=session_id, limit=_CHAT_MSG_LIMIT)
|
||||
msgs = store.get_messages(session_id=session_id, limit=int(limit))
|
||||
msgs = _filter_internal_instruction_user_messages(msgs)
|
||||
return {
|
||||
"ok": True,
|
||||
|
|
@ -1151,13 +1212,26 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
sess = _resolve_chat_session(store, ctx, session_id)
|
||||
if not sess:
|
||||
raise HTTPException(status_code=404, detail="session_not_found")
|
||||
interaction_mode, specialist, memory_mode = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
s_mm, s_em = _resolve_session_dialog_chat_settings(
|
||||
store=store, tenant_id=tenant_id, user_id=user_id, session_id=str(session_id)
|
||||
)
|
||||
return {"ok": True, "interaction_mode": interaction_mode, "specialist": specialist, "memory_mode": memory_mode}
|
||||
u_im, u_sp, u_cs, u_pav = _resolve_user_menu_chat_settings(store=store, tenant_id=tenant_id, user_id=user_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"memory_mode": s_mm,
|
||||
"execution_mode": s_em,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
"plan_agent_v2_globally_enabled": bool(v2_feature_enabled(store=store)),
|
||||
"global_menu": {
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
},
|
||||
}
|
||||
|
||||
@chat.post("/sessions/{session_id}/mode")
|
||||
def api_chat_session_mode_set(
|
||||
|
|
@ -1173,20 +1247,90 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
sess = _resolve_chat_session(store, ctx, session_id)
|
||||
if not sess:
|
||||
raise HTTPException(status_code=404, detail="session_not_found")
|
||||
interaction_mode = normalize_interaction_mode(payload.get("interaction_mode"))
|
||||
specialist = normalize_requested_specialist(payload.get("specialist"))
|
||||
specialist = _apply_specialist_flags(store, specialist)
|
||||
memory_mode = _normalize_memory_mode(payload)
|
||||
_persist_mode_settings(
|
||||
execution_mode = _normalize_execution_mode(payload)
|
||||
_persist_session_dialog_chat_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
memory_mode=memory_mode,
|
||||
execution_mode=execution_mode,
|
||||
)
|
||||
s_mm, s_em = _resolve_session_dialog_chat_settings(
|
||||
store=store, tenant_id=tenant_id, user_id=user_id, session_id=str(session_id)
|
||||
)
|
||||
u_im, u_sp, u_cs, u_pav = _resolve_user_menu_chat_settings(store=store, tenant_id=tenant_id, user_id=user_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"memory_mode": s_mm,
|
||||
"execution_mode": s_em,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
"plan_agent_v2_globally_enabled": bool(v2_feature_enabled(store=store)),
|
||||
"global_menu": {
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
},
|
||||
}
|
||||
|
||||
@chat.get("/user-mode")
|
||||
def api_chat_user_mode_get(
|
||||
authorization: str | None = Header(default=None),
|
||||
) -> dict[str, Any]:
|
||||
store = SqliteStore(db_path())
|
||||
ctx = resolve_auth(store, authorization)
|
||||
tenant_id = str(ctx.get("tenant_id") or "")
|
||||
user_id = str(ctx.get("user_id") or "")
|
||||
u_im, u_sp, u_cs, u_pav = _resolve_user_menu_chat_settings(store=store, tenant_id=tenant_id, user_id=user_id)
|
||||
return {
|
||||
"ok": True,
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
"plan_agent_v2_globally_enabled": bool(v2_feature_enabled(store=store)),
|
||||
}
|
||||
|
||||
@chat.post("/user-mode")
|
||||
def api_chat_user_mode_set(
|
||||
payload: dict[str, Any] | None = Body(default=None),
|
||||
authorization: str | None = Header(default=None),
|
||||
) -> dict[str, Any]:
|
||||
payload = payload or {}
|
||||
store = SqliteStore(db_path())
|
||||
ctx = resolve_auth(store, authorization)
|
||||
tenant_id = str(ctx.get("tenant_id") or "")
|
||||
user_id = str(ctx.get("user_id") or "")
|
||||
interaction_mode = normalize_interaction_mode(payload.get("interaction_mode"))
|
||||
specialist = normalize_requested_specialist(payload.get("specialist"))
|
||||
specialist = _apply_specialist_flags(store, specialist)
|
||||
confirm_strategy = _normalize_confirm_strategy(payload)
|
||||
plan_agent_version = _normalize_plan_agent_version(payload)
|
||||
_persist_user_menu_chat_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
interaction_mode=interaction_mode,
|
||||
specialist=specialist,
|
||||
memory_mode=memory_mode,
|
||||
confirm_strategy=confirm_strategy,
|
||||
plan_agent_version=plan_agent_version,
|
||||
)
|
||||
return {"ok": True, "interaction_mode": interaction_mode, "specialist": specialist, "memory_mode": memory_mode}
|
||||
u_im, u_sp, u_cs, u_pav = _resolve_user_menu_chat_settings(store=store, tenant_id=tenant_id, user_id=user_id)
|
||||
# Mirror Plan/Agent version to the gateway feature gate (⋯ menu is the control surface).
|
||||
store.set_setting("AIA_EXPERT_PLAN_AGENT_V2_ENABLED", "1" if str(u_pav or "").strip().lower() == "v2" else "0")
|
||||
return {
|
||||
"ok": True,
|
||||
"interaction_mode": u_im,
|
||||
"specialist": u_sp,
|
||||
"confirm_strategy": u_cs,
|
||||
"plan_agent_version": u_pav,
|
||||
"plan_agent_v2_globally_enabled": bool(v2_feature_enabled(store=store)),
|
||||
}
|
||||
|
||||
@chat.get("/admin/user-stats")
|
||||
def api_chat_admin_user_stats(
|
||||
|
|
@ -1751,27 +1895,44 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
attachments = _parse_attachments_payload(payload.get("attachments"))
|
||||
interaction_mode, selected_specialist = _normalize_chat_mode(payload)
|
||||
memory_mode = _normalize_memory_mode(payload)
|
||||
execution_mode = _normalize_execution_mode(payload)
|
||||
if "interaction_mode" not in payload and "chat_mode" not in payload:
|
||||
interaction_mode, _, _ = _resolve_mode_settings(
|
||||
interaction_mode, _, _, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "specialist" not in payload:
|
||||
_, selected_specialist, _ = _resolve_mode_settings(
|
||||
_, selected_specialist, _, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "memory_mode" not in payload:
|
||||
_, _, memory_mode = _resolve_mode_settings(
|
||||
_, _, memory_mode, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "execution_mode" not in payload:
|
||||
_, _, _, execution_mode, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "plan_agent_version" not in payload:
|
||||
_, _, _, _, _, plan_agent_version = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
else:
|
||||
plan_agent_version = _normalize_plan_agent_version(payload)
|
||||
selected_specialist = _apply_specialist_flags(store, selected_specialist)
|
||||
if not text_raw and not attachments:
|
||||
raise HTTPException(status_code=400, detail="text_or_attachments_required")
|
||||
|
|
@ -1826,6 +1987,8 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
"interaction_mode": interaction_mode,
|
||||
"selected_specialist": selected_specialist,
|
||||
"memory_mode": memory_mode,
|
||||
"execution_mode": execution_mode,
|
||||
"plan_agent_version": plan_agent_version,
|
||||
},
|
||||
)
|
||||
gw_result = gw.handle_turn(
|
||||
|
|
@ -1869,27 +2032,44 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
attachments = _parse_attachments_payload(payload.get("attachments"))
|
||||
interaction_mode, selected_specialist = _normalize_chat_mode(payload)
|
||||
memory_mode = _normalize_memory_mode(payload)
|
||||
execution_mode = _normalize_execution_mode(payload)
|
||||
if "interaction_mode" not in payload and "chat_mode" not in payload:
|
||||
interaction_mode, _, _ = _resolve_mode_settings(
|
||||
interaction_mode, _, _, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "specialist" not in payload:
|
||||
_, selected_specialist, _ = _resolve_mode_settings(
|
||||
_, selected_specialist, _, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "memory_mode" not in payload:
|
||||
_, _, memory_mode = _resolve_mode_settings(
|
||||
_, _, memory_mode, _, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "execution_mode" not in payload:
|
||||
_, _, _, execution_mode, _, _ = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
if "plan_agent_version" not in payload:
|
||||
_, _, _, _, _, plan_agent_version = _resolve_mode_settings(
|
||||
store=store,
|
||||
tenant_id=tenant_id,
|
||||
user_id=user_id,
|
||||
session_id=str(session_id),
|
||||
)
|
||||
else:
|
||||
plan_agent_version = _normalize_plan_agent_version(payload)
|
||||
selected_specialist = _apply_specialist_flags(store, selected_specialist)
|
||||
if not text_raw and not attachments:
|
||||
raise HTTPException(status_code=400, detail="text_or_attachments_required")
|
||||
|
|
@ -1933,6 +2113,8 @@ def include_chat_routes(router: APIRouter, *, resolve_auth: Callable[[SqliteStor
|
|||
"interaction_mode": interaction_mode,
|
||||
"selected_specialist": selected_specialist,
|
||||
"memory_mode": memory_mode,
|
||||
"execution_mode": execution_mode,
|
||||
"plan_agent_version": plan_agent_version,
|
||||
}
|
||||
|
||||
_DONE = object()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue