feat(ui): refine subscription model and usage controls

This commit is contained in:
Alexandre Teixeira
2026-09-22 13:12:19 +01:00
parent ed7ccfd584
commit 411559913c
17 changed files with 1258 additions and 103 deletions
+17
View File
@@ -2135,6 +2135,14 @@ def setup_chat_routes(
from src.model_profiles import supports_user_thinking_toggle
if not supports_user_thinking_toggle(sess.model):
thinking_mode = "off"
reasoning_effort = None
req_effort = getattr(chat_request, "reasoning_effort", None)
if req_effort:
reasoning_effort = str(req_effort).strip().lower()
elif session_mode.startswith("effort:"):
reasoning_effort = session_mode[7:].strip()
from src.chatgpt_subscription import validate_reasoning_effort
reasoning_effort = validate_reasoning_effort(sess.model, reasoning_effort)
owner = effective_user(request)
_reconcile_selected_route_from_request(request, sess, session, {
"selected_model": sess.model,
@@ -2253,6 +2261,7 @@ def setup_chat_routes(
prompt_type=preset_id,
session_id=session,
thinking_mode=thinking_mode,
reasoning_effort=reasoning_effort,
)
actual_index = _candidate_index(foreground_candidates, actual_candidate)
apply_compaction_state(
@@ -2351,6 +2360,8 @@ def setup_chat_routes(
compare_mode = str(form_data.get("compare_mode", "")).lower() == "true"
thinking_mode = str(form_data.get("thinking_mode") or "").strip().lower()
thinking_mode = thinking_mode if thinking_mode in {"on", "off"} else None
raw_effort = str(form_data.get("reasoning_effort") or (body or {}).get("reasoning_effort") or "").strip().lower()
reasoning_effort = raw_effort if raw_effort else None
temperature_override = None
raw_temperature = form_data.get("temperature")
if raw_temperature not in (None, ""):
@@ -2620,6 +2631,10 @@ def setup_chat_routes(
from src.model_profiles import supports_user_thinking_toggle
if not supports_user_thinking_toggle(sess.model):
thinking_mode = "off"
if reasoning_effort is None and session_mode.startswith("effort:"):
reasoning_effort = session_mode[7:].strip()
from src.chatgpt_subscription import validate_reasoning_effort
reasoning_effort = validate_reasoning_effort(sess.model, reasoning_effort)
if getattr(sess, "temperature_override", None) is not None:
temperature_override = float(sess.temperature_override)
# A resumed session may omit workspace/cwd from the new request.
@@ -3925,6 +3940,7 @@ def setup_chat_routes(
candidate_request_factory=_chat_request_factory,
candidate_route_descriptors=_foreground_route_descriptors,
thinking_mode=thinking_mode,
reasoning_effort=reasoning_effort,
):
if chunk.startswith("data: ") and not chunk.startswith("data: [DONE]"):
try:
@@ -4368,6 +4384,7 @@ def setup_chat_routes(
exact_approval=exact_tool_approval,
client_runtime_context=client_runtime_context,
thinking_mode=thinking_mode,
reasoning_effort=reasoning_effort,
):
if chunk.startswith("data: ") and not chunk.startswith("data: [DONE]"):
try:
+51 -11
View File
@@ -1024,16 +1024,49 @@ def setup_history_routes(session_manager, upload_handler=None) -> APIRouter:
body = await request.json()
except KeyError:
raise HTTPException(404, "Session not found")
mode = str(body.get("thinking_mode") or "").lower()
if mode not in {"", "on", "off"}:
raise HTTPException(400, "Invalid thinking mode")
from src.model_profiles import supports_user_thinking_toggle
if not supports_user_thinking_toggle(session.model):
mode = "off"
temperature = body.get("temperature_override")
temperature = None if temperature in (None, "") else max(0.0, min(2.0, float(temperature)))
max_tokens = body.get("max_tokens_override")
max_tokens = None if max_tokens in (None, "", 0) else max(256, min(32768, int(max_tokens)))
mode = getattr(session, "thinking_mode", "off") or "off"
raw_effort = body.get("reasoning_effort")
if raw_effort is not None:
clean_effort = str(raw_effort).strip().lower()
if clean_effort in {"", "default"}:
mode = "off"
else:
from src.chatgpt_subscription import get_chatgpt_model_metadata
meta = get_chatgpt_model_metadata(session.model)
if meta and clean_effort in [lvl.lower() for lvl in meta.get("supported_reasoning_levels", [])]:
mode = f"effort:{clean_effort}"
else:
mode = "off"
elif "thinking_mode" in body:
raw_mode = str(body.get("thinking_mode") or "").strip().lower()
if raw_mode.startswith("effort:"):
clean_effort = raw_mode[7:].strip()
from src.chatgpt_subscription import get_chatgpt_model_metadata
meta = get_chatgpt_model_metadata(session.model)
if meta and clean_effort in [lvl.lower() for lvl in meta.get("supported_reasoning_levels", [])]:
mode = f"effort:{clean_effort}"
else:
mode = "off"
elif raw_mode in {"", "on", "off"}:
mode = raw_mode
from src.model_profiles import supports_user_thinking_toggle
if not supports_user_thinking_toggle(session.model):
mode = "off"
else:
raise HTTPException(400, "Invalid thinking mode")
if "temperature_override" in body:
temperature = body.get("temperature_override")
temperature = None if temperature in (None, "") else max(0.0, min(2.0, float(temperature)))
else:
temperature = getattr(session, "temperature_override", None)
if "max_tokens_override" in body:
max_tokens = body.get("max_tokens_override")
max_tokens = None if max_tokens in (None, "", 0) else max(256, min(32768, int(max_tokens)))
else:
max_tokens = getattr(session, "max_tokens_override", None)
db = SessionLocal()
try:
row = db.query(DbSession).filter(DbSession.id == session_id).first()
@@ -1042,7 +1075,14 @@ def setup_history_routes(session_manager, upload_handler=None) -> APIRouter:
row.thinking_mode, row.temperature_override, row.max_tokens_override = mode, temperature, max_tokens
db.commit()
session.thinking_mode, session.temperature_override, session.max_tokens_override = mode, temperature, max_tokens
return {"status": "success", "thinking_mode": mode, "temperature_override": temperature, "max_tokens_override": max_tokens}
resp_effort = mode[7:] if mode.startswith("effort:") else ("default" if mode in {"", "off"} else None)
return {
"status": "success",
"thinking_mode": mode,
"reasoning_effort": resp_effort,
"temperature_override": temperature,
"max_tokens_override": max_tokens,
}
finally:
db.close()
+7 -1
View File
@@ -1663,7 +1663,12 @@ def setup_model_routes(model_discovery):
for m in pinned:
if m not in curated:
curated.append(m)
extra = [m for m in extra if m not in pinned]
models_metadata = {}
from src.chatgpt_subscription import get_chatgpt_model_metadata
for mid in list(curated) + list(extra):
meta = get_chatgpt_model_metadata(mid)
if meta:
models_metadata[mid] = meta
items.append({
"host": "custom",
"port": 0,
@@ -1677,6 +1682,7 @@ def setup_model_routes(model_discovery):
"category": category,
"endpoint_kind": kind,
"model_type": ep_model_type,
"models_metadata": models_metadata,
})
else:
# Endpoint unreachable but still show it greyed out
+7
View File
@@ -705,6 +705,12 @@ def setup_session_routes(
session.headers = build_headers(endpoint_api_key, endpoint_base_url)
else:
session.headers = {}
if getattr(session, "thinking_mode", "").startswith("effort:"):
current_effort = session.thinking_mode[7:]
from src.chatgpt_subscription import get_chatgpt_model_metadata
meta = get_chatgpt_model_metadata(model)
if not meta or current_effort not in [lvl.lower() for lvl in meta.get("supported_reasoning_levels", [])]:
session.thinking_mode = "off"
# Persist to DB
db = SessionLocal()
try:
@@ -714,6 +720,7 @@ def setup_session_routes(
db_session.endpoint_url = endpoint_url
db_session.endpoint_id = session.endpoint_id
db_session.headers = session.headers or {}
db_session.thinking_mode = getattr(session, "thinking_mode", "off") or "off"
db_session.updated_at = utcnow_naive()
db.commit()
finally: