feat: 支持多语言提示词本地化和界面优化
- 添加 prompt_locale 参数支持简体中文、繁体中文和英文提示词本地化 - 移除内置 agents 配置以简化系统架构 - 更新 ContextBuilder 使用动态提示词模板而非硬编码内容 - 在 AgentLoop、Web 接口和 AgentService 中传递 locale 参数 - 添加输出语言指令确保用户界面内容按指定语言生成 - 扩展前端 LanguageSwitcher 组件支持三种语言选项 - 优化 Header 和侧边栏组件的响应式布局和文本截断处理 - 更新测试用例验证不同语言环境下的提示词正确性
This commit is contained in:
@ -26,3 +26,26 @@ def test_context_builder_injects_current_date_and_time() -> None:
|
||||
assert "Local UTC offset: +08:00" in system_prompt
|
||||
assert '"today", "tomorrow", "now", "this week", and "next month"' in system_prompt
|
||||
assert result.messages[-1] == {"role": "user", "content": "今天几号?"}
|
||||
|
||||
|
||||
def test_context_builder_uses_simplified_main_agent_prompt_by_default() -> None:
|
||||
system_prompt = ContextBuilder().build_system_prompt(ContextBuildInput())
|
||||
|
||||
assert "你是海狸 (Beaver)" in system_prompt
|
||||
assert "博维资讯系统有限公司研发的 AI 助手" in system_prompt
|
||||
assert "使用简体中文进行面向用户的回复" in system_prompt
|
||||
|
||||
|
||||
def test_context_builder_uses_traditional_main_agent_prompt_for_zh_hant() -> None:
|
||||
system_prompt = ContextBuilder().build_system_prompt(ContextBuildInput(prompt_locale="zh-Hant"))
|
||||
|
||||
assert "你是海狸 (Beaver)" in system_prompt
|
||||
assert "博維資訊系統有限公司研發的 AI 助手" in system_prompt
|
||||
assert "使用繁體中文進行面向使用者的回覆" in system_prompt
|
||||
|
||||
|
||||
def test_context_builder_uses_english_main_agent_prompt_for_en() -> None:
|
||||
system_prompt = ContextBuilder().build_system_prompt(ContextBuildInput(prompt_locale="en"))
|
||||
|
||||
assert "You are Beaver, an AI assistant developed by Boway Information Systems Co., Ltd." in system_prompt
|
||||
assert "Use English for user-facing replies" in system_prompt
|
||||
|
||||
@ -15,6 +15,7 @@ class StubProvider(LLMProvider):
|
||||
def __init__(self, responses: list[LLMResponse]) -> None:
|
||||
super().__init__()
|
||||
self._responses = list(responses)
|
||||
self.seen_messages: list[list[dict]] = []
|
||||
|
||||
async def chat(
|
||||
self,
|
||||
@ -26,6 +27,7 @@ class StubProvider(LLMProvider):
|
||||
) -> LLMResponse:
|
||||
if not self._responses:
|
||||
raise AssertionError("No stubbed provider responses left")
|
||||
self.seen_messages.append(messages)
|
||||
return self._responses.pop(0)
|
||||
|
||||
def get_default_model(self) -> str:
|
||||
@ -99,6 +101,52 @@ def test_task_run_records_evidence_and_waits_for_acceptance(tmp_path: Path) -> N
|
||||
assert "validated" not in event_types
|
||||
|
||||
|
||||
def test_task_mode_injects_prompt_locale_output_language(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
workspace=tmp_path,
|
||||
task_execution_planner=StubTaskExecutionPlanner(),
|
||||
)
|
||||
)
|
||||
main_provider = StubProvider(
|
||||
[
|
||||
LLMResponse(
|
||||
content="Done",
|
||||
finish_reason="stop",
|
||||
provider_name="stub",
|
||||
model="stub-model",
|
||||
)
|
||||
]
|
||||
)
|
||||
bundle = ProviderBundle(
|
||||
main_runtime=SimpleNamespace(model="stub-model", provider_name="stub"),
|
||||
main_provider=main_provider,
|
||||
auxiliary_runtime=SimpleNamespace(model="stub-model", provider_name="stub"),
|
||||
auxiliary_provider=StubProvider([_route_response("new_task", "Product summary")]),
|
||||
)
|
||||
|
||||
result = asyncio.run(
|
||||
service.process_direct(
|
||||
"Summarize the uploaded report in English",
|
||||
session_id="web:locale-task",
|
||||
prompt_locale="en",
|
||||
provider_bundle=bundle,
|
||||
)
|
||||
)
|
||||
|
||||
assert result.task_id
|
||||
assert main_provider.seen_messages
|
||||
system_prompt = main_provider.seen_messages[-1][0]["content"]
|
||||
assert "Use English for user-facing replies" in system_prompt
|
||||
assert "Output language: English." in system_prompt
|
||||
|
||||
task_service = service.create_loop().boot().task_service
|
||||
assert task_service is not None
|
||||
task = task_service.get_task(result.task_id)
|
||||
assert task is not None
|
||||
assert task.metadata["prompt_locale"] == "en"
|
||||
|
||||
|
||||
def test_unrelated_simple_chat_auto_accepts_active_task(tmp_path: Path) -> None:
|
||||
service = AgentService(
|
||||
loader=EngineLoader(
|
||||
|
||||
@ -73,6 +73,7 @@ def test_websocket_message_returns_chat_metadata_and_session_updated() -> None:
|
||||
{
|
||||
"type": "message",
|
||||
"content": "hello",
|
||||
"prompt_locale": "zh-Hant",
|
||||
"metadata": {"source": "test"},
|
||||
"attachments": [{"file_id": "file-1", "name": "a.txt"}],
|
||||
}
|
||||
@ -89,6 +90,7 @@ def test_websocket_message_returns_chat_metadata_and_session_updated() -> None:
|
||||
"user_id": None,
|
||||
"title": None,
|
||||
"execution_context": None,
|
||||
"prompt_locale": "zh-Hant",
|
||||
"model": None,
|
||||
"provider_name": None,
|
||||
"embedding_model": None,
|
||||
@ -134,6 +136,7 @@ def test_websocket_message_uses_direct_processing_when_loop_is_not_running() ->
|
||||
"user_id": None,
|
||||
"title": None,
|
||||
"execution_context": None,
|
||||
"prompt_locale": None,
|
||||
"model": None,
|
||||
"provider_name": None,
|
||||
"embedding_model": None,
|
||||
@ -149,7 +152,10 @@ def test_rest_chat_uses_direct_processing_when_loop_is_not_running() -> None:
|
||||
app = create_app(service=service, manage_service_lifecycle=False)
|
||||
|
||||
with TestClient(app) as client:
|
||||
response = client.post("/api/chat", json={"session_id": "web:alpha", "message": "hello"})
|
||||
response = client.post(
|
||||
"/api/chat",
|
||||
json={"session_id": "web:alpha", "message": "hello", "prompt_locale": "en"},
|
||||
)
|
||||
|
||||
assert response.status_code == 200
|
||||
assert service.calls == [
|
||||
@ -160,6 +166,7 @@ def test_rest_chat_uses_direct_processing_when_loop_is_not_running() -> None:
|
||||
"user_id": None,
|
||||
"title": None,
|
||||
"execution_context": None,
|
||||
"prompt_locale": "en",
|
||||
"model": None,
|
||||
"provider_name": None,
|
||||
"embedding_model": None,
|
||||
|
||||
Reference in New Issue
Block a user