动态能力进入 Prompt 有两条主路径:可直接调用的工具变成 ToolSpec,沿 Prompt.tools 结构化通道发送;暂不展开的 Deferred Tool namespace 和 Extension 状态变成 World State 片段。把两者都写成自然语言工具清单,会丢失参数 Schema 和执行路由。
MCP Tool 先过滤,再建立 Runtime
MCP runtime 提供的 ToolInfo 先按模型可见性过滤。普通 MCP 排除 Codex Apps 专用 server;Apps 工具还要通过 connector allowlist 与策略评估。过滤后的每项创建 McpHandler,失败项记录警告并跳过。
def build_mcp_runtimes(tool_infos, connectors, policy, deferred_enabled):
runtimes = []
for info in filter_model_visible(tool_infos, connectors, policy):
try:
handler = McpHandler(info)
except InvalidToolSchema:
warn_skip(info)
continue
handler.exposure = "deferred" if deferred_enabled else "direct"
runtimes.append(handler)
return runtimes
Direct exposure 直接进入 router.model_visible_specs();开启搜索机制时可改为 Deferred,只把 namespace 概览告诉模型,待工具搜索后再补充具体规格。
Extension 可以贡献 Context 与 World State
Extension contributor 在 Thread、Turn 两个边界返回 RenderedContextFragment,初始上下文按角色接收。每个 Step 还可返回 WorldStateSectionContribution:带稳定 ID、JSON Snapshot、保留/遗留匹配器和差异渲染函数。
async def capture_extension_capabilities(extension, step):
context = await extension.contribute_turn_context(step.turn_input)
sections = await extension.contribute_world_state(step.world_input)
tools = await extension.register_tools(step.tool_input)
return ExtensionCapture(context, sections, tools)
ToolsState 对 Deferred namespace 使用 BTreeMap Snapshot,描述只保留首行和有限字符,整个片段限制在约 4 KiB;超出时记录省略数量。按 namespace 的对象结构还允许 Merge Patch 精确增加或删除单个命名空间。
一致性与失败边界
StepContext 捕获完成后,World State 工具概览、模型可见 ToolSpec 和执行 Router 必须保持一致。MCP 刷新应作用于下一 Step,不应在已发请求等待返回时替换当前 Router。Extension Snapshot 不能为 null,ID 冲突必须被发现,否则两个贡献者会互相覆盖持久化状态。
源码与测试锚点
codex-rs/core/src/mcp_tool_exposure.rs:MCP/App 过滤与 exposure。codex-rs/core/src/context/world_state/tools.rs:Deferred namespace Snapshot 和预算。codex-rs/core/src/session/world_state.rs:Extension section 装配。codex-rs/core/src/session/turn.rs::build_prompt:ToolSpec 汇合点。
评论
登录后即可评论