ForcePilot/backend/package/yuxi/channels/adapters/yuanbao/outbound_queue.py
Kris 1f78c44b03 refactor: 整理并清理项目中的冗余代码与格式问题
这是一个批量整理提交,包含以下主要改动:
1.  删除多处冗余的空行和未使用的导入
2.  修复文件末尾缺少换行符的问题
3.  调整部分模块的导入顺序与代码排版
4.  修复部分配置默认值与策略逻辑
5.  新增多个功能模块与辅助工具
6.  完善异常处理与日志记录
7.  修复速率限制、消息缓存、权限校验等逻辑bug
8.  废弃部分旧有API与配置项并添加警告提示
2026-05-12 14:51:53 +08:00

101 lines
3.3 KiB
Python

from __future__ import annotations
import asyncio
from collections.abc import Callable, Awaitable
from typing import Any
from yuxi.channels.models import ChannelResponse, ChannelIdentity, DeliveryResult
from yuxi.utils.logging_config import logger
class OutboundQueue:
def __init__(
self,
config: dict[str, Any],
send_fn: Callable[[ChannelResponse], Awaitable[DeliveryResult]],
):
strategy = config.get("outboundQueueStrategy", "merge-text")
self._strategy = strategy
self._min_chars = config.get("minChars", 2800)
self._max_chars = config.get("maxChars", 3000)
self._idle_ms = config.get("idleMs", 5000)
self._send_fn = send_fn
self._buffer: list[str] = []
self._buffer_len = 0
self._idle_task: asyncio.Task | None = None
self._lock = asyncio.Lock()
self._flush_event = asyncio.Event()
self._first_identity: ChannelIdentity | None = None
self._first_metadata: dict[str, Any] = {}
async def enqueue(self, response: ChannelResponse) -> DeliveryResult | None:
if self._strategy == "immediate":
return await self._send_fn(response)
return await self._enqueue_merge(response)
async def _enqueue_merge(self, response: ChannelResponse) -> DeliveryResult | None:
content = response.content
async with self._lock:
if not self._buffer:
self._first_identity = response.identity
self._first_metadata = response.metadata
self._buffer.append(content)
self._buffer_len += len(content)
if self._buffer_len >= self._max_chars:
return await self._flush()
elif self._buffer_len >= self._min_chars:
return await self._flush()
self._cancel_idle()
self._idle_task = asyncio.create_task(self._idle_flush())
return None
async def flush(self) -> DeliveryResult | None:
async with self._lock:
return await self._flush()
async def _flush(self) -> DeliveryResult | None:
if not self._buffer:
return None
merged = "\n\n".join(self._buffer)
identity = self._first_identity
metadata = self._first_metadata
self._buffer.clear()
self._buffer_len = 0
self._first_identity = None
self._first_metadata = {}
self._cancel_idle()
logger.debug(f"[Yuanbao] OutboundQueue flushed {len(merged)} chars")
if identity is None:
logger.error("[Yuanbao] OutboundQueue: _flush called without identity, dropping messages")
return DeliveryResult(success=False, error="OutboundQueue: missing identity in flushed response")
response = ChannelResponse(
identity=identity,
content=merged,
metadata=metadata,
)
return await self._send_fn(response)
async def _idle_flush(self) -> None:
await asyncio.sleep(self._idle_ms / 1000)
async with self._lock:
if self._buffer:
logger.debug("[Yuanbao] OutboundQueue idle flush triggered")
await self._flush()
def _cancel_idle(self) -> None:
if self._idle_task and not self._idle_task.done():
self._idle_task.cancel()
self._idle_task = None