落地并存测服全端:智能体 Graph/路由、后台切 8180、主账与部署脚本齐备,便于线上重发与验收。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
linmianxun
2026-09-13 21:15:58 +08:00
co-authored by Cursor
parent 0eb1adecc8
commit 8103b3b651
143 changed files with 8968 additions and 277 deletions
+82
View File
@@ -0,0 +1,82 @@
"""
Worker 侧:消费主账/文件完成等结构化 wake。
本文件职责:Redis Stream 入队/认领;在 HTTP 类槽内调 GraphRuntime.wake_from_worker。
禁止:在企微回调线程调用;禁止用户文字冒充本路径。
"""
from __future__ import annotations
import logging
from typing import Any, Optional
from agent.graph.runtime import GraphRuntime
from agent.graph.wake import WorkerWakePayload
from agent.redis_coord.client import RedisClient
from agent.redis_coord.stream_queue import StreamQueue
logger = logging.getLogger(__name__)
STREAM_WAKE = "stream:wake"
WAKE_GROUP = "inquiry-wake-workers"
def wake_stream(client: RedisClient) -> StreamQueue:
"""结构化 wake 专用 Stream。"""
q = StreamQueue(client=client, stream_suffix=STREAM_WAKE, group=WAKE_GROUP)
q.ensure_group()
return q
def enqueue_wake(client: RedisClient, payload: WorkerWakePayload) -> str:
"""
入队 wake(HTTP bridge 快回路径)。
副作用:XADD;不跑 Graph。
"""
payload.validate()
q = wake_stream(client)
return q.enqueue(
payload={
"thread_id": payload.thread_id,
"inquiry_no": payload.inquiry_no,
"quote_version": int(payload.quote_version),
"wait_version": int(payload.wait_version),
"kind": payload.kind,
"detail": payload.detail or {},
},
idempotency_key=f"wake:{payload.thread_id}:{payload.wait_version}:{payload.kind}",
)
def claim_and_apply_wake(
*,
queue: StreamQueue,
graph: GraphRuntime,
consumer: str,
) -> bool:
"""
认领 1 条并 wake Graph。成功/失败均 ack(骨架防堵死;正式应进死信)。
返回:是否领到任务。
"""
claimed = queue.claim(consumer=consumer, count=1, block_ms=200)
if not claimed:
return False
entry_id, data = claimed[0]
try:
wake = WorkerWakePayload(
thread_id=str(data.get("thread_id") or ""),
inquiry_no=str(data.get("inquiry_no") or ""),
quote_version=int(data.get("quote_version") or 0),
wait_version=int(data.get("wait_version") or 0),
kind=str(data.get("kind") or ""),
detail=dict(data.get("detail") or {}),
)
graph.wake_from_worker(wake)
logger.info("wake 已处理 id=%s thread=%s kind=%s", entry_id, wake.thread_id, wake.kind)
except Exception: # noqa: BLE001
logger.exception("wake 处理失败 id=%s", entry_id)
finally:
queue.ack(entry_id)
return True