mirror of
https://github.com/zhenxun-org/zhenxun_bot.git
synced 2026-10-21 04:00:04 +08:00
♻️ refactor(tools): 重构工具装饰器系统并优化沙箱与文档注释 (#2147)
* ♻️ refactor(ai): 重构 AI 服务模块并完善文档注释 - 【重构】统一清理并优化所有 AI 服务模块文件的导入语句,将其移至文件顶部 - 【重构】重构 `hooks.py` 中的 `Hooks` 派发逻辑,使用通用管道函数消除重复代码,并引入 `HookPoint` 描述符 - 【重构】重构工具装饰器实现,新增 `toolkit` 类装饰器,优化 `BaseToolkit` 配置合并与前缀处理 - 【功能】Docker 沙箱容器创建时支持自动注入系统代理环境变量并配置 `ExtraHosts` - 【功能】Jupyter 服务启动前自动清理旧进程并初始化临时目录权限 - 【修复】优化 Pydantic 结构化输出校验失败时的错误信息提取,提供更详细的字段级错误反馈 - 【修复】在 `api.py` 中避免将 `ModelRetry` 和 `ControlFlowExit` 异常错误地包装为 `LLMException` - 【文档】为 AI 服务、沙箱、工具链、工作流等核心模块补充完整的 Docstring 和类型注释 * 📝 docs(ai): 补全核心模块文档注释并清理冗余代码 - 补全 `run/context`、`run/hooks` 和 `tools/engine/registry` 中类与方法的中文文档注释 - 清理 `tools/providers/builtin/sandbox` 中未使用的 `PythonPluginProtocol` 协议及相关导入 - 规范化部分代码的格式与尾随逗号 * ♻️ refactor!(flow): 重构 Task 为 AgentTask 并优化工作流元数据定义 - 【Breaking Change】将 `Task` 重命名为 `AgentTask` 以避免命名冲突 - 更新 Agent、Team、Workflow 等模块中的类型声明与相关逻辑 - 引入 `AutoNodeMeta` 强类型元数据,替换工作流装饰器中的裸字典定义 - 将 `StepMeta`、`ConditionMeta` 和 `RouterMeta` 统一移动至 `types.py` - 优化 `RunnableNode` 对上游 `AgentTask` 的处理与拼接逻辑 - 调整团队协作策略中 `FinishAction` 的返回值为完整结果对象 * ♻️ refactor(workflow): 移除人工确认机制并重构错误策略 - 移除工作流节点的人工确认(HITL)与挂起继续机制 - 删除 `auto` 自动化工作流及相关装饰器文件 - 将错误处理策略类从 `types.py` 拆分并移动到新文件 `policies.py` - 优化节点执行失败时的异常信息格式化输出 - 移除 `WorkflowRunResult` 和 `StepOutput` 中与挂起相关的状态字段 * 🚨 auto fix by pre-commit hooks --------- Co-authored-by: webjoin111 <455457521@qq.com> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
co-authored by
webjoin111
pre-commit-ci[bot]
parent
80fc5b86a7
commit
0b32d69c9c
@@ -1,7 +1,8 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import hashlib
|
||||
import json
|
||||
from typing import Any
|
||||
from typing import Any, cast
|
||||
|
||||
from zhenxun.models.user_console import UserConsole
|
||||
from zhenxun.services.ai.capabilities import (
|
||||
@@ -9,18 +10,24 @@ from zhenxun.services.ai.capabilities import (
|
||||
WrapModelRequestHandler,
|
||||
WrapToolExecuteHandler,
|
||||
)
|
||||
from zhenxun.services.ai.config import get_llm_config
|
||||
from zhenxun.services.ai.core.exceptions import (
|
||||
AbortException,
|
||||
ControlFlowExit,
|
||||
GuardrailViolationError,
|
||||
LLMException,
|
||||
ModelRetry,
|
||||
ResponseParseException,
|
||||
SchemaParseError,
|
||||
ToolFatalError,
|
||||
ToolFinishException,
|
||||
ToolRetryError,
|
||||
UpstreamServerException,
|
||||
)
|
||||
from zhenxun.services.ai.core.messages import (
|
||||
ChatRequest,
|
||||
ChatResponse,
|
||||
LLMMessage,
|
||||
ToolCallPart,
|
||||
)
|
||||
from zhenxun.services.ai.core.models import LLMContext
|
||||
@@ -49,8 +56,6 @@ class StuckDetectionCapability(AbstractCapability):
|
||||
llm_context: LLMContext[ChatRequest, ChatResponse],
|
||||
handler: WrapModelRequestHandler,
|
||||
) -> ChatResponse:
|
||||
import hashlib
|
||||
|
||||
max_repeated_errors = 3
|
||||
action_hashes = []
|
||||
messages = list(llm_context.request.messages)
|
||||
@@ -131,13 +136,9 @@ class GlobalCycleLimitCapability(AbstractCapability):
|
||||
|
||||
global_max = llm_context.request.extra.get("__global_max_cycles__")
|
||||
if global_max is None:
|
||||
from zhenxun.services.ai.config import get_llm_config
|
||||
|
||||
global_max = get_llm_config().agent_settings.global_max_cycles
|
||||
|
||||
if global_max is not None and global_cycles > global_max:
|
||||
from zhenxun.services.ai.core.exceptions import AbortException
|
||||
|
||||
logger.error(
|
||||
"🚨 触发全局防护:整个流水线执行步数已达到全局上限 "
|
||||
f"({global_max}),强制熔断!"
|
||||
@@ -175,8 +176,6 @@ class PermissionCapability(AbstractCapability):
|
||||
f"🛡️ [Capability] 权限拦截: 用户 {user_id} 尝试调用 "
|
||||
f"{getattr(tool, 'name', 'unknown')}"
|
||||
)
|
||||
from zhenxun.services.ai.core.exceptions import ToolFatalError
|
||||
|
||||
raise ToolFatalError(
|
||||
msg, display_content=f"❌ 权限不足: 需要等级 {admin_level}"
|
||||
)
|
||||
@@ -216,8 +215,6 @@ class BillingCapability(AbstractCapability):
|
||||
f"💰 [Capability] 金币拦截: 用户 {user_id} 尝试调用 "
|
||||
f"{getattr(tool, 'name', 'unknown')}"
|
||||
)
|
||||
from zhenxun.services.ai.core.exceptions import ToolFatalError
|
||||
|
||||
raise ToolFatalError(
|
||||
msg, display_content=f"❌ 余额不足: 需要 {cost_gold} 金币"
|
||||
)
|
||||
@@ -241,12 +238,6 @@ class ToolRetryAndReflectionCapability(AbstractCapability):
|
||||
try:
|
||||
return await handler(arguments)
|
||||
except Exception as e:
|
||||
from zhenxun.services.ai.core.exceptions import (
|
||||
AbortException,
|
||||
ControlFlowExit,
|
||||
ToolFatalError,
|
||||
ToolFinishException,
|
||||
)
|
||||
from zhenxun.services.ai.tools.engine.executor import ToolExecutionPolicy
|
||||
from zhenxun.services.ai.tools.models import ToolResult
|
||||
|
||||
@@ -257,8 +248,6 @@ class ToolRetryAndReflectionCapability(AbstractCapability):
|
||||
retries += 1
|
||||
context.run.tool_retries[tool_name] = retries
|
||||
|
||||
from typing import cast
|
||||
|
||||
from zhenxun.services.ai.tools.core.tool import BaseTool
|
||||
|
||||
tool = cast(BaseTool, context.call.current_tool)
|
||||
@@ -280,7 +269,7 @@ class ToolRetryAndReflectionCapability(AbstractCapability):
|
||||
|
||||
class ReflexionCapability(AbstractCapability):
|
||||
"""自愈反思与验证引擎 (Reflexion Engine)。
|
||||
统一处理结构化解析失败 and 语义护栏拦截。"""
|
||||
统一处理结构化解析失败和语义护栏拦截。"""
|
||||
|
||||
async def wrap_tool_execute(self, context, tool_name, arguments, handler):
|
||||
try:
|
||||
@@ -289,7 +278,6 @@ class ReflexionCapability(AbstractCapability):
|
||||
from zhenxun.services.ai.core.engine.structured_parser import (
|
||||
DEFAULT_IVR_TEMPLATE,
|
||||
)
|
||||
from zhenxun.services.ai.core.exceptions import ModelRetry, ToolRetryError
|
||||
from zhenxun.services.ai.tools.models import ToolResult
|
||||
|
||||
if isinstance(error, ToolRetryError | ModelRetry):
|
||||
@@ -301,6 +289,82 @@ class ReflexionCapability(AbstractCapability):
|
||||
).as_error()
|
||||
raise error.with_traceback(None) from None
|
||||
|
||||
def _extract_error_info(
|
||||
self, e: Exception, current_response_text: str
|
||||
) -> tuple[str, str, bool]:
|
||||
"""
|
||||
统一提取异常报错详情与可恢复标记
|
||||
返回 (error_msg, raw_response, is_recoverable)
|
||||
"""
|
||||
is_model_retry = isinstance(e, ModelRetry)
|
||||
is_llm_error = isinstance(e, LLMException)
|
||||
llm_error = cast(LLMException, e) if is_llm_error else None
|
||||
|
||||
if (
|
||||
not is_model_retry
|
||||
and llm_error
|
||||
and not isinstance(
|
||||
llm_error, ResponseParseException | UpstreamServerException
|
||||
)
|
||||
):
|
||||
raise e
|
||||
|
||||
if is_model_retry:
|
||||
error_msg = getattr(e, "message", str(e))
|
||||
raw_response = current_response_text
|
||||
else:
|
||||
error_msg = (
|
||||
llm_error.details.get("validation_error", str(e))
|
||||
if llm_error
|
||||
else str(e)
|
||||
)
|
||||
raw_response = current_response_text or (
|
||||
llm_error.details.get("raw_response", "") if llm_error else ""
|
||||
)
|
||||
|
||||
is_recoverable = getattr(llm_error, "recoverable", True) if llm_error else True
|
||||
return error_msg, raw_response, is_recoverable
|
||||
|
||||
def _generate_feedback_prompt(
|
||||
self, e: Exception, error_msg: str, error_template: str | None
|
||||
) -> str:
|
||||
"""
|
||||
根据不同的异常类型生成针对性的自愈反思提示词 (Feedback Prompt)
|
||||
"""
|
||||
if isinstance(e, SchemaParseError):
|
||||
if "数据内容未通过规则校验" in error_msg:
|
||||
return f"""### ⚠️ [数据内容校验失败]
|
||||
你输出的 JSON 格式完全正确,但部分字段的内容未能通过业务规则约束。
|
||||
|
||||
**失败详情:**
|
||||
> {error_msg}
|
||||
|
||||
**修正要求:** 请仔细阅读上述失败详情,你必须打破先前的部分指令限制以满足上述规则,调整报错字段的值并重新输出。""" # noqa: E501
|
||||
else:
|
||||
return f"""### ❌ [格式解析失败]
|
||||
你输出的结构化数据(JSON)格式损坏或字段类型不匹配,未能通过校验。
|
||||
|
||||
**解析错误报告:**
|
||||
> {error_msg}
|
||||
|
||||
**修正要求:** 请仔细检查缺失的必填字段、错误的数据类型或未闭合的括号,严格参考你可用的 Schema 定义,重新输出正确格式的数据。""" # noqa: E501
|
||||
elif isinstance(e, GuardrailViolationError):
|
||||
return f"""### 🛡️ [业务护栏违规]
|
||||
你输出的数据格式完全正确,但在业务逻辑层触发了合规/风控护栏。
|
||||
|
||||
**拦截原因报告:**
|
||||
> {error_msg}
|
||||
|
||||
**修正要求:** 请结合上述反馈报告,反思你的决策逻辑或内容生成,在保持数据格式正确的前提下,重新生成符合护栏规范的内容。""" # noqa: E501
|
||||
else:
|
||||
if error_template:
|
||||
return error_template.format(error_msg=error_msg)
|
||||
from zhenxun.services.ai.core.engine.structured_parser import (
|
||||
DEFAULT_IVR_TEMPLATE,
|
||||
)
|
||||
|
||||
return DEFAULT_IVR_TEMPLATE.format(error_msg=error_msg)
|
||||
|
||||
async def wrap_model_request(
|
||||
self,
|
||||
context: RunContext,
|
||||
@@ -335,8 +399,6 @@ class ReflexionCapability(AbstractCapability):
|
||||
llm_context.request.messages, context
|
||||
)
|
||||
|
||||
from typing import cast
|
||||
|
||||
response = await handler(llm_context)
|
||||
current_response_text = response.text
|
||||
|
||||
@@ -354,8 +416,6 @@ class ReflexionCapability(AbstractCapability):
|
||||
resp_out, final_obj_out = await pipeline.run_output_pipeline(
|
||||
response, final_obj, context
|
||||
)
|
||||
from typing import cast
|
||||
|
||||
response = cast("ChatResponse", resp_out)
|
||||
final_obj = final_obj_out
|
||||
current_response_text = response.text
|
||||
@@ -364,42 +424,15 @@ class ReflexionCapability(AbstractCapability):
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
from typing import cast
|
||||
|
||||
from zhenxun.services.ai.core.messages import LLMMessage
|
||||
|
||||
is_model_retry = isinstance(e, ModelRetry)
|
||||
is_llm_error = isinstance(e, LLMException)
|
||||
llm_error: LLMException | None = (
|
||||
cast(LLMException, e) if is_llm_error else None
|
||||
)
|
||||
last_exception = e
|
||||
|
||||
if (
|
||||
not is_model_retry
|
||||
and llm_error
|
||||
and not isinstance(
|
||||
llm_error, ResponseParseException | UpstreamServerException
|
||||
try:
|
||||
error_msg, raw_response, is_recoverable = self._extract_error_info(
|
||||
e, current_response_text
|
||||
)
|
||||
):
|
||||
raise e
|
||||
except Exception as fatal_e:
|
||||
raise fatal_e.with_traceback(None) from None
|
||||
|
||||
if attempt < max_retries:
|
||||
if is_model_retry:
|
||||
error_msg = getattr(e, "message", str(e))
|
||||
raw_response = current_response_text
|
||||
else:
|
||||
error_msg = (
|
||||
llm_error.details.get("validation_error", str(e))
|
||||
if llm_error
|
||||
else str(e)
|
||||
)
|
||||
raw_response = current_response_text or (
|
||||
llm_error.details.get("raw_response", "")
|
||||
if llm_error
|
||||
else ""
|
||||
)
|
||||
|
||||
logger.warning(
|
||||
"输出校验未通过 "
|
||||
f"(尝试 {attempt + 1}/{max_retries + 1})。"
|
||||
@@ -414,45 +447,16 @@ class ReflexionCapability(AbstractCapability):
|
||||
)
|
||||
)
|
||||
|
||||
if isinstance(e, SchemaParseError):
|
||||
feedback_prompt = (
|
||||
"### ❌ [格式解析失败]\n"
|
||||
"你输出的结构化数据(JSON)格式损坏或字段不匹配,"
|
||||
"未能通过 Schema 校验。\n\n"
|
||||
"**解析错误报告:**\n"
|
||||
f"> {error_msg}\n\n"
|
||||
"**修正要求:** 请仔细检查缺失的必填字段、错误的数据类型或"
|
||||
"未闭合的括号,严格参考你可用的工具 Schema 定义,"
|
||||
"重新输出正确格式的数据。"
|
||||
)
|
||||
elif isinstance(e, GuardrailViolationError):
|
||||
feedback_prompt = (
|
||||
"### 🛡️ [业务护栏违规]\n"
|
||||
"你输出的数据格式完全正确,但在业务逻辑层触发了合规/风控护栏。\n\n"
|
||||
"**拦截原因报告:**\n"
|
||||
f"> {error_msg}\n\n"
|
||||
"**修正要求:** 请结合上述反馈报告,"
|
||||
"反思你的决策逻辑或内容生成,"
|
||||
"在保持数据格式正确的前提下,重新生成符合护栏规范的内容。"
|
||||
)
|
||||
else:
|
||||
if output_processor and error_template:
|
||||
feedback_prompt = error_template.format(error_msg=error_msg)
|
||||
else:
|
||||
from zhenxun.services.ai.core.engine import (
|
||||
structured_parser as sp,
|
||||
)
|
||||
|
||||
feedback_prompt = sp.DEFAULT_IVR_TEMPLATE.format(
|
||||
error_msg=error_msg
|
||||
)
|
||||
feedback_prompt = self._generate_feedback_prompt(
|
||||
e, error_msg, error_template
|
||||
)
|
||||
ivr_messages.append(
|
||||
cast(LLMMessage, LLMMessage.user(feedback_prompt))
|
||||
)
|
||||
continue
|
||||
|
||||
if llm_error and not getattr(llm_error, "recoverable", True):
|
||||
raise llm_error.with_traceback(None) from None
|
||||
if not is_recoverable:
|
||||
raise last_exception.with_traceback(None) from None
|
||||
|
||||
if last_exception:
|
||||
raise last_exception.with_traceback(None) from None
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections.abc import Callable
|
||||
import copy
|
||||
import graphlib
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from nonebot.utils import is_coroutine_callable
|
||||
|
||||
from zhenxun.services.ai.core.messages import ChatRequest, ChatResponse
|
||||
from zhenxun.services.ai.core.options import GenerationConfig
|
||||
|
||||
@@ -91,10 +94,11 @@ class CombinedCapability(AbstractCapability):
|
||||
"""
|
||||
组合能力容器。
|
||||
将多个 Capability 按顺序融合成一个复合的洋葱模型,
|
||||
处理生命周期的正序/倒序和链式调用。
|
||||
处理生命周期的正序/倒序 and 链式调用。
|
||||
"""
|
||||
|
||||
def __init__(self, capabilities: list[AbstractCapability]):
|
||||
"""初始化组合能力,对传入能力集进行展平去重和拓扑排序"""
|
||||
flat = []
|
||||
for c in capabilities:
|
||||
if isinstance(c, CombinedCapability):
|
||||
@@ -111,6 +115,7 @@ class CombinedCapability(AbstractCapability):
|
||||
self.capabilities = sort_capabilities(deduped)
|
||||
|
||||
async def for_run(self, context: RunContext) -> "AbstractCapability":
|
||||
"""为当前运行实例解析并更新所包裹的能力列表"""
|
||||
new_caps = []
|
||||
changed = False
|
||||
for cap in self.capabilities:
|
||||
@@ -126,6 +131,7 @@ class CombinedCapability(AbstractCapability):
|
||||
async def get_generation_config(
|
||||
self, context: RunContext
|
||||
) -> GenerationConfig | None:
|
||||
"""获取组合中所有能力合并后的生成配置"""
|
||||
final_config = None
|
||||
for cap in self.capabilities:
|
||||
cap_config = await cap.get_generation_config(context)
|
||||
@@ -137,12 +143,14 @@ class CombinedCapability(AbstractCapability):
|
||||
return final_config
|
||||
|
||||
async def get_system_prompts(self, context: RunContext) -> list[str]:
|
||||
"""获取组合中所有能力提供的系统提示词列表"""
|
||||
prompts = []
|
||||
for cap in self.capabilities:
|
||||
prompts.extend(await cap.get_system_prompts(context))
|
||||
return prompts
|
||||
|
||||
async def get_tools(self, context: RunContext) -> list[Any]:
|
||||
"""获取组合中所有能力附带注册的工具列表"""
|
||||
tools = []
|
||||
for cap in self.capabilities:
|
||||
tools.extend(await cap.get_tools(context))
|
||||
@@ -151,6 +159,7 @@ class CombinedCapability(AbstractCapability):
|
||||
async def prepare_tools(
|
||||
self, context: RunContext, tool_defs: list[Any]
|
||||
) -> list[Any]:
|
||||
"""依次调用组合中所有能力的准备工具钩子处理工具定义"""
|
||||
current_defs = list(tool_defs)
|
||||
for cap in self.capabilities:
|
||||
res = await cap.prepare_tools(context, current_defs)
|
||||
@@ -161,6 +170,7 @@ class CombinedCapability(AbstractCapability):
|
||||
async def wrap_run(
|
||||
self, context: RunContext, handler: WrapRunHandler
|
||||
) -> "AgentRunResult[Any]":
|
||||
"""串联能力组合的 wrap_run 洋葱模型拦截器链"""
|
||||
chain = handler
|
||||
for cap in reversed(self.capabilities):
|
||||
chain = _make_wrap_link(cap, "wrap_run", context, {}, chain, None)
|
||||
@@ -172,6 +182,7 @@ class CombinedCapability(AbstractCapability):
|
||||
llm_context: LLMContext[ChatRequest, ChatResponse],
|
||||
handler: WrapModelRequestHandler,
|
||||
) -> ChatResponse:
|
||||
"""串联能力组合的 wrap_model_request 洋葱模型拦截器链"""
|
||||
chain = handler
|
||||
for cap in reversed(self.capabilities):
|
||||
chain = _make_wrap_link(
|
||||
@@ -186,6 +197,7 @@ class CombinedCapability(AbstractCapability):
|
||||
args: str | dict[str, Any],
|
||||
handler: WrapToolValidateHandler,
|
||||
) -> dict[str, Any]:
|
||||
"""串联能力组合的 wrap_tool_validate 洋葱模型拦截器链"""
|
||||
chain = handler
|
||||
for cap in reversed(self.capabilities):
|
||||
chain = _make_wrap_link(
|
||||
@@ -205,6 +217,7 @@ class CombinedCapability(AbstractCapability):
|
||||
arguments: dict[str, Any],
|
||||
handler: WrapToolExecuteHandler,
|
||||
) -> Any:
|
||||
"""串联能力组合的 wrap_tool_execute 洋葱模型拦截器链"""
|
||||
chain = handler
|
||||
for cap in reversed(self.capabilities):
|
||||
chain = _make_wrap_link(
|
||||
@@ -250,15 +263,16 @@ class DynamicCapability(AbstractCapability):
|
||||
"""动态能力注入:允许在运行时基于上下文生成真正的 Capability"""
|
||||
|
||||
def __init__(self, capability_func: Callable):
|
||||
"""初始化动态能力"""
|
||||
self.capability_func = capability_func
|
||||
|
||||
@classmethod
|
||||
def get_serialization_name(cls) -> str | None:
|
||||
"""获取反序列化标识"""
|
||||
return None
|
||||
|
||||
async def for_run(self, context: RunContext) -> "AbstractCapability":
|
||||
from nonebot.utils import is_coroutine_callable
|
||||
|
||||
"""在运行时基于当前上下文动态实例化并执行真正的 Capability"""
|
||||
if is_coroutine_callable(self.capability_func):
|
||||
cap = await self.capability_func(context)
|
||||
else:
|
||||
@@ -275,17 +289,19 @@ class WrapperCapability(AbstractCapability):
|
||||
"""
|
||||
|
||||
def __init__(self, wrapped: AbstractCapability):
|
||||
"""初始化代理包装器"""
|
||||
self.wrapped = wrapped
|
||||
|
||||
@classmethod
|
||||
def get_serialization_name(cls) -> str | None:
|
||||
"""获取反序列化标识"""
|
||||
return None
|
||||
|
||||
async def for_run(self, context: RunContext) -> "AbstractCapability":
|
||||
"""对内部包裹的实例执行运行时解析并深度克隆"""
|
||||
new_wrapped = await self.wrapped.for_run(context)
|
||||
if new_wrapped is self.wrapped:
|
||||
return self
|
||||
import copy
|
||||
|
||||
new_self = copy.copy(self)
|
||||
new_self.wrapped = new_wrapped
|
||||
@@ -294,22 +310,27 @@ class WrapperCapability(AbstractCapability):
|
||||
async def get_generation_config(
|
||||
self, context: RunContext
|
||||
) -> GenerationConfig | None:
|
||||
"""透传获取内部包裹实例的生成配置"""
|
||||
return await self.wrapped.get_generation_config(context)
|
||||
|
||||
async def get_system_prompts(self, context: RunContext) -> list[str]:
|
||||
"""透传获取内部包裹实例的系统提示词"""
|
||||
return await self.wrapped.get_system_prompts(context)
|
||||
|
||||
async def get_tools(self, context: RunContext) -> list[Any]:
|
||||
"""透传获取内部包裹实例的工具列表"""
|
||||
return await self.wrapped.get_tools(context)
|
||||
|
||||
async def prepare_tools(
|
||||
self, context: RunContext, tool_defs: list[Any]
|
||||
) -> list[Any]:
|
||||
"""透传执行内部包裹实例的准备工具钩子"""
|
||||
return await self.wrapped.prepare_tools(context, tool_defs)
|
||||
|
||||
async def wrap_run(
|
||||
self, context: RunContext, handler: WrapRunHandler
|
||||
) -> "AgentRunResult[Any]":
|
||||
"""透传执行内部包裹实例的 wrap_run 拦截器"""
|
||||
return await self.wrapped.wrap_run(context, handler)
|
||||
|
||||
async def wrap_model_request(
|
||||
@@ -318,6 +339,7 @@ class WrapperCapability(AbstractCapability):
|
||||
llm_context: LLMContext[ChatRequest, ChatResponse],
|
||||
handler: WrapModelRequestHandler,
|
||||
) -> ChatResponse:
|
||||
"""透传执行内部包裹实例的 wrap_model_request 拦截器"""
|
||||
return await self.wrapped.wrap_model_request(context, llm_context, handler)
|
||||
|
||||
async def wrap_tool_validate(
|
||||
@@ -327,6 +349,7 @@ class WrapperCapability(AbstractCapability):
|
||||
args: str | dict[str, Any],
|
||||
handler: WrapToolValidateHandler,
|
||||
) -> dict[str, Any]:
|
||||
"""透传执行内部包裹实例的 wrap_tool_validate 拦截器"""
|
||||
return await self.wrapped.wrap_tool_validate(context, tool_name, args, handler)
|
||||
|
||||
async def wrap_tool_execute(
|
||||
@@ -336,6 +359,7 @@ class WrapperCapability(AbstractCapability):
|
||||
arguments: dict[str, Any],
|
||||
handler: WrapToolExecuteHandler,
|
||||
) -> Any:
|
||||
"""透传执行内部包裹实例的 wrap_tool_execute 拦截器"""
|
||||
return await self.wrapped.wrap_tool_execute(
|
||||
context, tool_name, arguments, handler
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user