feat(agent): migrate to native CrewAI tool loop and async resume enqueue

This commit is contained in:
zl-q
2026-03-08 16:01:16 +08:00
parent 120df903d2
commit 8a23018b6d
29 changed files with 2234 additions and 1115 deletions
@@ -25,22 +25,39 @@ from models.system_agents import SystemAgents
async def test_run_then_resume_persists_messages_and_session_state(
monkeypatch: pytest.MonkeyPatch,
) -> None:
def _fake_execute(self, *, user_input: str) -> dict[str, object]:
del user_input
return {
"assistant_text": "Mocked answer",
"prompt_tokens": 11,
"completion_tokens": 7,
"total_tokens": 18,
"cost": 0.0025,
"agui_events": [
{"type": "TEXT_MESSAGE_START", "data": {"session_id": "__TBD__"}},
{
"type": "TEXT_MESSAGE_CONTENT",
"data": {"session_id": "__TBD__", "text": "Mocked answer"},
call_count = {"n": 0}
def _fake_execute(
self,
*,
user_input: str,
system_prompt: str | None = None,
tools: list[dict[str, object]] | None = None,
) -> dict[str, object]:
del self, user_input, system_prompt, tools
call_count["n"] += 1
if call_count["n"] == 1:
return {
"assistant_text": "请确认是否跳转。",
"prompt_tokens": 11,
"completion_tokens": 7,
"total_tokens": 18,
"cost": 0.0025,
"pending_front_tool": {
"name": "front.navigate_to_route",
"args": {"target": "/calendar/dayweek", "replace": False},
"target": "frontend",
},
{"type": "TEXT_MESSAGE_END", "data": {"session_id": "__TBD__"}},
],
"agui_events": [],
}
return {
"assistant_text": "已继续执行并完成。",
"prompt_tokens": 3,
"completion_tokens": 2,
"total_tokens": 5,
"cost": 0.001,
"pending_front_tool": None,
"agui_events": [],
}
monkeypatch.setattr(
@@ -85,12 +102,17 @@ async def test_run_then_resume_persists_messages_and_session_state(
await seed_session.commit()
published: list[str] = []
queued_commands: list[dict[str, object]] = []
async def _publish(event: dict[str, object]) -> None:
event_type = event.get("type")
if isinstance(event_type, str):
published.append(event_type)
async def _enqueue(command: dict[str, object]) -> str:
queued_commands.append(command)
return "task-followup-1"
try:
run_input_payload = {
"threadId": str(session_uuid),
@@ -101,7 +123,7 @@ async def test_run_then_resume_persists_messages_and_session_state(
],
"tools": [
{
"name": "navigate_to_route",
"name": "front.navigate_to_route",
"description": "navigate route",
"parameters": {"type": "object"},
}
@@ -115,6 +137,7 @@ async def test_run_then_resume_persists_messages_and_session_state(
"run_input": run_input_payload,
},
publish_event=_publish,
enqueue_command=_enqueue,
run_service=RunService(),
resume_service=ResumeService(),
)
@@ -138,7 +161,7 @@ async def test_run_then_resume_persists_messages_and_session_state(
"toolCallId": pending_tool_call_id,
"content": json.dumps(
{
"toolName": "navigate_to_route",
"toolName": "front.navigate_to_route",
"toolArgs": {
"target": "/calendar/dayweek",
"replace": False,
@@ -158,6 +181,16 @@ async def test_run_then_resume_persists_messages_and_session_state(
},
},
publish_event=_publish,
enqueue_command=_enqueue,
run_service=RunService(),
resume_service=ResumeService(),
)
assert len(queued_commands) == 1
await run_agent_task(
queued_commands[0],
publish_event=_publish,
enqueue_command=_enqueue,
run_service=RunService(),
resume_service=ResumeService(),
)
@@ -168,8 +201,8 @@ async def test_run_then_resume_persists_messages_and_session_state(
assert db_session is not None
assert db_session.status == AgentChatSessionStatus.COMPLETED
assert db_session.message_count == 4
assert db_session.total_tokens == 18
assert db_session.total_cost == Decimal("0.002500")
assert db_session.total_tokens == 23
assert db_session.total_cost == Decimal("0.003500")
assert db_session.state_snapshot == {
"status": "completed",
"pending_tool_call_id": None,
@@ -193,6 +226,7 @@ async def test_run_then_resume_persists_messages_and_session_state(
assert messages[1].input_tokens == 11
assert messages[1].output_tokens == 7
assert messages[1].cost == Decimal("0.002500")
assert messages[3].content == "已继续执行并完成。"
assert "RUN_STARTED" in published
assert "RUN_FINISHED" in published