Files
inquiry_robot/inquiry-agent/agent/channel/bridge/__init__.py
T

103 lines
3.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
主账唤醒桥接路由(合并原 bridge_api)。
本文件职责:校验 callback token,接收结构化 wake,写入 Redis Stream 后快回。
禁止:在本请求线程跑完整 Graph;禁止本包直连 MySQL / TMS。
Worker:jobs.wake_consumer 认领后 GraphRuntime.wake_from_worker。
"""
from __future__ import annotations
import logging
from typing import Any, Optional
from fastapi import APIRouter, Header, HTTPException
from pydantic import BaseModel, Field
from agent.config import get_settings
from agent.graph.wake import WorkerWakePayload
from agent.jobs.wake_consumer import enqueue_wake
from agent.redis_coord import get_redis_runtime
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/internal/bridge", tags=["bridge"])
class BridgeWakeBody(BaseModel):
"""主账 → 智能体结构化唤醒。"""
thread_id: str
inquiry_no: str
quote_version: int = 0
wait_version: int = 0
kind: str = Field(description="如 recognition_done / pdf_done / ledger_transition")
detail: dict[str, Any] = Field(default_factory=dict)
def _expected_token() -> str:
s = get_settings()
return (s.agent_callback_token or s.inquiry_agent_callback_token or "").strip()
def _check_token(authorization: Optional[str], x_agent_token: Optional[str]) -> None:
expected = _expected_token()
if not expected:
if (get_settings().ytd_env or "").lower() == "prod":
raise HTTPException(status_code=503, detail="callback token 未配置")
logger.warning("bridge:未配置 callback token,test 允许空校验(仅骨架)")
return
provided = (x_agent_token or "").strip()
if not provided and authorization:
auth = authorization.strip()
if auth.lower().startswith("bearer "):
provided = auth[7:].strip()
else:
provided = auth
if provided != expected:
raise HTTPException(status_code=401, detail="unauthorized")
@router.get("/ping")
def bridge_ping() -> dict[str, str]:
return {"status": "ok", "channel": "bridge"}
@router.post("/wake")
def bridge_wake(
body: BridgeWakeBody,
authorization: Optional[str] = Header(default=None),
x_agent_callback_token: Optional[str] = Header(
default=None, alias="X-Agent-Callback-Token"
),
) -> dict[str, Any]:
"""
接收结构化 wake:校验后写入 Redis Stream,立即返回。
不在此 invoke Graph。
"""
_check_token(authorization, x_agent_callback_token)
try:
payload = WorkerWakePayload(
thread_id=body.thread_id,
inquiry_no=body.inquiry_no,
quote_version=body.quote_version,
wait_version=body.wait_version,
kind=body.kind,
detail=body.detail,
)
entry_id = enqueue_wake(get_redis_runtime().client, payload)
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
except Exception as exc: # noqa: BLE001
logger.exception("bridge.wake 入队失败")
raise HTTPException(status_code=503, detail=f"enqueue_failed:{exc}") from exc
logger.info(
"bridge.wake 已入队 Redis thread=%s kind=%s id=%s",
body.thread_id,
body.kind,
entry_id,
)
return {"status": "accepted", "entry_id": entry_id}