diff --git a/offline-backend-20260512/backend/app/gateway/routers/open_3qfx.py b/offline-backend-20260512/backend/app/gateway/routers/open_3qfx.py index ede4d92b..b15bb77a 100644 --- a/offline-backend-20260512/backend/app/gateway/routers/open_3qfx.py +++ b/offline-backend-20260512/backend/app/gateway/routers/open_3qfx.py @@ -42,6 +42,7 @@ from pydantic import BaseModel, Field from app.gateway.routers.thread_runs import RunCreateRequest from app.gateway.services import start_run from deerflow.config import get_app_config +from deerflow.runtime.user_context import DEFAULT_USER_ID, reset_current_user, set_current_user logger = logging.getLogger(__name__) @@ -51,6 +52,18 @@ router = APIRouter(prefix="/api/open/3qfx", tags=["open"]) _THREEQ_BUSINESS_CODE = "3Q" +class _OpenDefaultUser: + """开放接口(免登录)以「default」用户桶运行的占位 user。 + + 满足 :class:`deerflow.runtime.user_context.CurrentUser` 协议(仅需 ``.id``)。 + 免登录请求本身没有 user context,而 ``start_run`` 写 thread_meta 时默认 ``user_id=AUTO``, + 无 context 会抛 ``RuntimeError`` → 被 ``start_run`` 的 try/except 当「非致命」吞掉 → + **thread_meta 行从未创建**,于是前端按 ``metadata.taskId`` 怎么也搜不到这条会话。 + """ + + id = DEFAULT_USER_ID + + class ThreeQAskRequest(BaseModel): """3qfx 开放问答请求体。""" @@ -174,8 +187,16 @@ async def ask_3qfx(body: ThreeQAskRequest, request: Request) -> ThreeQAskRespons multitask_strategy="reject", ) + # 免登录 → 无 user context。显式设成「default」用户桶,否则 start_run 写 thread_meta 时 + # resolve_user_id(AUTO) 抛 RuntimeError 被吞掉,thread_meta 建不出来、前端按 taskId 搜不到。 + # run_agent 是后台 task,在 create_task 时快照本 context,故后台运行也归属 default 用户 + # (与 metadata.taskId「任务深链对话全局共享、按创建者解析文件」语义一致)。 # enforce_access=False:开放接口已自行解析 admin 配置的 3Q 智能体,不再按当前(无)登录用户做可见性校验。 - record = await start_run(run_body, thread_id, request, enforce_access=False) + token = set_current_user(_OpenDefaultUser()) + try: + record = await start_run(run_body, thread_id, request, enforce_access=False) + finally: + reset_current_user(token) return ThreeQAskResponse( thread_id=record.thread_id, diff --git a/offline-backend-20260512/config.yaml b/offline-backend-20260512/config.yaml index 34b86761..3360a25a 100644 --- a/offline-backend-20260512/config.yaml +++ b/offline-backend-20260512/config.yaml @@ -354,6 +354,9 @@ task_deeplink: test: true # 目的树查询走 mock.purpose_detail 假数据;同时 rwfx 进入「3q 是否完成」预检走 mock.sq_report 假数据 delete_test: true # 删除接口走 mock.delete 假数据(该接口尚未开发完) action_test: true # 行动→任务解析走 mock.action_detail 假数据(xdfx 行动id→任务id) + # 开放接口 POST /api/open/3qfx/ask 按 taskId 拉取任务详情拼开场白;上游不可达时打开下面开关走 mock.cop_task_detail。 + cop_task_detail_test: true + cop_task_detail_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/cop-task-detail" purpose_detail_url: "https://ch1.b.uat.4.cn/consumer/taskAnalyseSearch/getTaskPurposeDetail" # rwfx 与 xdfx 共用同一删除接口:rwfx 追加 ?taskId=(不传 actionId);xdfx 追加 ?actionId=(不传 taskId,直接不出现)。 delete_url: "https://ch1.b.uat.4.cn/bwjt/dropSixOrSevenData" @@ -417,3 +420,11 @@ task_deeplink: taskId: 3338 categoryType: "敌情关键事件 JSON" contentJson: "[{\"topic\":\"示例研判事件\",\"count\":1}]" + # cop_task_detail_test=true 时原样返回给开放接口 /api/open/3qfx/ask(结构同真实 cop-task-detail 返回)。 + cop_task_detail: + data: + id: 2055 + overview: "暑期文旅消费高峰期间的舆情态势综合研判与引导任务" + taskDirection: "正向引导 + 风险预警" + taskName: "任务01:暑期文旅舆情综合研判" + taskContent: "围绕暑期文旅消费高峰,对重点城市、重点景区的公众情绪与舆情态势做综合研判,识别情绪拐点与潜在风险,提出正向引导与处置建议。"