177 lines
5.5 KiB
Python
177 lines
5.5 KiB
Python
from __future__ import annotations
|
|
|
|
import unittest
|
|
from types import SimpleNamespace
|
|
|
|
from fastapi import HTTPException
|
|
from routes.assistants import _validate_startup_actions
|
|
from schemas import AssistantUpsert
|
|
from services.config_resolver import _runtime_tool_ids
|
|
|
|
|
|
def startup_body(
|
|
*,
|
|
phase: str = "opening",
|
|
bind_tool: bool = False,
|
|
) -> AssistantUpsert:
|
|
return AssistantUpsert(
|
|
name="启动动作测试",
|
|
type="prompt",
|
|
runtimeMode="pipeline",
|
|
toolIds=["tool_message"] if bind_tool else [],
|
|
startup={
|
|
"executionMode": "sequential",
|
|
"actions": [
|
|
{
|
|
"id": "opening_message",
|
|
"phase": phase,
|
|
"toolId": "tool_message",
|
|
"arguments": {
|
|
"title": "重要提示",
|
|
"message": "请确认已阅读。",
|
|
"actions": [
|
|
{
|
|
"id": "confirmed",
|
|
"label": "确认",
|
|
"style": "primary",
|
|
}
|
|
],
|
|
"dismissible": False,
|
|
},
|
|
"required": True,
|
|
}
|
|
],
|
|
},
|
|
)
|
|
|
|
|
|
class FakeSession:
|
|
def __init__(self, tool):
|
|
self.tool = tool
|
|
|
|
async def get(self, _model, tool_id):
|
|
return self.tool if self.tool is not None and tool_id == self.tool.id else None
|
|
|
|
|
|
class StartupActionValidationTests(unittest.IsolatedAsyncioTestCase):
|
|
def test_runtime_pool_includes_bound_and_startup_only_tools(self):
|
|
self.assertEqual(
|
|
_runtime_tool_ids(
|
|
["conversation_tool", "shared_tool"],
|
|
{
|
|
"actions": [
|
|
{"tool_id": "opening_tool"},
|
|
{"toolId": "shared_tool"},
|
|
]
|
|
},
|
|
),
|
|
["conversation_tool", "shared_tool", "opening_tool"],
|
|
)
|
|
|
|
def test_realtime_rejects_startup_actions(self):
|
|
with self.assertRaisesRegex(ValueError, "Realtime"):
|
|
AssistantUpsert(
|
|
name="Realtime 启动动作",
|
|
type="prompt",
|
|
runtimeMode="realtime",
|
|
startup=startup_body().startup,
|
|
)
|
|
|
|
def test_realtime_rejects_builtin_opening_message(self):
|
|
with self.assertRaisesRegex(ValueError, "Realtime"):
|
|
AssistantUpsert(
|
|
name="Realtime 开场消息",
|
|
type="prompt",
|
|
runtimeMode="realtime",
|
|
startup={
|
|
"openingMessage": {
|
|
"title": "重要提示",
|
|
"message": "请确认已阅读。",
|
|
"confirmLabel": "确认",
|
|
}
|
|
},
|
|
)
|
|
|
|
async def test_builtin_opening_message_does_not_reference_a_tool(self):
|
|
body = AssistantUpsert(
|
|
name="内置开场消息",
|
|
type="prompt",
|
|
startup={
|
|
"openingMessage": {
|
|
"title": "重要提示",
|
|
"message": "请确认已阅读。",
|
|
"confirmLabel": "确认",
|
|
}
|
|
},
|
|
)
|
|
|
|
await _validate_startup_actions(FakeSession(None), body)
|
|
|
|
self.assertEqual(body.startup.actions, [])
|
|
self.assertEqual(body.startup.opening_message.confirm_label, "确认")
|
|
|
|
async def test_startup_tool_does_not_need_conversation_binding(self):
|
|
tool = SimpleNamespace(
|
|
id="tool_message",
|
|
name="重要提示",
|
|
function_name="show_message",
|
|
type="client",
|
|
status="active",
|
|
definition={
|
|
"config": {
|
|
"wait_for_response": True,
|
|
"response_wait_mode": "session",
|
|
}
|
|
},
|
|
)
|
|
|
|
body = startup_body(bind_tool=False)
|
|
await _validate_startup_actions(FakeSession(tool), body)
|
|
self.assertEqual(body.tool_ids, [])
|
|
|
|
async def test_show_message_requires_session_wait(self):
|
|
tool = SimpleNamespace(
|
|
id="tool_message",
|
|
name="重要提示",
|
|
function_name="show_message",
|
|
type="client",
|
|
status="active",
|
|
definition={
|
|
"config": {
|
|
"wait_for_response": True,
|
|
"response_wait_mode": "timeout",
|
|
}
|
|
},
|
|
)
|
|
|
|
with self.assertRaisesRegex(HTTPException, "会话内等待"):
|
|
await _validate_startup_actions(FakeSession(tool), startup_body())
|
|
|
|
tool.definition["config"]["response_wait_mode"] = "session"
|
|
await _validate_startup_actions(FakeSession(tool), startup_body())
|
|
|
|
async def test_preflight_rejects_client_tools(self):
|
|
tool = SimpleNamespace(
|
|
id="tool_message",
|
|
name="重要提示",
|
|
function_name="show_message",
|
|
type="client",
|
|
status="active",
|
|
definition={
|
|
"config": {
|
|
"wait_for_response": True,
|
|
"response_wait_mode": "session",
|
|
}
|
|
},
|
|
)
|
|
|
|
with self.assertRaisesRegex(HTTPException, "preflight"):
|
|
await _validate_startup_actions(
|
|
FakeSession(tool),
|
|
startup_body(phase="preflight"),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|