| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586 |
- import asyncio
- import json
- from pathlib import Path
- from uuid import UUID, uuid4
- from sqlalchemy import func, select
- from test_after_sales import scenario # noqa: F401
- from zhifu.modules.after_sales.models import Approval, OrderProjection, Ticket
- from zhifu.modules.agent_runtime.budget_callback import CallAllowance
- from zhifu.modules.agent_runtime.config import AgentSettings
- from zhifu.modules.agent_runtime.models import AgentRun, ModelAttempt
- from zhifu.modules.agent_runtime.worker import execute_one
- from zhifu.modules.identity.auth import now
- def reserve_allowance():
- # 独占预留文件限制本专项的实际外呼总数,失败后不会自动再次执行。
- with Path(".work/clarification-allowance.json").open("x", encoding="utf-8") as stream:
- json.dump({"reserved_requests": 3, "automatic_retries": 0}, stream)
- async def test_real_model_waits_for_order_and_reason(scenario): # noqa: F811
- sessions, state = scenario["app"].state.sessions, scenario["app"].state.state
- async with sessions() as session:
- assert await session.scalar(select(func.count()).select_from(AgentRun).where(
- AgentRun.status.in_(["QUEUED", "RUNNING"]))) == 0
- for role in ("agent", "memory"):
- async for _ in state.scan_iter(match=f"monitor:worker:{role}:*"):
- raise RuntimeError("模型补问专项要求停止其他生成工作进程")
- async with sessions.begin() as session:
- session.add(OrderProjection(
- id=uuid4().bytes, tenant_id=scenario["tenant"].bytes, store_id=scenario["store"].bytes,
- subject_id=scenario["accounts"]["customer"].bytes, source_system="acceptance",
- source_version=1, item_id="keyboard-2", product_type="keyboard", available_quantity=1,
- signed_at=now(), observed_at=now(),
- ))
- await asyncio.to_thread(reserve_allowance)
- allowance, run_id = CallAllowance(3), None
- call = scenario["call"]
- try:
- async with asyncio.timeout(100):
- response = await call("POST", "/openapi/v1/agent/runs", payload={
- "store_id": str(scenario["store"]),
- "message": "我想换货,请查询我的订单让我选择,我还没有说明故障原因。",
- })
- assert response.status_code == 202, response.text
- run_id = UUID(response.json()["run_id"])
- assert await execute_one(sessions, state,
- AgentSettings(max_output_tokens=512, model_timeout=30),
- scenario["app"].state.knowledge.search, allowance=allowance)
- path = f"/openapi/v1/agent/runs/{run_id}"
- response = await call("GET", path)
- view = response.json()
- assert view["status"] == "WAITING_USER", response.text
- assert len(view["waiting"]["candidate_orders"]) == 2
- assert {"order_id", "reason"} <= set(view["waiting"]["missing_fields"])
- async with sessions() as session:
- for model in (Approval, Ticket):
- assert await session.scalar(select(func.count()).select_from(model).where(
- model.tenant_id == scenario["tenant"].bytes)) == 0
- response = await call("POST", path + "/inputs", payload={
- "interrupt_id": view["waiting"]["interrupt_id"],
- "expected_run_version": view["run_version"],
- "answer": f"选择订单{scenario['order_id']},按键失灵,申请1件。",
- })
- assert response.status_code == 202, response.text
- assert response.json()["run"]["run_id"] == str(run_id)
- assert response.json()["run"]["status"] == "QUEUED"
- assert (await call("POST", path + "/cancel")).status_code == 200
- finally:
- if run_id is not None:
- async with sessions() as session:
- run = await session.get(AgentRun, run_id.bytes)
- attempts = (await session.scalars(select(ModelAttempt).where(
- ModelAttempt.run_id == run_id.bytes))).all()
- report = {
- "run_id": str(run_id), "status": run.status, "request_limit": 3,
- "reserved_attempts": allowance.started, "max_output_tokens": 512,
- "model_timeout_seconds": 30, "total_timeout_seconds": 100,
- "automatic_retries": 0,
- "attempts": [{"status": row.status, "usage": row.usage} for row in attempts],
- "messages": run.messages,
- }
- await asyncio.to_thread(Path(".work/clarification-model.json").write_text,
- json.dumps(report, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
|