refactor: 重构聊天模块支持 SSE 断线重连及用户上下文隔离

This commit is contained in:
zl-q
2026-03-30 09:06:10 +08:00
parent 1aac62f39e
commit 4285b4ec80
28 changed files with 1624 additions and 658 deletions
@@ -12,10 +12,8 @@ from schemas.agent.runtime_models import (
ResultType,
ResultTyping,
RouterAgentOutput,
RouterUiDecision,
TaskType,
TaskTyping,
UiMode,
WorkerAgentOutputLite,
)
from schemas.agent.system_agent import AgentType
@@ -65,10 +63,6 @@ def test_build_worker_input_messages_only_contains_router_contract() -> None:
task_typing=TaskTyping(primary=TaskType.SCHEDULING),
execution_mode=ExecutionMode.TOOL_ASSISTED,
result_typing=ResultTyping(primary=ResultType.EXECUTION_REPORT),
ui=RouterUiDecision(
ui_mode=UiMode.NONE,
ui_decision_reason="单一执行任务,文本输出足够",
),
)
input_messages = runner._build_worker_input_messages(router_output=router_output)
@@ -239,10 +233,6 @@ async def test_execute_runs_router_then_worker(
task_typing=TaskTyping(primary=TaskType.SCHEDULING),
execution_mode=ExecutionMode.TOOL_ASSISTED,
result_typing=ResultTyping(primary=ResultType.EXECUTION_REPORT),
ui=RouterUiDecision(
ui_mode=UiMode.NONE,
ui_decision_reason="单任务",
),
)
async def _fake_execute_worker_step(**kwargs: object) -> WorkerAgentOutputLite:
@@ -308,10 +298,6 @@ async def test_execute_raises_cancelled_error_before_worker_when_cancel_requeste
task_typing=TaskTyping(primary=TaskType.SCHEDULING),
execution_mode=ExecutionMode.TOOL_ASSISTED,
result_typing=ResultTyping(primary=ResultType.EXECUTION_REPORT),
ui=RouterUiDecision(
ui_mode=UiMode.NONE,
ui_decision_reason="单任务",
),
)
async def _fake_execute_worker_step(**kwargs: object) -> WorkerAgentOutputLite:
@@ -0,0 +1,64 @@
from __future__ import annotations
from typing import Any
from core.agentscope.runtime.ui_compiler import compile as compile_ui
from schemas.agent.ui_schema import UiStatus, build_status_panel
from schemas.agent.ui_hints import UiHintsPayload
def _collect_badge_labels(node: Any) -> list[str]:
labels: list[str] = []
if isinstance(node, dict):
if node.get("type") == "badge" and isinstance(node.get("label"), str):
labels.append(node["label"])
for value in node.values():
labels.extend(_collect_badge_labels(value))
elif isinstance(node, list):
for item in node:
labels.extend(_collect_badge_labels(item))
return labels
def test_compile_status_badge_uses_stable_status_token() -> None:
hints = UiHintsPayload.model_validate(
{
"intent": "status",
"status": "success",
"title": "日程已创建",
"body": "已为您创建提醒。",
}
)
schema = compile_ui(hints)
badge_labels = _collect_badge_labels(schema)
assert "ui.status.success" in badge_labels
def test_compile_status_badge_does_not_emit_uppercase_legacy_label() -> None:
hints = UiHintsPayload.model_validate(
{
"intent": "status",
"status": "error",
"title": "创建失败",
"body": "请稍后重试。",
}
)
schema = compile_ui(hints)
badge_labels = _collect_badge_labels(schema)
assert "ERROR" not in badge_labels
assert "ui.status.error" in badge_labels
def test_build_status_panel_uses_stable_status_token_label() -> None:
panel = build_status_panel(
title="已创建",
message="提醒创建成功",
status=UiStatus.SUCCESS,
)
badge_labels = _collect_badge_labels(panel)
assert "ui.status.success" in badge_labels