| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384 |
- """聊天、审批恢复和定时执行共用的准入与运行装配。"""
- from __future__ import annotations
- import asyncio
- from dataclasses import dataclass
- from typing import TYPE_CHECKING
- if TYPE_CHECKING:
- from runtime.engine import Execution, ExecutionResult
- from runtime import concurrency
- from billing import guard
- from db import chat_store
- @dataclass
- class Admission:
- session: concurrency.SessionLease
- slot: concurrency.TaskSlot
- def release(self):
- self.slot.release()
- self.session.release()
- async def admit(user_name: str, session_id: str) -> Admission:
- session = concurrency.acquire_session(session_id)
- slot = None
- try:
- slot = concurrency.acquire_task_slot(user_name)
- if not await asyncio.to_thread(chat_store.get_session_for_user, session_id, user_name):
- raise concurrency.SessionMissingError("会话不存在")
- await asyncio.to_thread(guard.precheck, user_name)
- return Admission(session, slot)
- except BaseException:
- if slot:
- slot.release()
- session.release()
- raise
- async def build_execution(admission: Admission, *, agent=None, **kwargs) -> Execution:
- from agents import agent_registry
- from runtime.engine import Execution, ExecutionRequest
- try:
- if agent is None:
- agent = await asyncio.to_thread(agent_registry.get_agent)
- graph_config = kwargs["config"]
- graph_config.setdefault("configurable", {}).update(
- workspace_user=kwargs["user_name"], workspace_session=kwargs["session_id"],
- )
- return Execution(ExecutionRequest(agent=agent, slot=admission.slot,
- session_lease=admission.session, **kwargs))
- except BaseException:
- admission.release()
- raise
- async def execute(*, user_name: str, session_id: str, message: str, agent=None,
- kind: str = "batch", graph_config: dict | None = None, trace_id: str = "") -> ExecutionResult:
- """非 HTTP 入口:对已有且归属当前用户的会话执行一次任务,返回完整结果。
- 独立批量任务应各自创建会话;额度与并发限制和聊天入口一致。
- """
- from obs import bind_trace_id, unbind_trace_id, get_trace_id, log_context
- token = bind_trace_id(trace_id or get_trace_id())
- try:
- with log_context(session_id=session_id, user_name=user_name, kind=kind):
- from copy import deepcopy
- admission = await admit(user_name, session_id)
- try:
- options = deepcopy(graph_config) if graph_config is not None else {}
- options.setdefault("configurable", {})["thread_id"] = session_id
- execution = await build_execution(admission, agent=agent, session_id=session_id,
- thread_id=session_id, user_name=user_name, message=message, original_user_message=message,
- kind=kind, config=options, trace_id=get_trace_id())
- from runtime.interrupts import pending_interrupts, ResumeError
- if await pending_interrupts(execution.req.agent, options):
- raise ResumeError("pending_interrupt", "请先处理当前待确认请求")
- return await execution.run()
- finally:
- admission.release()
- finally:
- unbind_trace_id(token)
|