feat(routing): ô định tuyến chỉ còn Auto và Manual
Bỏ hai chế độ Off và Fallback ở ô định tuyến cạnh khung chat và ở mục Định
tuyến trong Cài đặt. Mặc định chuyển sang Auto.
- USER_ROUTING_MODES = ("auto", "manual"); giá trị off/fallback/lạ còn lưu trong
config hay project đều được hiểu là Auto (routing_mode_for,
project_routing_mode, set_*). Engine vẫn hiểu "off" khi truyền mode_override
tường minh.
- RoutingScheduler: định tuyến giờ luôn bật nên việc chấm điểm model định kỳ
luôn chạy; muốn tắt thì đặt reassess_interval_hours = 0.
- Cập nhật các test đang ghim hành vi "mặc định off".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
fefc9f94db
commit
0b6b220bd9
@@ -32,16 +32,29 @@ def _mk(ctx, name):
|
||||
def test_defaults_follow_global_when_no_override(ctx):
|
||||
a = _mk(ctx, "Alpha")
|
||||
ctx.active_project_id = a.project_id
|
||||
# Global default switch_mode is "off".
|
||||
assert ctx.project_routing_mode("cowork") == "off"
|
||||
# Global default switch_mode is "auto" (Off was removed).
|
||||
assert ctx.project_routing_mode("cowork") == "auto"
|
||||
# Change the GLOBAL default → project with no override follows it.
|
||||
ctx.config.data["routing"]["switch_mode"] = "auto"
|
||||
ctx.config.data["routing"]["switch_mode"] = "manual"
|
||||
assert ctx.project_routing_mode("cowork") == "manual"
|
||||
|
||||
|
||||
def test_legacy_off_and_fallback_resolve_to_auto(ctx):
|
||||
a = _mk(ctx, "Alpha")
|
||||
ctx.active_project_id = a.project_id
|
||||
ctx.config.data["routing"]["switch_mode"] = "manual"
|
||||
for legacy in ("off", "fallback"):
|
||||
a.routing_modes = {"cowork": legacy}
|
||||
save_project(a)
|
||||
assert ctx.project_routing_mode("cowork") == "auto"
|
||||
ctx.set_project_routing_mode("cowork", "off")
|
||||
assert ctx.project_routing_mode("cowork") == "auto"
|
||||
|
||||
|
||||
def test_per_workspace_routing_is_isolated(ctx):
|
||||
a = _mk(ctx, "Alpha")
|
||||
b = _mk(ctx, "Beta")
|
||||
ctx.config.data["routing"]["switch_mode"] = "manual"
|
||||
|
||||
ctx.active_project_id = a.project_id
|
||||
ctx.set_project_routing_mode("cowork", "auto")
|
||||
@@ -49,16 +62,19 @@ def test_per_workspace_routing_is_isolated(ctx):
|
||||
|
||||
# Switching to workspace B must NOT see A's override (falls back to global).
|
||||
ctx.active_project_id = b.project_id
|
||||
assert ctx.project_routing_mode("cowork") == "off"
|
||||
|
||||
# B sets its own, independently.
|
||||
ctx.set_project_routing_mode("cowork", "manual")
|
||||
assert ctx.project_routing_mode("cowork") == "manual"
|
||||
|
||||
# A is unchanged.
|
||||
# B sets its own, independently.
|
||||
ctx.set_project_routing_mode("cowork", "auto")
|
||||
ctx.active_project_id = a.project_id
|
||||
ctx.set_project_routing_mode("cowork", "manual")
|
||||
ctx.active_project_id = b.project_id
|
||||
assert ctx.project_routing_mode("cowork") == "auto"
|
||||
|
||||
# A keeps its own.
|
||||
ctx.active_project_id = a.project_id
|
||||
assert ctx.project_routing_mode("cowork") == "manual"
|
||||
|
||||
|
||||
def test_per_surface_isolated_within_a_workspace(ctx):
|
||||
a = _mk(ctx, "Alpha")
|
||||
@@ -68,7 +84,8 @@ def test_per_surface_isolated_within_a_workspace(ctx):
|
||||
# co4e untouched → global default.
|
||||
assert ctx.project_routing_mode("cowork") == "auto"
|
||||
assert ctx.project_routing_mode("ai_edit") == "manual"
|
||||
assert ctx.project_routing_mode("co4e") == "off"
|
||||
ctx.config.data["routing"]["switch_mode"] = "manual"
|
||||
assert ctx.project_routing_mode("co4e") == "manual"
|
||||
|
||||
|
||||
def test_routing_mode_persists_to_disk(ctx):
|
||||
|
||||
@@ -88,12 +88,21 @@ def test_best_for_returns_strong(service):
|
||||
assert ranking.best.assessment.metadata.model_id == "strong-model"
|
||||
|
||||
|
||||
def test_route_off_never_switches(service):
|
||||
def test_route_off_explicit_override_never_switches(service):
|
||||
# "off" is no longer user-selectable, but the engine still honours it
|
||||
# when passed explicitly.
|
||||
service.reassess()
|
||||
r = service.route("cowork", "Write a Python function", "anthropic", "weak-model",
|
||||
mode_override="off")
|
||||
assert r.mode == SwitchMode.OFF
|
||||
assert r.should_switch is False
|
||||
|
||||
|
||||
def test_legacy_off_in_config_routes_as_auto(service):
|
||||
service.reassess()
|
||||
service.ctx.config.data["routing"]["switch_mode"] = "off"
|
||||
r = service.route("cowork", "Write a Python function", "anthropic", "weak-model")
|
||||
assert r.mode == SwitchMode.OFF
|
||||
assert r.should_switch is False
|
||||
assert r.mode == SwitchMode.AUTO
|
||||
|
||||
|
||||
def test_route_auto_switches_to_strong(service):
|
||||
@@ -147,12 +156,12 @@ def test_route_never_raises_on_broken_store(ctx, tmp_path):
|
||||
|
||||
def test_per_surface_mode_override(service):
|
||||
service.reassess()
|
||||
service.ctx.config.data["routing"]["switch_mode"] = "off"
|
||||
service.ctx.config.data["routing"]["switch_mode"] = "manual"
|
||||
service.ctx.config.data["routing"]["surface_modes"]["co4e"] = "auto"
|
||||
# cowork follows global (off); co4e overridden to auto
|
||||
# cowork follows global (manual); co4e overridden to auto
|
||||
r_cowork = service.route("cowork", "Write a Python function", "anthropic", "weak-model")
|
||||
r_co4e = service.route("co4e", "Write a Python function", "anthropic", "weak-model")
|
||||
assert r_cowork.mode == SwitchMode.OFF
|
||||
assert r_cowork.mode == SwitchMode.MANUAL
|
||||
assert r_co4e.mode == SwitchMode.AUTO
|
||||
assert r_co4e.should_switch is True
|
||||
|
||||
|
||||
Reference in New Issue
Block a user