这份文档总结当前最重要的 package exports、runtime surface,以及你真正应该关心的协议对象。
它不是源码替代品。
它的作用是告诉你:当前稳定 API 面到底在哪里。
openagents 当前导出:
AppConfigLocalSkillsManagerRuntimeRunContextSessionSkillSummarySkillsPluginload_configload_config_dictrun_agentrun_agent_detailedrun_agent_detailed_with_configrun_agent_with_configrun_agent_with_dict
RunStreamChunkRunStreamChunkKind
ModelRetryError— pattern 可抛出以请求模型重试OutputValidationError— 结构化输出校验在用尽重试次数后抛出
LocalSkillsManagerSessionSkillSummary
toolmemorypatternruntimesessionevent_bustool_executorcontext_assembler
get_toolget_memoryget_patternget_runtimeget_sessionget_event_busget_tool_executorget_context_assembler
list_toolslist_memorieslist_patternslist_runtimeslist_sessionslist_event_buseslist_tool_executorslist_context_assemblers
!!! note "seam 合并(2026-04-18)"
execution_policy / followup_resolver / response_repair_policy
三套 decorator / registry 已移除。
- tool 权限 → ToolExecutorPlugin.evaluate_policy()
- follow-up → PatternPlugin.resolve_followup()
- empty response repair → PatternPlugin.repair_empty_response()
对外的 runtime facade。config.agents 至少要有一个 agent;顶层 runtime/session/events/skills 可以全部省略——pydantic schema 会把它们填成 builtin 默认引用(default/in_memory/async/local),插件加载器按统一路径解析。
内部持有:
- app config
- 顶层 runtime / session / events / skills 组件(始终经由 loader 加载)
- 按 session + agent 缓存的插件 bundle
Runtime(AppConfig(agents=[...])) # 只填 agents,其他 schema 补默认
Runtime.from_dict({"agents": [...]}) # 最小 dict
Runtime.from_config("agent.json") # 完整 JSON从磁盘加载 JSON 配置,构造 runtime。
直接从 Python dict 构造 runtime。
兼容型入口,返回 RunResult.final_output。
如果 run 失败,会抛异常。
结构化入口。
如果你在做更高层的 runtime / framework / product,优先用这个。
流式入口(0.3.0 新增)。异步生成器,按序产出 RunStreamChunk 对象。
最后一个 chunk 的 kind 为 RUN_FINISHED,携带完整的 RunResult。
详见 流式 API 深度指南。
run() 的同步封装。
重新加载最初的 config 文件。
只更新 future run 会用到的 agent 定义,不热切换顶层组件。
失效一个 agent 在各个 session 下的缓存 bundle。
返回当前活跃 session 数量。
返回最小 agent 信息列表,只含 id 和 name。
返回:
- 该 agent 的 selector 配置
- 当前是否已有已加载的 plugin 实例
关闭一个 session 的插件 bundle。也会级联调用 release_session(session_id) 释放 runtime 级共享资源(如 MCP session pool)。
释放 runtime 自身持有、与 session_id 挂钩的共享资源(当前:DefaultRuntime 的 MCP 会话池共享连接),不动 session 的 agent plugin bundle。幂等,未使用过的 session_id 也安全调用。
关闭 runtime 及可关闭的下游资源。对 DefaultRuntime,会级联排空所有 MCP session pool。
属性,返回当前 event bus 实例。
属性,返回当前 session manager 实例。
从文件路径加载配置并同步运行。
从预加载 config 同步运行。
从文件路径做同步 detailed run。
从预加载 config 做同步 detailed run。
直接从 Python dict 做同步运行。
从 Python dict 同步流式运行(0.3.0 新增)。
在非 async 上下文中使用;不可在已运行的 event loop 内调用。
从 JSON 配置文件路径同步流式运行(0.3.0 新增)。
内部调用 stream_agent_with_dict。
str 枚举,表示 chunk 的来源事件类型:
| 枚举成员 | 值 | 描述 |
|---|---|---|
RUN_STARTED |
run.started |
run 开始 |
LLM_DELTA |
llm.delta |
LLM 增量文本输出 |
LLM_FINISHED |
llm.finished |
单次 LLM 调用完成 |
TOOL_STARTED |
tool.started |
工具即将执行 |
TOOL_DELTA |
tool.delta |
工具流式输出 |
TOOL_FINISHED |
tool.finished |
工具执行结束(成功或失败) |
ARTIFACT |
artifact |
artifact 已产出 |
VALIDATION_RETRY |
validation.retry |
结构化输出校验失败,正在重试 |
RUN_FINISHED |
run.finished |
run 完成(终结 chunk) |
| 字段 | 类型 | 描述 |
|---|---|---|
kind |
RunStreamChunkKind |
chunk 类型 |
run_id |
str |
对应的 run ID |
session_id |
str |
所属 session |
agent_id |
str |
所属 agent |
sequence |
int |
单次 run 内单调递增,可用于断连检测 |
timestamp_ms |
int |
Unix 毫秒时间戳 |
payload |
dict[str, Any] |
事件特定数据(见下表) |
result |
RunResult | None |
仅 RUN_FINISHED chunk 携带此字段 |
各 kind 的 payload 关键字段:
| Kind | payload 字段 |
|---|---|
llm.delta |
text: str |
llm.finished |
model: str |
tool.started |
tool_id: str, params: dict |
tool.delta |
tool_id: str, text: str |
tool.finished |
tool_id: str, result: Any(成功)或 error: str(失败) |
artifact |
name: str, kind: str, payload: Any |
validation.retry |
attempt: int, error: str |
!!! tip
sequence 字段在 run 范围内保证单调递增。消费者可通过检测序号跳跃来判断是否发生了断连。
RunRequest.output_type 接受一个 Pydantic 模型类,runtime 会用它对最终输出进行校验:
from pydantic import BaseModel
from openagents.interfaces.runtime import RunRequest, RunBudget
class Answer(BaseModel):
value: str
confidence: float
request = RunRequest(
agent_id="assistant",
session_id="s1",
input_text="What is 2+2?",
output_type=Answer,
budget=RunBudget(max_validation_retries=3),
)
result = await runtime.run_detailed(request=request)
answer: Answer = result.final_output校验重试机制:
- pattern 执行完成后,runtime 对
final_output做 Pydantic 校验。 - 失败时,错误信息注入
context.scratch["last_validation_error"],并向 event bus 发送validation.retry事件。 - runtime 重新进入
pattern.execute(),pattern 可读取 scratch 调整输出。 - 超过
RunBudget.max_validation_retries(默认 3)次后,抛出OutputValidationError。
相关符号:
RunRequest.output_type: type[T] | None— 目标 Pydantic 模型RunBudget.max_validation_retries: int | None = 3— 最大校验重试次数OutputValidationError— 重试耗尽后抛出;携带output_type、attempts、last_validation_errorModelRetryError— pattern 可主动抛出,请求 runtime 重试当前步骤
| 字段 | 类型 | 描述 |
|---|---|---|
cost_usd |
float | None |
本次 run 的总美元成本(当 LLM 能提供 token 计数时自动计算) |
cost_breakdown |
dict[str, float] |
按成本类别分解(如 input、output、cached_read) |
在 llm 配置中添加 pricing 字段可覆盖内置价格表(单位:每百万 token 美元):
{
"llm": {
"provider": "anthropic",
"model": "claude-sonnet-4-6",
"pricing": {
"input": 3.00,
"output": 15.00,
"cached_read": 0.30,
"cached_write": 3.75
}
}
}Anthropic(每百万 token,美元):
| 模型 | input | output | cached_read | cached_write |
|---|---|---|---|---|
claude-opus-4-6 |
15.00 | 75.00 | 1.50 | 18.75 |
claude-sonnet-4-6 |
3.00 | 15.00 | 0.30 | 3.75 |
claude-haiku-4-5 |
0.80 | 4.00 | 0.08 | 1.00 |
OpenAI / openai_compatible(每百万 token,美元):
| 模型 | input | output | cached_read |
|---|---|---|---|
gpt-4o |
2.50 | 10.00 | 1.25 |
gpt-4o-mini |
0.15 | 0.60 | 0.075 |
o1 |
15.00 | 60.00 | 7.50 |
!!! note
RunBudget.max_cost_usd 设置后,当累计成本超过限额时,runtime 会以 stop_reason=budget_exhausted 终止 run。
主要字段:
version: stragents: list[AgentDefinition]runtime: RuntimeRefsession: SessionRefevents: EventBusRefskills: SkillsReflogging: LoggingConfig | None
主要字段:
id: strname: strmemory: MemoryRefpattern: PatternRefllm: LLMOptions | Nonetool_executor: ToolExecutorRef | Nonecontext_assembler: ContextAssemblerRef | Nonetools: list[ToolRef]runtime: RuntimeOptions
!!! warning
execution_policy / followup_resolver / response_repair_policy 三个字段在
2026-04-18 seam 合并中已移除;strict schema 会拒绝这些旧 key。
字段:
max_steps: int = 16step_timeout_ms: int = 30000session_queue_size: int = 1000event_queue_size: int = 2000
字段:
provider: str = "mock"—"anthropic"/"openai_compatible"/"mock"model: str | Noneapi_base: str | None—openai_compatible必须提供api_key_env: str | Nonetemperature: float | Nonemax_tokens: int | Nonetimeout_ms: int = 30000stream_endpoint: str | Nonepricing: LLMPricing | None— 覆盖内置价格表retry: LLMRetryOptions | None— 传输层重试策略(默认None→ provider 使用内置默认:3 次,指数退避 500ms→2000ms→5000ms,自动重试 429/502/503/504 + Anthropic 529 +httpx.ConnectError/ReadTimeout)extra_headers: dict[str, str] | None— 合入每次请求的自定义 header;用户 key 覆盖 provider 默认(如{"anthropic-beta": "prompt-caching-2024-07-31"})reasoning_model: bool | None— 仅openai_compatible:显式标记是否为推理模型(o1/o3/o4/gpt-5-thinking…)。None时基于 model 名称正则自动判定。True时使用max_completion_tokens并丢弃temperatureopenai_api_style: Literal["chat_completions", "responses"] | None— 仅openai_compatible:选择 OpenAI API 风格。None时根据api_base自动判定(以/responses结尾 →"responses",否则"chat_completions")。Responses API (v2) 的 payload 形状完全不同:messages→input+instructions;max_tokens→max_output_tokens;response_format→text.format(扁平化,不再嵌套json_schema)。response.output[]的type为message/reasoning/function_call。目前流式仅 Chat Completions 原生支持;Responses API 的complete_stream()会降级为一次性非流式调用seed/top_p/parallel_tool_calls— 仅openai_compatible(通过extra="allow"透传);每次请求自动写入 payload
max_attempts: int = 3(设为1可关闭重试)initial_backoff_ms: int = 500max_backoff_ms: int = 5000backoff_multiplier: float = 2.0retry_on_connection_errors: bool = Truetotal_budget_ms: int | None = None— 总墙钟预算上限;预算耗尽前不再发起新 attempt
流式响应块,新增字段:
error_type: Literal["rate_limit", "connection", "response", "unknown"] | None = None— 非错误块恒为None;错误块按LLMError子类归一化分类
Anthropic — content 保留 thinking / redacted_thinking 块(不计入 output_text);system 接受 str 或 list[dict](后者保留块级 cache_control);tools 与消息内容块的 cache_control 原样透传;529 归类为 rate_limit 并纳入重试。
OpenAI-compatible — 推理模型(o\d+(-.*)? / gpt-5-thinking* 或 reasoning_model=True)使用 max_completion_tokens 并丢弃 temperature;usage.completion_tokens_details.reasoning_tokens 写入 LLMUsage.metadata["reasoning_tokens"](不重复计入 output_tokens);finish_reason="tool_calls" 归一化为 stop_reason="tool_use"。
单次 run 的可选限制:
| 字段 | 类型 | 默认值 | 描述 |
|---|---|---|---|
max_steps |
int | None |
None |
最大步数 |
max_duration_ms |
int | None |
None |
最大执行时长(毫秒) |
max_tool_calls |
int | None |
None |
最大工具调用次数 |
max_validation_retries |
int | None |
3 |
结构化输出校验最大重试次数 |
max_cost_usd |
float | None |
None |
最大成本上限(美元) |
max_resume_attempts |
int | None |
3 |
durable run 的最大自动恢复次数(0.4.x 新增) |
run 产物:
name: strkind: str = "generic"payload: Anymetadata: dict[str, Any]
run 的 usage 聚合:
llm_calls: inttool_calls: intinput_tokens: intoutput_tokens: inttotal_tokens: intinput_tokens_cached: intinput_tokens_cache_creation: intcost_usd: float | Nonecost_breakdown: dict[str, float]
结构化输入:
agent_id: strsession_id: strinput_text: strrun_id: str— 默认 UUID4 自动生成parent_run_id: str | Nonemetadata: dict[str, Any]context_hints: dict[str, Any]budget: RunBudget | Nonedeps: Anyoutput_type: type[BaseModel] | None— 结构化输出目标类型(0.3.0 新增)durable: bool = False— 开启 durable execution:每个 step 边界自动 checkpoint,retryable 错误自动从最近 checkpoint 恢复(0.4.x 新增)resume_from_checkpoint: str | None = None— 显式从给定 checkpoint 恢复一个新 run;DefaultRuntime会跳过context_assembler.assemble()和memory.inject(),直接从 checkpoint 的 transcript / artifacts / usage 重建状态(0.4.x 新增)
Durable execution 是 runtime 层面的容错机制,不是新 seam。开启方式:
from openagents.interfaces.runtime import RunBudget, RunRequest
request = RunRequest(
agent_id="coding-agent",
session_id="my-session",
input_text="refactor this module...",
durable=True, # 自动 checkpoint + 自动 resume
budget=RunBudget(max_resume_attempts=3),
)
result = await runtime.run_detailed(request=request)checkpoint 粒度:每次成功的 llm.succeeded / tool.succeeded 事件后写一个 checkpoint,checkpoint_id = f"{run_id}:step:{n}"。批量工具调用(call_tool_batch)整体算一个 step。
retryable 错误分类:LLMRateLimitError、LLMConnectionError、ToolRateLimitError、ToolUnavailableError 会触发自动 resume;其余错误(PermanentToolError、ConfigError、BudgetExhausted、OutputValidationError)直接终止 run。
显式恢复:若进程崩溃,可以用持久化的 session backend(jsonl_file / sqlite)跨进程恢复:
# 在新进程里
request = RunRequest(
agent_id="coding-agent",
session_id="my-session",
input_text="refactor this module...",
resume_from_checkpoint="abc123:step:7", # 从第 7 步继续
)事件:durable execution 会发出五个新事件:
run.checkpoint_saved— 每次成功 checkpoint 后run.checkpoint_failed— create_checkpoint 抛错(run 继续,不失败)run.resume_attempted— 捕获 retryable 错误后准备 resumerun.resume_succeeded— resume 状态重建完成run.resume_exhausted— 达到max_resume_attempts上限run.durable_idempotency_warning— 工具声明durable_idempotent=False时一次性提示(每 (run, tool) 只发一次)
ToolPlugin.durable_idempotent(类属性,默认 True):写文件、发 HTTP、shell 子进程等有副作用的工具应声明为 False,在 durable run 中被调用时 runtime 会发出一次性警告。内建工具中 WriteFileTool、DeleteFileTool、HttpRequestTool、ShellExecTool、ExecuteCommandTool、SetEnvTool 已默认标为 False。
结构化输出(泛型,0.3.0 起):
run_id: strfinal_output: T | Nonestop_reason: StopReasonusage: RunUsageartifacts: list[RunArtifact]error: str | Noneexception: OpenAgentsError | Nonemetadata: dict[str, Any]
取值:
completedfailedcancelledtimeoutmax_stepsbudget_exhausted
RunContext 是 pattern 和 tool 真正消费的运行态对象。
主要字段:
agent_idsession_idrun_idinput_textdepsstatetoolsllm_clientllm_optionsevent_busmemory_viewtool_resultsscratchsystem_prompt_fragmentstranscriptsession_artifactsassembly_metadatarun_requesttool_executorusageartifacts
execution_policy/followup_resolver/response_repair_policy属性在 2026-04-18 seam 合并中移除 —— 权限判断由tool_executor.evaluate_policy()负责, follow-up / empty-response 走PatternPlugin上的方法覆写。
这是 app-defined middle protocol 最重要的 carrier。
执行元信息:
concurrency_safeinterrupt_behaviorside_effectsapproval_modedefault_timeout_msreads_fileswrites_files
policy 输出:
allowedreasonmetadata
结构化 tool 执行输入:
tool_idtoolparamscontextexecution_specmetadata
结构化 tool 执行输出:
tool_idsuccessdataerrorexceptionmetadata
结构化 pre-run context:
transcriptsession_artifactsmetadata
字段:
statusoutputreasonmetadata
当前推荐状态:
resolvedabstainerror
字段:
statusoutputreasonmetadata
当前推荐状态:
repairedabstainerror
字段:
namekindpayloadmetadata
字段:
checkpoint_idstatetranscript_lengthartifact_countcreated_at
主要方法:
async invoke(params, context) -> Anyasync invoke_stream(params, context)execution_spec() -> ToolExecutionSpecschema() -> dictdescribe() -> dictvalidate_params(params) -> tuple[bool, str | None]get_dependencies() -> list[str]async fallback(error, params, context) -> Any
扩展方法(2026-04-19)—— 全部带默认实现,单工具按需覆写:
async invoke_batch(items: list[BatchItem], context) -> list[BatchResult]—— 默认顺序循环invoke;可覆写以下沉(MCP 单会话批量、多文件批读等)。结果顺序与item_id与输入严格一致。async invoke_background(params, context) -> JobHandle—— 提交长任务,立即返回句柄;默认NotImplementedError。async poll_job(handle, context) -> JobStatus—— 查询后台任务状态;默认NotImplementedError。async cancel_job(handle, context) -> bool—— 取消后台任务;默认NotImplementedError。requires_approval(params, context) -> bool—— 是否需要人工审批;默认读execution_spec().approval_mode == "always"。async before_invoke(params, context)/async after_invoke(params, context, result, exception=None)—— 每次调用前/后钩子(区别于每 run 一次的preflight)。after_invoke在成功与失败分支都会运行。
伴随的新 pydantic 模型:BatchItem / BatchResult / JobHandle / JobStatus(见 openagents.interfaces.tool)。
主要方法:
async evaluate_policy(request) -> PolicyDecision— override to restrict tool execution (default:allow all)async execute(request) -> ToolExecutionResultasync execute_stream(request)async execute_batch(requests) -> list[ToolExecutionResult]—— 默认顺序循环execute;builtinConcurrentBatchExecutor按execution_spec.concurrency_safe分组并发。
ToolExecutionRequest 新增 cancel_event: asyncio.Event | None 字段;DefaultRuntime 在每个 run 前种入 ctx.scratch['__cancel_event__'],_BoundTool.invoke 把它串入 request,SafeToolExecutor.execute 会与 cancel_event / timeout 三方竞速。ToolExecutionSpec.interrupt_behavior == "block" 时忽略 cancel 并等待 tool 自然完成。
新错误子类(openagents.errors.exceptions):
ToolValidationError / ToolAuthError(不重试)、ToolRateLimitError / ToolUnavailableError(RetryToolExecutor 默认重试)、ToolCancelledError(cancel_event 触发时由 SafeToolExecutor 抛出,不重试)。
Pattern 便捷方法:PatternPlugin.call_tool_batch(requests: list[tuple[str, dict]]) -> list[Any] —— 按 tool_id 分组调用 invoke_batch,保持输入顺序;发 tool.batch.started / tool.batch.completed 事件。
主要方法:
async inject(context) -> Noneasync writeback(context) -> Noneasync retrieve(query, context) -> list[dict[str, Any]]async close() -> None
主要方法:
async setup(...) -> Noneasync execute() -> Anyasync react() -> dict[str, Any]async emit(event_name, **payload) -> Noneasync call_tool(tool_id, params=None) -> Anyasync call_llm(...) -> strasync compress_context() -> Noneadd_artifact(...) -> Noneasync resolve_followup(*, context) -> FollowupResolution | None— override to answer follow-ups locally (default:abstain)async repair_empty_response(*, context, messages, assistant_content, stop_reason, retries) -> ResponseRepairDecision | None— override to recover from bad LLM responses (default:abstain)
主要方法:
prepare_session(session_id, session_manager) -> dict[str, SessionSkillSummary]load_references(session_id, skill_name, session_manager) -> list[dict[str, str]]run_skill(session_id, skill_name, payload, session_manager) -> dict[str, Any]
主要方法:
async assemble(request, session_state, session_manager) -> ContextAssemblyResultasync finalize(request, session_state, session_manager, result) -> result
主要方法:
async initialize() -> Noneasync validate() -> Noneasync health_check() -> boolasync run(...) -> RunResultasync pause() -> Noneasync resume() -> Noneasync close() -> None
主要方法:
async with session(session_id)async get_state(session_id) -> dict[str, Any]async set_state(session_id, state) -> Noneasync delete_session(session_id) -> Noneasync list_sessions() -> list[str]async append_message(session_id, message) -> Noneasync load_messages(session_id) -> list[dict[str, Any]]async save_artifact(session_id, artifact) -> Noneasync list_artifacts(session_id) -> list[SessionArtifact]async create_checkpoint(session_id, checkpoint_id) -> SessionCheckpointasync load_checkpoint(session_id, checkpoint_id) -> SessionCheckpoint | Noneasync close() -> None
主要方法:
subscribe(event_name, handler) -> Noneasync emit(event_name, **payload) -> RuntimeEventasync get_history(event_name=None, limit=None) -> list[RuntimeEvent]async clear_history() -> Noneasync close() -> None
get_* helper 返回的是 decorator registry 里的类。
list_* helper 返回的是 decorator registry 里的名称。
它们不是 builtin registry 的完整替代品。
供自定义 combinator 与 pattern 作者使用的公开 helper。
| Symbol | Module | Purpose |
|---|---|---|
load_plugin(kind, ref, *, required_methods=()) |
openagents.plugins.loader |
公开的子插件加载入口,combinator (memory.chain, tool_executor.retry, execution_policy.composite, events.file_logging) 内部都走它 |
unwrap_tool_result(result) -> tuple[data, metadata | None] |
openagents.interfaces.pattern |
把 _BoundTool.invoke() 返回的 ToolExecutionResult 解包成 (data, executor_metadata);对 raw ToolPlugin.invoke() 返回值则直接 passthrough,metadata 为 None |
TypedConfigPluginMixin |
openagents.interfaces.typed_config |
Mixin,提供基于嵌套 Config(BaseModel) 的 self.cfg 校验;未知键发 warning 而非报错 |
openagents.plugins.loader._load_plugin 仍保留为 deprecated 别名,
会发 DeprecationWarning。
| Symbol | Module | Purpose |
|---|---|---|
OpenAgentsError(message, *, hint=None, docs_url=None, ...) |
openagents.errors.exceptions |
基类异常;新增可选 hint / docs_url。str(exc) 在被设置时会多输出 hint: ... / docs: ... 行,首行保持原 message 不变 |
near_match(needle, candidates, *, cutoff=0.6) |
openagents.errors.suggestions |
轻量 "did you mean?" 包装,基于 difflib.get_close_matches;返回最近匹配或 None |
EVENT_SCHEMAS |
openagents.interfaces.event_taxonomy |
已声明事件名 → EventSchema(name, required_payload, optional_payload, description) 的字典。AsyncEventBus.emit 在缺少必需 key 时 logger.warning,从不 raise |
EventSchema |
openagents.interfaces.event_taxonomy |
单个事件 schema 的 frozen dataclass |
gen_event_doc.render_doc() / write_doc(target) / main(argv) |
openagents.tools.gen_event_doc |
从 EVENT_SCHEMAS 重新生成 docs/event-taxonomy.md 的 helper |
These builtins ship under openagents/plugins/builtin/ but require an
optional extra to construct. Module import always succeeds; instantiation
without the extra raises PluginLoadError with an install hint.
| Class | Seam / type key | Module | Extra |
|---|---|---|---|
Mem0Memory |
memory / mem0 |
openagents.plugins.builtin.memory.mem0_memory |
mem0 |
McpTool |
tool / mcp |
openagents.plugins.builtin.tool.mcp_tool |
mcp |
SqliteSessionManager |
session / sqlite |
openagents.plugins.builtin.session.sqlite_backed |
sqlite |
OtelEventBusBridge |
events / otel_bridge |
openagents.plugins.builtin.events.otel_bridge |
otel |
Install with uv sync --extra <name> (or uv sync --extra all). Each
module is also added to [tool.coverage.report] omit in pyproject.toml
so the 92% coverage floor stays intact when the extra is not installed.
McpTool.Config 除了 server 与 tools 外,还支持:
connection_mode: "per_call" | "pooled"(默认per_call)。per_call保持 anyio cancel-scope 不跨调用泄漏;pooled复用长连接、N 次调用只 fork 一次子进程。probe_on_preflight: bool(默认false)。开启后preflight()会在 agent 循环启动前多开一次临时连接并list_tools()。dedup_inflight: bool(默认true)。合并per_call模式下同(tool, arguments)的并发调用,减少重复子进程启动。
ToolPlugin 新增可选钩子 async def preflight(self, context) -> None,默认实现为 no-op;DefaultRuntime 在每个 session 第一轮 agent turn 之前会依次调用。McpTool 重写此钩子,验证 mcp SDK、shutil.which 命令、URL 合法性,失败抛 PermanentToolError 由运行时翻译成 StopReason.FAILED 的 RunResult(不会进入 pattern loop)。
运行时会发射 tool.preflight、tool.mcp.preflight、tool.mcp.connect、tool.mcp.call、tool.mcp.close 结构化事件;payload 仅携带 id / 状态 / 耗时,不记录参数与返回值。