refactor(webui): infer fallback from active model

This commit is contained in:
chengyongru
2026-08-21 16:49:30 +08:00
committed by chengyongru
parent 7f97373490
commit 953d2ed217
9 changed files with 8 additions and 19 deletions
-1
View File
@@ -100,7 +100,6 @@ class TurnModelUpdatedEvent(OutboundEvent):
model: str model: str
model_preset: str | None = None model_preset: str | None = None
context_window_tokens: int | None = None context_window_tokens: int | None = None
is_fallback: bool = False
def outbound_message_for_event( def outbound_message_for_event(
-3
View File
@@ -1685,7 +1685,6 @@ class WebSocketChannel(BaseChannel):
model_name=event.model, model_name=event.model,
model_preset=event.model_preset, model_preset=event.model_preset,
context_window_tokens=event.context_window_tokens, context_window_tokens=event.context_window_tokens,
is_fallback=event.is_fallback,
) )
return return
if isinstance(event, UserInputEvent): if isinstance(event, UserInputEvent):
@@ -2103,7 +2102,6 @@ class WebSocketChannel(BaseChannel):
model_name: Any, model_name: Any,
model_preset: Any = None, model_preset: Any = None,
context_window_tokens: Any = None, context_window_tokens: Any = None,
is_fallback: Any = False,
) -> None: ) -> None:
"""Notify one chat's subscribers which model is handling its current request.""" """Notify one chat's subscribers which model is handling its current request."""
conns = list(self._subs.get(chat_id, ())) conns = list(self._subs.get(chat_id, ()))
@@ -2117,7 +2115,6 @@ class WebSocketChannel(BaseChannel):
"event": "turn_model_updated", "event": "turn_model_updated",
"chat_id": chat_id, "chat_id": chat_id,
"model_name": model_name.strip(), "model_name": model_name.strip(),
"is_fallback": is_fallback is True,
} }
if isinstance(model_preset, str) and model_preset.strip(): if isinstance(model_preset, str) and model_preset.strip():
body["model_preset"] = model_preset.strip() body["model_preset"] = model_preset.strip()
@@ -2061,7 +2061,6 @@ async def test_send_scopes_turn_model_updates_to_the_subscribed_chat() -> None:
model="deepseek/deepseek-chat", model="deepseek/deepseek-chat",
model_preset="Deep Research", model_preset="Deep Research",
context_window_tokens=128_000, context_window_tokens=128_000,
is_fallback=True,
), ),
) )
) )
@@ -2073,7 +2072,6 @@ async def test_send_scopes_turn_model_updates_to_the_subscribed_chat() -> None:
"model_name": "deepseek/deepseek-chat", "model_name": "deepseek/deepseek-chat",
"model_preset": "Deep Research", "model_preset": "Deep Research",
"context_window_tokens": 128_000, "context_window_tokens": 128_000,
"is_fallback": True,
} }
chat_two.send.assert_not_awaited() chat_two.send.assert_not_awaited()
-1
View File
@@ -495,7 +495,6 @@ def build_webui_fallback_model_observer(bus: MessageBus) -> FallbackModelObserve
if context.runtime is not None if context.runtime is not None
else None else None
), ),
is_fallback=True,
), ),
metadata=context.metadata, metadata=context.metadata,
) )
-2
View File
@@ -179,7 +179,6 @@ async def test_fallback_model_is_scoped_to_its_websocket_chat() -> None:
assert isinstance(outbound.event, TurnModelUpdatedEvent) assert isinstance(outbound.event, TurnModelUpdatedEvent)
assert outbound.event.model == "deepseek/deepseek-chat" assert outbound.event.model == "deepseek/deepseek-chat"
assert outbound.event.model_preset == "Deep Research" assert outbound.event.model_preset == "Deep Research"
assert outbound.event.is_fallback is True
@pytest.mark.asyncio @pytest.mark.asyncio
@@ -219,7 +218,6 @@ async def test_admitted_runtime_publishes_chat_scoped_model_and_preset(tmp_path)
assert isinstance(outbound.event, TurnModelUpdatedEvent) assert isinstance(outbound.event, TurnModelUpdatedEvent)
assert outbound.event.model == "openai-codex/gpt-5.6" assert outbound.event.model == "openai-codex/gpt-5.6"
assert outbound.event.model_preset == "Codex" assert outbound.event.model_preset == "Codex"
assert outbound.event.is_fallback is False
@pytest.mark.asyncio @pytest.mark.asyncio
+8 -5
View File
@@ -400,7 +400,7 @@ function toModelBadgeInfo(
); );
return { return {
label, label,
model: toModelBadgeLabel(model), model: model?.trim() || null,
provider, provider,
providerLabel: provider ? providerDisplayLabel(settings?.providers ?? [], provider) : null, providerLabel: provider ? providerDisplayLabel(settings?.providers ?? [], provider) : null,
needsSetup, needsSetup,
@@ -959,9 +959,12 @@ export function ThreadShell({
setFallbackModelName(null); setFallbackModelName(null);
return client.onChat(chatId, (event) => { return client.onChat(chatId, (event) => {
if (event.event !== "turn_model_updated") return; if (event.event !== "turn_model_updated") return;
setFallbackModelName(event.is_fallback ? event.model_name : null); const activeModel = event.model_name.trim();
setFallbackModelName(
modelBadge.model && activeModel !== modelBadge.model ? activeModel : null,
);
}); });
}, [chatId, client]); }, [chatId, client, modelBadge.model]);
useEffect(() => { useEffect(() => {
if (!historyKey || !chatId || loading) return; if (!historyKey || !chatId || loading) return;
@@ -1451,7 +1454,7 @@ export function ThreadShell({
: t("thread.composer.placeholderThread") : t("thread.composer.placeholderThread")
} }
modelLabel={modelBadgeLabel} modelLabel={modelBadgeLabel}
modelDetail={modelBadge.model} modelDetail={toModelBadgeLabel(modelBadge.model)}
modelPreset={activeModelPreset} modelPreset={activeModelPreset}
modelPresets={modelPresetOptions} modelPresets={modelPresetOptions}
onModelPresetChange={handleModelPresetChange} onModelPresetChange={handleModelPresetChange}
@@ -1498,7 +1501,7 @@ export function ThreadShell({
: t("thread.composer.placeholderHero") : t("thread.composer.placeholderHero")
} }
modelLabel={modelBadgeLabel} modelLabel={modelBadgeLabel}
modelDetail={modelBadge.model} modelDetail={toModelBadgeLabel(modelBadge.model)}
modelPreset={activeModelPreset} modelPreset={activeModelPreset}
modelPresets={modelPresetOptions} modelPresets={modelPresetOptions}
onModelPresetChange={handleModelPresetChange} onModelPresetChange={handleModelPresetChange}
-1
View File
@@ -1313,7 +1313,6 @@ export type InboundEvent =
chat_id: string; chat_id: string;
model_name: string; model_name: string;
model_preset?: string | null; model_preset?: string | null;
is_fallback?: boolean;
} }
| ({ | ({
event: "turn_end"; event: "turn_end";
-2
View File
@@ -1724,7 +1724,6 @@ describe("NanobotClient", () => {
chat_id: "chat-a", chat_id: "chat-a",
model_name: "deepseek/deepseek-chat", model_name: "deepseek/deepseek-chat",
model_preset: "Deep Research", model_preset: "Deep Research",
is_fallback: true,
}); });
expect(chatHandler).toHaveBeenCalledWith({ expect(chatHandler).toHaveBeenCalledWith({
@@ -1732,7 +1731,6 @@ describe("NanobotClient", () => {
chat_id: "chat-a", chat_id: "chat-a",
model_name: "deepseek/deepseek-chat", model_name: "deepseek/deepseek-chat",
model_preset: "Deep Research", model_preset: "Deep Research",
is_fallback: true,
}); });
}); });
-2
View File
@@ -720,7 +720,6 @@ describe("ThreadShell", () => {
event: "turn_model_updated", event: "turn_model_updated",
chat_id: "fallback-model", chat_id: "fallback-model",
model_name: "openai-codex/gpt-5.5", model_name: "openai-codex/gpt-5.5",
is_fallback: false,
}); });
}); });
@@ -731,7 +730,6 @@ describe("ThreadShell", () => {
event: "turn_model_updated", event: "turn_model_updated",
chat_id: "fallback-model", chat_id: "fallback-model",
model_name: "deepseek/deepseek-chat", model_name: "deepseek/deepseek-chat",
is_fallback: true,
}); });
}); });