Codex 系统手册

Core src 运行时、会话、策略和状态测试

stage-23.2.140 个文件

这一阶段不是系统真正“干活”的代码,而是给核心运行时做体检的测试区,属于幕后守门员。它从一次会话怎么启动、恢复、压缩历史,到模型输出怎么变成消息,再到代理线程、子任务、插件改写、图片和实时对话交接,都逐项检查。另一大块盯安全:命令能不能跑、文件能不能改、联网和工具调用要不要审批,Guardian 和执行策略是否拦得住。还有状态、Git、Shell、配置迁移等杂项检查,确保前台聊天顺畅,后台边界不乱。

本阶段的文件40

会话生命周期测试

这些测试涵盖核心会话引擎,包括轮次处理、guardian 审批路径、发布重建及相关状态语义。

core/src/session/tests.rs源码 ↗
testtest

这一段测试主要覆盖会话运行中很容易出事故的地方:新一轮对话是否及时发出开始事件,打断时是否有正确的结束标记;恢复旧对话时历史、token 统计和上下文是否还原;用户配置改了以后,应用、工具建议和钩子是否刷新;受管网络代理是否按权限启用,危险的全访问模式是否不会偷偷套上代理;以及助手流式文本里的引用和计划标签是否能跨片段正确解析。文件里还放了不少小帮手,用来造用户消息、助手消息、测试会话、测试配置和临时 hook 文件。整体作用不是实现产品功能,而是把这些复杂规则固定下来,像安全网一样保护 Session 子系统。 这段测试像是在给会话系统做体检。会话可以理解成一次聊天线程:里面有历史记录、当前模型、权限设置、令牌用量,也会把关键事件写到磁盘,方便恢复或分叉。这里的测试会故意制造很多场景,比如换模型、修改配置、从旧线程分叉、回滚最近几轮对话、命令超时、工具返回结构化数据等,然后检查系统给出的结果是否符合预期。它也验证扩展插件能不能在“回合开始”“出错”“令牌用量变化”“配置变化”时拿到正确资料。没有这些测试,系统可能表面能跑,但在恢复历史、统计用量、权限边界或回滚对话时悄悄出错,用户很难发现原因。 从这一段可以看出,这个测试文件像一套“验收清单”。Session 是系统运行时的核心对象,里面装着当前模型、工作目录、权限、环境、历史记录和各种服务。如果这些东西在更新时处理错了,轻则下一轮对话用错目录,重则把不该写的文件开放给工具。本段测试主要做三类事:先搭出假的测试会话和测试配置;再模拟用户改设置、切权限、切工作目录、创建子代理、回滚线程等情况;最后检查系统发出的事件、保存的配置和权限边界是否符合预期。这里还包含一些等待事件的小工具函数,避免异步测试因为消息还没到就误判失败。 这一段测试主要围绕 Session,也就是一次用户和助手对话的运行容器。它会造出临时配置、假认证、假模型管理器和事件通道,然后启动一个接近真实但不碰真实服务的测试会话。后面的测试会检查很多边界情况:恢复旧对话时 session_id 应该怎么继承;工具申请网络或文件权限时,是否按“本轮”“整个会话”和“具体环境”正确记录;相对路径是否按选中的环境目录展开;请求被策略禁止时是否静默拒绝;追踪信息是否能从外部请求一路带到任务里;关闭时是否先中断当前任务,再通知线程停止。简单说,这个文件不是实现功能,而是在给会话系统装“报警器”:一旦这些约定被破坏,测试就会失败。 这一段测试主要围绕 Session,也就是一次对话线程的运行状态。它会造出假的会话、假的配置、假的认证和事件通道,然后模拟真实使用里的情况:父会话关闭时子代理也要收到关闭命令;MCP 服务器刷新要等到下一轮再做;环境、时间、实时语音状态变化时要写进给模型看的上下文;扩展和多代理提示只在该出现时出现;技能说明太多时要裁剪并打点;图片生成成功才写保存说明;权限沙盒和上下文快照要能被持久化。可以把它理解成一套“验收清单”:不是给用户直接用,而是替开发者守住会话系统的关键承诺。 这段测试主要围绕 Session,也就是一次聊天线程里的运行管家。它检查很多容易出事故的边界情况:上下文更新是否正确写进 rollout(可恢复的对话流水账)、单独跑 shell 命令会不会误改上一轮上下文、实时语音列表是否固定、任务被取消时客户端先看到什么事件、追加输入是否只允许加到正确的活跃轮次里、代理之间的邮箱消息该留到当前轮还是下一轮、工具调用失败或取消时是否干净收尾。这里还放了几个测试用的假任务,比如马上结束的任务、永远不结束的任务、故意触发 guardian 拒绝的任务。它们像实验用的“假机器零件”,让测试能稳定地模拟完成、卡住、被打断等场景。

函数细节231
user_message187–197 ↗
fn user_message(text: &str) -> ResponseItem

作用:造一条“用户说了某段话”的测试消息。测试里不用每次手写完整结构,直接传文本就能得到标准用户输入。

数据流:输入一段字符串 → 把它放进 ResponseItem::Message,角色设成 user,内容设成输入文本 → 返回这条可放进历史记录的用户消息,不改动外部状态。

调用关系:它是很多回滚、重放和任务拒绝测试的造数工具;这些测试用它快速拼出对话历史,再交给 Session 的相关流程验证。

调用图:被 8 处调用(recompute_token_usage_uses_session_base_instructions, thread_rollback_persists_marker_and_replays_cumulatively, thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay, thread_rollback_restores_cleared_reference_context_item_after_compaction, try_start_turn_if_idle_rejects_active_review_turn_without_injecting, try_start_turn_if_idle_rejects_active_turn_without_injecting, try_start_turn_if_idle_rejects_pending_trigger_turn_without_injecting, try_start_turn_if_idle_rejects_plan_mode_without_injecting);外部调用 1 个(vec!)。

assistant_message199–209 ↗
fn assistant_message(text: &str) -> ResponseItem

作用:造一条“助手回复了某段话”的测试消息。它让测试能方便地构造一段已有的助手输出。

数据流:输入一段字符串 → 包装成角色为 assistant、内容为输出文本的 ResponseItem → 返回测试用的助手消息。

调用关系:它被线程回滚和历史重放相关测试调用,用来模拟旧对话里助手已经说过的话。

调用图:被 3 处调用(thread_rollback_persists_marker_and_replays_cumulatively, thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay, thread_rollback_restores_cleared_reference_context_item_after_compaction);外部调用 1 个(vec!)。

test_session_telemetry_without_metadata211–231 ↗
fn test_session_telemetry_without_metadata() -> SessionTelemetry

作用:创建一个不带账号等个人元数据的测试遥测对象。遥测就是记录指标和事件的工具,这里用于检查指标是否正确产生。

数据流:函数内部创建内存里的指标导出器和 MetricsClient → 创建 SessionTelemetry,并关掉用户提示记录和元数据标签 → 返回可在测试中读取指标的遥测对象。

调用关系:它被技能指标测试调用,测试用它收集线程启动时的指标,再检查描述长度、启用技能数量等统计是否正确。

调用图:调用 4 个内部函数(new, new, in_memory, new);被 2 处调用(emit_thread_start_skill_metrics_records_description_truncated_chars_without_omitted_skills, emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values);外部调用 2 个(default, env!)。

find_metric233–242 ↗
fn find_metric(resource_metrics: &'a ResourceMetrics, name: &str) -> &'a Metric

作用:从一包测试指标里按名字找出某个指标。找不到就直接让测试失败。

数据流:输入 ResourceMetrics 和指标名 → 遍历所有 scope 里的 metric → 找到同名指标就返回引用;找不到就 panic,让测试报错。

调用关系:它是 histogram_sum 的底层查找工具;histogram_sum 先靠它拿到指标,再读取直方图数值。

调用图:被 1 处调用(histogram_sum);外部调用 2 个(scope_metrics, panic!)。

histogram_sum244–257 ↗
fn histogram_sum(resource_metrics: &ResourceMetrics, name: &str) -> u64

作用:读取某个直方图指标的总和。直方图可以理解成“分桶统计”,这里测试只关心所有值加起来是多少。

数据流:输入指标集合和指标名 → 用 find_metric 找到指标 → 确认它是浮点直方图且只有一个数据点 → 返回四舍五入后的总和数字。

调用关系:它依赖 find_metric;在指标类测试里用来把底层复杂的指标格式变成一个好比较的整数。

调用图:调用 1 个内部函数(find_metric);外部调用 2 个(assert_eq!, panic!)。

skill_message259–269 ↗
fn skill_message(text: &str) -> ResponseItem

作用:造一条包含技能内容的用户消息。技能在这里也是以用户输入文本的形式放入历史里。

数据流:输入技能文本 → 包装成 role 为 user、content 为 InputText 的 ResponseItem → 返回这条测试消息。

调用关系:它服务于技能和应用提及解析测试,让测试可以放入一段像 <skill>...</skill> 的文本后检查解析结果。

调用图:外部调用 1 个(vec!)。

regular_turn_emits_turn_started_with_trace_id_without_waiting_for_startup_prewarm272–322 ↗
async fn regular_turn_emits_turn_started_with_trace_id_without_waiting_for_startup_prewarm()

作用:验证普通对话轮次会立刻发出“轮次已开始”事件,并带上追踪 ID,不会被启动预热卡住。追踪 ID 用来把一次请求在不同系统里的日志串起来。

数据流:先设置一个带 W3C trace 信息的父 span → 创建 session 和 turn context → 放入一个永远等不到完成的启动预热任务 → 启动普通任务 → 从事件通道读到 TurnStarted,并确认 turn_id 和 trace_id 正确,最后中止任务。

调用关系:它调用测试会话创建工具和 test_model_client_session;重点检查 Session::spawn_task 在预热未完成时仍先通知外部“轮次开始”。

调用图:调用 5 个内部函数(make_session_and_context_with_rx, test_model_client_session, new, new, install_test_tracing);外部调用 10 个(clone, new, assert!, assert_eq!, info_span!, panic!, from_millis, now, spawn, timeout)。

request_mcp_server_elicitation_auto_accepts_when_auto_deny_is_enabled325–365 ↗
async fn request_mcp_server_elicitation_auto_accepts_when_auto_deny_is_enabled()

作用:验证 MCP 服务器请求用户确认时,如果开启了自动拒绝模式,这里会直接生成一个自动接受的空响应且不发给前端。MCP 可以理解成外部工具服务器协议。

数据流:创建 session → 把 MCP elicitation 设置为 auto_deny → 构造一个表单请求 → 调用 request_mcp_server_elicitation → 得到 Accept 和空内容,同时 sent 为 false,事件通道也没有新消息。

调用关系:它直接测试 Session 处理 MCP elicitation 的分支,确保自动策略不会让界面弹出请求。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 5 个(String, assert!, assert_eq!, json!, from_value)。

interrupting_regular_turn_waiting_on_startup_prewarm_emits_turn_aborted368–425 ↗
async fn interrupting_regular_turn_waiting_on_startup_prewarm_emits_turn_aborted()

作用:验证普通轮次即使正在等启动预热,被用户打断时也会发出“轮次已中止”事件。这样界面不会一直以为任务还在跑。

数据流:创建 session 和一个卡住的预热任务 → 启动普通任务 → 先确认收到 TurnStarted → 调用 abort_all_tasks → 再确认收到原始标记事件和 TurnAborted,且原因、完成时间和耗时都存在。

调用关系:它和预热相关的启动测试配套,检查 Session 的中止流程能正确通知事件通道。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, test_model_client_session, new, new);外部调用 10 个(clone, new, assert!, assert_eq!, panic!, from_millis, from_secs, now, spawn, timeout)。

test_model_client_session427–442 ↗
fn test_model_client_session() -> crate::client::ModelClientSession

作用:创建一个测试用的模型客户端会话。模型客户端会话代表一次能和模型服务通信的连接上下文。

数据流:函数内部固定一个合法线程 ID → 用 OpenAI provider 信息创建 ModelClient → 调用 new_session → 返回可用于测试的 ModelClientSession。

调用关系:它被启动预热相关测试放进异步任务里,用来模拟预热最终会产出的模型会话。

调用图:调用 3 个内部函数(new, create_openai_provider, try_from);被 2 处调用(interrupting_regular_turn_waiting_on_startup_prewarm_emits_turn_aborted, regular_turn_emits_turn_started_with_trace_id_without_waiting_for_startup_prewarm)。

developer_input_texts444–459 ↗
fn developer_input_texts(items: &[ResponseItem]) -> Vec<&str>

作用:从一批消息里抽出 developer 角色的所有输入文本。developer 消息通常是系统给模型的开发者指令。

数据流:输入 ResponseItem 列表 → 只保留 role 为 developer 的消息 → 展开其中 InputText 内容 → 返回字符串切片列表。

调用关系:它被初始上下文和设置更新测试使用,用来检查生成给模型的开发者指令里到底包含了哪些文字。

调用图:被 9 处调用(build_initial_context_omits_default_image_save_location_with_image_history, build_initial_context_omits_default_image_save_location_without_image_history, build_initial_context_restates_realtime_start_when_reference_context_is_missing, build_initial_context_trims_skill_metadata_from_context_window_budget, build_initial_context_uses_previous_realtime_state, build_initial_context_uses_previous_turn_settings_for_realtime_end, build_settings_update_items_emits_realtime_end_when_session_stops_being_live, build_settings_update_items_emits_realtime_start_when_session_becomes_live, build_settings_update_items_uses_previous_turn_settings_for_realtime_end);外部调用 1 个(iter)。

developer_message_texts461–480 ↗
fn developer_message_texts(items: &[ResponseItem]) -> Vec<Vec<&str>>

作用:按消息分组提取 developer 消息里的文本。和 developer_input_texts 不同,它保留“每条 developer 消息各有哪些文本”的层次。

数据流:输入消息列表 → 找到每条 developer 消息 → 抽出每条消息里的 InputText → 返回 Vec<Vec<&str>>,外层是一条条消息,内层是该消息的文本片段。

调用关系:它用于检查多代理提示、扩展提示片段等是否作为独立 developer 消息出现,而不是只看扁平文本。

调用图:被 6 处调用(build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message, build_initial_context_adds_multi_agent_v2_subagent_usage_hint_as_developer_message, build_initial_context_includes_prompt_fragments_from_extensions, build_initial_context_omits_multi_agent_v2_usage_hints_when_feature_disabled, build_initial_context_omits_multi_agent_v2_usage_hints_when_hint_disabled, build_initial_context_omits_prompt_fragments_without_extension_state);外部调用 1 个(iter)。

user_input_texts482–497 ↗
fn user_input_texts(items: &[ResponseItem]) -> Vec<&str>

作用:从一批消息里抽出用户角色的输入文本。测试用它检查环境变化等内容是否被放进用户可见上下文。

数据流:输入 ResponseItem 列表 → 过滤 role 为 user 的消息 → 展开 InputText 内容 → 返回所有用户文本。

调用关系:它被设置更新相关测试调用,用来确认网络、时间等环境项该出现时出现、不该出现时不出现。

调用图:被 3 处调用(build_settings_update_items_emits_environment_item_for_network_changes, build_settings_update_items_emits_environment_item_for_time_changes, build_settings_update_items_omits_environment_item_when_disabled);外部调用 1 个(iter)。

write_project_hooks499–518 ↗
fn write_project_hooks(dot_codex: &Path) -> std::io::Result<()>

作用:在测试项目的 .codex 目录里写一个 hooks.json。hook 可以理解成某些事件发生时自动运行的命令。

数据流:输入 .codex 目录路径 → 创建目录 → 写入一个 SessionStart hook,命令是 echo hello from hook → 返回文件写入结果。

调用关系:它被项目 hook 信任测试调用,用来准备一个项目层 hook,再验证只有可信项目里的 hook 才会被加载。

调用图:被 2 处调用(session_start_hooks_only_load_from_trusted_project_layers, session_start_hooks_require_project_trust_without_config_toml);外部调用 3 个(join, create_dir_all, write)。

write_project_trust_config520–545 ↗
async fn write_project_trust_config(
    codex_home: &Path,
    trusted_projects: &[(&Path, TrustLevel)],
) -> std::io::Result<()>

作用:写一份测试用的用户配置,标记哪些项目是可信的。没有信任信息时,项目 hook 不应该随便执行。

数据流:输入 codex_home 和项目信任列表 → 把每个项目路径转成配置 key,并写入 trust_level → 序列化成 config.toml → 异步写入磁盘。

调用关系:它和 write_project_hooks 一起服务于 hook 信任测试:一个准备 hook 文件,一个准备信任配置。

调用图:被 2 处调用(session_start_hooks_only_load_from_trusted_project_layers, session_start_hooks_require_project_trust_without_config_toml);外部调用 5 个(default, iter, join, write, to_string)。

preview_session_start_hooks547–568 ↗
async fn preview_session_start_hooks(
    config: &crate::config::Config,
) -> std::io::Result<Vec<codex_protocol::protocol::HookRunSummary>>

作用:用给定配置预览 SessionStart hook 会运行哪些。预览只看结果,不真正执行命令。

数据流:输入 Config → 创建启用 hook 功能的 Hooks 对象 → 构造一次会话启动请求 → 返回 preview_session_start 的摘要列表。

调用关系:它是测试 hook 加载行为的便利入口,把配置层栈交给 Hooks 后检查会话启动 hook 是否会被识别。

调用图:调用 2 个内部函数(new, new);外部调用 1 个(default)。

test_tool_runtime570–584 ↗
fn test_tool_runtime(session: Arc<Session>, turn_context: Arc<TurnContext>) -> ToolCallRuntime

作用:创建测试用的工具调用运行环境。工具运行环境把工具路由、会话、当前轮次和变更追踪器绑在一起。

数据流:输入 Session 和 TurnContext → 从 turn context 创建 ToolRouter → 创建 TurnDiffTracker 的互斥锁(一把锁,防止并发乱改)→ 返回 ToolCallRuntime。

调用关系:它被工具输出、工具取消和邮箱投递相关测试调用,为工具执行流程搭一个最小可用环境。

调用图:调用 3 个内部函数(new, from_turn_context, new);被 4 处调用(handle_output_item_done_records_image_save_history_message, handle_output_item_done_skips_image_save_message_when_save_fails, shell_tool_cancellation_waits_for_runtime_cleanup, tool_calls_reopen_mailbox_delivery_for_current_turn);外部调用 4 个(new, default, new, new)。

make_connector586–602 ↗
fn make_connector(id: &str, name: &str) -> AppInfo

作用:造一个测试用的应用连接器信息。连接器就是某个外部应用或服务的入口,比如 calendar。

数据流:输入 id 和 name → 填入 AppInfo 的必要字段,其他字段为空或默认可访问、已启用 → 返回 AppInfo。

调用关系:它被技能文本提及应用的测试使用,让解析函数有一份“已知应用列表”可以匹配。

调用图:外部调用 1 个(new)。

assistant_message_stream_parsers_can_be_seeded_from_output_item_added_text605–619 ↗
fn assistant_message_stream_parsers_can_be_seeded_from_output_item_added_text()

作用:验证助手流式解析器可以先吃一段已有文本,再继续解析后续增量,并正确识别记忆引用标签。

数据流:创建解析器 → 先 seed 文本 hello 和半截 citation 标签 → 再 parse_delta 补上标签结尾和正文 → finish 收尾 → 断言可见文本是 hello 与 world,引用是 doc1。

调用关系:它直接测试 AssistantMessageStreamParsers,确保输出项新增事件和后续增量事件之间的标签能接上。

调用图:调用 1 个内部函数(new);外部调用 1 个(assert_eq!)。

assistant_message_stream_parsers_seed_buffered_prefix_stays_out_of_finish_tail622–636 ↗
fn assistant_message_stream_parsers_seed_buffered_prefix_stays_out_of_finish_tail()

作用:验证解析器遇到半截标签前缀时,不会把这段缓存错误地在结束时当成正文吐出来。

数据流:先 seed 到 hello 和半截 <oai-mem- → 后续 delta 补完整 citation → finish 收尾 → 检查最终只有 hello 和 world 可见,引用为 doc,尾巴为空。

调用关系:它补充覆盖 AssistantMessageStreamParsers 的边界情况,防止跨片段标签污染用户可见文本。

调用图:调用 1 个内部函数(new);外部调用 1 个(assert_eq!)。

assistant_message_stream_parsers_seed_plan_parser_across_added_and_delta_boundaries639–664 ↗
fn assistant_message_stream_parsers_seed_plan_parser_across_added_and_delta_boundaries()

作用:验证计划模式下,<proposed_plan> 标签即使被切在两段消息之间,也能被解析成计划片段。

数据流:创建 plan_mode 为 true 的解析器 → seed 一段 Intro 和半截 proposed 标签 → delta 补完整计划、步骤和 Outro → finish → 检查普通文本、计划开始、计划内容、计划结束这些片段顺序正确。

调用关系:它测试 AssistantMessageStreamParsers 的计划解析能力,保证流式输出切片不会破坏计划展示。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert!, assert_eq!)。

validated_network_policy_amendment_host_allows_normalized_match667–681 ↗
fn validated_network_policy_amendment_host_allows_normalized_match()

作用:验证网络策略修改里的主机名经过规范化后能正确匹配已批准主机。比如大小写、末尾点和端口不该导致误拒绝。

数据流:构造 host 为 ExAmPlE.Com.:443 的规则和 example.com 的审批上下文 → 调用 Session::validated_network_policy_amendment_host → 得到规范化后的 example.com。

调用关系:它直接测试 Session 的网络策略校验函数,确保用户批准的同一主机不会因为写法不同被当成不同目标。

调用图:外部调用 2 个(assert_eq!, validated_network_policy_amendment_host)。

validated_network_policy_amendment_host_rejects_mismatch684–699 ↗
fn validated_network_policy_amendment_host_rejects_mismatch()

作用:验证网络策略修改不能拿一个主机的批准去改另一个主机。这样可以防止权限被偷换。

数据流:构造 evil.example.com 的规则和 api.example.com 的审批上下文 → 调用校验函数 → 预期返回错误,并检查错误信息提到主机不匹配。

调用关系:它和正常匹配测试成对出现,固定 Session 网络审批的安全边界。

调用图:外部调用 2 个(assert!, validated_network_policy_amendment_host)。

start_managed_network_proxy_applies_execpolicy_network_rules702–734 ↗
async fn start_managed_network_proxy_applies_execpolicy_network_rules() -> anyhow::Result<()>

作用:验证启动受管网络代理时,会把执行策略里的网络允许规则应用进去。受管网络代理就是统一控制工具网络访问的本地代理。

数据流:创建 workspace-write 权限和代理规格 → 在执行策略里允许 example.com 的 HTTPS → 启动代理 → 读取当前配置 → 确认允许域名只有 example.com。

调用关系:它测试 Session::start_managed_network_proxy 如何合并执行策略,确保工具运行时能按策略访问指定域名。

调用图:调用 2 个内部函数(from_config_and_constraints, workspace_write);外部调用 5 个(assert_eq!, empty, start_managed_network_proxy, default, default)。

start_managed_network_proxy_ignores_invalid_execpolicy_network_rules737–779 ↗
async fn start_managed_network_proxy_ignores_invalid_execpolicy_network_rules() -> anyhow::Result<()>

作用:验证当管理约束要求只能使用指定域名时,执行策略里额外的网络规则会被忽略。

数据流:创建只允许 managed.example.com 的网络约束 → 执行策略另加 example.com → 启动代理 → 检查最终允许域名仍是 managed.example.com。

调用关系:它保护受管配置的优先级,确保 Session 启动代理时不会让低优先级规则绕过管理员要求。

调用图:调用 2 个内部函数(from_config_and_constraints, workspace_write);外部调用 7 个(default, assert_eq!, empty, start_managed_network_proxy, default, default, from)。

managed_network_proxy_decider_survives_full_access_start782–847 ↗
async fn managed_network_proxy_decider_survives_full_access_start() -> anyhow::Result<()>

作用:验证即使用全访问权限启动受管网络代理,后续切回受限权限时,网络决策器仍然有效。决策器就是遇到不确定请求时负责判断放行还是拦截的组件。

数据流:用全访问权限启动代理并装入一个会计数且返回 ask 的决策器 → 重新按 workspace-write 权限应用配置 → 通过代理请求 example.com → 读取 HTTP 响应 → 确认被 403 拦截,且决策器被调用一次。

调用关系:它覆盖 Session 启动和重新应用代理配置的连续场景,防止权限模式切换后丢掉网络审批逻辑。

调用图:调用 2 个内部函数(from_config_and_constraints, workspace_write);外部调用 14 个(clone, new, default, from_secs, from_utf8_lossy, assert!, assert_eq!, empty, start_managed_network_proxy, default (+4 more))。

new_turn_refreshes_managed_network_proxy_for_sandbox_change850–937 ↗
async fn new_turn_refreshes_managed_network_proxy_for_sandbox_change() -> anyhow::Result<()>

作用:验证新一轮对话改变沙箱权限时,受管网络代理配置会刷新。沙箱权限决定工具能不能访问文件和网络等资源。

数据流:先启动一个包含 .example.com 和 evil.com 的代理 → 把它塞进 session 状态 → 开启新轮次并把沙箱改成 DangerFullAccess → 再读代理配置 → 确认 evil.com 被移除,只剩要求里的 .example.com。

调用关系:它测试 Session::new_turn_with_sub_id 对权限变化的响应,确保每轮对话使用的网络规则跟当前沙箱一致。

调用图:调用 3 个内部函数(from_config_and_constraints, make_session_and_context, workspace_write);外部调用 9 个(new, default, assert_eq!, empty, start_managed_network_proxy, default, default, from, vec!)。

danger_full_access_turns_do_not_expose_managed_network_proxy940–962 ↗
async fn danger_full_access_turns_do_not_expose_managed_network_proxy() -> anyhow::Result<()>

作用:验证危险全访问模式下,新轮次不会把受管网络代理暴露给 turn context。全访问意味着不通过这套受管网络约束。

数据流:创建启用网络代理的配置,但权限设为 Disabled 全访问 → 创建 session → 开默认轮次 → 检查 turn_context.network 是空。

调用关系:它和 workspace-write 的正向测试对照,确认 Session 不会在全访问模式下错误套用代理。

调用图:调用 2 个内部函数(from_config_and_constraints, make_session_with_config);外部调用 3 个(default, assert!, default)。

danger_full_access_tool_attempts_do_not_enforce_managed_network965–1075 ↗
async fn danger_full_access_tool_attempts_do_not_enforce_managed_network() -> anyhow::Result<()>

作用:验证全访问模式下,工具执行尝试不会强制使用受管网络。这里用一个探针工具记录运行时收到的开关值。

数据流:定义 ProbeToolRuntime,在 run 时记录 attempt.enforce_managed_network → 创建全访问 session 且配置里有网络要求 → 新建轮次并确认没有 network → 用 ToolOrchestrator 跑探针工具 → 确认记录值是 false。

调用关系:它测试工具编排器和 Session 生成的 turn context 如何配合,确保全访问工具不会被错误加上受管网络限制。

调用图:调用 4 个内部函数(from_config_and_constraints, make_session_with_config, new, plain);外部调用 6 个(clone, default, default, assert!, assert_eq!, default)。

workspace_write_turns_continue_to_expose_managed_network_proxy1078–1101 ↗
async fn workspace_write_turns_continue_to_expose_managed_network_proxy() -> anyhow::Result<()>

作用:验证 workspace-write 权限下,新轮次仍然会带上受管网络代理。workspace-write 是比较受控的工作区写权限模式。

数据流:创建启用网络代理的 workspace-write 配置 → 创建 session → 开默认轮次 → 检查 turn_context.network 存在。

调用关系:它和全访问不暴露代理的测试形成对照,说明只有该受管的权限模式才会把代理交给工具。

调用图:调用 3 个内部函数(from_config_and_constraints, make_session_with_config, workspace_write);外部调用 3 个(default, assert!, default)。

user_shell_commands_do_not_inherit_managed_network_proxy1104–1151 ↗
async fn user_shell_commands_do_not_inherit_managed_network_proxy() -> anyhow::Result<()>

作用:验证用户手动运行的 shell 命令不会继承受管网络代理环境变量。这样用户自己的命令不会被会话工具网络策略意外影响。

数据流:创建带受管网络代理的 session 和轮次 → 执行一个打印 HTTP_PROXY 的用户 shell 命令 → 从事件通道等到命令结束 → 确认退出码为 0,输出是 not-set。

调用关系:它测试 execute_user_shell_command 和 Session 网络环境的边界:工具可用代理,但用户独立命令不应自动套用。

调用图:调用 3 个内部函数(from_config_and_constraints, make_session_with_config_and_rx, workspace_write);外部调用 7 个(clone, new, default, assert!, assert_eq!, execute_user_shell_command, default)。

get_base_instructions_no_user_content1154–1207 ↗
async fn get_base_instructions_no_user_content()

作用:验证基础指令只来自模型配置,不混入用户内容。基础指令就是每次发给模型的底层行为说明。

数据流:读取内置模型列表和提示文件 → 对多个模型 slug 取出模型信息 → 把模型 base_instructions 写入 session 状态 → 调用 get_base_instructions → 确认返回文本等于模型配置里的基础指令。

调用关系:它检查 Session::get_base_instructions 的来源是否干净,避免用户内容或别的上下文污染基础提示。

调用图:调用 2 个内部函数(test_config, make_session_and_context);外部调用 4 个(assert_eq!, bundled_models_response, include_str!, vec!)。

reload_user_config_layer_updates_effective_apps_config1210–1240 ↗
async fn reload_user_config_layer_updates_effective_apps_config()

作用:验证重新加载用户配置后,应用配置会反映最新文件内容。

数据流:在 codex_home 写入 config.toml,关闭 calendar 应用和破坏性功能 → 调用 reload_user_config_layer → 读取当前配置并解析 apps 表 → 确认 calendar.enabled 为 false,destructive_enabled 为 false。

调用关系:它测试 Session 运行中重载用户配置的能力,保证外部改配置文件后应用开关会更新。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 5 个(assert!, assert_eq!, deserialize, create_dir_all, write)。

reload_user_config_layer_updates_base_and_selected_profile_layers1243–1304 ↗
async fn reload_user_config_layer_updates_base_and_selected_profile_layers()

作用:验证用户配置重载会同时更新基础配置和当前选中的 profile 配置。profile 可以理解成一套命名配置方案。

数据流:写基础 config.toml 和 work.config.toml → 构建使用 work profile 的配置并放进 session → 修改两个文件 → 调用 reload_user_config_layer → 检查当前用户配置文件仍是 profile 文件,合并结果里 model 来自 profile-new,approval_policy 来自新基础配置 never。

调用关系:它覆盖 ConfigBuilder、配置层栈和 Session 重载流程的配合,防止 profile 用户修改后不生效。

调用图:调用 3 个内部函数(without_managed_config_for_tests, without_managed_config_for_tests, make_session_and_context);外部调用 4 个(new, assert_eq!, create_dir_all, write)。

reload_user_config_layer_refreshes_hooks1307–1378 ↗
async fn reload_user_config_layer_refreshes_hooks() -> anyhow::Result<()>

作用:验证用户配置重载后,hook 列表也会刷新,并且只有被信任的 hook 才会出现在预览里。

数据流:创建启用 hook 功能的 session → 准备一个用户 hook 配置 → 先确认当前预览为空 → 用 list_hooks 算出 hook key 和 hash,并构造带 trusted_hash 的配置写入文件 → reload_user_config_layer → 再预览 SessionStart hook,确认有 1 个。

调用关系:它测试 Session、codex_hooks 和配置层栈的联动,确保运行中信任 hook 后无需重启也能生效。

调用图:调用 1 个内部函数(make_session_with_config);外部调用 9 个(assert!, assert_eq!, list_hooks, default, from_value, json!, create_dir_all, write, to_string)。

refresh_runtime_config_refreshes_hooks1381–1453 ↗
async fn refresh_runtime_config_refreshes_hooks() -> anyhow::Result<()>

作用:验证直接刷新运行时配置时,hook 对象也会跟着更新。这和从磁盘重载类似,但入口不同。

数据流:在 session 原始配置中启用 hook 功能 → 写入带可信 hash 的用户 hook 配置 → 先确认当前 hooks 预览为空 → load_latest_config_for_session 得到新配置 → refresh_runtime_config → 确认预览里出现 1 个 hook。

调用关系:它测试 Session::refresh_runtime_config 的副作用,确保刷新配置不只是改字段,也会重建 hooks 运行组件。

调用图:调用 2 个内部函数(load_latest_config_for_session, make_session_and_context);外部调用 12 个(new, assert!, assert_eq!, try_from, version_for_toml, format!, from_value, json!, create_dir_all, write (+2 more))。

reload_user_config_layer_updates_effective_tool_suggest_config1456–1482 ↗
async fn reload_user_config_layer_updates_effective_tool_suggest_config()

作用:验证重载用户配置会更新工具建议的禁用列表。工具建议用于决定哪些连接器或插件不应被推荐。

数据流:写入 tool_suggest.disabled_tools,其中 connector id 带空格、plugin id 正常 → 调用 reload_user_config_layer → 读取配置 → 确认 connector id 被修剪成 calendar,plugin 保持 slack@openai-curated。

调用关系:它固定用户配置到 Session 有效配置的转换行为,尤其是工具 ID 的清理规则。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert_eq!, create_dir_all, write)。

refresh_runtime_config_updates_runtime_refreshable_fields_and_keeps_session_static_settings1485–1538 ↗
async fn refresh_runtime_config_updates_runtime_refreshable_fields_and_keeps_session_static_settings()

作用:验证运行时刷新只更新允许热更新的字段,同时保留会话启动时固定的设置。热更新就是不重启也能改的配置。

数据流:写入 apps 和 tool_suggest 配置 → 读取原始 session 配置 → 加载新配置后故意修改 model 和 notify → refresh_runtime_config → 确认 apps、tool_suggest 已更新,但 model 和 notify 仍保持原值。

调用关系:它测试 Session::refresh_runtime_config 的边界,防止会话中途把模型等静态设置偷偷换掉。

调用图:调用 2 个内部函数(load_latest_config_for_session, make_session_and_context);外部调用 6 个(assert!, assert_eq!, deserialize, create_dir_all, write, vec!)。

collect_explicit_app_ids_from_skill_items_includes_linked_mentions1541–1551 ↗
fn collect_explicit_app_ids_from_skill_items_includes_linked_mentions()

作用:验证技能文本里用链接形式提到应用时,能收集到对应应用 ID。

数据流:准备 calendar 连接器和一条包含 $calendar(app://calendar) 的技能消息 → 调用 collect_explicit_app_ids_from_skill_items → 得到包含 calendar 的集合。

调用关系:它测试技能上下文和应用连接器的匹配逻辑,确保明确链接不会被漏掉。

调用图:外部调用 3 个(new, assert_eq!, vec!)。

collect_explicit_app_ids_from_skill_items_resolves_unambiguous_plain_mentions1554–1564 ↗
fn collect_explicit_app_ids_from_skill_items_resolves_unambiguous_plain_mentions()

作用:验证技能文本里简单写 $calendar,且没有歧义时,也能解析成 calendar 应用。

数据流:准备 calendar 连接器和包含 use $calendar 的技能消息 → 传入空的技能名冲突表 → 调用解析函数 → 返回 calendar 集合。

调用关系:它补充测试非链接写法,保证用户或技能作者用简写时也能关联应用。

调用图:外部调用 3 个(new, assert_eq!, vec!)。

collect_explicit_app_ids_from_skill_items_skips_plain_mentions_with_skill_conflicts1567–1581 ↗
fn collect_explicit_app_ids_from_skill_items_skips_plain_mentions_with_skill_conflicts()

作用:验证当 $calendar 同时可能是技能名时,不会把普通提及误判成应用。这样可以避免歧义。

数据流:准备 calendar 连接器和包含 $calendar 的技能消息 → 提供一个 skill_name_counts_lower,表示 calendar 也是技能名 → 调用解析函数 → 返回空集合。

调用关系:它和无歧义解析测试配套,固定 collect_explicit_app_ids_from_skill_items 在冲突时更保守的规则。

调用图:外部调用 3 个(from, assert_eq!, vec!)。

reconstruct_history_matches_live_compactions1584–1595 ↗
async fn reconstruct_history_matches_live_compactions()

作用:验证从 rollout 日志重建历史时,结果和真实运行中的压缩历史一致。rollout 可以理解成保存下来的会话流水账。

数据流:创建 session 和样例 rollout → 新建一个重建用 turn → 调用 reconstruct_history_from_rollout → 比较重建 history 和预期一致,并确认 window_id 为 2。

调用关系:它测试 Session 的历史恢复算法,保证恢复旧会话时和当时在线压缩得到的历史相同。

调用图:调用 2 个内部函数(make_session_and_context, sample_rollout);外部调用 1 个(assert_eq!)。

reconstruct_history_uses_replacement_history_verbatim1598–1635 ↗
async fn reconstruct_history_uses_replacement_history_verbatim()

作用:验证压缩项里如果带了 replacement_history,就原样使用它,不再重新拼装。replacement_history 是压缩后用来替代旧历史的一整段记录。

数据流:构造一个 Compacted rollout 项,里面有 summary 和 stale developer instructions 组成的 replacement_history,window_id 为 42 → 调用 reconstruct_history_from_rollout → 确认 history 完全等于 replacement_history,window_id 为 42。

调用关系:它固定重建逻辑的优先级:压缩记录已经给出替代历史时,Session 不应自作主张修改。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 2 个(assert_eq!, vec!)。

record_initial_history_reconstructs_resumed_transcript1638–1652 ↗
async fn record_initial_history_reconstructs_resumed_transcript()

作用:验证恢复会话时,record_initial_history 会把保存的 transcript 重建进当前历史。

数据流:创建样例 rollout 和预期历史 → 调用 record_initial_history,传入 InitialHistory::Resumed → 从 session 状态读取历史 → 确认 raw_items 等于预期。

调用关系:它测试 Session 启动恢复流程,把 reconstruct_history_from_rollout 的结果真正安装到会话状态里。

调用图:调用 3 个内部函数(make_session_and_context, sample_rollout, default);外部调用 3 个(from, assert_eq!, Resumed)。

resize_all_images_prepares_failures_before_history_insertion1655–1712 ↗
async fn resize_all_images_prepares_failures_before_history_insertion()

作用:验证开启“调整所有图片”功能后,坏的图片数据在写入历史前会被替换成说明文字。这样历史里不会保存无法处理的脏图片。

数据流:创建启用 ResizeAllImages 的 session → 构造工具输出,包含文字、坏 base64 图片和正常 URL 图片 → record_conversation_items → 读取历史 → 确认坏图片变成“image content omitted...”文本,正常 URL 图片保留。

调用关系:它测试 Session 记录对话项前的图片预处理,防止后续历史、恢复或发送模型时再遇到坏图片。

调用图:调用 2 个内部函数(make_session_and_context_with_auth_and_config_and_rx, from_api_key);外部调用 5 个(new, assert_eq!, ContentItems, from_ref, vec!)。

resize_all_images_prepares_resumed_history_before_installing_it1715–1765 ↗
async fn resize_all_images_prepares_resumed_history_before_installing_it()

作用:验证恢复旧历史时,也会先处理坏图片再放进当前会话历史。

数据流:创建启用 ResizeAllImages 的 session → 构造一条恢复历史,包含坏 base64 图片和 keep me 文本 → record_initial_history 恢复它 → 读取历史 → 确认坏图片被替换成说明文字,文本保留。

调用关系:它补充覆盖恢复入口,确保图片清理不只发生在新记录的消息上,也发生在旧 transcript 装载时。

调用图:调用 3 个内部函数(make_session_and_context_with_auth_and_config_and_rx, from_api_key, default);外部调用 5 个(from, new, assert_eq!, Resumed, vec!)。

resolve_multi_agent_version_handles_unset_and_legacy_history1768–1831 ↗
fn resolve_multi_agent_version_handles_unset_and_legacy_history()

作用:验证多代理版本的推断规则。多代理版本决定会话是否以及如何支持多个代理协作。

数据流:分别构造新会话、恢复空历史、带继承版本、带 session meta、forked 历史等场景 → 调用 resolve_multi_agent_version → 检查返回 None、V1、V2 或 Disabled 是否符合预期。

调用关系:它直接测试版本解析函数,保证旧历史默认按 V1 处理,明确元数据或继承值时按规则覆盖。

调用图:调用 1 个内部函数(default);外部调用 1 个(assert_eq!)。

record_initial_history_new_defers_initial_context_until_first_turn1834–1843 ↗
async fn record_initial_history_new_defers_initial_context_until_first_turn()

作用:验证全新会话记录初始历史时,不会立刻塞入初始上下文,而是等第一轮真正需要时再做。

数据流:创建 session → 调用 record_initial_history(InitialHistory::New) → 读取历史、reference_context_item 和 previous_turn_settings → 确认历史为空,上下文项为空,上一轮设置为空。

调用关系:它测试 Session 新会话启动的懒加载行为,避免在还没开始对话时提前污染历史。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 2 个(assert!, assert_eq!)。

session_meta_item1845–1857 ↗
fn session_meta_item(
    thread_id: ThreadId,
    multi_agent_version: Option<MultiAgentVersion>,
) -> RolloutItem

作用:造一条测试用的会话元数据 rollout 项。元数据里主要放线程 ID 和多代理版本。

数据流:输入 ThreadId 和可选 MultiAgentVersion → 填进 SessionMetaLine,其他元数据用默认值,git 为空 → 返回 RolloutItem::SessionMeta。

调用关系:它被多代理版本解析测试使用,用来模拟旧 transcript 里保存过的 session meta 行。

调用图:调用 1 个内部函数(default);外部调用 1 个(SessionMeta)。

resumed_history_injects_initial_context_on_first_context_update_only1860–1891 ↗
async fn resumed_history_injects_initial_context_on_first_context_update_only()

作用:验证恢复历史后,初始上下文只会在第一次上下文更新时注入一次,不会重复追加。

数据流:恢复样例 rollout 到 session → 确认初始历史等于预期 → 第一次 record_context_updates_and_set_reference_context_item 后构造 initial_context 并追加到预期,检查历史一致 → 第二次再调用同一函数,确认历史没有变化。

调用关系:它测试恢复会话后的上下文补种流程,防止每次上下文更新都重复把初始说明塞进历史。

调用图:调用 3 个内部函数(make_session_and_context, sample_rollout, default);外部调用 3 个(from, assert_eq!, Resumed)。

record_initial_history_seeds_token_info_from_rollout1894–1968 ↗
async fn record_initial_history_seeds_token_info_from_rollout()

作用:验证恢复历史时,会从 rollout 里的 token 统计事件中取最后一个有效统计值。token 是模型处理文本的大致计量单位。

数据流:在样例 rollout 后追加多个 TokenCount 事件,其中有空 info 和两个有效 info → record_initial_history 恢复 → 读取 session token_info → 确认保存的是最后一个有效的 info2。

调用关系:它测试 Session 恢复 token 计数状态的逻辑,保证恢复后界面或后续预算计算能接着旧统计走。

调用图:调用 3 个内部函数(make_session_and_context, sample_rollout, default);外部调用 5 个(from, assert_eq!, TokenCount, Resumed, EventMsg)。

recompute_token_usage_uses_session_base_instructions1971–2008 ↗
async fn recompute_token_usage_uses_session_base_instructions()

作用:这个测试确认重新计算令牌用量时,用的是会话里当前保存的基础指令,而不是模型默认指令。令牌可以粗略理解成模型读写文字时计费和限长用的小单位。

数据流:测试先创建一个会话和回合上下文,再把会话的基础指令改成一段很长的特殊文字。然后放入一条用户消息,分别按“会话指令”和“模型默认指令”估算令牌数,确认两者不同。最后调用重新计算功能,检查会话状态里记录的实际令牌数变成按会话指令算出的值。

调用关系:它通过 make_session_and_context 搭出测试场景,通过 user_message 放入聊天内容,最后直接验证 session.recompute_token_usage 的行为。这个测试保护的是令牌统计流程,避免配置被改后统计仍沿用旧规则。

调用图:调用 2 个内部函数(make_session_and_context, user_message);外部调用 3 个(assert_eq!, assert_ne!, from_ref)。

recompute_token_usage_updates_model_context_window2011–2030 ↗
async fn recompute_token_usage_updates_model_context_window()

作用:这个测试确认重新计算令牌用量时,也会顺手更新模型的上下文窗口大小。上下文窗口就是模型一次最多能看多少内容的容量上限。

数据流:测试先在会话状态里放一个旧的上下文窗口值 258400,再把当前回合里的模型窗口改成 128000。调用重新计算后,它读取会话保存的 token_info,确认里面的 model_context_window 已经变成新的 128000。

调用关系:它直接覆盖 session.recompute_token_usage 在更新 token_info 时的附带行为。这样后续依赖窗口大小做截断或显示的代码,不会拿到过期数据。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 2 个(assert_eq!, default)。

record_token_usage_info_notifies_extension_contributors2033–2147 ↗
async fn record_token_usage_info_notifies_extension_contributors()

作用:这个测试确认每次记录令牌用量时,注册的扩展插件都会收到通知,而且能拿到会话、线程、当前回合三层数据。

数据流:测试先定义一个假的令牌记录插件,把收到的内容存进共享列表。然后创建会话,注册这个插件,并在会话级和线程级数据仓库里放入标记。接着连续记录两次令牌用量。最后检查插件收到了两条记录:第一条是首次用量,第二条是累计后的总用量,并且插件确实看到了两层标记。

调用关系:它围绕 session.record_token_usage_info 展开,模拟扩展系统里的 TokenUsageContributor。这个测试保证主流程更新用量时,不只是自己记账,也会把账单同步给外部扩展。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 7 个(clone, new, new, assert_eq!, new, new, vec!)。

turn_start_lifecycle_exposes_turn_metadata_and_token_baseline2150–2253 ↗
async fn turn_start_lifecycle_exposes_turn_metadata_and_token_baseline()

作用:这个测试确认一个新回合开始时,扩展插件能看到回合编号、协作模式,以及回合开始前已有的令牌用量。

数据流:测试先准备一个假的“回合生命周期”插件,用来记录 on_turn_start 收到的数据。它给会话设置一份已有令牌用量,然后启动一个不会自己结束的任务。任务开始时应触发回合开始回调。最后测试中止任务,并检查插件只收到一条记录,里面包含正确的会话编号、线程编号、回合编号、协作模式和令牌基线。

调用关系:它通过 sess.spawn_task 触发真实的回合启动路径,再用 abort_all_tasks 收尾。这个测试保证扩展能在回合刚开始时拿到足够上下文,而不是等事情发生后才补通知。

调用图:调用 2 个内部函数(make_session_and_context, set_total_token_usage);外部调用 6 个(clone, new, new, assert_eq!, new, new)。

turn_error_lifecycle_exposes_error_and_stores2256–2339 ↗
async fn turn_error_lifecycle_exposes_error_and_stores()

作用:这个测试确认回合报错时,扩展插件能收到错误类型,也能访问会话级和线程级的数据仓库。

数据流:测试创建一个假的生命周期插件,专门记录 on_turn_error 的输入。随后给会话注册插件,并放入会话级、线程级标记。调用 emit_turn_error_lifecycle 发出一个 UsageLimitExceeded 错误后,测试检查插件记录里有正确的三层编号、回合编号、错误信息,并且能看到那些标记。

调用关系:它直接测试 session.emit_turn_error_lifecycle 这条错误通知路径。这个测试保护的是异常流程,确保出错时扩展仍能拿到完整现场。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 6 个(clone, new, new, assert_eq!, new, new)。

config_change_contributor_observes_effective_config_changes2342–2466 ↗
async fn config_change_contributor_observes_effective_config_changes()

作用:这个测试确认配置真的发生变化时,配置扩展插件能看到变化前和变化后的有效配置。

数据流:测试先注册一个配置记录插件。然后第一次通过 update_settings 改模型,插件应看到模型从旧值变新值。接着测试把用户配置文件写到磁盘,里面禁用了两个工具,再刷新运行时配置。插件应看到禁用工具列表从旧值变成清洗后的新值,比如去掉 id 两边空格。最后检查两次记录都完整且能访问数据仓库。

调用关系:它覆盖两条配置变化路径:运行中的设置更新,以及从配置文件重新加载。它把 load_latest_config_for_session、update_settings 和 refresh_runtime_config 串起来,确认最终通知的是“真正生效”的配置。

调用图:调用 2 个内部函数(load_latest_config_for_session, make_session_and_context);外部调用 10 个(clone, new, default, new, assert_eq!, new, create_dir_all, write, new, vec!)。

record_initial_history_reconstructs_forked_transcript2469–2479 ↗
async fn record_initial_history_reconstructs_forked_transcript()

作用:这个测试确认从已有线程分叉时,系统能把传入的历史记录重建成正确的聊天历史。

数据流:测试先生成一份样例 rollout。rollout 可以理解成保存在线程日志里的事件流水。然后用 InitialHistory::Forked 把它交给 record_initial_history。最后读取会话内存里的历史,确认它和预期重建结果完全一样。

调用关系:它专门测试 session.record_initial_history 对分叉历史的处理。这个功能是线程分叉能继续对话的基础。

调用图:调用 2 个内部函数(make_session_and_context, sample_rollout);外部调用 2 个(assert_eq!, Forked)。

session_configured_reports_permission_profile_for_external_sandbox2482–2509 ↗
async fn session_configured_reports_permission_profile_for_external_sandbox() -> anyhow::Result<()>

作用:这个测试确认当会话使用外部沙盒时,对外报告的权限配置仍然明确写成“外部沙盒”,不会被错误压扁成别的权限类型。

数据流:测试启动一个模拟服务器,配置一个外部沙盒策略和对应的权限档案。构建测试会话后,它读取 session_configured 事件里的 permission_profile,确认和预期的外部权限档案一致。

调用关系:它通过 test_codex 搭建接近真实启动的会话配置流程。这个测试保护客户端看到的权限信息,避免 UI 或调用方误判沙盒能力。

调用图:调用 2 个内部函数(start_mock_server, test_codex);外部调用 1 个(assert_eq!)。

session_permission_profile_rebinds_runtime_workspace_roots2512–2555 ↗
async fn session_permission_profile_rebinds_runtime_workspace_roots() -> anyhow::Result<()>

作用:这个测试确认“工作区可写目录”这种运行时路径不会被永久写死,而是会随着会话工作区变化重新绑定。

数据流:测试先创建配置,其中旧工作区根目录被加入可写范围。它检查从配置生成的权限状态本身仍保留符号化的工作区规则,不直接写死旧路径。然后把这个状态放进会话配置,确认旧根目录当前可写。接着应用一次设置更新,把工作区根目录改成新路径。最后确认新路径可写,旧路径不再可写。

调用关系:它测试 SessionConfiguration.apply 和权限档案状态之间的配合。这个测试防止用户切换工作区后,旧目录还意外保留写权限。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 7 个(default, new, assert!, default, test_path_buf, new, vec!)。

fork_startup_context_then_first_turn_diff_snapshot2558–2667 ↗
async fn fork_startup_context_then_first_turn_diff_snapshot() -> anyhow::Result<()>

作用:这个测试用快照确认:从一个已有线程分叉后,第一次请求模型时带上的上下文、审批策略变化和协作模式变化都正确。

数据流:测试先让初始线程完成一轮对话,并强制把 rollout 写到磁盘。然后用不同审批策略从这个 rollout 分叉出新线程。分叉后提交一条新用户输入,并在该回合里切到计划模式、设置新的开发者指令和审批策略。测试捕获发给模拟模型服务器的第一条请求,格式化成可读快照,再和保存的快照比对。

调用关系:它串起模拟服务器、真实提交用户输入、线程分叉和请求快照检查。这个测试更像端到端验收,保护分叉启动上下文不会悄悄改变。

调用图:调用 7 个内部函数(allow_any, default, format_labeled_requests_snapshot, mount_sse_once, sse, start_mock_server, test_codex);外部调用 4 个(default, wait_for_event, clone_current, vec!)。

record_initial_history_forked_hydrates_previous_turn_settings2670–2750 ↗
async fn record_initial_history_forked_hydrates_previous_turn_settings()

作用:这个测试确认从分叉历史恢复时,系统能从上一轮的上下文里取回模型等设置,但不会把旧对话内容直接塞进当前历史。

数据流:测试手工构造一个包含 TurnStarted、UserMessage、TurnContext、TurnComplete 的分叉 rollout,其中 TurnContext 记录了上一轮使用的模型。调用 record_initial_history 后,它检查 previous_turn_settings 已恢复为上一轮模型和实时状态;同时检查当前聊天历史为空;还检查 reference_context_item 保存了那份上一轮上下文。

调用关系:它测试 InitialHistory::Forked 的特殊恢复规则。这个规则让分叉线程知道自己继承了什么设置,但又能从干净的当前历史开始。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert_eq!, Forked, vec!)。

thread_rollback_drops_last_turn_from_history2753–2818 ↗
async fn thread_rollback_drops_last_turn_from_history()

作用:这个测试确认线程回滚一轮时,会从内存历史里删掉最后一轮对话,并清理上一轮设置和参考上下文。

数据流:测试先给会话接上持久化文件,再构造初始上下文、第一轮、第二轮的完整历史,并把这些内容写入 rollout。随后设置一些会过期的 previous_turn_settings 和 reference_context_item。调用 thread_rollback 回滚 1 轮后,测试等待回滚事件,检查历史只剩初始上下文加第一轮,旧设置被清空,并且持久化日志里写入了 ThreadRolledBack 标记。

调用关系:它通过 handlers::thread_rollback 走真实回滚入口,并用 wait_for_thread_rolled_back 验证对外事件。这个测试保证内存状态和磁盘日志一起被更新。

调用图:调用 5 个内部函数(thread_rollback, attach_thread_persistence, make_session_and_context_with_rx, wait_for_thread_rolled_back, get_rollout_history);外部调用 6 个(get_mut, new, assert!, assert_eq!, panic!, vec!)。

thread_rollback_clears_history_when_num_turns_exceeds_existing_turns2821–2848 ↗
async fn thread_rollback_clears_history_when_num_turns_exceeds_existing_turns()

作用:这个测试确认如果要求回滚的轮数超过已有对话轮数,系统不会崩溃,而是尽量回到只剩初始上下文的状态。

数据流:测试构造一个只有一轮用户消息的历史并写入持久化。然后请求回滚 99 轮。回滚完成后,它检查发出的事件仍记录请求的 99,内存历史则只保留初始上下文。

调用关系:它测试 handlers::thread_rollback 的过量回滚场景。这个边界情况很重要,因为用户或客户端可能传入比实际更多的回滚轮数。

调用图:调用 4 个内部函数(thread_rollback, attach_thread_persistence, make_session_and_context_with_rx, wait_for_thread_rolled_back);外部调用 4 个(get_mut, new, assert_eq!, vec!)。

thread_rollback_fails_without_persisted_thread_history2851–2870 ↗
async fn thread_rollback_fails_without_persisted_thread_history()

作用:这个测试确认没有持久化线程历史时,线程回滚会明确失败,而不是凭空猜测该删什么。

数据流:测试创建会话但不接持久化日志,只把初始上下文记到内存历史。调用 thread_rollback 后,它等待失败事件,检查错误消息是“thread rollback requires persisted thread history”,错误类型也是 ThreadRollbackFailed,并确认内存历史没有被改动。

调用关系:它保护 handlers::thread_rollback 的前置条件:回滚必须依赖磁盘上的事件流水重放。没有这个日志,系统宁可失败也不冒险破坏历史。

调用图:调用 3 个内部函数(thread_rollback, make_session_and_context_with_rx, wait_for_thread_rollback_failed);外部调用 1 个(assert_eq!)。

thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay2873–2992 ↗
async fn thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay()

作用:这个测试确认回滚后,上一轮设置和参考上下文不是沿用旧内存值,而是从持久化日志重新播放得出。

数据流:测试手工写入两轮完整 rollout:第一轮正常,第二轮是将被回滚的轮次,并故意把当前内存历史和 previous_turn_settings 设成过期假数据。回滚 1 轮后,系统重放日志,只留下第一轮用户和助手消息。测试检查 previous_turn_settings 恢复成第一轮模型信息,reference_context_item 也恢复成第一轮上下文。

调用关系:它验证 handlers::thread_rollback 内部的“从日志重放恢复状态”机制。这个测试防止回滚后留下旧状态,导致下一轮请求带错模型或上下文。

调用图:调用 6 个内部函数(thread_rollback, assistant_message, attach_thread_persistence, make_session_and_context_with_rx, user_message, wait_for_thread_rolled_back);外部调用 11 个(get_mut, default, new, assert_eq!, TurnComplete, TurnStarted, UserMessage, EventMsg, ResponseItem, TurnContext (+1 more))。

thread_rollback_restores_cleared_reference_context_item_after_compaction2995–3114 ↗
async fn thread_rollback_restores_cleared_reference_context_item_after_compaction()

作用:这个测试确认如果历史曾经被压缩,回滚后会恢复到压缩后的历史窗口,并正确处理参考上下文和窗口编号。

数据流:测试写入一段 rollout:第一轮正常,接着有一次压缩,压缩项带有替换后的历史和窗口编号 7,然后第三段是将被回滚的回合。它先把内存历史设成过期内容,并设置一个过期窗口编号 99。回滚 1 轮后,测试检查历史变成压缩项里的 replacement_history,参考上下文为空,当前窗口编号结尾变成 :7。

调用关系:它测试回滚和压缩历史之间的配合。压缩像把旧账本汇总成一页摘要,这个测试确保回滚不会把账本翻回错误页。

调用图:调用 6 个内部函数(thread_rollback, assistant_message, attach_thread_persistence, make_session_and_context_with_rx, user_message, wait_for_thread_rolled_back);外部调用 13 个(get_mut, default, new, assert!, assert_eq!, TurnComplete, TurnStarted, UserMessage, Compacted, EventMsg (+3 more))。

thread_rollback_persists_marker_and_replays_cumulatively3117–3237 ↗
async fn thread_rollback_persists_marker_and_replays_cumulatively()

作用:这个测试确认连续回滚会累计生效,并且每次回滚都会在持久化日志里留下标记。

数据流:测试写入三轮完整 rollout。然后连续调用两次 thread_rollback,每次回滚 1 轮,并分别等待成功事件。最后检查内存历史只剩第一轮的用户和助手消息;再读取 rollout 文件,统计 ThreadRolledBack 标记,确认有两个。

调用关系:它测试 handlers::thread_rollback 多次执行时的累计效果。这个测试保证日志不是只记录最后一次状态,而是保留每次回滚动作。

调用图:调用 7 个内部函数(thread_rollback, assistant_message, attach_thread_persistence, make_session_and_context_with_rx, user_message, wait_for_thread_rolled_back, get_rollout_history);外部调用 11 个(get_mut, default, new, assert_eq!, panic!, TurnComplete, TurnStarted, UserMessage, EventMsg, ResponseItem (+1 more))。

thread_rollback_fails_when_turn_in_progress3240–3258 ↗
async fn thread_rollback_fails_when_turn_in_progress()

作用:这个测试确认当有一轮对话正在进行时,系统拒绝回滚,避免一边生成回答一边删除历史。

数据流:测试先记录初始上下文,然后手动把 active_turn 设成正在进行。调用 thread_rollback 后,它等待失败事件,确认错误类型是 ThreadRollbackFailed,并检查历史保持不变。

调用关系:它保护 handlers::thread_rollback 的并发安全。active_turn 像门口挂着“正在施工”的牌子,回滚必须等施工结束。

调用图:调用 4 个内部函数(thread_rollback, make_session_and_context_with_rx, wait_for_thread_rollback_failed, default);外部调用 1 个(assert_eq!)。

thread_rollback_fails_when_num_turns_is_zero3261–3279 ↗
async fn thread_rollback_fails_when_num_turns_is_zero()

作用:这个测试确认请求回滚 0 轮会被当作无效请求并失败。

数据流:测试记录初始上下文后,调用 thread_rollback,num_turns 传 0。它等待失败事件,检查错误消息是“num_turns must be >= 1”,错误类型是 ThreadRollbackFailed,并确认历史没有变化。

调用关系:它测试 handlers::thread_rollback 的输入校验。这样调用方传错参数时,系统会给出清楚错误,而不是做一个意义不明的空操作。

调用图:调用 3 个内部函数(thread_rollback, make_session_and_context_with_rx, wait_for_thread_rollback_failed);外部调用 1 个(assert_eq!)。

set_rate_limits_retains_previous_credits3282–3385 ↗
async fn set_rate_limits_retains_previous_credits()

作用:这个测试确认更新限流信息时,如果新数据没带余额信息,系统会保留旧的余额和套餐信息。

数据流:测试先创建一份 SessionState,并设置一份初始 RateLimitSnapshot,其中有额度窗口、credits 余额和 plan_type 套餐。然后再设置一份更新数据,这次有新的限流窗口,但 credits 和 plan_type 为空。最后检查 state.latest_rate_limits:窗口变成新的,余额和套餐仍沿用旧的。

调用关系:它直接测试 SessionState.set_rate_limits 的合并规则。这个规则很实用,因为服务端有时只发部分字段,客户端不能因为缺字段就把余额显示清空。

调用图:调用 5 个内部函数(build_test_config, new, construct_model_info_offline_for_tests, get_model_offline_for_tests, new);外部调用 6 个(clone, new, new, assert_eq!, from_config, tempdir)。

set_rate_limits_updates_plan_type_when_present3388–3491 ↗
async fn set_rate_limits_updates_plan_type_when_present()

作用:这个测试确认更新限流信息时,如果新数据明确带了新的套餐类型,系统会采用新套餐,同时仍保留没更新的余额。

数据流:测试先设置一份初始限流快照,套餐是 Plus,余额存在。然后设置第二份快照,套餐变成 Pro,但余额为空。最后检查最新状态:限流窗口使用新值,plan_type 变成 Pro,credits 仍保留初始余额。

调用关系:它和 set_rate_limits_retains_previous_credits 互补,覆盖“字段缺失就保留”和“字段出现就更新”两种情况。核心被测对象仍是 SessionState.set_rate_limits。

调用图:调用 5 个内部函数(build_test_config, new, construct_model_info_offline_for_tests, get_model_offline_for_tests, new);外部调用 6 个(clone, new, new, assert_eq!, from_config, tempdir)。

prefers_structured_content_when_present3494–3519 ↗
fn prefers_structured_content_when_present()

作用:这个测试确认 MCP 工具调用结果里如果有结构化内容,就优先把结构化内容返回给模型,而不是普通文本内容。MCP 可以理解成外部工具接入协议。

数据流:测试构造一个 McpCallToolResult:content 里放了应被忽略的文本,structured_content 里放 JSON 对象。调用 into_function_call_output_payload 后,检查输出正文是这个 JSON 对象序列化后的字符串,success 是 true。

调用关系:它测试工具结果转换函数 into_function_call_output_payload。这个规则让模型拿到机器更容易理解的结构化结果,而不是退回到文本列表。

调用图:外部调用 5 个(assert_eq!, json!, Text, to_string, vec!)。

includes_timed_out_message3522–3539 ↗
async fn includes_timed_out_message()

作用:这个测试确认命令执行超时时,格式化给用户或模型看的输出里会明确写出超时信息。

数据流:测试构造一个 ExecToolCallOutput,里面有聚合输出“Command output”,耗时 1 秒,并标记 timed_out 为 true。调用 format_exec_output_str 后,检查结果以“command timed out after 1000 milliseconds”开头,然后跟着原命令输出。

调用关系:它测试命令工具输出的格式化逻辑。这样调用方不会只看到一段输出,却不知道命令其实是超时结束的。

调用图:调用 3 个内部函数(make_session_and_context, format_exec_output_str, new);外部调用 3 个(from_secs, new, assert_eq!)。

turn_context_with_model_updates_model_fields3542–3576 ↗
async fn turn_context_with_model_updates_model_fields()

作用:这个测试确认把回合上下文切换到另一个模型时,相关字段会一起更新,而不是只改一个名字。

数据流:测试先创建会话和回合上下文,并把 reasoning_effort 设成 Minimal。然后调用 with_model 切换到 gpt-5.4。它再从模型管理器拿到这个模型的预期信息,并检查更新后的配置模型名、协作模式模型名、model_info、推理强度、配置里的推理强度、截断策略都同步到了新模型应有的值。

调用关系:它测试 TurnContext.with_model 和 models_manager 的配合。这个测试防止换模型后,仍沿用旧模型的窗口、截断或推理强度设置。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 1 个(assert_eq!)。

falls_back_to_content_when_structured_is_null3579–3596 ↗
fn falls_back_to_content_when_structured_is_null()

作用:这个测试确认 MCP 工具结果里的 structured_content 如果只是 JSON 的 null,就当作没有结构化内容,改用普通 content。

数据流:测试构造一个 McpCallToolResult,content 里有 hello 和 world 两段文本,structured_content 是 Null。调用转换函数后,检查输出正文是 content 列表序列化后的字符串,success 是 true。

调用关系:它补充测试 into_function_call_output_payload 的降级规则。这样工具误传 null 时,系统仍能把可用文本结果交出去。

调用图:外部调用 4 个(assert_eq!, Text, to_string, vec!)。

success_flag_reflects_is_error_true3599–3616 ↗
fn success_flag_reflects_is_error_true()

作用:这个测试确认 MCP 工具结果标记 is_error 为 true 时,最终输出里的 success 会变成 false。

数据流:测试构造一个工具结果:structured_content 是错误消息 JSON,is_error 是 true。调用 into_function_call_output_payload 后,检查正文是错误 JSON 字符串,同时 success 是 false。

调用关系:它测试工具结果转换时的成功失败标记。这样上层模型或客户端不必猜正文是不是错误,可以直接看 success。

调用图:外部调用 5 个(assert_eq!, json!, Text, to_string, vec!)。

success_flag_true_with_no_error_and_content_used3619–3636 ↗
fn success_flag_true_with_no_error_and_content_used()

作用:测试一个工具调用结果在没有报错时,会被转换成“成功”的函数输出。它确认文本内容不会丢,而且成功标记会变成 true。

数据流:输入是一个假的 McpCallToolResult,里面有一段文本 alpha,is_error 明确是 false。函数把它转换成 FunctionCallOutputPayload,再手工拼出期望结果。最后比较两边是否完全一样;它不改外部状态。

调用关系:这是一个独立断言测试,专门盯住工具结果到函数输出载荷的转换规则。它借助 text_block 形状相同的 JSON 文本块,防止转换逻辑以后被改坏。

调用图:外部调用 4 个(assert_eq!, Text, to_string, vec!)。

wait_for_thread_rolled_back3638–3652 ↗
async fn wait_for_thread_rolled_back(rx: &async_channel::Receiver<Event>) -> ThreadRolledBackEvent

作用:在异步测试里等待“线程已经回滚”的事件。它像在收件箱里等一封指定主题的信,等到了就返回。

数据流:输入是事件接收器 rx。函数最多等 2 秒,不断从 rx 收事件;如果事件消息是 ThreadRolledBack,就取出里面的回滚信息返回;其他事件会被跳过。超时或通道断开会让测试失败。

调用关系:多个线程回滚测试会调用它,先触发回滚操作,再用它确认系统真的发出了成功回滚事件。它不负责发起回滚,只负责在事件流里捞出正确结果。

调用图:调用 1 个内部函数(recv);被 5 处调用(thread_rollback_clears_history_when_num_turns_exceeds_existing_turns, thread_rollback_drops_last_turn_from_history, thread_rollback_persists_marker_and_replays_cumulatively, thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay, thread_rollback_restores_cleared_reference_context_item_after_compaction);外部调用 3 个(from_secs, now, timeout)。

wait_for_thread_rollback_failed3654–3672 ↗
async fn wait_for_thread_rollback_failed(rx: &async_channel::Receiver<Event>) -> ErrorEvent

作用:在异步测试里等待“线程回滚失败”的错误事件。它用于确认非法回滚场景确实失败,而不是静默成功。

数据流:输入是事件接收器 rx。函数在 2 秒内反复收事件,只接受 Error 事件,并且错误类型必须是 ThreadRollbackFailed;匹配后返回错误内容,其他事件忽略。等不到就让测试失败。

调用关系:回滚参数为 0、当前有任务进行中、没有持久化历史等失败场景会调用它。它把事件流里的失败信号交给测试继续检查。

调用图:调用 1 个内部函数(recv);被 3 处调用(thread_rollback_fails_when_num_turns_is_zero, thread_rollback_fails_when_turn_in_progress, thread_rollback_fails_without_persisted_thread_history);外部调用 3 个(from_secs, now, timeout)。

attach_thread_persistence3674–3712 ↗
async fn attach_thread_persistence(session: &mut Session) -> PathBuf

作用:给测试 Session 挂上线程持久化能力,也就是让会话历史能落到本地文件里。没有它,很多回滚和重放测试就没有真实的历史文件可查。

数据流:输入是一个可修改的 Session。函数读取 Session 的配置,创建 LiveThread,填入当前目录、模型提供方、记忆模式等元信息;然后把 LiveThread 放回 Session,确保 rollout 文件被创建并刷新到磁盘。输出是当前 rollout 文件路径,同时修改了 Session 的持久化服务状态。

调用关系:需要测试历史保存、回滚、上下文重放的用例会先调用它。它把普通测试会话升级成带历史文件的会话,后续测试再基于这个文件检查系统行为。

调用图:调用 2 个内部函数(default, create);被 9 处调用(cached_guardian_subagent_exposes_its_rollout_path, record_context_updates_and_set_reference_context_item_persists_baseline_without_emitting_diffs, record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout, record_context_updates_and_set_reference_context_item_persists_split_file_system_policy_to_rollout, thread_rollback_clears_history_when_num_turns_exceeds_existing_turns, thread_rollback_drops_last_turn_from_history, thread_rollback_persists_marker_and_replays_cumulatively, thread_rollback_recomputes_previous_turn_settings_and_reference_context_from_replay, thread_rollback_restores_cleared_reference_context_item_after_compaction);外部调用 6 个(clone, new, current_rollout_path, ensure_rollout_materialized, flush_rollout, get_config)。

text_block3714–3719 ↗
fn text_block(s: &str) -> serde_json::Value

作用:生成一个测试用的文本 JSON 块。它让测试不用每次手写同样的 JSON 结构。

数据流:输入是一段字符串 s。函数把它包成 { type: "text", text: s } 这样的 JSON 值并返回;不读取也不修改外部状态。

调用关系:工具输出转换测试会用它造内容。它是小型测试辅助函数,保证测试数据格式统一。

调用图:外部调用 1 个(json!)。

build_test_config3721–3727 ↗
async fn build_test_config(codex_home: &Path) -> Config

作用:创建一份适合测试用的默认配置。它把配置目录指向临时目录,避免测试污染用户真实配置。

数据流:输入是 codex_home 路径。函数用测试专用的 ConfigBuilder 构造配置,把 codex_home 写进去,然后异步加载并返回 Config;如果加载失败,测试直接失败。

调用关系:很多测试会话构造函数都会先调用它。它是测试世界里的“默认配置工厂”,让后续 Session、SessionConfiguration 都从一致的起点开始。

调用图:调用 1 个内部函数(without_managed_config_for_tests);被 8 处调用(make_session_and_context, make_session_and_context_with_auth_config_home_and_rx, make_session_configuration_for_tests, make_session_with_config_and_rx, make_session_with_history_source_and_agent_control_and_rx, session_new_fails_when_zsh_fork_enabled_without_packaged_zsh, set_rate_limits_retains_previous_credits, set_rate_limits_updates_plan_type_when_present);外部调用 1 个(to_path_buf)。

session_telemetry3729–3747 ↗
fn session_telemetry(
    conversation_id: ThreadId,
    config: &Config,
    model_info: &ModelInfo,
    session_source: SessionSource,
) -> SessionTelemetry

作用:为测试会话创建遥测信息。遥测就是记录会话来源、模型等统计信息,测试里用假账号和固定字段来避免依赖真实用户。

数据流:输入包括会话/线程 ID、配置、模型信息和会话来源。函数选出离线测试模型名,填入测试邮箱、认证模式、来源标识等字段,输出一个 SessionTelemetry。

调用关系:测试构造完整 Session 或 TurnContext 时会调用它。后面的事件上报和模型请求上下文会拿这份遥测信息当会话身份说明。

调用图:调用 2 个内部函数(get_model_offline_for_tests, new);被 2 处调用(make_session_and_context, make_session_and_context_with_auth_config_home_and_rx)。

model_with_default_service_tier3749–3758 ↗
fn model_with_default_service_tier(default_service_tier: Option<&str>) -> ModelInfo

作用:造一个带服务档位信息的测试模型。服务档位可以理解成“处理优先级套餐”,比如 Fast。

数据流:输入是可选的默认服务档位字符串。函数先按 gpt-5.4 造模型信息,再把支持的档位设成 Fast,并把默认档位设成输入值。输出是 ModelInfo。

调用关系:服务档位选择规则的多组测试都用它准备模型。这样每个测试只关注“配置怎么选”,不用重复搭模型数据。

调用图:调用 1 个内部函数(model_info_from_slug);被 6 处调用(get_service_tier_does_not_default_when_model_has_no_default, get_service_tier_does_not_use_model_default_when_absent_and_fast_mode_enabled, get_service_tier_does_not_use_model_default_when_fast_mode_disabled, get_service_tier_drops_unsupported_configured_tier_when_fast_mode_enabled, get_service_tier_ignores_configured_tier_when_fast_mode_disabled, get_service_tier_keeps_supported_explicit_tier);外部调用 1 个(vec!)。

get_service_tier_does_not_use_model_default_when_absent_and_fast_mode_enabled3761–3772 ↗
fn get_service_tier_does_not_use_model_default_when_absent_and_fast_mode_enabled()

作用:测试即使模型有默认 Fast 档位,只要用户没显式配置,系统也不会自动使用它。

数据流:函数先造一个默认档位为 Fast 的模型,再调用 get_service_tier,传入“没有配置档位”和“fast mode 开启”。期望输出是 None,表示请求里不带服务档位。

调用关系:它验证 get_service_tier 的一条边界规则:模型默认值不能擅自变成用户请求。它依赖 model_with_default_service_tier 准备测试模型。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

get_service_tier_does_not_use_model_default_when_fast_mode_disabled3775–3786 ↗
fn get_service_tier_does_not_use_model_default_when_fast_mode_disabled()

作用:测试 fast mode 关闭时,模型自带默认档位也不会被使用。

数据流:函数创建默认 Fast 的模型,调用 get_service_tier,传入没有用户配置且 fast mode 关闭。返回应为 None。

调用关系:它和前一个测试一起确认:无论 fast mode 开不开,都不会因为模型有默认档位就自动发服务档位。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

get_service_tier_keeps_supported_explicit_tier3789–3800 ↗
fn get_service_tier_keeps_supported_explicit_tier()

作用:测试用户明确选择了模型支持的服务档位时,系统会保留这个选择。

数据流:输入场景是模型支持 Fast,用户也配置 Fast,并且 fast mode 开启。函数调用 get_service_tier 后,期望得到 Fast 对应的请求值。

调用关系:它验证 get_service_tier 的正常路径:显式、合法、当前模式允许的配置应该被带到请求里。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

get_service_tier_does_not_default_when_model_has_no_default3803–3814 ↗
fn get_service_tier_does_not_default_when_model_has_no_default()

作用:测试模型没有默认服务档位时,系统不会自己编一个默认值。

数据流:函数造一个没有 default_service_tier 的模型,调用 get_service_tier,传入没有用户配置且 fast mode 开启。结果应为 None。

调用关系:它保护服务档位逻辑不要过度推断。模型没说默认值、用户也没说,就不发送档位。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

get_service_tier_drops_unsupported_configured_tier_when_fast_mode_enabled3817–3844 ↗
fn get_service_tier_drops_unsupported_configured_tier_when_fast_mode_enabled()

作用:测试 fast mode 开启时,不受模型支持的服务档位会被丢弃。这样请求不会带上后端不认识或不允许的值。

数据流:函数用一个只支持 Fast 的模型,分别传 unsupported、Flex 和 default 请求值。前两个期望返回 None,default 请求值被允许保留。

调用关系:它检查 get_service_tier 对“用户配置了但不合法”的过滤行为。这个测试防止错误档位一路传到模型服务。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

get_service_tier_ignores_configured_tier_when_fast_mode_disabled3847–3882 ↗
fn get_service_tier_ignores_configured_tier_when_fast_mode_disabled()

作用:测试 fast mode 关闭时,不管用户配置什么服务档位,都不会使用。

数据流:函数用同一个模型,分别传 Fast、default、unsupported 和 None。每次调用 get_service_tier 都应返回 None。

调用关系:它确认 fast mode 是服务档位生效的总开关。即使配置看起来合法,只要开关关了就不带档位。

调用图:调用 1 个内部函数(model_with_default_service_tier);外部调用 1 个(assert_eq!)。

session_settings_null_service_tier_update_uses_default_service_tier3885–3899 ↗
async fn session_settings_null_service_tier_update_uses_default_service_tier()

作用:测试设置更新里把 service_tier 传成 null 时,会被解释为“使用默认服务档位请求值”。

数据流:函数先创建测试 SessionConfiguration,再应用一个 service_tier 为 Some(None) 的更新。输出是更新后的配置;断言 service_tier 变成默认请求值。

调用关系:它直接测试 SessionConfiguration.apply 的兼容规则。客户端传 null 时,系统不是清空,而是转成约定的默认档位值。

调用图:调用 1 个内部函数(make_session_configuration_for_tests);外部调用 2 个(default, assert_eq!)。

session_settings_legacy_fast_service_tier_update_uses_priority_request_value3902–3916 ↗
async fn session_settings_legacy_fast_service_tier_update_uses_priority_request_value()

作用:测试老写法 fast 会被转换成新的 Fast 请求值。这样旧客户端仍能正常工作。

数据流:函数创建测试配置,应用 service_tier 为 "fast" 的更新。结果中的 service_tier 应等于 ServiceTier::Fast 的正式请求字符串。

调用关系:它验证 SessionConfiguration.apply 的向后兼容处理。老字段进入后,会被翻译成新协议使用的值。

调用图:调用 1 个内部函数(make_session_configuration_for_tests);外部调用 2 个(default, assert_eq!)。

make_session_configuration_for_tests3918–3967 ↗
async fn make_session_configuration_for_tests() -> SessionConfiguration

作用:创建一份完整的测试用 SessionConfiguration。它像给测试会话填一张“启动表”,包含模型、权限、工作目录、指令等。

数据流:函数创建临时 codex_home,加载测试配置,构造离线模型信息和协作模式,再把配置里的权限、目录、指令、人格、沙箱等级等字段整理成 SessionConfiguration 返回。

调用关系:大量测试会调用它作为起点,然后只改自己关心的字段。它内部依赖 build_test_config、离线模型信息和 Windows 沙箱配置转换。

调用图:调用 4 个内部函数(build_test_config, construct_model_info_offline_for_tests, get_model_offline_for_tests, new);被 24 处调用(lock_contains_prompts_and_materializes_features, lock_skips_session_values_when_model_catalog_fields_are_not_saved, lock_validation_can_ignore_codex_version_mismatch, lock_validation_ignores_removed_apps_mcp_path_override, lock_validation_rejects_codex_version_mismatch_by_default, lock_validation_reports_config_diff, active_profile_update_rebuilds_network_proxy_config, emit_subagent_session_started_includes_fork_lineage_from_session_configuration, session_configuration_apply_permission_profile_accepts_direct_write_roots, session_configuration_apply_permission_profile_preserves_existing_deny_read_entries (+14 more));外部调用 5 个(clone, new, new, from_config, tempdir)。

emit_subagent_session_started_includes_fork_lineage_from_session_configuration3970–4046 ↗
async fn emit_subagent_session_started_includes_fork_lineage_from_session_configuration()

作用:测试子代理启动埋点里包含父线程 ID 和 fork 来源线程 ID。这样后台分析能看出子会话是从哪里分出来的。

数据流:函数启动一个假的 HTTP 服务器接收埋点,创建测试认证和 AnalyticsEventsClient,构造父线程、fork 来源线程、子线程,再触发 emit_subagent_session_started。随后轮询服务器收到的请求,找到 codex_thread_initialized 事件,断言里面的 parent_thread_id 和 forked_from_thread_id 正确。

调用关系:它验证埋点发送函数和 SessionConfiguration 快照之间的配合。测试不连真实网络,而是用 wiremock 假服务器收请求。

调用图:调用 6 个内部函数(new, make_session_configuration_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing, from, new);外部调用 9 个(from_millis, from_secs, given, start, new, assert_eq!, from_slice, sleep, timeout)。

resolved_environments_for_configuration4048–4060 ↗
async fn resolved_environments_for_configuration(
    session_configuration: &SessionConfiguration,
) -> (Arc<EnvironmentManager>, TurnEnvironmentSnapshot)

作用:根据 SessionConfiguration 解析出测试用运行环境快照。运行环境可以理解成“这一轮命令要在哪个文件系统和 shell 里跑”。

数据流:输入是 SessionConfiguration。函数创建测试 EnvironmentManager 和 ThreadEnvironments,使用默认 shell、禁用 shell 快照,再把配置里的环境选择应用进去。输出环境管理器和当前环境快照。

调用关系:构造测试 Session 和 TurnContext 时会调用它。它把配置里的抽象环境选择,变成后续 turn 可以直接使用的环境对象。

调用图:调用 5 个内部函数(new, environment_selections, default_user_shell, disabled, default_for_tests);被 2 处调用(make_session_and_context, make_session_and_context_with_auth_config_home_and_rx);外部调用 3 个(clone, new, default)。

session_configuration_apply_preserves_profile_file_system_policy_on_cwd_only_update4063–4117 ↗
async fn session_configuration_apply_preserves_profile_file_system_policy_on_cwd_only_update()

作用:测试只改当前工作目录时,不会把权限配置里的文件系统规则弄丢。尤其是配置档案里的读写限制要继续保留。

数据流:函数先建测试配置和临时目录,设置一个工作区写权限沙箱,以及一个包含“项目根可写、docs 可读”的文件系统策略。然后只更新 cwd。输出的新配置应保留原本物化后的文件系统沙箱策略。

调用关系:它测试 SessionConfiguration.apply 在 cwd-only 更新时的权限保持逻辑。没有这个保护,换目录可能意外放宽或丢失文件访问限制。

调用图:调用 6 个内部函数(make_session_configuration_for_tests, from_runtime_permissions_with_enforcement, from_legacy_sandbox_policy, restricted, from, new);外部调用 6 个(default, new, assert_eq!, create_dir_all, tempdir, vec!)。

session_configuration_apply_permission_profile_preserves_existing_deny_read_entries4120–4173 ↗
async fn session_configuration_apply_permission_profile_preserves_existing_deny_read_entries()

作用:测试更新权限档案时,已有的“禁止读取”规则不会被冲掉。比如禁止读 .env 文件这种安全规则必须留下。

数据流:函数先设置一个已有文件系统策略,里面加上 deny 条目和扫描深度。再用新的 permission_profile 更新配置。结果应该基于请求策略重建,但保留原来的 deny 条目和 glob_scan_max_depth。

调用关系:它验证 SessionConfiguration.apply 合并权限时的安全优先原则:新配置可以更新权限,但不能悄悄删除已有的拒绝读取规则。

调用图:调用 6 个内部函数(make_session_configuration_for_tests, from_runtime_permissions, from_runtime_permissions_with_enforcement, from_legacy_sandbox_policy, from_legacy_sandbox_policy_for_cwd, new);外部调用 5 个(default, new, new_workspace_write_policy, assert_eq!, tempdir)。

session_configuration_apply_permission_profile_accepts_direct_write_roots4176–4220 ↗
async fn session_configuration_apply_permission_profile_accepts_direct_write_roots()

作用:测试权限更新可以接受直接指定的绝对写入目录。也就是说,不一定只能写当前工作区,也能明确允许某个外部目录。

数据流:函数创建一个外部临时目录,把它作为 FileSystemSandboxPolicy 里的写入路径,再转成 PermissionProfile 应用到会话配置。结果应同时保留 permission_profile、文件系统策略,并生成包含该写入根的旧式 SandboxPolicy。

调用关系:它检查新权限模型和旧沙箱模型之间的转换。测试确保直接写入根不会在 apply 时被拒绝或误删。

调用图:调用 5 个内部函数(make_session_configuration_for_tests, from_runtime_permissions, restricted, new, from_absolute_path);外部调用 6 个(default, new, assert_eq!, canonicalize_preserving_symlinks, tempdir, vec!)。

session_configuration_apply_rebinds_symbolic_profile_to_updated_workspace_roots4223–4263 ↗
async fn session_configuration_apply_rebinds_symbolic_profile_to_updated_workspace_roots()

作用:测试使用符号规则“项目根”的权限档案,在工作区根目录改变后会重新绑定到新目录。

数据流:函数设置旧 workspace root,再创建一个权限策略,允许写 Special project_roots。应用更新时同时换成新 workspace root,并设置 active profile 信息。结果应允许写新根、不允许写旧根,并保存 active profile 和 profile workspace roots。

调用关系:它验证符号路径不是固定死的真实路径,而是会跟随新的 workspace_roots 重新解释。SessionConfiguration.apply 负责完成这个重绑定。

调用图:调用 4 个内部函数(new, make_session_configuration_for_tests, from_runtime_permissions, restricted);外部调用 5 个(default, assert!, assert_eq!, tempdir, vec!)。

session_configuration_apply_retargets_implicit_workspace_root_on_cwd_update4266–4308 ↗
async fn session_configuration_apply_retargets_implicit_workspace_root_on_cwd_update()

作用:测试当当前目录改变时,隐含的工作区根会从旧目录转向新目录,同时保留额外工作区根。

数据流:函数把旧 cwd 和额外目录设为 workspace_roots,并设置允许写项目根的策略。随后只更新 cwd 到新目录。结果的 workspace_roots 应变成新目录加额外目录;权限允许写新目录和额外目录,不再允许写旧目录。

调用关系:它测试 cwd 更新和 workspace_roots 自动调整的配合。这样用户切项目后,权限会跟着新项目走,而不是还指向旧项目。

调用图:调用 4 个内部函数(make_session_configuration_for_tests, from_runtime_permissions, restricted, new);外部调用 6 个(default, new, assert!, assert_eq!, tempdir, vec!)。

active_profile_update_rebuilds_network_proxy_config4311–4416 ↗
async fn active_profile_update_rebuilds_network_proxy_config() -> std::io::Result<()>

作用:测试切换活动权限档案时,网络代理配置也会重新计算。否则用户切到“允许联网并带代理”的档案,实际请求可能仍然没有代理。

数据流:函数写入一份临时 config.toml,里面有 locked-down 和 web-enabled 两个权限档案,后者带代理地址。先加载默认 locked 配置确认没有该代理,再加载选中 web-enabled 的配置。然后把测试 SessionConfiguration 从 locked 更新到 selected profile,最后检查更新后的原始配置里代理地址变成 127.0.0.1:43128 且 socks 关闭。

调用关系:它覆盖 SessionConfiguration.apply 对 active_permission_profile 的副作用:不仅权限对象要变,依赖该档案生成的网络代理配置也要同步刷新。

调用图:调用 1 个内部函数(make_session_configuration_for_tests);外部调用 13 个(clone, new, default, assert!, assert_eq!, assert_ne!, Access, default, from, write (+3 more))。

new_default_turn_uses_config_aware_skills_for_role_overrides4420–4503 ↗
async fn new_default_turn_uses_config_aware_skills_for_role_overrides()

作用:测试创建新默认 turn 时,会按子角色覆盖后的配置来决定技能是否启用。turn 可以理解成一次用户请求的执行轮次。

数据流:函数先创建会话,在 codex_home 下写一个 demo 技能,并确认父配置下技能启用。接着写一个角色配置文件,把这个技能设为 disabled,再把角色应用到 child_config,并放进 Session 状态。最后创建新默认 turn,检查同一个技能仍能被发现,但启用状态变成 false。

调用关系:它验证角色配置、技能加载和 Session.new_default_turn_with_sub_id 的衔接。重点是新 turn 要看当前会话配置,而不是继续沿用旧的父配置。

调用图:调用 2 个内部函数(apply_role_to_config, make_session_and_context);外部调用 8 个(clone, new, new, assert_eq!, skills_load_input_from_config, format!, create_dir_all, write)。

session_configuration_apply_retargets_legacy_workspace_root_on_cwd_update4506–4557 ↗
async fn session_configuration_apply_retargets_legacy_workspace_root_on_cwd_update()

作用:测试旧式 workspace-write 沙箱在 cwd 改变时,会把隐含可写根转到新 cwd。

数据流:函数设置原 cwd、workspace_roots 和旧式 WorkspaceWrite 沙箱转换出的文件系统策略。然后只把 cwd 更新到另一个项目目录。结果 workspace_roots 应只包含新项目,新项目可写,旧项目不可写。

调用关系:它保护旧配置格式的兼容行为。即使权限来自 legacy sandbox policy,SessionConfiguration.apply 也要正确迁移隐含工作区。

调用图:调用 6 个内部函数(make_session_configuration_for_tests, from_runtime_permissions_with_enforcement, from_legacy_sandbox_policy, from_legacy_sandbox_policy_for_cwd, from, new);外部调用 6 个(default, new, assert!, assert_eq!, tempdir, vec!)。

session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_update4560–4619 ↗
async fn session_configuration_apply_preserves_absolute_cwd_write_root_on_cwd_update()

作用:测试如果权限里明确写着旧 cwd 的绝对路径,那么改 cwd 时不能把它误当成“当前工作区”来重定向。

数据流:函数创建 repo-a 和 repo-b,把权限设成根目录可读、repo-a 绝对路径可写。然后更新 cwd 到 repo-b。结果文件系统策略必须原样保留:repo-a 仍可写,repo-b 不会因为成为新 cwd 就自动可写。

调用关系:它区分两种权限:符号工作区规则会跟 cwd 变,绝对路径规则不会。SessionConfiguration.apply 必须保持这个边界。

调用图:调用 4 个内部函数(make_session_configuration_for_tests, from_runtime_permissions_with_enforcement, restricted, new);外部调用 7 个(default, new, assert!, assert_eq!, create_dir_all, tempdir, vec!)。

session_update_settings_does_not_rewrite_sticky_environment_cwds4622–4669 ↗
async fn session_update_settings_does_not_rewrite_sticky_environment_cwds()

作用:测试更新会话设置时,不会改写已有环境选择里“固定住”的工作目录。

数据流:函数创建会话,取出当前环境列表并保存期望值,再把会话 cwd 更新到 project,同时把原环境列表传回去。更新后检查 SessionConfiguration 的 cwd 已变,但环境列表没变;再创建下一轮 turn,确认实际 turn 仍使用原来的环境 cwd。

调用关系:它测试 Session.update_settings 和 new_default_turn 的配合。会话主 cwd 可以更新,但已有显式环境的 cwd 不能被偷偷重写。

调用图:调用 2 个内部函数(make_session_and_context, new);外部调用 3 个(default, assert_eq!, create_dir_all)。

relative_cwd_update_without_environments_resolves_under_session_cwd4672–4701 ↗
async fn relative_cwd_update_without_environments_resolves_under_session_cwd()

作用:测试没有显式环境列表时,更新 cwd 能正确落到会话当前目录下的目标路径,并保持环境列表为空。

数据流:函数先把 SessionConfiguration 的 environments 列表清空,记住原 cwd,创建原 cwd/project 目录。然后用 TurnEnvironmentSelections 更新到这个目录且不带环境。结果配置里的 cwd 变成该目录,环境选择仍为空。

调用关系:它检查 Session.update_settings 对“只有 cwd、没有环境”的简单路径。这个场景不能误造环境,也不能解析错目录。

调用图:调用 2 个内部函数(make_session_and_context, new);外部调用 5 个(default, new, assert!, assert_eq!, create_dir_all)。

environment_settings_preserve_explicit_primary_cwd4704–4734 ↗
async fn environment_settings_preserve_explicit_primary_cwd()

作用:测试如果环境里已经明确指定了自己的 cwd,更新会话主 cwd 时不能覆盖它。

数据流:函数创建一个显式 local 环境,cwd 指向 original/environment。然后把会话主 cwd 更新到 original/project,同时带回原环境列表。结果会话 cwd 变成 project,但第一个环境的 cwd 仍是 environment。

调用关系:它和 sticky environment 测试一起保护环境选择的独立性。Session.update_settings 只该改用户要求改的主 cwd,不该改显式环境。

调用图:调用 2 个内部函数(make_session_and_context, new);外部调用 4 个(default, assert_eq!, create_dir_all, vec!)。

absolute_cwd_update_with_turn_environment_is_allowed4737–4764 ↗
async fn absolute_cwd_update_with_turn_environment_is_allowed()

作用:测试创建新 turn 时,如果同时给了绝对 cwd 和对应的显式环境,这是允许的。

数据流:函数从当前会话 cwd 下创建 absolute-turn 目录,然后调用 new_turn_with_sub_id,传入该绝对目录和一个 local 环境。返回的 TurnContext 应使用这个 cwd,配置里的 cwd 也相同,并且有一个 turn 环境。

调用关系:它验证 Session.new_turn_with_sub_id 对单轮设置更新的接受规则。明确给出环境时,绝对路径 cwd 不应被错误拒绝。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, new);外部调用 4 个(default, assert_eq!, create_dir_all, vec!)。

session_new_fails_when_zsh_fork_enabled_without_packaged_zsh4767–4873 ↗
async fn session_new_fails_when_zsh_fork_enabled_without_packaged_zsh()

作用:测试启用 zsh fork 功能但没有可用的打包 zsh 时,Session 启动会失败并给出清楚错误。

数据流:函数创建测试配置,打开 ShellZshFork 特性,把 zsh_path 设成 None,然后手工准备认证、模型、插件、MCP、技能、环境、线程存储等 Session::new 需要的依赖。调用 Session::new 后应得到错误;最后检查错误文本包含“没有 packaged zsh fork”。

调用关系:它覆盖 Session::new 的启动前置检查。这个测试防止系统在缺少必要 shell 组件时继续启动,之后才在执行命令时出更难懂的错误。

调用图:调用 17 个内部函数(new, new, default, new, new, build_test_config, models_manager_with_provider, default_for_tests, new, from_auth_for_testing (+7 more));外部调用 12 个(clone, new, new, assert!, unbounded, default, default, format!, panic!, from_config (+2 more))。

make_session_and_context4876–5098 ↗
async fn make_session_and_context() -> (Session, TurnContext)

作用:创建一套可直接用于测试的 Session 和 TurnContext。它是很多测试的“搭舞台”函数。

数据流:函数创建事件通道、临时配置、认证、模型管理器、执行策略、会话配置、环境管理器、插件/技能/MCP 管理器、模型客户端等一整套依赖。然后加载插件和技能,调用 Session::make_turn_context 生成 turn 上下文,最后手工组装 Session 并连同 TurnContext 返回。

调用关系:大量会话行为测试都会调用它,而不是自己重复造这些复杂对象。它把 build_test_config、session_telemetry、resolved_environments_for_configuration 和各种服务拼成一个完整测试会话。

调用图:调用 33 个内部函数(new, new, new_uninitialized_with_permission_profile, new, new, new, new, default, new, new (+15 more));被 269 处调用(process_compacted_history_with_test_session, test_review_params, build_guardian_prompt_includes_parent_turn_denied_reads, build_guardian_prompt_items_includes_parent_session_id, guardian_review_request_layout_matches_model_visible_request_snapshot, guardian_test_session_and_turn_with_base_url, routes_approval_to_guardian_allows_granular_review_policy, routes_approval_to_guardian_can_use_app_reviewer_override, routes_approval_to_guardian_requires_guardian_reviewer, hook_run_analytics_payload_falls_back_to_turn_context_id (+15 more));外部调用 28 个(clone, new, new, new, default, new, from, new, new, from_pointee (+15 more))。

make_session_with_config5100–5105 ↗
async fn make_session_with_config(
    mutator: impl FnOnce(&mut Config),
) -> anyhow::Result<Arc<Session>>

作用:用一个修改函数创建自定义配置的测试 Session。测试可以只写“我要怎么改配置”,不用关心底层搭建细节。

数据流:输入是 mutator,一个会修改 Config 的闭包。函数把它交给 make_session_with_config_and_rx,拿到 Session 和事件接收器后丢掉接收器,只返回 Arc<Session> 或错误。

调用关系:需要自定义配置但不关心事件流的测试会调用它。它是 make_session_with_config_and_rx 的简化包装。

调用图:调用 1 个内部函数(make_session_with_config_and_rx);被 5 处调用(danger_full_access_tool_attempts_do_not_enforce_managed_network, danger_full_access_turns_do_not_expose_managed_network_proxy, reload_user_config_layer_refreshes_hooks, shell_tool_cancellation_waits_for_runtime_cleanup, workspace_write_turns_continue_to_expose_managed_network_proxy)。

load_latest_config_for_session5107–5115 ↗
async fn load_latest_config_for_session(session: &Session) -> Config

作用:从某个 Session 的配置目录重新加载最新配置。它用于测试运行时刷新配置是否真的读到了磁盘上的新内容。

数据流:输入是 Session 引用。函数先读取当前 Session 配置,拿到 codex_home 和 cwd,再用默认 ConfigBuilder 从这个目录重新 build 一份 Config。输出是最新加载的配置。

调用关系:配置刷新相关测试会调用它,把会话当前配置和磁盘最新配置做对照。它不修改 Session,只负责重新读配置文件。

调用图:被 3 处调用(config_change_contributor_observes_effective_config_changes, refresh_runtime_config_refreshes_hooks, refresh_runtime_config_updates_runtime_refreshable_fields_and_keeps_session_static_settings);外部调用 2 个(default, get_config)。

make_session_with_config_and_rx5117–5217 ↗
async fn make_session_with_config_and_rx(
    mutator: impl FnOnce(&mut Config),
) -> anyhow::Result<(Arc<Session>, async_channel::Receiver<Event>)>

作用:创建一个测试用的 Session,并把它发出的事件接收器一起返回。测试可以传入一个小函数修改配置,用来模拟不同启动条件。

数据流:进去的是一个配置修改函数 → 它先建临时目录和测试配置,再补上假 API Key、模型信息、插件、技能、环境和线程存储等零件 → 出来的是一个可共享的会话对象,以及一个能收到会话事件的通道;它不会使用真实用户目录。

调用关系:这是测试准备工具,被 make_session_with_config 和 user_shell_commands_do_not_inherit_managed_network_proxy 这类测试拿来快速搭好会话。它最后把所有准备好的零件交给 Session::new。

调用图:调用 17 个内部函数(new, new, default, new, new, build_test_config, models_manager_with_provider, default_for_tests, new, from_auth_for_testing (+7 more));被 2 处调用(make_session_with_config, user_shell_commands_do_not_inherit_managed_network_proxy);外部调用 10 个(clone, new, new, unbounded, default, default, from_config, tempdir, vec!, channel)。

make_session_with_history_source_and_agent_control_and_rx5219–5328 ↗
async fn make_session_with_history_source_and_agent_control_and_rx(
    initial_history: InitialHistory,
    session_source: SessionSource,
    agent_control: AgentControl,
) -> anyhow::Result<(Arc<Se

作用:创建一个带“历史来源”和“代理控制信息”的测试会话。它专门服务于恢复旧会话、子代理继承会话编号这类测试。

数据流:进去的是初始历史、会话来源和代理控制设置 → 它构造临时配置,打开临时状态库,拼好模型、环境、权限、插件、技能等会话配置 → 出来的是新建好的 Session 和事件接收器;同时把传入的历史和控制信息真正塞进 Session::new。

调用关系:resumed_root_session_uses_thread_id_as_session_id 和 resumed_subagent_session_keeps_inherited_session_id 会调用它。它和前一个辅助函数很像,但重点是测试“恢复”和“继承编号”。

调用图:调用 18 个内部函数(new, new, default, new, new, build_test_config, models_manager_with_provider, default_for_tests, new, from_auth_for_testing (+8 more));被 2 处调用(resumed_root_session_uses_thread_id_as_session_id, resumed_subagent_session_keeps_inherited_session_id);外部调用 10 个(clone, new, new, clone, unbounded, default, from_config, tempdir, vec!, channel)。

resumed_root_session_uses_thread_id_as_session_id5331–5354 ↗
async fn resumed_root_session_uses_thread_id_as_session_id()

作用:确认恢复一个普通根会话时,会话编号会直接使用线程编号。这样旧对话重新打开后,对外看到的身份不会乱。

数据流:进去的是一个新生成的 thread_id,并把它放进恢复历史里 → 测试创建恢复会话,读取 session.thread_id 和 session.session_id,再接收 SessionConfigured 事件 → 断言对象内部和事件里的 thread_id、session_id 都一致。

调用关系:测试框架运行它。它通过 make_session_with_history_source_and_agent_control_and_rx 搭环境,然后检查 Session::new 发出的配置事件是否符合恢复规则。

调用图:调用 2 个内部函数(make_session_with_history_source_and_agent_control_and_rx, new);外部调用 5 个(new, assert_eq!, default, panic!, Resumed)。

resumed_subagent_session_keeps_inherited_session_id5357–5389 ↗
async fn resumed_subagent_session_keeps_inherited_session_id()

作用:确认恢复子代理会话时,线程编号可以是自己的,但 session_id 要继续沿用父会话的编号。这样多个子任务仍能被归到同一个上层会话下。

数据流:进去的是父线程编号、父 session_id、子线程编号和子代理来源信息 → 它创建一个恢复会话,并通过 AgentControl 传入继承的 session_id → 出来通过断言确认 thread_id 是子线程,session_id 是父会话,事件里也同样如此。

调用关系:测试框架运行它。它依赖 make_session_with_history_source_and_agent_control_and_rx 创建带子代理来源的会话,用来覆盖和根会话不同的编号规则。

调用图:调用 3 个内部函数(make_session_with_history_source_and_agent_control_and_rx, from, new);外部调用 6 个(new, SubAgent, assert_eq!, default, panic!, Resumed)。

notify_request_permissions_response_ignores_unmatched_call_id5392–5418 ↗
async fn notify_request_permissions_response_ignores_unmatched_call_id()

作用:确认如果收到一个找不到对应请求编号的权限回复,系统会忽略它。这样外部发错或过期的回复不会误开权限。

数据流:进去的是一个不存在的 call_id 和一份允许网络的权限回复 → 它让会话处理这份回复 → 出来检查当前轮次没有获得任何权限,也就是回复没有产生副作用。

调用关系:测试框架运行它。它用 make_session_and_context 建会话,然后直接调用 session.notify_request_permissions_response,检查防错行为。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 2 个(default, assert_eq!)。

record_granted_request_permissions_for_turn_uses_originating_turn5421–5469 ↗
async fn record_granted_request_permissions_for_turn_uses_originating_turn()

作用:确认“本轮有效”的权限会记录到最初发起申请的那一轮,而不是后来变成当前活动的那一轮。这样异步回复回来晚了,也不会记错地方。

数据流:进去的是两个不同的 ActiveTurn 和一份允许网络的权限 → 它先保存发起申请那一轮的状态,再切换当前活动轮次,然后记录权限时明确传入原始轮次状态 → 出来只有原始轮次有权限,当前轮次和会话级权限都没有。

调用关系:测试框架运行它。它直接验证 session.record_granted_request_permissions_for_turn 在异步场景下使用传入的 originating_turn_state,而不是盲目使用 session.active_turn。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 3 个(clone, default, assert_eq!)。

request_permission_grants_are_environment_keyed5472–5522 ↗
async fn request_permission_grants_are_environment_keyed()

作用:确认权限是按环境编号分别保存的。比如 remote 环境拿到的权限,不能自动变成本地 local 环境也有。

数据流:进去的是一份网络权限和环境名 remote → 它先按本轮范围记录,再读取 remote 和 local 的权限;随后又按整个会话范围记录 remote → 出来 remote 有权限,local 没权限,说明权限没有串环境。

调用关系:测试框架运行它。它覆盖 record_granted_request_permissions_for_turn 和 granted_session_permissions 这类读取接口,保证环境隔离。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 3 个(clone, default, assert_eq!)。

enable_strict_auto_review_for_turn_uses_originating_turn5525–5555 ↗
async fn enable_strict_auto_review_for_turn_uses_originating_turn()

作用:确认“严格自动审核”这个开关也会打到最初发起请求的轮次上。它和权限一样,不能因为回复晚到就影响错轮次。

数据流:进去的是原始轮次状态,以及一份 strict_auto_review 为 true 的权限回复 → 它记录这份回复 → 出来原始轮次状态里的严格自动审核标记变为开启。

调用关系:测试框架运行它。它和 record_granted_request_permissions_for_turn_uses_originating_turn 检查同一类异步归属问题,只是对象从权限变成了审核开关。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 3 个(clone, default, assert!)。

strict_auto_review_session_scope_grants_no_permissions5558–5584 ↗
fn strict_auto_review_session_scope_grants_no_permissions()

作用:确认如果用户请求的是“整个会话范围”的严格自动审核,系统会把它规范化为不给任何权限。这样一个危险的长期授权不会被误接受。

数据流:进去的是一份网络权限,以及 scope 为 Session、strict_auto_review 为 true 的回复 → 它调用 Session::normalize_request_permissions_response 做规范化 → 出来变成空权限、本轮范围、不开启严格自动审核。

调用关系:测试框架运行它。它直接测试 Session 的回复规范化规则,不需要启动完整异步会话。

调用图:外部调用 4 个(default, assert_eq!, normalize_request_permissions_response, new)。

request_permissions_emits_event_when_granular_policy_allows_requests5587–5673 ↗
async fn request_permissions_emits_event_when_granular_policy_allows_requests()

作用:确认当细粒度审批策略允许工具申请权限时,系统会真的发出一个权限请求事件,并等待外部回复。

数据流:进去的是一轮会话、允许 request_permissions 的审批策略、一个申请网络权限的 call_id → 它异步调用 request_permissions_for_environment,另一边从事件通道收到 RequestPermissions 事件,再模拟外部批准 → 出来请求函数返回同一份批准回复。

调用关系:测试框架运行它。它把 session.request_permissions_for_environment、事件通道和 notify_request_permissions_response 串起来,验证完整的申请-通知-回复流程。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, default);外部调用 11 个(clone, get_mut, new, new, from_secs, default, Granular, assert_eq!, panic!, spawn (+1 more))。

request_permissions_tool_resolves_relative_paths_against_selected_environment5676–5782 ↗
async fn request_permissions_tool_resolves_relative_paths_against_selected_environment()

作用:确认 request_permissions 工具里的相对文件路径,会按被选中的环境目录来解释,而不是按默认目录乱拼。

数据流:进去的是一个 remote 环境,它的工作目录被改到 request-permissions-environment;工具参数里申请写入 relative.txt → 处理器把相对路径展开成 remote 环境目录下的绝对路径,并发出权限请求事件 → 测试回复批准后,工具调用正常结束。

调用关系:测试框架运行它。它通过 RequestPermissionsHandler.handle 走工具入口,验证工具层到 session 权限请求层之间的路径转换。

调用图:调用 6 个内部函数(make_session_and_context_with_rx, new, default, new, plain, from_abs_path);外部调用 15 个(clone, get_mut, new, new, default, from_secs, Granular, assert_eq!, json!, panic! (+5 more))。

request_permissions_tool_rejects_unknown_environment_id5785–5814 ↗
async fn request_permissions_tool_rejects_unknown_environment_id()

作用:确认工具如果指定了不存在的环境编号,会被明确拒绝。这样模型或调用方不能对一个不存在的执行环境申请权限。

数据流:进去的是 environment_id 为 missing 的工具调用参数 → RequestPermissionsHandler.handle 查找环境失败 → 出来是一个返回给模型的错误文本:unknown turn environment id missing

调用关系:测试框架运行它。它直接走 RequestPermissionsHandler,验证错误会以 FunctionCallError::RespondToModel 的形式返回,而不是继续发权限事件。

调用图:调用 3 个内部函数(make_session_and_context, new, plain);外部调用 6 个(new, new, assert_eq!, json!, panic!, new)。

request_permissions_response_materializes_session_cwd_grants_before_recording5817–5924 ↗
async fn request_permissions_response_materializes_session_cwd_grants_before_recording()

作用:确认权限回复里像“项目根目录”这种特殊路径,在记录成会话级权限前会先变成实际目录。这样后续执行时拿到的是清楚的真实路径。

数据流:进去的是申请写入 project_roots 的权限请求 → 系统发出 RequestPermissions 事件,并带上本轮 cwd → 测试模拟批准后,回复被规范化为对这个 cwd 的读写根授权,并记录到会话级权限里。

调用关系:测试框架运行它。它串起 request_permissions_for_environment、notify_request_permissions_response 和 granted_session_permissions,重点验证特殊路径落地。

调用图:调用 3 个内部函数(make_session_and_context_with_rx, default, from_read_write_roots);外部调用 12 个(clone, get_mut, new, new, default, from_secs, Granular, assert_eq!, panic!, spawn (+2 more))。

request_permissions_is_auto_denied_when_granular_policy_blocks_tool_requests5927–5985 ↗
async fn request_permissions_is_auto_denied_when_granular_policy_blocks_tool_requests()

作用:确认细粒度审批策略禁止工具申请权限时,系统会自动拒绝,而且不打扰外部界面。这样策略关掉后不会弹出无意义的请求。

数据流:进去的是 request_permissions=false 的审批配置和一份网络权限申请 → session.request_permissions_for_environment 直接生成空权限回复 → 出来没有事件从通道发出,返回值表示本轮空授权。

调用关系:测试框架运行它。它验证审批策略在权限请求入口处生效,和允许时会发事件的测试形成对照。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, default);外部调用 7 个(get_mut, new, new, default, Granular, assert!, assert_eq!)。

submit_with_id_captures_current_span_trace_context5988–6032 ↗
async fn submit_with_id_captures_current_span_trace_context()

作用:确认提交操作时,如果当前代码处在一个追踪 span 里,提交内容会带上这段追踪信息。追踪信息可以理解成快递单号,用来把跨模块的一次请求串起来。

数据流:进去的是一个带 W3C Trace Context 的当前 span,以及一个没有 trace 的 Submission → codex.submit_with_id 在提交前读取当前 span 的追踪上下文并填进 Submission → 出来从提交通道收到的对象带有 expected_trace。

调用关系:测试框架运行它。它构造 Codex 的提交通道,安装测试追踪,再验证 submit_with_id 会自动补 trace。

调用图:调用 2 个内部函数(make_session_and_context, install_test_tracing);外部调用 7 个(new, assert!, assert_eq!, bounded, unbounded, info_span!, channel)。

new_default_turn_captures_current_span_trace_id6035–6068 ↗
async fn new_default_turn_captures_current_span_trace_id()

作用:确认创建默认新轮次时,会把当前追踪编号记进 TurnContext。这样一轮对话后续的日志和后台任务能和入口请求对上。

数据流:进去的是当前 span 中的 trace_id → session.new_default_turn 创建 TurnContext → 出来 turn_context.trace_id 等于当前 span 的 trace_id。

调用关系:测试框架运行它。它直接调用 session.new_default_turn,验证会话生成轮次上下文时会读取 tracing 当前上下文。

调用图:调用 2 个内部函数(make_session_and_context, install_test_tracing);外部调用 4 个(current, assert!, assert_eq!, info_span!)。

submission_dispatch_span_prefers_submission_trace_context6071–6102 ↗
fn submission_dispatch_span_prefers_submission_trace_context()

作用:确认分发提交时,如果 Submission 自己带了追踪信息,就优先用它,而不是用周围环境的追踪信息。

数据流:进去的是一个 ambient 外层 trace 和一个 submission 自带 trace → submission_dispatch_span 根据提交创建分发 span → 出来的 span trace_id 等于 submission 自带的 55,而不是外层的 33。

调用关系:测试框架运行它。它直接测试 submission_dispatch_span 的选择规则,保证跨服务传来的 trace 不会被本地环境覆盖。

调用图:调用 1 个内部函数(install_test_tracing);外部调用 3 个(assert!, assert_eq!, info_span!)。

submission_dispatch_span_uses_debug_for_realtime_audio6105–6127 ↗
fn submission_dispatch_span_uses_debug_for_realtime_audio()

作用:确认实时音频提交使用 DEBUG 级别的追踪 span。DEBUG 是较低的日志级别,避免高频音频帧把普通日志刷爆。

数据流:进去的是一个 RealtimeConversationAudio 提交,里面有一小段假音频帧 → submission_dispatch_span 创建分发 span → 出来检查这个 span 的日志级别是 DEBUG。

调用关系:测试框架运行它。它单独验证 submission_dispatch_span 对高频实时音频这种特殊操作的降噪处理。

调用图:调用 1 个内部函数(install_test_tracing);外部调用 2 个(assert_eq!, RealtimeConversationAudio)。

op_kind_for_input_and_context_ops6130–6149 ↗
fn op_kind_for_input_and_context_ops()

作用:确认 Op 这个操作枚举能给用户输入和线程设置返回稳定的字符串类型名。这样的名字通常会被日志、指标或分发逻辑使用。

数据流:进去的是 UserInput 和 ThreadSettings 两种操作值 → 调用它们的 kind 方法 → 出来分别得到 user_input 和 thread_settings。

调用关系:测试框架运行它。它直接覆盖 Op::kind 的基础约定,防止字符串名字被误改。

调用图:外部调用 1 个(assert_eq!)。

user_turn_updates_approvals_reviewer6152–6194 ↗
async fn user_turn_updates_approvals_reviewer()

作用:确认用户发起一轮对话时,如果线程设置里指定了审批复核人,Session 的配置会随之更新。

数据流:进去的是一条用户文本 hello,以及 thread_settings 里 approvals_reviewer=AutoReview → handlers::user_input_or_turn 处理这次输入并应用设置 → 出来 session.state 中的 session_configuration.approvals_reviewer 变成 AutoReview。

调用关系:测试框架运行它。它走 handlers::user_input_or_turn,验证用户输入入口不仅提交内容,也会更新会话设置。

调用图:调用 3 个内部函数(user_input_or_turn, make_session_and_context_with_rx, local_selections);外部调用 3 个(default, assert_eq!, vec!)。

turn_environments_set_primary_environment6197–6256 ↗
async fn turn_environments_set_primary_environment()

作用:确认新一轮如果指定了环境选择,第一项会成为主环境,并且这个选择会保存给后续默认轮次继续使用。

数据流:进去的是一个 selected 目录和只包含这个目录的环境列表 → session.new_turn_with_sub_id 创建新 TurnContext → 出来该环境成为 primary,turn_context.cwd 和 config.cwd 都是 selected,并且 session 服务里保存的主环境会被默认轮次继承。

调用关系:测试框架运行它。它测试 new_turn_with_sub_id、turn_environments 服务和 new_default_turn 之间的环境传递。

调用图:调用 3 个内部函数(make_session_and_context_with_rx, new, try_from);外部调用 4 个(default, assert!, assert_eq!, vec!)。

default_turn_does_not_overlay_legacy_fallback_cwd_onto_stored_thread_environments6259–6289 ↗
async fn default_turn_does_not_overlay_legacy_fallback_cwd_onto_stored_thread_environments()

作用:确认默认新轮次不会把老的兜底 cwd 强行盖到已经保存的线程环境上。这样用户之前选过的环境目录不会被旧逻辑悄悄覆盖。

数据流:进去的是服务和会话配置里已保存的 selected 环境 → session.new_default_turn 创建默认轮次 → 出来轮次仍使用 selected 作为环境 cwd 和 config.cwd,而不是回到 session 原始 cwd。

调用关系:测试框架运行它。它直接设置 turn_environments 服务和 session_configuration,然后检查 new_default_turn 是否尊重已保存环境。

调用图:调用 3 个内部函数(make_session_and_context_with_rx, local, try_from);外部调用 3 个(assert!, assert_eq!, vec!)。

default_turn_honors_empty_stored_thread_environments6292–6311 ↗
async fn default_turn_honors_empty_stored_thread_environments()

作用:确认如果保存的线程环境列表明确为空,默认新轮次也应该没有主环境。空列表不是“没设置”,而是“清空环境”。

数据流:进去的是空的环境选择,以及状态里空的 environments → session.new_default_turn 创建轮次 → 出来 primary 为 None,turn_environments 为空,但 cwd 仍保留 session 的基础 cwd 作为兼容字段。

调用关系:测试框架运行它。它验证 new_default_turn 能区分“没有环境”和“用旧 cwd 兜底”这两件事。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 3 个(new, assert!, assert_eq!)。

primary_environment_uses_first_turn_environment6314–6353 ↗
async fn primary_environment_uses_first_turn_environment()

作用:确认多个轮次环境存在时,主环境就是列表里的第一个。这个规则简单但重要,因为很多默认操作都依赖主环境。

数据流:进去的是已有的第一个环境,再手动追加一个 second 环境和它自己的 cwd → 调用 primary 并检查列表内容 → 出来 primary 仍是第一个环境,第二个环境的 cwd 保持为 second 路径。

调用关系:测试框架运行它。它主要验证 TurnEnvironmentSelections.primary 的约定,以及附加环境不会改变主环境。

调用图:调用 3 个内部函数(make_session_and_context, new, from_abs_path);外部调用 2 个(clone, assert_eq!)。

empty_turn_environments_clear_primary_environment6356–6379 ↗
async fn empty_turn_environments_clear_primary_environment()

作用:确认一轮设置里传入空环境列表,会清掉主环境。这样用户或上层系统可以明确表示本轮没有可用执行环境。

数据流:进去的是 environments=空列表 的 SessionSettingsUpdate → session.new_turn_with_sub_id 创建新轮次 → 出来 primary 为 None,环境列表为空,cwd 保持为会话基础 cwd。

调用关系:测试框架运行它。它通过 new_turn_with_sub_id 验证环境清空请求会生效,而不是被默认环境自动补回。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, new);外部调用 4 个(default, assert!, assert_eq!, vec!)。

spawn_task_turn_span_inherits_dispatch_trace_context6382–6482 ↗
async fn spawn_task_turn_span_inherits_dispatch_trace_context()

作用:确认会话里启动的任务会继承提交分发时的追踪上下文。这样从外部请求到内部任务的日志能连成一条线。

数据流:进去的是一个带 trace 的提交分发 span,以及一个会记录当前 trace 的测试任务 → session.spawn_task 在该 span 中启动任务 → 出来任务捕获到的 trace_id 和提交 trace_id 一样,但 span_id 不同,说明是同一条链路里的新子步骤。

调用关系:测试框架运行它。它自定义一个 TraceCaptureTask,交给 session.spawn_task,再等 TurnComplete 事件确认任务跑完。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, install_test_tracing);外部调用 11 个(clone, new, from_secs, assert!, assert_eq!, assert_ne!, context_from_w3c_trace_context, new, timeout, info_span! (+1 more))。

shutdown_complete_does_not_append_to_thread_store_after_shutdown6486–6530 ↗
async fn shutdown_complete_does_not_append_to_thread_store_after_shutdown()

作用:确认关闭完成后,不会再往线程存储里追加内容。关闭就像把账本合上,之后不应该再偷偷写一笔。

数据流:进去的是一个带内存线程存储的会话和已创建的 LiveThread → handlers::shutdown 执行关闭 → 出来检查线程存储只发生 create_thread 和 shutdown_thread,没有额外 append。

调用关系:测试框架运行它。它把 session 的 thread_store 换成可统计调用次数的 InMemoryThreadStore,然后验证 shutdown 的持久化行为。

调用图:调用 3 个内部函数(make_session_and_context, default, create);外部调用 6 个(clone, new, new, assert!, assert_eq!, default)。

submission_loop_channel_close_emits_thread_stop_lifecycle6533–6582 ↗
async fn submission_loop_channel_close_emits_thread_stop_lifecycle()

作用:确认提交通道关闭时,submission_loop 会触发线程停止生命周期回调。生命周期回调就是给插件的“线程结束通知”。

数据流:进去的是一个马上关闭的提交通道,以及注册了 on_thread_stop 的扩展记录器 → submission_loop 发现通道关闭并收尾 → 出来记录器被调用一次,并能看到会话级和线程级扩展数据。

调用关系:测试框架运行它。它构造扩展注册表,关闭 tx_sub 后调用 submission_loop,验证线程停止通知没有漏发。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 6 个(clone, new, assert_eq!, bounded, new, new)。

submission_loop_channel_close_aborts_active_turn_before_thread_stop_lifecycle6585–6664 ↗
async fn submission_loop_channel_close_aborts_active_turn_before_thread_stop_lifecycle()

作用:确认提交通道关闭时,如果还有正在跑的轮次,会先中断轮次,再通知线程停止。顺序很重要:先停手头任务,再宣布整条线程结束。

数据流:进去的是一个永不结束的测试任务和一个关闭的提交通道 → submission_loop 收尾时先触发 turn_abort,再触发 thread_stop → 出来记录到的调用顺序正好是 turn_abort、thread_stop。

调用关系:测试框架运行它。它通过扩展记录器同时监听轮次中止和线程停止,验证 submission_loop 的关闭顺序。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 7 个(clone, new, new, assert_eq!, bounded, new, new)。

shutdown_and_wait_allows_multiple_waiters6667–6702 ↗
async fn shutdown_and_wait_allows_multiple_waiters()

作用:确认多个调用方可以同时等待同一次关闭完成。这样界面层或服务层重复调用关闭等待时,不会互相打架。

数据流:进去的是一个 Codex 对象和两个并发 shutdown_and_wait 调用 → 第一个发送 Shutdown 提交,后台模拟会话循环稍后结束 → 出来两个等待者都正常返回成功。

调用关系:测试框架运行它。它用一个假的 session loop handle 配合 Codex.shutdown_and_wait,验证等待关闭的共享机制。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 9 个(clone, new, from_millis, assert_eq!, bounded, unbounded, spawn, sleep, channel)。

shutdown_and_wait_waits_when_shutdown_is_already_in_progress6705–6739 ↗
async fn shutdown_and_wait_waits_when_shutdown_is_already_in_progress()

作用:确认关闭已经在进行时,再调用 shutdown_and_wait 会继续等到会话循环真正结束,而不是提前返回。

数据流:进去的是一个提交接收端已关闭、但 session loop 还被 oneshot 卡住的 Codex → 调用 shutdown_and_wait 后先观察它没有完成 → 再发送完成信号 → 出来等待者才成功结束。

调用关系:测试框架运行它。它模拟“关闭请求已经发不出去或已开始,但后台循环还没停”的情况,验证 shutdown_and_wait 仍以 session loop 结束为准。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 10 个(clone, new, from_millis, assert!, bounded, unbounded, spawn, channel, sleep, channel)。

shutdown_and_wait_shuts_down_cached_guardian_subagent6742–6796 ↗
async fn shutdown_and_wait_shuts_down_cached_guardian_subagent()

作用:验证父会话关闭时,缓存起来的 guardian 子代理也会一起收到关闭命令。guardian 可以理解成负责复核或守门的辅助代理。

数据流:它先创建父会话和子会话,把子会话塞进父会话的 guardian 缓存里;然后调用父 Codex 的关闭并等待;最后检查子会话的接收通道里确实来了一个 Shutdown 操作。

调用关系:这个测试用 make_session_and_context 搭测试会话,用 submission_loop 跑父会话循环,再通过 shutdown_and_wait 触发整条关闭链路,确保父子会话不会留下后台任务。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 8 个(clone, new, assert_eq!, bounded, unbounded, spawn, channel, channel)。

cached_guardian_subagent_exposes_its_rollout_path6799–6828 ↗
async fn cached_guardian_subagent_exposes_its_rollout_path()

作用:验证缓存的 guardian 子代理如果有持久化记录路径,父会话能把这个路径暴露出来。rollout path 可以理解成对话过程的保存文件位置。

数据流:它给子会话挂上线程持久化,得到一个保存路径;再把子 Codex 放进父会话的 guardian 缓存;最后读取 trunk_rollout_path,确认返回的就是子会话那条路径。

调用关系:这个测试依赖 attach_thread_persistence 制造可保存的子会话,检查 GuardianReviewSessionManager 对外提供路径的行为。

调用图:调用 2 个内部函数(attach_thread_persistence, make_session_and_context);外部调用 6 个(new, assert_eq!, bounded, unbounded, spawn, channel)。

shutdown_and_wait_shuts_down_tracked_ephemeral_guardian_review6831–6885 ↗
async fn shutdown_and_wait_shuts_down_tracked_ephemeral_guardian_review()

作用:验证临时登记的 guardian review 会话也会在父会话关闭时被关掉。ephemeral 的意思是临时的、不长期缓存的。

数据流:它创建父子两个会话,把子 Codex 登记成临时 guardian review;父会话执行 shutdown_and_wait 后,子会话通道应收到 Shutdown;测试用一次性信号确认这件事发生了。

调用关系:它和缓存 guardian 的关闭测试相似,但走的是 register_ephemeral_for_test 这条登记路径,覆盖另一种子代理生命周期。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 8 个(clone, new, assert_eq!, bounded, unbounded, spawn, channel, channel)。

make_session_and_context_with_auth_and_config_and_rx6887–6907 ↗
async fn make_session_and_context_with_auth_and_config_and_rx(
    auth: CodexAuth,
    dynamic_tools: Vec<DynamicToolSpec>,
    configure_config: F,
) -> (
    Arc<Session>,
    Arc<TurnContext>,

作用:这是测试用的便捷工厂,用指定认证、动态工具和配置改动,快速造出一个会话、一个轮次上下文和一个事件接收器。

数据流:输入认证信息、动态工具列表和一个修改配置的函数;它先创建临时 codex_home 目录;再把这些交给更底层的 make_session_and_context_with_auth_config_home_and_rx;输出可共享的 Session、TurnContext 和事件 Receiver。

调用关系:很多测试不想关心目录准备细节,所以会调用它;它把真正繁琐的组装工作转交给 make_session_and_context_with_auth_config_home_and_rx。

调用图:调用 1 个内部函数(make_session_and_context_with_auth_config_home_and_rx);被 5 处调用(build_initial_context_omits_multi_agent_v2_usage_hints_when_hint_disabled, make_multi_agent_v2_usage_hint_test_session, make_session_and_context_with_dynamic_tools_and_rx, resize_all_images_prepares_failures_before_history_insertion, resize_all_images_prepares_resumed_history_before_installing_it);外部调用 1 个(tempdir)。

make_session_and_context_with_auth_config_home_and_rx6909–7143 ↗
async fn make_session_and_context_with_auth_config_home_and_rx(
    auth: CodexAuth,
    dynamic_tools: Vec<DynamicToolSpec>,
    codex_home: &Path,
    configure_config: F,
) -> (
    Arc<Session>,

作用:这是本段测试里最完整的会话搭建器,用来模拟一个足够真实、但不需要联网的测试会话。

数据流:它接收认证、动态工具、测试目录和配置修改函数;内部创建配置、认证管理器、模型信息、服务集合、环境、插件、技能、事件通道和会话状态;最后返回一个可运行的 Session、对应的 TurnContext,以及用来观察事件的接收器。

调用关系:它是多个测试辅助函数的底座;上层工厂只包装参数,它负责把 Session::make_turn_context、SessionServices、模型客户端、技能加载等零件装成一台测试用会话机器。

调用图:调用 32 个内部函数(new, new, new_uninitialized_with_permission_profile, new, new, new, new, default, new, new (+15 more));被 1 处调用(make_session_and_context_with_auth_and_config_and_rx);外部调用 26 个(clone, new, new, new, default, new, from, new, from_pointee, from (+15 more))。

make_session_and_context_with_dynamic_tools_and_rx7145–7158 ↗
async fn make_session_and_context_with_dynamic_tools_and_rx(
    dynamic_tools: Vec<DynamicToolSpec>,
) -> (
    Arc<Session>,
    Arc<TurnContext>,
    async_channel::Receiver<Event>,
)

作用:这是更简单的测试工厂,专门用来创建带动态工具的默认测试会话。

数据流:输入动态工具列表;它使用固定的测试 API Key 和默认配置;输出 Session、TurnContext 和事件接收器。

调用关系:它调用 make_session_and_context_with_auth_and_config_and_rx,供需要事件通道或动态工具的测试复用。

调用图:调用 2 个内部函数(make_session_and_context_with_auth_and_config_and_rx, from_api_key);被 4 处调用(make_session_and_context_with_rx, assert_failed_apply_patch_tracks_committed_delta, invalidation_emits_empty_turn_diff, net_zero_patch_emits_empty_turn_diff)。

make_session_and_context_with_rx7162–7168 ↗
async fn make_session_and_context_with_rx() -> (
    Arc<Session>,
    Arc<TurnContext>,
    async_channel::Receiver<Event>,
)

作用:这是最常用的测试工厂之一,用默认设置创建会话并额外返回事件接收器。

数据流:它不接收业务参数;内部传入空的动态工具列表;返回 Session、TurnContext 和事件 Receiver。

调用关系:许多测试只需要一个普通会话和事件流时会调用它,它再委托给 make_session_and_context_with_dynamic_tools_and_rx。

调用图:调用 1 个内部函数(make_session_and_context_with_dynamic_tools_and_rx);被 68 处调用(delegated_mcp_guardian_abort_returns_synthetic_decline_answer, delegated_mcp_user_reviewer_returns_none_without_metadata, forward_events_cancelled_while_send_blocked_shuts_down_delegate, forward_ops_preserves_submission_trace_context, handle_exec_approval_uses_call_id_for_guardian_review_and_approval_id_for_reply, handle_request_permissions_uses_tool_call_id_for_round_trip, run_codex_thread_interactive_respects_pre_cancelled_spawn, test_review_session, cancelled_guardian_review_emits_terminal_abort_without_warning, guardian_review_surfaces_responses_api_errors_in_rejection_reason (+15 more));外部调用 1 个(new)。

refresh_mcp_servers_is_deferred_until_next_turn7171–7213 ↗
async fn refresh_mcp_servers_is_deferred_until_next_turn()

作用:验证 MCP 服务器刷新请求不会立刻打断当前状态,而是等到下一轮处理时才执行。MCP 是一种让模型调用外部工具的协议。

数据流:它先取旧的启动取消令牌,手动放入一份待刷新配置;确认旧令牌还没取消;调用 refresh_mcp_servers_if_requested 后,旧令牌应被取消,待刷新配置被清空,并生成新的未取消令牌。

调用关系:这个测试直接检查 Session 的延迟刷新入口,确保配置变更被排队到下一轮,而不是随手立即执行。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert!, json!, to_value)。

spawn_task_does_not_update_previous_turn_settings_for_non_run_turn_tasks7216–7240 ↗
async fn spawn_task_does_not_update_previous_turn_settings_for_non_run_turn_tasks()

作用:验证启动非正式“运行一轮”的任务时,不会误改上一轮对话设置。

数据流:它把 previous_turn_settings 设为空,启动一个永不结束的普通任务,然后中断所有任务;最后确认 previous_turn_settings 仍然是空。

调用关系:它通过 spawn_task 和 abort_all_tasks 覆盖任务生命周期,防止后台任务污染真正轮次的状态记录。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 3 个(clone, assert_eq!, vec!)。

build_settings_update_items_emits_environment_item_for_network_changes7243–7302 ↗
async fn build_settings_update_items_emits_environment_item_for_network_changes()

作用:验证网络权限变化时,会生成一段新的环境上下文给模型看。

数据流:它从旧上下文复制出新上下文,往配置层里加入允许和拒绝的域名;调用 build_settings_update_items;最后从生成的用户文本里确认出现了包含允许 api.example.com、拒绝 blocked.example.com 的 network 片段。

调用关系:它检查 Session 的设置差异生成逻辑,确保网络约束变化能被传给后续模型请求。

调用图:调用 4 个内部函数(new, new, make_session_and_context, user_input_texts);外部调用 4 个(new, default, assert!, from)。

environment_context_uses_session_shell_when_environment_shell_is_absent7305–7345 ↗
async fn environment_context_uses_session_shell_when_environment_shell_is_absent()

作用:验证环境自己没声明 shell 时,会退回使用会话级别的 shell;如果环境声明了 shell,则优先用环境自己的。

数据流:它把会话 shell 设成 PowerShell,并清空各环境的 shell;渲染环境上下文后应看到 powershell;再给主环境设置 cmd,重新渲染后应看到 cmd。

调用关系:它测试 EnvironmentContext::from_turn_context 的取值优先级,避免模型收到错误的命令行环境说明。

调用图:调用 2 个内部函数(from_turn_context, make_session_and_context);外部调用 3 个(new, from, assert!)。

build_settings_update_items_emits_environment_item_for_time_changes7348–7371 ↗
async fn build_settings_update_items_emits_environment_item_for_time_changes()

作用:验证日期或时区变化时,会生成环境上下文更新。

数据流:它在新上下文里设置 current_date 和 timezone;调用 build_settings_update_items;最后确认生成文本包含对应日期和时区标签。

调用关系:它覆盖设置差异里的时间信息分支,保证模型能知道当前时间背景变了。

调用图:调用 2 个内部函数(make_session_and_context, user_input_texts);外部调用 2 个(new, assert!)。

build_settings_update_items_omits_environment_item_when_disabled7374–7400 ↗
async fn build_settings_update_items_omits_environment_item_when_disabled()

作用:验证配置关闭环境上下文后,即使环境信息变化,也不会再生成环境上下文。

数据流:它把 include_environment_context 设为 false,并改动日期;调用 build_settings_update_items;最后确认所有用户文本都不含 environment_context。

调用关系:它检查配置开关是否真正控制了 Session 的上下文注入行为。

调用图:调用 2 个内部函数(make_session_and_context, user_input_texts);外部调用 2 个(new, assert!)。

build_settings_update_items_emits_realtime_start_when_session_becomes_live7403–7428 ↗
async fn build_settings_update_items_emits_realtime_start_when_session_becomes_live()

作用:验证会话从非实时变成实时状态时,会生成一条开发者提示告诉模型实时对话开始了。

数据流:它把当前上下文的 realtime_active 设为 true;构建设置更新;最后在开发者文本里查找 realtime_conversation 标记。

调用关系:它测试 build_settings_update_items 对实时状态从关到开的差异处理。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 2 个(new, assert!)。

build_settings_update_items_emits_realtime_end_when_session_stops_being_live7431–7456 ↗
async fn build_settings_update_items_emits_realtime_end_when_session_stops_being_live()

作用:验证实时会话结束时,会生成一条说明结束原因的开发者提示。

数据流:它让旧上下文处于实时状态,新上下文变成非实时;构建更新项;最后确认开发者文本里有 Reason: inactive。

调用关系:它覆盖实时状态从开到关的差异处理,和实时开始测试形成一对。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

build_settings_update_items_uses_previous_turn_settings_for_realtime_end7459–7490 ↗
async fn build_settings_update_items_uses_previous_turn_settings_for_realtime_end()

作用:验证当前参考上下文里缺少实时状态时,系统还能用 previous_turn_settings 判断实时会话已经结束。

数据流:它把旧上下文项的 realtime_active 清空,但在会话里记录上一轮 realtime_active 为 true;当前上下文为 false;构建更新后应看到结束提示。

调用关系:它检查 build_settings_update_items 不只依赖上下文项,也会参考 Session 保存的上一轮设置。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

build_initial_context_uses_previous_realtime_state7493–7519 ↗
async fn build_initial_context_uses_previous_realtime_state()

作用:验证初始上下文会说明当前实时状态,但在恢复已有参考上下文时不会重复说明。

数据流:它先把 turn_context 标成实时并构建初始上下文,确认有 realtime_conversation;再把同样的上下文项存成参考基线;重新构建时确认不再重复出现该提示。

调用关系:它测试 build_initial_context 和 SessionState 里的 reference context 如何配合,避免重复给模型塞相同信息。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

make_multi_agent_v2_usage_hint_test_session7521–7537 ↗
async fn make_multi_agent_v2_usage_hint_test_session(
    enable_multi_agent_v2: bool,
) -> (Arc<Session>, Arc<TurnContext>)

作用:这是多代理 v2 使用提示相关测试的专用工厂。

数据流:输入是否启用 MultiAgentV2;它创建默认会话,并按需打开功能开关,同时写入根代理提示和子代理提示文本;输出 Session 和 TurnContext。

调用关系:后面的多代理提示测试都通过它准备统一环境,减少重复配置代码。

调用图:调用 2 个内部函数(make_session_and_context_with_auth_and_config_and_rx, from_api_key);被 3 处调用(build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message, build_initial_context_adds_multi_agent_v2_subagent_usage_hint_as_developer_message, build_initial_context_omits_multi_agent_v2_usage_hints_when_feature_disabled);外部调用 1 个(new)。

PromptExtensionTestContributor::contribute7543–7562 ↗
fn contribute(
        &'a self,
        _session_store: &'a codex_extension_api::ExtensionData,
        thread_store: &'a codex_extension_api::ExtensionData,
    ) -> std::pin::Pin<
        Box<dyn s

作用:这是一个测试用扩展贡献者,用来模拟扩展往提示词里加一段开发者规则。

数据流:它读取线程级扩展数据;如果里面有 PromptExtensionTestState,就返回一个内容为 prompt extension enabled 的开发者提示片段;否则返回空列表。

调用关系:prompt_extension_test_registry 会注册它,随后初始上下文相关测试用它验证扩展提示是否按状态出现。

调用图:外部调用 1 个(pin)。

prompt_extension_test_registry7565–7570 ↗
fn prompt_extension_test_registry() -> Arc<codex_extension_api::ExtensionRegistry<crate::config::Config>>

作用:创建一个只包含测试提示贡献者的扩展注册表。

数据流:它新建扩展注册表构建器,注册 PromptExtensionTestContributor,然后构建并包进 Arc 共享指针里返回。

调用关系:扩展提示的两个测试会把它塞到 session.services.extensions 中,用来替换默认扩展系统。

调用图:调用 1 个内部函数(new);被 2 处调用(build_initial_context_includes_prompt_fragments_from_extensions, build_initial_context_omits_prompt_fragments_without_extension_state);外部调用 1 个(new)。

build_initial_context_includes_prompt_fragments_from_extensions7573–7591 ↗
async fn build_initial_context_includes_prompt_fragments_from_extensions()

作用:验证当扩展状态存在时,初始上下文会包含扩展贡献的开发者提示。

数据流:它给会话装上测试扩展注册表,并在线程扩展数据里插入状态;构建初始上下文;最后确认开发者消息里有 prompt extension enabled。

调用关系:它把 prompt_extension_test_registry 和 PromptExtensionTestContributor 串起来,检查 build_initial_context 会收集扩展提示片段。

调用图:调用 3 个内部函数(developer_message_texts, make_session_and_context, prompt_extension_test_registry);外部调用 1 个(assert!)。

build_initial_context_omits_prompt_fragments_without_extension_state7594–7608 ↗
async fn build_initial_context_omits_prompt_fragments_without_extension_state()

作用:验证没有扩展状态时,扩展贡献者不会凭空添加提示。

数据流:它只安装测试扩展注册表,但不插入 PromptExtensionTestState;构建初始上下文;最后确认开发者消息里没有 prompt extension enabled。

调用关系:它和“包含扩展提示”的测试配对,证明扩展提示受线程状态控制。

调用图:调用 3 个内部函数(developer_message_texts, make_session_and_context, prompt_extension_test_registry);外部调用 1 个(assert!)。

build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message7611–7630 ↗
async fn build_initial_context_adds_multi_agent_v2_root_usage_hint_as_developer_message()

作用:验证启用多代理 v2 且当前是根线程时,会加入根代理使用提示。

数据流:它创建启用 MultiAgentV2 的测试会话;构建初始上下文;最后确认开发者消息有 Root guidance,且没有 Subagent guidance。

调用关系:它使用 make_multi_agent_v2_usage_hint_test_session,检查 build_initial_context 对根代理场景的分支。

调用图:调用 2 个内部函数(developer_message_texts, make_multi_agent_v2_usage_hint_test_session);外部调用 1 个(assert!)。

build_initial_context_adds_multi_agent_v2_subagent_usage_hint_as_developer_message7633–7668 ↗
async fn build_initial_context_adds_multi_agent_v2_subagent_usage_hint_as_developer_message()

作用:验证启用多代理 v2 且当前是子代理线程时,会加入子代理使用提示。

数据流:它创建启用功能的会话,把 session_source 改成 SubAgent;构建初始上下文;最后确认只出现 Subagent guidance,不出现 Root guidance。

调用关系:它手动调整 Session 状态和 TurnContext,让 build_initial_context 走子代理路径。

调用图:调用 4 个内部函数(developer_message_texts, make_multi_agent_v2_usage_hint_test_session, try_from, new);外部调用 3 个(get_mut, SubAgent, assert!)。

build_initial_context_omits_multi_agent_v2_usage_hints_when_feature_disabled7671–7687 ↗
async fn build_initial_context_omits_multi_agent_v2_usage_hints_when_feature_disabled()

作用:验证多代理 v2 功能没打开时,不会加入任何多代理使用提示。

数据流:它创建未启用 MultiAgentV2 的测试会话;构建初始上下文;最后确认根提示和子提示都没有出现。

调用关系:它和启用功能的两个测试形成对照,保证功能开关有效。

调用图:调用 2 个内部函数(developer_message_texts, make_multi_agent_v2_usage_hint_test_session);外部调用 1 个(assert!)。

build_initial_context_omits_multi_agent_v2_usage_hints_when_hint_disabled7690–7715 ↗
async fn build_initial_context_omits_multi_agent_v2_usage_hints_when_hint_disabled()

作用:验证即使多代理 v2 功能打开,只要 usage hint 开关关闭,也不会加入使用提示。

数据流:它创建会话时启用 MultiAgentV2,但把 multi_agent_v2.usage_hint_enabled 设为 false,并配置两种提示文本;构建初始上下文后确认两者都没有出现。

调用关系:它直接使用通用会话工厂改配置,覆盖“功能开但提示关闭”的细分开关。

调用图:调用 3 个内部函数(developer_message_texts, make_session_and_context_with_auth_and_config_and_rx, from_api_key);外部调用 2 个(new, assert!)。

build_initial_context_omits_default_image_save_location_with_image_history7718–7741 ↗
async fn build_initial_context_omits_default_image_save_location_with_image_history()

作用:验证即使历史里已有图片生成记录,初始上下文也不会再塞默认图片保存位置说明。

数据流:它把一条已完成的 ImageGenerationCall 放进历史;构建初始上下文;最后确认开发者文本不含 Generated images are saved to。

调用关系:它保护图片相关提示不要在初始上下文里重复或过度出现。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 2 个(assert!, vec!)。

build_initial_context_omits_default_image_save_location_without_image_history7744–7756 ↗
async fn build_initial_context_omits_default_image_save_location_without_image_history()

作用:验证没有图片历史时,初始上下文同样不会出现默认图片保存位置说明。

数据流:它创建普通会话并直接构建初始上下文;读取开发者文本;确认不含 Generated images are saved to。

调用关系:它和有图片历史的测试一起确认该默认说明已经不会由 build_initial_context 注入。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

build_initial_context_trims_skill_metadata_from_context_window_budget7759–7804 ↗
async fn build_initial_context_trims_skill_metadata_from_context_window_budget()

作用:验证技能说明太多、模型上下文窗口太小时,初始上下文会把技能元数据裁掉,而且不会把预算警告直接塞给模型。

数据流:它给 turn_context 放入两个技能,并把模型上下文窗口设得很小;构建初始上下文;最后确认开发者文本里既没有预算超限警告,也没有技能条目。

调用关系:它检查 build_initial_context 和 build_available_skills 的配合,确保给模型看的内容被预算限制住。

调用图:调用 3 个内部函数(developer_input_texts, make_session_and_context, new);外部调用 4 个(new, assert!, default, vec!)。

emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values7807–7850 ↗
fn emit_thread_start_skill_metrics_records_enabled_kept_and_truncated_values()

作用:验证线程开始时渲染技能,如果预算太小,会正确记录“启用多少、保留多少、截断多少”等指标。

数据流:它创建测试遥测对象和一个技能,用 1 个字符的预算渲染技能;得到超预算警告;再读取指标快照,确认启用为 1、保留为 0、截断为 1、描述截断字符数为 4。

调用关系:它直接调用 build_available_skills,并通过 SkillRenderSideEffects::ThreadStart 检查遥测打点。

调用图:调用 1 个内部函数(test_session_telemetry_without_metadata);外部调用 4 个(assert_eq!, default, Characters, vec!)。

emit_thread_start_skill_metrics_records_description_truncated_chars_without_omitted_skills7853–7906 ↗
fn emit_thread_start_skill_metrics_records_description_truncated_chars_without_omitted_skills()

作用:验证没有遗漏技能、只是描述被缩短时,也会记录被截掉的描述字符数。

数据流:它创建两个带描述的技能,计算刚好容纳技能行但放不下完整描述的预算;渲染后确认遗漏数量为 0、描述截断字符数为 8;再检查指标里截断技能数为 0、描述截断字符数为 8。

调用关系:它补充覆盖 build_available_skills 的另一种裁剪情况:技能还在,但说明变短了。

调用图:调用 1 个内部函数(test_session_telemetry_without_metadata);外部调用 5 个(assert_eq!, default, Characters, test_path_buf, vec!)。

build_initial_context_emits_thread_start_skill_warning_on_repeated_builds7909–7961 ↗
async fn build_initial_context_emits_thread_start_skill_warning_on_repeated_builds()

作用:验证初始上下文反复构建时,技能预算超限警告每次都会通过事件发出去。

数据流:它创建带事件接收器的会话,设置两个技能和很小的上下文窗口;第一次 build_initial_context 后从事件通道收到警告;第二次再构建后也应再次收到同样警告。

调用关系:它把 build_initial_context、事件通道和技能预算警告连起来,确认警告不是只发一次。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, new);外部调用 7 个(into_inner, new, from_secs, assert!, default, timeout, vec!)。

handle_output_item_done_records_image_save_history_message7964–8018 ↗
async fn handle_output_item_done_records_image_save_history_message()

作用:验证图片生成结果保存成功时,历史里会先记录一条“图片保存在哪里”的说明,再记录图片生成项本身。

数据流:它准备一个 base64 结果为 foo 的图片生成项,调用 handle_output_item_done;之后读取会话历史,确认有保存说明和原始图片项;再检查磁盘上确实写出了内容为 foo 的文件。

调用关系:它通过 HandleOutputCtx 调用输出处理逻辑,覆盖图片生成完成后的保存和历史记录流程。

调用图:调用 6 个内部函数(into, new, make_session_and_context, test_tool_runtime, image_generation_artifact_path, new);外部调用 6 个(clone, new, new, assert_eq!, remove_file, vec!)。

handle_output_item_done_skips_image_save_message_when_save_fails8021–8057 ↗
async fn handle_output_item_done_skips_image_save_message_when_save_fails()

作用:验证图片保存失败时,不会把“保存位置”说明写进历史,但图片生成项本身仍然会完成记录。

数据流:它构造一个无法正确解码的图片结果,调用 handle_output_item_done;之后检查历史只有原始图片项,并确认预期保存路径不存在。

调用关系:它和保存成功测试配对,确认错误情况下不会向用户或模型留下假的保存说明。

调用图:调用 4 个内部函数(make_session_and_context, test_tool_runtime, image_generation_artifact_path, new);外部调用 7 个(clone, new, new, assert!, assert_eq!, remove_file, vec!)。

build_initial_context_uses_previous_turn_settings_for_realtime_end8060–8079 ↗
async fn build_initial_context_uses_previous_turn_settings_for_realtime_end()

作用:验证构建初始上下文时,也能根据上一轮设置判断实时会话已经结束。

数据流:它把 previous_turn_settings 设为上一轮 realtime_active 为 true,而当前 turn_context 默认非实时;构建初始上下文;最后确认开发者文本包含 Reason: inactive。

调用关系:它覆盖 build_initial_context 使用 previous_turn_settings 的路径,和设置更新里的实时结束测试相呼应。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

build_initial_context_restates_realtime_start_when_reference_context_is_missing8082–8102 ↗
async fn build_initial_context_restates_realtime_start_when_reference_context_is_missing()

作用:验证没有参考上下文时,即使上一轮设置也说实时已开启,初始上下文仍会重新说明当前实时正在进行。

数据流:它把当前 turn_context 标为实时,也把 previous_turn_settings 标为实时;构建初始上下文;最后确认仍包含 realtime_conversation。

调用关系:它确保 build_initial_context 在缺少 reference context 的恢复场景下不会漏掉实时状态说明。

调用图:调用 2 个内部函数(developer_input_texts, make_session_and_context);外部调用 1 个(assert!)。

file_system_policy_with_unreadable_glob8104–8119 ↗
fn file_system_policy_with_unreadable_glob(turn_context: &TurnContext) -> FileSystemSandboxPolicy

作用:这是测试辅助函数,用来基于当前轮次的文件系统沙盒策略,再额外加一条禁止读取 .env 文件的通配规则。

数据流:输入 TurnContext;它先从旧式沙盒策略转换出新的 FileSystemSandboxPolicy;再把当前目录下所有 .env 文件的 GlobPattern 加成 Deny;返回修改后的策略。

调用关系:后面的权限和 rollout 持久化测试用它制造一个“和默认策略不同”的文件系统策略。

调用图:调用 2 个内部函数(sandbox_policy, from_legacy_sandbox_policy_for_cwd);被 2 处调用(record_context_updates_and_set_reference_context_item_persists_split_file_system_policy_to_rollout, turn_context_item_stores_split_file_system_sandbox_policy_when_different);外部调用 1 个(format!)。

turn_context_item_uses_turn_context_comp_hash_snapshot8122–8131 ↗
async fn turn_context_item_uses_turn_context_comp_hash_snapshot()

作用:验证 TurnContext 转成可保存的上下文项时,使用的是 TurnContext 自己保存的 comp_hash 快照,而不是模型信息里的值。

数据流:它分别给 turn_context.comp_hash 和 turn_context.model_info.comp_hash 设置不同字符串;转换成 turn_context_item;确认结果取的是 turn-context-hash。

调用关系:它检查 TurnContext::to_turn_context_item 的字段来源,防止恢复上下文时用错版本指纹。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 1 个(assert_eq!)。

turn_context_item_omits_legacy_equivalent_file_system_sandbox_policy8134–8144 ↗
async fn turn_context_item_omits_legacy_equivalent_file_system_sandbox_policy()

作用:验证如果文件系统沙盒策略和旧权限配置等价,就不在上下文项里额外存一份策略。

数据流:它创建默认会话并转换 TurnContext;确认 file_system_sandbox_policy 是 None,同时 permission_profile 正常保存。

调用关系:它让 to_turn_context_item 避免存重复数据,只在需要时记录拆分后的文件系统策略。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 1 个(assert_eq!)。

turn_context_item_stores_split_file_system_sandbox_policy_when_different8147–8166 ↗
async fn turn_context_item_stores_split_file_system_sandbox_policy_when_different()

作用:验证文件系统沙盒策略和默认权限不一样时,上下文项会明确保存这份单独策略。

数据流:它用 file_system_policy_with_unreadable_glob 生成额外拒绝 .env 的策略,并把 permission_profile 更新成使用该策略;转换上下文项后,确认其中保存了这份文件系统策略和权限配置。

调用关系:它和省略等价策略的测试配对,确认 to_turn_context_item 只在策略有差异时写入。

调用图:调用 3 个内部函数(file_system_policy_with_unreadable_glob, make_session_and_context, from_runtime_permissions_with_enforcement);外部调用 1 个(assert_eq!)。

record_context_updates_and_set_reference_context_item_injects_full_context_when_baseline_missing8169–8185 ↗
async fn record_context_updates_and_set_reference_context_item_injects_full_context_when_baseline_missing()

作用:验证没有旧的参考上下文时,记录上下文更新会把完整初始上下文写进历史,并设置新的参考项。

数据流:它创建会话后直接调用 record_context_updates_and_set_reference_context_item;读取历史应等于 build_initial_context 的结果;再确认 reference_context_item 等于当前 TurnContext 转出的项。

调用关系:它检查 Session 在第一次建立上下文基线时的行为,确保历史和内部参考状态同步。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 1 个(assert_eq!)。

record_context_updates_and_set_reference_context_item_reinjects_full_context_after_clear8188–8226 ↗
async fn record_context_updates_and_set_reference_context_item_reinjects_full_context_after_clear()

作用:验证参考上下文被清掉后,再记录上下文会重新注入完整上下文,而不会只写差异。

数据流:它先写入一条压缩摘要,再记录上下文;随后手动清空参考项并把历史恢复成只有摘要;再次记录上下文后,历史应变成摘要加完整初始上下文。

调用关系:它模拟压缩或恢复后基线丢失的情况,检查 record_context_updates_and_set_reference_context_item 能自我修复。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert_eq!, from_ref, vec!)。

record_context_updates_and_set_reference_context_item_persists_baseline_without_emitting_diffs8229–8285 ↗
async fn record_context_updates_and_set_reference_context_item_persists_baseline_without_emitting_diffs()

作用:验证当只需要更新参考基线、不需要给模型发差异时,系统仍会把新的上下文项持久化到 rollout 记录里。

数据流:它先设置旧参考上下文,再切换到另一个模型上下文;确认 build_settings_update_items 没有生成更新项;调用记录函数后,历史仍为空,但 reference_context_item 变成新上下文;刷新 rollout 后,从文件里读到的新 TurnContext 也应匹配。

调用关系:它把上下文基线、历史、线程持久化和 RolloutRecorder 串起来,防止“没消息可发”时漏存新基线。

调用图:调用 3 个内部函数(attach_thread_persistence, make_session_and_context, get_rollout_history);外部调用 2 个(assert_eq!, panic!)。

record_context_updates_and_set_reference_context_item_persists_split_file_system_policy_to_rollout8288–8319 ↗
async fn record_context_updates_and_set_reference_context_item_persists_split_file_system_policy_to_rollout()

作用:验证拆分出来的文件系统沙盒策略会被写进 rollout 持久化记录。

数据流:它给 turn_context 加上额外拒绝 .env 的文件系统策略,挂上线程持久化;记录上下文并刷新 rollout;最后从保存文件里找 TurnContext,确认其中的 file_system_sandbox_policy 就是那份策略。

调用关系:它复用 file_system_policy_with_unreadable_glob,专门检查权限细节不会在持久化过程中丢失。

调用图:调用 5 个内部函数(attach_thread_persistence, file_system_policy_with_unreadable_glob, make_session_and_context, from_runtime_permissions_with_enforcement, get_rollout_history);外部调用 2 个(assert_eq!, panic!)。

build_initial_context_prepends_model_switch_message8322–8343 ↗
async fn build_initial_context_prepends_model_switch_message()

作用:验证上一轮模型和当前模型不同时,初始上下文最前面会加一条模型切换说明。

数据流:它把 previous_turn_settings 的 model 设成 previous-regular-model;构建初始上下文;检查第一条消息是 developer 角色,并且文本里包含 model_switch 标签。

调用关系:它检查 build_initial_context 对模型切换的提示顺序,确保模型先看到“已经换模型”这个重要背景。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert!, assert_eq!, panic!)。

record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout8346–8406 ↗
async fn record_context_updates_and_set_reference_context_item_persists_full_reinjection_to_rollout()

作用:测试切换模型后,新的完整上下文会被写进 rollout 记录里。这样以后恢复线程时,不会拿旧模型或旧设置继续跑。

数据流:它先创建一个会话和旧上下文,再换成另一个模型生成新上下文,并打开线程持久化。然后写入一条种子消息、清空参考上下文、记录上一轮设置,再调用上下文更新逻辑。最后它从磁盘 rollout 里读回历史,确认里面保存的 TurnContext 和当前新上下文完全一致。

调用关系:这个测试通过 attach_thread_persistence 准备可落盘的线程,通过 make_session_and_context 构造测试会话,最后用 RolloutRecorder::get_rollout_history 验证 record_context_updates_and_set_reference_context_item 的结果。它关注的是会话恢复链路里“上下文是否真的持久化”这一环。

调用图:调用 3 个内部函数(attach_thread_persistence, make_session_and_context, get_rollout_history);外部调用 6 个(default, new, assert_eq!, panic!, UserMessage, EventMsg)。

run_user_shell_command_does_not_set_reference_context_item8409–8436 ↗
async fn run_user_shell_command_does_not_set_reference_context_item()

作用:测试用户单独执行 shell 命令时,不会把这次命令误当成下一轮对话的参考上下文。shell 命令只是临时任务,不应该污染聊天状态。

数据流:它创建带事件接收器的会话,先把参考上下文清空。然后运行一条 echo shell 命令,等待收到 TurnComplete 表示任务结束。最后检查 session.reference_context_item 仍然是空的。

调用关系:这个测试直接调用 handlers::run_user_shell_command,并监听会话发出的事件。它保护的是独立 shell 任务和正常聊天轮次之间的边界。

调用图:调用 2 个内部函数(run_user_shell_command, make_session_and_context_with_rx);外部调用 5 个(from_secs, assert!, matches!, now, timeout)。

realtime_conversation_list_voices_emits_builtin_list8439–8481 ↗
async fn realtime_conversation_list_voices_emits_builtin_list()

作用:测试实时语音接口会返回内置的语音名单和默认语音。这样客户端打开语音选择器时能拿到稳定结果。

数据流:它创建会话和事件接收器,调用 realtime_conversation_list_voices。随后读取一条事件,取出 voices 字段,和预期的 v1、v2 语音列表以及默认值逐项比较。

调用关系:这个测试覆盖 handlers::realtime_conversation_list_voices 的输出事件。它确保会话层不用访问外部服务,也能给客户端发出固定的语音能力清单。

调用图:调用 2 个内部函数(realtime_conversation_list_voices, make_session_and_context_with_rx);外部调用 2 个(assert_eq!, panic!)。

CompletingTask::kind8487–8489 ↗
fn kind(&self) -> TaskKind

作用:告诉测试框架这个假任务是普通任务。普通任务代表正常的一轮对话,而不是审核或压缩之类的特殊轮次。

数据流:它不读取外部输入,只返回 TaskKind::Regular。调用前后没有状态变化。

调用关系:CompletingTask 被 task_finish_emits_thread_idle_lifecycle_after_active_turn_clears 使用,用来模拟一个会立刻结束的正常任务。会话调度器通过 kind 判断它属于哪类轮次。

CompletingTask::span_name8491–8493 ↗
fn span_name(&self) -> &'static str

作用:给这个假任务提供一个追踪名字,方便日志或测试追踪里识别它。这里的名字表示“正在完成的会话任务”。

数据流:它不接收业务数据,直接返回固定字符串 session_task.completing。没有副作用。

调用关系:会话任务运行框架会在创建追踪 span(可理解为一段可观察的运行记录)时使用这个名字。

CompletingTask::run8495–8503 ↗
async fn run(
        self: Arc<Self>,
        _session: Arc<SessionTaskContext>,
        _ctx: Arc<TurnContext>,
        _input: Vec<TurnInput>,
        _cancellation_token: CancellationToken,
    )

作用:模拟一个马上完成、且没有最后回复内容的任务。它用来测试任务结束后的收尾流程。

数据流:它收到会话、上下文、输入和取消令牌,但都不使用。执行后直接返回 None,表示没有最后的助手消息,也不改动会话。

调用关系:这个假任务由 spawn_task 启动,随后会话会走 on_task_finished 一类的完成流程。测试用它观察线程空闲生命周期钩子是否被触发。

NeverEndingTask::kind8513–8515 ↗
fn kind(&self) -> TaskKind

作用:返回这个永不结束假任务被设置成的任务类型。测试可以把它伪装成普通、审核或压缩任务。

数据流:它读取 self.kind,然后原样返回。不会修改任何东西。

调用关系:多个测试用 NeverEndingTask 制造“活跃轮次还没结束”的场景,会话调度器靠这个 kind 决定是否允许追加输入或如何取消。

NeverEndingTask::span_name8517–8519 ↗
fn span_name(&self) -> &'static str

作用:给永不结束的假任务起一个固定追踪名。这样日志里能看出这是测试用的卡住任务。

数据流:它直接返回 session_task.never_ending,不读取也不改动状态。

调用关系:会话任务框架运行 NeverEndingTask 时会使用这个名字做运行追踪。

NeverEndingTask::run8521–8535 ↗
async fn run(
        self: Arc<Self>,
        _session: Arc<SessionTaskContext>,
        _ctx: Arc<TurnContext>,
        _input: Vec<TurnInput>,
        cancellation_token: CancellationToken,
    ) -

作用:模拟一个一直不结束的任务,用来测试取消、打断和活跃轮次保护。它可以选择听取消信号,也可以故意无视取消。

数据流:它接收取消令牌。如果 listen_to_cancellation_token 为真,就等待取消信号,然后返回 None;否则每 60 秒睡一次,永远循环。它不产出内容。

调用关系:很多测试通过 spawn_task 启动它,制造“当前有任务占着”的状态。abort_all_tasks、steer_input、try_start_turn_if_idle 等流程都会在这种场景下被验证。

调用图:外部调用 3 个(cancelled, from_secs, sleep)。

GuardianDeniedApprovalTask::kind8542–8544 ↗
fn kind(&self) -> TaskKind

作用:声明这个 guardian 测试任务是普通任务。它虽然会触发审核拒绝,但轮次类型仍按普通对话处理。

数据流:它不读外部数据,直接返回 TaskKind::Regular。没有状态改动。

调用关系:guardian_auto_review_interrupts_after_three_consecutive_denials 用它来模拟普通任务里连续被 guardian 拒绝的情况。

GuardianDeniedApprovalTask::span_name8546–8548 ↗
fn span_name(&self) -> &'static str

作用:给这个会触发 guardian 拒绝的假任务提供追踪名。这个名字帮助区分测试里的任务来源。

数据流:它直接返回 session_task.guardian_denied_approval,不产生副作用。

调用关系:会话任务运行框架用它标记这类测试任务的运行片段。

GuardianDeniedApprovalTask::run8550–8564 ↗
async fn run(
        self: Arc<Self>,
        session: Arc<SessionTaskContext>,
        ctx: Arc<TurnContext>,
        _input: Vec<TurnInput>,
        cancellation_token: CancellationToken,
    ) ->

作用:故意连续记录三次 guardian 拒绝,然后等待被取消。它用来测试“连续拒绝三次就打断当前轮”的保护开关。

数据流:它拿到会话和轮次上下文,克隆出 Session,循环三次调用 record_guardian_denial_for_test。之后等待取消令牌触发,最后返回 None。

调用关系:guardian_auto_review_interrupts_after_three_consecutive_denials 启动这个任务。guardian 子系统记录拒绝后,会话应该发出 TurnAborted 事件。

调用图:外部调用 2 个(cancelled, record_guardian_denial_for_test)。

guardian_auto_review_interrupts_after_three_consecutive_denials8568–8599 ↗
async fn guardian_auto_review_interrupts_after_three_consecutive_denials()

作用:测试自动 guardian 审查连续拒绝三次后,会打断当前对话轮。这样系统不会在被安全检查反复否决时继续执行。

数据流:它创建会话,准备一条用户输入,启动 GuardianDeniedApprovalTask。然后从事件通道里等 TurnAborted 事件,并确认打断原因是 Interrupted。

调用关系:它依赖 GuardianDeniedApprovalTask 主动制造三次拒绝。测试目标是 guardian 记录拒绝后触发的会话中断流程。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 7 个(clone, new, assert_eq!, TurnAborted, from_secs, timeout, vec!)。

guardian_helper_review_interrupts_after_three_consecutive_denials8602–8661 ↗
async fn guardian_helper_review_interrupts_after_three_consecutive_denials()

作用:测试来自辅助审核线程的 guardian 拒绝也能触发三次中断规则。也就是说,不管拒绝从主任务还是旁路 helper 来,都要保护当前轮。

数据流:它先启动一个会听取消信号的 NeverEndingTask 保持轮次活跃。然后另起一个线程,在线程里的 Tokio 运行时中记录三次 guardian 拒绝。最后等待 TurnAborted 事件,并确认原因是 Interrupted。

调用关系:它把 NeverEndingTask 当作正在运行的对话,把 record_guardian_denial_for_test 放到 helper 线程里执行。这样验证跨线程的 guardian 事件仍会正确影响 Session。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 8 个(clone, from_secs, new, assert_eq!, TurnAborted, spawn, timeout, vec!)。

abort_regular_task_emits_marker_before_turn_aborted8665–8703 ↗
async fn abort_regular_task_emits_marker_before_turn_aborted()

作用:测试强制打断普通任务时,系统会先给模型历史放入“本轮已中止”的标记,再通知客户端 TurnAborted。顺序很重要,因为模型下次要知道上一轮为什么断了。

数据流:它启动一个无视取消的 NeverEndingTask,然后调用 abort_all_tasks。接着从事件通道读取第一条 RawResponseItem 标记事件,再读取 TurnAborted,并确认没有多余事件。

调用关系:它覆盖 abort_all_tasks 对普通任务的强制中断路径。RawResponseItem 是写给模型看的历史项,TurnAborted 是发给客户端看的状态事件。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 7 个(clone, assert!, assert_eq!, panic!, from_secs, timeout, vec!)。

abort_gracefully_emits_marker_before_turn_aborted8706–8744 ↗
async fn abort_gracefully_emits_marker_before_turn_aborted()

作用:测试任务愿意响应取消时,也仍然先写入中止标记,再发 TurnAborted。无论是温和取消还是强制取消,客户端和模型看到的顺序都应一致。

数据流:它启动一个会监听取消令牌的 NeverEndingTask,调用 abort_all_tasks。然后确认先收到 RawResponseItem,再收到 TurnAborted,最后通道里没有额外事件。

调用关系:它和 abort_regular_task_emits_marker_before_turn_aborted 配对,分别验证“任务不配合取消”和“任务配合取消”两条路径。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 7 个(clone, assert!, assert_eq!, panic!, from_secs, timeout, vec!)。

task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input8747–8866 ↗
async fn task_finish_emits_turn_item_lifecycle_for_leftover_pending_user_input()

作用:测试一轮任务结束时,如果中途还有用户追加输入没处理,系统会把它写入历史,并按完整生命周期发事件。这样迟到的用户输入不会丢。

数据流:它启动一个卡住的普通任务,清空早期事件。然后通过 steer_input 追加一条带文本标记的用户输入,再手动触发 on_task_finished。之后检查历史里有这条用户消息,并依次收到 RawResponseItem、ItemStarted、ItemCompleted、旧版 UserMessage、TurnComplete。

调用关系:这个测试连接了 steer_input、输入队列、on_task_finished、历史记录和事件广播。它确保任务收尾时会把 pending input 当成正式用户消息补齐。

调用图:调用 2 个内部函数(new, make_session_and_context_with_rx);外部调用 6 个(clone, default, assert!, from_secs, timeout, vec!)。

task_finish_emits_thread_idle_lifecycle_after_active_turn_clears8869–8914 ↗
async fn task_finish_emits_thread_idle_lifecycle_after_active_turn_clears()

作用:测试任务结束后,系统先清掉活跃轮次,再触发“线程空闲”生命周期钩子。扩展插件看到线程空闲时,应该拿到正确的线程信息。

数据流:它定义一个 ThreadIdleRecorder,记录 on_thread_idle 被调用次数并发信号。然后把它注册进扩展系统,启动会立即完成的 CompletingTask,等待 idle 信号,最后确认调用一次且 active_turn 已为空。

调用关系:CompletingTask 负责快速结束,扩展注册表负责接收线程生命周期通知。这个测试验证 Session 的收尾顺序和扩展回调时机。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 10 个(clone, new, from_secs, new, assert!, assert_eq!, bounded, new, new, timeout)。

thread_idle_lifecycle_waits_for_trigger_turn_mailbox_work8917–8954 ↗
async fn thread_idle_lifecycle_waits_for_trigger_turn_mailbox_work()

作用:测试如果邮箱里还有会触发下一轮的代理消息,线程不能被认为已经空闲。否则插件可能误以为工作完成了。

数据流:它注册一个会计数的 ThreadIdleRecorder,然后往 input_queue 放入 trigger_turn 为真的 InterAgentCommunication。调用 emit_thread_idle_lifecycle_if_idle 后,确认计数仍是 0。

调用关系:它直接验证 emit_thread_idle_lifecycle_if_idle 会查看 input_queue。只要还有“会触发轮次”的邮箱消息,线程空闲钩子就不能运行。

调用图:调用 3 个内部函数(make_session_and_context, root, new);外部调用 6 个(clone, new, new, assert_eq!, new, new)。

try_start_turn_if_idle_rejects_active_turn_without_injecting8957–8983 ↗
async fn try_start_turn_if_idle_rejects_active_turn_without_injecting()

作用:测试当前已有活跃轮次时,try_start_turn_if_idle 不会偷偷塞入新输入。拒绝时还必须把原输入原样还给调用方。

数据流:它启动一个活跃的 NeverEndingTask,然后尝试用 synthetic idle input 自动开始新轮。函数返回 Busy 错误,错误里带回原输入,同时输入队列保持空。最后中断任务清理现场。

调用关系:这个测试覆盖 try_start_turn_if_idle 在“会话正忙”时的保护逻辑,防止自动输入混进正在运行的轮次。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, user_message);外部调用 4 个(clone, new, assert_eq!, vec!)。

try_start_turn_if_idle_rejects_plan_mode_without_injecting8986–9008 ↗
async fn try_start_turn_if_idle_rejects_plan_mode_without_injecting()

作用:测试计划模式下不会自动开始空闲轮次。计划模式通常需要更谨慎的用户确认,不能后台自启动。

数据流:它把会话协作模式改成 Plan,再调用 try_start_turn_if_idle。结果应是 PlanMode 拒绝,原输入被退回,active_turn 仍为空,输入队列也没有新内容。

调用关系:它验证 try_start_turn_if_idle 会读取 session_configuration.collaboration_mode,并在计划模式下直接拒绝。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, user_message);外部调用 3 个(assert!, assert_eq!, vec!)。

try_start_turn_if_idle_rejects_pending_trigger_turn_without_injecting9011–9036 ↗
async fn try_start_turn_if_idle_rejects_pending_trigger_turn_without_injecting()

作用:测试邮箱里已有触发下一轮的消息时,自动空闲输入不能抢先开新轮。否则代理消息和用户输入的顺序会乱。

数据流:它先往 input_queue 放一个 trigger_turn 邮箱消息。再调用 try_start_turn_if_idle,得到 PendingTriggerTurn 拒绝,原输入被退回,active_turn 仍为空,邮箱触发消息仍保留。

调用关系:它连接 input_queue 的 trigger-turn 状态和 try_start_turn_if_idle 的准入检查。重点是保证排队中的代理工作优先级不被破坏。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, user_message, root, new);外部调用 4 个(new, assert!, assert_eq!, vec!)。

try_start_turn_if_idle_rejects_active_review_turn_without_injecting9039–9065 ↗
async fn try_start_turn_if_idle_rejects_active_review_turn_without_injecting()

作用:测试活跃的是审核轮次时,也不能自动塞入空闲输入。审核轮次虽然不是普通聊天,但同样占用会话。

数据流:它启动一个 TaskKind::Review 的 NeverEndingTask,然后调用 try_start_turn_if_idle。结果是 Busy,输入原样返回,输入队列为空。最后中断任务。

调用关系:它和普通活跃轮次测试类似,但专门覆盖 Review 任务,确保 busy 判断不只看普通任务。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, user_message);外部调用 4 个(clone, new, assert_eq!, vec!)。

steer_input_requires_active_turn9068–9087 ↗
async fn steer_input_requires_active_turn()

作用:测试 steer_input 必须在有活跃轮次时才能追加输入。没有正在进行的对话,就没有地方可以“插话”。

数据流:它创建一个没有活跃任务的会话,尝试追加一段 steer 文本。调用返回 NoActiveTurn 错误,不会写入输入队列。

调用关系:这个测试覆盖 steer_input 的第一道门槛:必须存在 active_turn。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 3 个(default, assert!, vec!)。

steer_input_enforces_expected_turn_id9090–9133 ↗
async fn steer_input_enforces_expected_turn_id()

作用:测试追加输入时如果指定了期望轮次 ID,系统会严格核对。这样客户端不会把输入误加到另一轮对话里。

数据流:它启动一个普通活跃任务,然后用不同的 expected_turn_id 调用 steer_input。结果返回 ExpectedTurnMismatch,并带出 expected 和 actual 两个 ID。

调用关系:它验证 steer_input 对 active_turn.sub_id 的检查。这个保护对多客户端或异步 UI 很重要。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 5 个(clone, default, assert_eq!, panic!, vec!)。

steer_input_rejects_non_regular_turns9136–9179 ↗
async fn steer_input_rejects_non_regular_turns()

作用:测试审核轮次和压缩轮次不能被用户插话。只有普通对话轮次才允许 steer_input。

数据流:它分别启动 Review 和 Compact 两类 NeverEndingTask,然后尝试追加 steer 文本。每次都应返回 ActiveTurnNotSteerable,并说明是哪种不可插话轮次。最后中断任务。

调用关系:它覆盖 steer_input 对 TaskKind 的判断,避免把用户输入混入审核或上下文压缩这些内部流程。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 3 个(default, assert_eq!, vec!)。

steer_input_returns_active_turn_id9182–9218 ↗
async fn steer_input_returns_active_turn_id()

作用:测试成功追加输入后,steer_input 会返回当前活跃轮次的 ID。调用方可以用这个 ID 确认输入确实进了哪一轮。

数据流:它启动普通活跃任务,然后用匹配的 turn_id 调用 steer_input。函数返回 tc.sub_id,并且输入队列显示有 pending input。

调用关系:它验证 steer_input 的成功路径:校验通过、输入入队、把活跃轮次 ID 回传给调用方。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 5 个(clone, default, assert!, assert_eq!, vec!)。

abort_empty_active_turn_preserves_pending_input9221–9253 ↗
async fn abort_empty_active_turn_preserves_pending_input()

作用:测试一个没有真正任务的活跃轮次被中止时,已经挂在这个轮次状态上的待处理输入不会丢。中止清状态,但不应该吞消息。

数据流:它手动创建 ActiveTurn,拿到 turn_state,然后给这个状态塞入一条 pending ResponseItem。调用 abort_all_tasks 后,active_turn 被清空,但再从同一 turn_state 取 pending input 时还能取回原消息。

调用关系:这个测试覆盖 abort_all_tasks 对空 active_turn 的特殊情况,重点是 input_queue 的 pending input 生命周期。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 4 个(clone, assert!, assert_eq!, vec!)。

set_total_token_usage9255–9262 ↗
async fn set_total_token_usage(sess: &Session, total_token_usage: TokenUsage)

作用:这是测试辅助函数,用来给会话写入一个总 token 用量基线。token 可以理解为模型计费和上下文长度使用的基本单位。

数据流:它接收 Session 和 TokenUsage,锁住 session.state,把 TokenUsageInfo 写进去:total_token_usage 用传入值,last_token_usage 用默认值,model_context_window 为空。

调用关系:它被 turn_start_lifecycle_exposes_turn_metadata_and_token_baseline 调用,用于提前布置测试状态。它本身不验证行为,只负责准备数据。

调用图:被 1 处调用(turn_start_lifecycle_exposes_turn_metadata_and_token_baseline);外部调用 1 个(default)。

queue_only_mailbox_mail_waits_for_next_turn_after_answer_boundary9265–9306 ↗
async fn queue_only_mailbox_mail_waits_for_next_turn_after_answer_boundary()

作用:测试当前轮已经越过“回答边界”后,普通邮箱消息不会再插进当前轮,而是等下一轮。这样模型已经开始收尾的回答不会被突然改输入。

数据流:它启动活跃普通任务,调用 defer_mailbox_delivery_to_next_turn 标记当前轮不再接收邮箱消息,然后入队一个 trigger_turn 为 false 的通信。检查当前轮没有 pending input;中止当前任务后,再检查这条通信出现在下一轮可取的输入里。

调用关系:它验证 input_queue 在 answer boundary 之后的缓冲规则。abort_all_tasks 清掉当前轮后,队列才把消息交给下一轮。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, root, try_from, new);外部调用 4 个(clone, new, assert!, assert_eq!)。

trigger_turn_mailbox_mail_waits_for_next_turn_after_answer_boundary9309–9342 ↗
async fn trigger_turn_mailbox_mail_waits_for_next_turn_after_answer_boundary()

作用:测试会触发新轮的邮箱消息在回答边界之后也不能塞回当前轮。它应该保留为下一轮触发源。

数据流:它启动活跃任务,设置邮箱递送延后到下一轮,再入队 trigger_turn 为真的通信。当前轮没有 pending input;中止任务后,队列仍报告有 trigger-turn 邮箱项。

调用关系:它和 queue_only_mailbox_mail_waits_for_next_turn_after_answer_boundary 配对,覆盖 trigger_turn=true 的邮箱消息路径。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, root, try_from, new);外部调用 3 个(clone, new, assert!)。

steered_input_reopens_mailbox_delivery_for_current_turn9345–9396 ↗
async fn steered_input_reopens_mailbox_delivery_for_current_turn()

作用:测试用户在回答边界后又追加输入时,会重新打开当前轮的邮箱递送。因为用户明确继续这一轮,相关代理消息也可以一起送进来。

数据流:它先让当前轮延后邮箱递送,并缓存一条邮箱通信。随后调用 steer_input 追加 follow up。最后读取 pending input,确认先有用户追加输入,再有缓存的代理通信。

调用关系:它连接 steer_input 和 input_queue 的邮箱延后机制。用户插话会把“留到下一轮”的普通邮箱消息重新带回当前轮。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, root, try_from, new);外部调用 5 个(clone, default, new, assert_eq!, vec!)。

stale_defer_mailbox_delivery_does_not_override_steered_input9399–9454 ↗
async fn stale_defer_mailbox_delivery_does_not_override_steered_input()

作用:测试用户追加输入已经重新打开邮箱递送后,过期的延后请求不能再把它关掉。这样旧状态不会覆盖新动作。

数据流:它先延后邮箱、入队通信、再 steer_input 追加用户输入,让通信进入当前轮 pending input。随后再次调用 defer_mailbox_delivery_to_next_turn,最后确认 pending input 没被改坏,仍然包含用户输入和通信。

调用关系:这个测试保护 input_queue 的时序逻辑,防止迟来的 defer 调用覆盖 steer_input 已经做出的决定。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, root, try_from, new);外部调用 5 个(clone, default, new, assert_eq!, vec!)。

tool_calls_reopen_mailbox_delivery_for_current_turn9457–9509 ↗
async fn tool_calls_reopen_mailbox_delivery_for_current_turn()

作用:测试模型发起工具调用后,也会重新打开当前轮的邮箱递送。工具调用意味着当前轮还在继续处理,可以接收之前缓存的代理消息。

数据流:它启动活跃任务,延后邮箱递送并缓存一条通信。然后构造一个 test_tool 的 FunctionCall,交给 handle_output_item_done 处理。处理结果显示需要 follow-up 且有工具 future,同时 pending input 中出现缓存通信。

调用关系:它验证 handle_output_item_done 处理工具调用时会影响 input_queue。这个行为和 steer_input 类似,都会让当前轮重新接收邮箱消息。

调用图:调用 6 个内部函数(make_session_and_context_with_rx, test_tool_runtime, new, root, try_from, new);外部调用 6 个(clone, new, new, new, assert!, assert_eq!)。

abort_review_task_emits_exited_then_aborted_and_records_history9512–9586 ↗
async fn abort_review_task_emits_exited_then_aborted_and_records_history()

作用:测试审核任务被打断时,客户端先收到“退出审核模式”,再收到“轮次中止”,并且模型历史里仍记录中止标记。顺序和历史记录都很关键。

数据流:它启动 ReviewTask,随后 abort_all_tasks。然后在事件流中寻找 ExitedReviewMode 和 TurnAborted,确认前者出现且早于后者。最后检查会话历史里有一条用户消息包含 <turn_aborted> 类型的中止标记。

调用关系:它覆盖 ReviewTask 的取消路径、事件广播顺序和历史写入。ExitedReviewMode 面向客户端 UI,turn aborted marker 面向后续模型上下文。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, new);外部调用 7 个(clone, assert!, assert_eq!, from_secs, now, timeout, vec!)。

fatal_tool_error_stops_turn_and_reports_error9589–9646 ↗
async fn fatal_tool_error_stops_turn_and_reports_error()

作用:测试工具收到不兼容的调用格式时,会返回致命错误,而不是继续当前轮。这样坏的工具调用不会被悄悄吞掉。

数据流:它从会话加载工具列表,建立 ToolRouter,然后构造一个 CustomToolCall 形式的 shell_command,但 payload 不符合要求。dispatch_tool_call_with_code_mode_result 返回 FunctionCallError::Fatal,消息说明 shell_command payload 不兼容。

调用关系:它验证 ToolRouter::build_tool_call 和 dispatch_tool_call_with_code_mode_result 的错误路径。目标是确认工具层能把严重格式错误上报给会话流程。

调用图:调用 4 个内部函数(make_session_and_context_with_rx, build_tool_call, from_turn_context, new);外部调用 8 个(clone, new, new, default, new, assert_eq!, panic!, new)。

sample_rollout9648–9815 ↗
async fn sample_rollout(
    session: &Session,
    _turn_context: &TurnContext,
) -> (Vec<RolloutItem>, Vec<ResponseItem>)

作用:这是测试辅助函数,用来造一份包含初始上下文、用户/助手消息和两次压缩记录的 rollout 样本。它让多个恢复历史相关测试有同一份标准材料。

数据流:它接收 Session 和 TurnContext,创建 rollout_items 和 live_history。先构造初始上下文,必要时补上 personality_spec;再依次加入用户消息、助手回复、压缩摘要、更多消息。每加入一项都同步更新 live_history 和 rollout_items,最后返回 rollout 条目列表和压缩后的实时历史。

调用关系:它被 reconstruct_history_matches_live_compactions、record_initial_history_reconstructs_forked_transcript、record_initial_history_reconstructs_resumed_transcript 等测试复用。它模拟真实会话被压缩和恢复时的历史形态。

调用图:调用 4 个内部函数(into, build_compacted_history, new, new);被 5 处调用(reconstruct_history_matches_live_compactions, record_initial_history_reconstructs_forked_transcript, record_initial_history_reconstructs_resumed_transcript, record_initial_history_seeds_token_info_from_rollout, resumed_history_injects_initial_context_on_first_context_update_only);外部调用 7 个(new, build_initial_context, new_default_turn, Compacted, ResponseItem, once, vec!)。

rejects_escalated_permissions_when_policy_not_on_request9818–9912 ↗
async fn rejects_escalated_permissions_when_policy_not_on_request()

作用:测试旧版 shell_command 在审批策略不是 OnRequest 时,会拒绝请求提升权限。提升权限就是让命令跳出更安全的沙箱限制,必须受策略控制。

数据流:它把 turn_context 的 approval_policy 设为 OnFailure,然后调用 ShellCommandHandler,payload 里要求 RequireEscalated 并给出理由。结果应返回 RespondToModel 错误,告诉模型当前策略下不能请求提升权限;同时确认没有授予权限。随后它改成非提升权限路径,确认同一命令不会因为刚才的拒绝而被污染。

调用关系:它覆盖 ShellCommandHandler、exec_policy 和 granted_turn_permissions 的配合。重点是安全策略:不允许时要早拒绝,且拒绝不影响普通执行判断。

调用图:调用 4 个内部函数(make_session_and_context, from, new, plain);外部调用 10 个(clone, get_mut, new, new, assert!, format!, panic!, assert_eq!, json!, new)。

shell_tool_cancellation_waits_for_runtime_cleanup9916–9982 ↗
async fn shell_tool_cancellation_waits_for_runtime_cleanup() -> anyhow::Result<()>

作用:测试 shell 工具被取消时,会等子进程执行清理逻辑后再结束。否则临时文件、进程或外部资源可能残留。

数据流:它创建允许直接执行命令的会话,生成一个脚本:启动后写 ready,收到 TERM 信号后写 cleanup。测试启动工具调用,等 ready 文件出现后取消令牌,再等待工具任务结束,最后确认 cleanup 文件内容是 cleaned。

调用关系:它通过 test_tool_runtime 运行 shell_command 工具,使用 CancellationToken 模拟用户打断。这个测试保护工具运行时的取消和清理顺序。

调用图:调用 3 个内部函数(make_session_with_config, test_tool_runtime, build_tool_call);外部调用 13 个(clone, new, new, from_millis, from_secs, bail!, assert_eq!, format!, json!, new (+3 more))。

unified_exec_rejects_escalated_permissions_when_policy_not_on_request9985–10030 ↗
async fn unified_exec_rejects_escalated_permissions_when_policy_not_on_request()

作用:测试统一执行工具 exec_command 也遵守同样的提升权限策略。新旧执行入口不能有安全规则差异。

数据流:它把审批策略设为 OnFailure,调用 ExecCommandHandler,payload 要求 RequireEscalated。结果返回 RespondToModel 错误,内容说明当前策略下不能请求提升权限。

调用关系:它对应 rejects_escalated_permissions_when_policy_not_on_request,但覆盖 ExecCommandHandler 这条统一执行路径,确保安全规则一致。

调用图:调用 4 个内部函数(make_session_and_context, default, new, plain);外部调用 8 个(clone, new, new, format!, panic!, assert_eq!, json!, new)。

session_start_hooks_only_load_from_trusted_project_layers10033–10077 ↗
async fn session_start_hooks_only_load_from_trusted_project_layers() -> std::io::Result<()>

作用:测试会话启动钩子只从受信任的项目配置层加载。钩子是启动时会运行的脚本或动作,来源不可信就很危险。

数据流:它创建临时 home、项目根目录和嵌套目录,在根和嵌套 .codex 下都写 hooks。然后只把 nested 标成 Trusted,构建配置并列出 hooks。结果只发现 nested 的 hooks.json,trust_status 是 Untrusted,preview_session_start_hooks 不实际返回可运行钩子。

调用关系:它连接 ConfigBuilder、项目信任配置、codex_hooks::list_hooks 和 preview_session_start_hooks。重点是验证配置层筛选和信任状态不会让上层不可信钩子混进来。

调用图:调用 3 个内部函数(write_project_hooks, write_project_trust_config, from_absolute_path);外部调用 8 个(assert!, assert_eq!, list_hooks, default, default, create_dir_all, write, tempdir)。

session_start_hooks_require_project_trust_without_config_toml10080–10134 ↗
async fn session_start_hooks_require_project_trust_without_config_toml() -> std::io::Result<()>

作用:测试即使项目没有 config.toml,启动钩子也必须依赖项目信任状态。未知或不信任项目不能加载钩子,信任项目才会发现钩子。

数据流:它创建一个带 .git 和 .codex/hooks.json 的项目,但不写 config.toml。然后分别用 unknown、untrusted、trusted 三种信任配置构建会话配置,列出 hooks。前两种期望 0 个,trusted 期望 1 个,并确认预览启动钩子仍为空。

调用关系:它验证项目信任配置和 codex_hooks::list_hooks 的关系,特别覆盖没有 config.toml 的项目。这个测试防止只因为目录里有 hooks.json 就加载启动钩子。

调用图:调用 2 个内部函数(write_project_hooks, write_project_trust_config);外部调用 11 个(new, assert!, assert_eq!, list_hooks, default, format!, default, create_dir_all, write, tempdir (+1 more))。

core/src/session/tests/guardian_tests.rs源码 ↗
testtest

这里测试的是一个安全闸门:当系统或模型想临时放宽权限,比如允许联网或执行命令时,Guardian 会像“值班审核员”一样先看一眼,再决定放行还是拒绝。文件用假的模型服务器模拟 Guardian 的回答,避免真的连外部服务。测试会搭好会话、打开不同功能开关、伪造权限申请,然后确认请求有没有发给 Guardian、放行后权限有没有记录下来、取消时会不会立刻停住。它还检查一些容易漏掉的细节:严格自动审核授权后,命令仍然要经过 Guardian;对话历史被压缩后,Guardian 的开发者提示不能被旧消息覆盖;Guardian 作为子代理运行时,不能继承父会话里禁止命令的执行策略。整体上,这个文件不是产品功能本身,而是给安全权限系统装的一套报警器。

函数细节9
expect_text_output51–68 ↗
fn expect_text_output(output: &T) -> String

作用:这个小工具函数把一次工具调用的结果转成普通文字,方便测试直接检查里面有没有想要的内容。没有它,每个测试都要重复写一堆拆包装的代码。

数据流:输入是一份工具输出对象。它先把输出转换成协议里的“函数调用输出”格式,再从输出正文里取出文本;如果拿到的不是函数输出,它就直接让测试失败。结果是一段字符串,供后面的断言检查。

调用关系:它服务于多个命令执行相关测试。那些测试先调用 shell 命令处理器,拿到结果后交给 expect_text_output,再检查结果里是否包含例如“hi”这样的命令输出。

调用图:被 3 处调用(guardian_allows_shell_command_additional_permissions_requests_past_policy_validation, shell_command_allows_sticky_turn_permissions_without_inline_request_permissions_feature, strict_auto_review_turn_grant_forces_guardian_for_shell_command_policy_skip);外部调用 2 个(to_response_item, panic!)。

request_permissions_routes_to_guardian_when_reviewer_is_enabled71–167 ↗
async fn request_permissions_routes_to_guardian_when_reviewer_is_enabled()

作用:这个测试确认:当开启 Guardian 自动审核时,权限申请不会直接等用户批准,而是会发给 Guardian 审核。它验证的是权限申请路线有没有走对。

数据流:测试先启动一个假的服务器,让它假装 Guardian 返回“允许”。接着创建会话和回合上下文,打开“按请求审批”和 Guardian 功能,并申请本回合联网权限。最后它检查返回结果是允许、权限被记录到当前回合里,并且假的服务器确实收到包含 request_permissions 和申请理由的请求。

调用关系:它模拟真实的权限申请流程,核心调用会落到 session.request_permissions_for_environment。假的模型服务器通过 mount_sse_once 提供 Guardian 的流式回答,测试最后用请求日志确认系统真的把活交给了 Guardian。

调用图:调用 5 个内部函数(default, models_manager_with_provider, mount_sse_once, sse, start_mock_server);外部调用 11 个(clone, new, new, from_secs, default, assert!, assert_eq!, create_model_provider, format!, timeout (+1 more))。

request_permissions_guardian_review_stops_when_cancelled170–270 ↗
async fn request_permissions_guardian_review_stops_when_cancelled()

作用:这个测试确认:Guardian 审核如果还没完成,外部取消信号一来,权限申请会及时停止。它防止系统在用户取消后还傻等审核结果,或者错误地授予权限。

数据流:测试搭了一个会故意延迟 60 秒才回复的假 Guardian。然后发起联网权限申请,并等待系统发出“Guardian 已开始评估”的事件。随后触发取消令牌,检查任务很快结束、返回 None,并且没有把任何权限写进当前回合。

调用关系:它把权限申请放进 tokio 异步任务里跑,另一边监听事件频道,确认 Guardian 流程已启动后再取消。这个测试重点覆盖 request_permissions_for_environment 和取消令牌之间的配合。

调用图:调用 6 个内部函数(default, models_manager_with_provider, mount_response_once, sse, sse_response, start_mock_server);外部调用 13 个(clone, get_mut, new, new, from_secs, default, assert_eq!, create_model_provider, format!, matches! (+3 more))。

guardian_allows_shell_command_additional_permissions_requests_past_policy_validation273–363 ↗
async fn guardian_allows_shell_command_additional_permissions_requests_past_policy_validation()

作用:这个测试确认:传统 shell 命令如果声明需要额外权限,并且 Guardian 同意,就可以通过前置校验并真正执行。它防止权限申请已经被审核通过,却仍被本地校验误拦。

数据流:测试准备一个会返回“允许”的假 Guardian,打开 Guardian 审核和执行权限申请功能,然后构造一个 echo hi 命令,附带“需要额外联网权限”的申请。命令处理器执行后,测试把输出转成文本,并确认里面有 hi。

调用关系:它使用 ShellCommandHandler 走真实的 shell 工具处理路径,过程中会间接触发权限审核。最后通过 expect_text_output 读取命令输出,证明 Guardian 放行后命令确实跑起来了。

调用图:调用 8 个内部函数(expect_text_output, models_manager_with_provider, from, new, mount_sse_once, sse, start_mock_server, plain);外部调用 11 个(clone, new, new, assert!, cfg!, codex_linux_sandbox_exe_or_skip!, create_model_provider, format!, json!, new (+1 more))。

strict_auto_review_turn_grant_forces_guardian_for_shell_command_policy_skip366–461 ↗
async fn strict_auto_review_turn_grant_forces_guardian_for_shell_command_policy_skip()

作用:这个测试确认:如果某个回合拿到的是“严格自动审核”的临时权限,即使命令看起来可以跳过普通策略检查,也仍然要经过 Guardian。它防止严格模式被错误当成永久免审通行证。

数据流:测试先手动给当前回合记录一份严格自动审核的联网权限,再设置 shell 命令 echo hi。执行命令后,它确认命令输出正常,同时检查假 Guardian 收到的请求里包含 echo hi,说明这次命令确实被重新审核过。

调用关系:它把已授权权限写入 active turn 的状态,再通过 ShellCommandHandler 执行命令。expect_text_output 用来检查输出,假的服务器请求日志用来确认 Guardian 没有被绕过。

调用图:调用 9 个内部函数(expect_text_output, default, models_manager_with_provider, from, new, mount_sse_once, sse, start_mock_server, plain);外部调用 10 个(clone, new, new, default, assert!, create_model_provider, format!, json!, new, vec!)。

guardian_allows_unified_exec_additional_permissions_requests_past_policy_validation464–511 ↗
async fn guardian_allows_unified_exec_additional_permissions_requests_past_policy_validation()

作用:这个测试检查新版统一执行工具的参数校验:如果声明要额外权限,却没说清楚具体要网络还是文件权限,系统应该拒绝。名字里说 Guardian 放行,但实际断言的是缺少 additional_permissions 时必须报错。

数据流:测试创建会话,打开 Guardian 审核和执行权限申请功能,然后调用 exec_command,参数里写了 with_additional_permissions,但没有提供 additional_permissions。结果应该不是成功执行,而是返回给模型的一段明确错误文字。

调用关系:它走 ExecCommandHandler 的处理路径,重点不在假 Guardian,而在工具参数进入执行前的验证。测试用 assert_eq 检查错误提示完全符合预期,防止以后错误信息或校验规则被无意改坏。

调用图:调用 3 个内部函数(default, new, plain);外部调用 7 个(clone, new, new, assert_eq!, panic!, json!, new)。

process_compacted_history_preserves_separate_guardian_developer_message514–571 ↗
async fn process_compacted_history_preserves_separate_guardian_developer_message()

作用:这个测试确认:压缩对话历史时,Guardian 专用的开发者提示会被保留下来,而且不会和旧的开发者消息混在一起。它防止 Guardian 在长对话压缩后丢掉自己的安全规则。

数据流:测试把会话来源设成 Guardian 子代理,并把 Guardian 的策略提示放进当前上下文。然后传入一段压缩后的历史,里面故意包含一条过期的 developer 消息。处理完成后,它收集所有 developer 消息,确认旧消息被移除,并且最后一条是新的 Guardian 策略。

调用关系:它直接调用 compact_remote::process_compacted_history,这是对话历史压缩后的整理步骤。guardian_policy_prompt 提供 Guardian 应该使用的提示词,测试确保这个提示在压缩流程里仍然单独存在。

调用图:调用 1 个内部函数(process_compacted_history);外部调用 6 个(SubAgent, assert!, assert_eq!, guardian_policy_prompt, Other, vec!)。

shell_command_allows_sticky_turn_permissions_without_inline_request_permissions_feature579–643 ↗
async fn shell_command_allows_sticky_turn_permissions_without_inline_request_permissions_feature()

作用:这个测试确认:即使没有开启“命令里直接申请额外权限”的功能,只要当前回合已经有粘住的临时权限,shell 命令也不应该因为缺少内联申请而被误拒。这里的“粘住”就是本回合内已经批准过、后续还能继续用的权限。

数据流:测试先开启请求权限工具,并手动往当前回合状态里写入联网权限。之后执行 echo hi 命令,不在命令参数里再写 additional_permissions。如果成功,它检查输出包含 hi;如果返回给模型一个错误,也确认错误不是“额外权限被禁用”。

调用关系:它直接改 active turn 的内部状态来模拟之前已经授权过的情况,然后走 ShellCommandHandler。expect_text_output 只在命令成功时用来读取输出;如果失败,测试重点确认失败原因不是权限校验误伤。

调用图:调用 5 个内部函数(expect_text_output, default, from, new, plain);外部调用 8 个(clone, new, new, default, assert!, panic!, json!, new)。

guardian_subagent_does_not_inherit_parent_exec_policy_rules646–759 ↗
async fn guardian_subagent_does_not_inherit_parent_exec_policy_rules()

作用:这个测试确认:Guardian 作为子代理启动时,不会继承父会话的命令执行策略规则。这样 Guardian 审核别人的请求时,不会被父会话项目里的本地规则误限制。

数据流:测试先创建临时项目,并写入一条规则:禁止 rm 命令。它验证父执行策略确实会禁止 rm。然后用这份策略作为“继承策略”启动一个 Guardian 子代理。最后检查子代理自己的执行策略对 rm 的判断是允许,而不是继承父规则的禁止。

调用关系:它先用 ExecPolicyManager::load 读取父项目规则,再通过 Codex::spawn 启动一个 session_source 为 Guardian 的子代理。测试的核心关系是:父会话有禁令,但 Guardian 子代理启动时必须把这类父策略隔离开。

调用图:调用 13 个内部函数(new, new, new, load, new, spawn, models_manager_with_provider, default_for_tests, from_auth_for_testing, from_api_key (+3 more));外部调用 16 个(clone, new, default, new, default, SubAgent, assert_eq!, empty_extension_registry, default, default (+6 more))。

core/src/session/turn_tests.rs源码 ↗
testtest execution

这个测试文件关注一个很具体的场景:系统在计划模式里收到助手输出后,会把它整理成一次对话回合里的“助手消息”。这里故意做了一个假的扩展插件,像一个临时编辑一样,把助手原本说的“original assistant text”改成“plan contributed assistant text”。测试会先搭好一个会话,把这个插件注册进去,再模拟收到一条助手输出,最后检查系统保存的最后一条助手消息是不是已经被插件改过。这样可以确认扩展机制真的插进了计划模式的处理流程,而不是只在表面上注册了却没有生效。简单类比:助手写了一张便条,插件像审稿人一样改了便条内容,测试确认最后贴到墙上的确实是改后的版本。

函数细节3
RewriteAgentMessageContributor::contribute11–25 ↗
fn contribute(
        &'a self,
        _thread_store: &'a ExtensionData,
        _turn_store: &'a ExtensionData,
        item: &'a mut TurnItem,
    ) -> codex_extension_api::ExtensionFuture<'a, Res

作用:这是测试里做出来的一个假插件方法,用来证明插件确实能改写助手消息。它看到当前回合项是助手消息时,就把消息内容替换成固定的一句话。

数据流:进去的是扩展数据、当前回合数据,以及一个可修改的回合项;它不使用前两个数据,只检查这个回合项是不是助手消息;如果是,就把里面的文字列表改成只包含“plan contributed assistant text”,最后返回成功,表示插件处理完了。

调用关系:它由测试注册到扩展系统里,真正调用它的是计划模式处理助手输出的流程。测试函数 plan_mode_uses_contributed_turn_item_for_last_agent_message 依靠它来制造一个明显的改写效果,然后验证主流程有没有采用这个改写结果。

调用图:外部调用 2 个(pin, vec!)。

assistant_output_text28–38 ↗
fn assistant_output_text(text: &str) -> ResponseItem

作用:这是一个测试小工具,用来快速造出一条“助手输出文字”的模拟数据。有人写测试时不用手动拼一大段结构,只要给一句文字就能得到一条像真实助手回复一样的数据。

数据流:进去的是一段普通字符串;它把这段字符串放进一个 ResponseItem::Message 结构里,设置好消息编号、角色是 assistant、内容是输出文字;出来的是一条可交给会话处理流程的模拟助手消息。

调用关系:它被 plan_mode_uses_contributed_turn_item_for_last_agent_message 调用,用来准备测试输入。它本身不参与业务判断,只负责把“原始助手文本”包装成系统能识别的消息格式。

调用图:被 1 处调用(plan_mode_uses_contributed_turn_item_for_last_agent_message);外部调用 1 个(vec!)。

plan_mode_uses_contributed_turn_item_for_last_agent_message41–67 ↗
async fn plan_mode_uses_contributed_turn_item_for_last_agent_message()

作用:这是核心测试,验证计划模式在记录最后一条助手消息时,会使用扩展插件改写后的内容,而不是原始内容。它保证扩展系统和计划模式的消息处理流程是接通的。

数据流:开始时它创建一个测试会话和回合上下文;然后注册 RewriteAgentMessageContributor 这个假插件;再准备扩展数据、计划模式状态、空的“最后助手消息”变量,以及一条原始助手输出。接着它把这些交给计划模式的助手消息完成处理函数。处理结束后,它检查结果确实被处理了,并且最后助手消息从原文变成了插件写入的“plan contributed assistant text”。

调用关系:它是这个文件的测试入口。它先调用 make_session_and_context 搭测试环境,调用 assistant_output_text 准备输入,再让 handle_assistant_item_done_in_plan_mode 跑完整流程。流程中会触发已注册的 RewriteAgentMessageContributor::contribute,最后这个测试用断言确认整条链路按预期工作。

调用图:调用 5 个内部函数(make_session_and_context, new, assistant_output_text, new, new);外部调用 3 个(new, assert!, assert_eq!)。

core/src/session/rollout_reconstruction_tests.rs源码 ↗
testtest

系统会把一次聊天过程记成一串“流水账”,这里叫 rollout。重开会话时,程序要根据这串记录还原出:哪些消息还算有效、上一轮用了什么模型、哪个 TurnContextItem(一次对话轮次的环境说明,比如模型、目录、权限等)可以当作参考。这个文件就像给“恢复存档”功能做压力测试:它造出各种容易出错的记录,比如只写了一半的轮次、回滚了几轮、历史被压缩、跨代理消息、异常中止的轮次,然后检查还原结果是否符合预期。它的重要性在于,恢复历史一旦错了,模型可能会看到不该看的旧消息,或者丢掉该保留的设置,导致续聊行为前后不一致。

函数细节23
user_message15–25 ↗
fn user_message(text: &str) -> ResponseItem

作用:这个小工具用一段文字快速做出一条“用户说的话”。测试里反复需要造用户消息,用它可以少写很多重复结构。

数据流:输入一段普通文本 → 把它包进 ResponseItem::Message,并标成 role 为 user、内容类型为输入文本 → 返回一条可放进历史记录里的用户消息,不改动外部状态。

调用关系:它是测试数据的零件工厂。多个回滚重建测试会调用它来摆出“用户发了一句话”的场景,然后把结果交给会话重建逻辑,最后用断言检查这条消息该不该留下。

调用图:被 3 处调用(reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_completed_turns, reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_incomplete_turn, reconstruct_history_rollback_skips_non_user_turns_for_history_and_metadata);外部调用 1 个(vec!)。

assistant_message27–37 ↗
fn assistant_message(text: &str) -> ResponseItem

作用:这个小工具用一段文字快速做出一条“助手回复”。测试里用它来模拟模型已经回答过的内容。

数据流:输入一段回复文字 → 把它包进 ResponseItem::Message,并标成 role 为 assistant、内容类型为输出文本 → 返回一条助手消息,不改动外部状态。

调用关系:它和 user_message 配套使用,帮测试拼出一轮完整对话。回滚、跳过非用户轮次、跨代理轮次等测试会用它来制造预期历史,再和重建结果比较。

调用图:被 4 处调用(reconstruct_history_rollback_counts_inter_agent_assistant_turns, reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_completed_turns, reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_incomplete_turn, reconstruct_history_rollback_skips_non_user_turns_for_history_and_metadata);外部调用 1 个(vec!)。

inter_agent_assistant_message39–56 ↗
fn inter_agent_assistant_message(text: &str) -> ResponseItem

作用:这个小工具制造一条特殊的助手消息,内容其实是“代理之间通信”的 JSON 字符串。它用来测试多代理场景下,系统能不能把这种隐藏在文本里的指令当成特殊轮次处理。

数据流:输入一段通信文字 → 创建一个从根代理发给 worker 子代理的 InterAgentCommunication(代理间通信对象)→ 把它转成 JSON,再塞进助手输出消息里 → 返回这条特殊助手消息。

调用关系:只有跨代理回滚测试会调用它。它先造出一条看起来像助手消息、实际表示代理指令的记录,再交给历史重建逻辑,确认回滚计数会把这种助手触发的轮次也算进去。

调用图:调用 2 个内部函数(root, new);被 1 处调用(reconstruct_history_rollback_counts_inter_agent_assistant_turns);外部调用 2 个(new, vec!)。

record_initial_history_reconstructs_typed_inter_agent_message59–81 ↗
async fn record_initial_history_reconstructs_typed_inter_agent_message()

作用:这个测试确认:恢复旧会话时,如果历史里已经有结构化的代理间通信消息,系统会把它正确转换成模型输入历史。简单说,就是多代理消息不会在恢复时变形。

数据流:先创建测试会话和一个 InterAgentCommunication → 把它作为恢复历史传给 session.record_initial_history → 再读取会话内部历史 → 期望里面正好是这条通信消息转换后的模型输入项。

调用关系:它直接测试 record_initial_history 的恢复入口。测试先用 make_session_and_context 搭好假会话,再把构造好的恢复历史交给会话,最后用 assert_eq 检查会话状态。

调用图:调用 4 个内部函数(make_session_and_context, root, new, default);外部调用 5 个(from, new, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_bare_turn_context_does_not_hydrate_previous_turn_settings84–121 ↗
async fn record_initial_history_resumed_bare_turn_context_does_not_hydrate_previous_turn_settings()

作用:这个测试确认:如果恢复记录里只有孤零零的 TurnContextItem,系统不会误以为它代表上一轮有效对话。这样可以避免把无上下文的旧设置错误套到新会话上。

数据流:先造一个带旧模型名的 TurnContextItem → 只把这一项作为恢复历史写入会话 → 查询 previous_turn_settings 和 reference_context_item → 期望二者都是空。

调用关系:它验证 record_initial_history 对“裸上下文记录”的防误判。make_session_and_context 提供基础会话,record_initial_history 负责读取历史,断言负责确认没有错误填充上一轮设置。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_hydrates_previous_turn_settings_from_lifecycle_turn_with_missing_turn_context_id124–203 ↗
async fn record_initial_history_resumed_hydrates_previous_turn_settings_from_lifecycle_turn_with_missing_turn_context_id()

作用:这个测试确认:即使 TurnContextItem 自己缺少 turn_id,只要它夹在明确的轮次开始和结束事件之间,系统仍能把它识别为上一轮设置来源。

数据流:先造一个旧 TurnContextItem,并故意清掉它自己的 turn_id → 用 TurnStarted、UserMessage、TurnContext、TurnComplete 组成完整轮次 → 恢复到会话 → 期望 previous_turn_settings 里有旧模型、压缩哈希和实时状态。

调用关系:它测试恢复逻辑能根据外层生命周期事件补足上下文含义。record_initial_history 读入这串事件后,应该把 TurnContextItem 和正在进行的轮次关联起来。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert_eq!, Resumed, vec!)。

reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_completed_turns206–315 ↗
async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_completed_turns()

作用:这个测试确认:回滚已完成的轮次时,聊天历史和“上一轮设置”会一起退回到同一个位置。不会出现消息退回了,但模型设置还停在被回滚轮次上的错位情况。

数据流:构造两轮完整对话,第二轮随后被 ThreadRolledBack 回滚 → 调用 reconstruct_history_from_rollout → 得到重建结果 → 期望只保留第一轮消息,并且 previous_turn_settings 和 reference_context_item 也指向第一轮。

调用关系:它直接测试 reconstruct_history_from_rollout。user_message 和 assistant_message 用来造消息,测试会话调用重建函数,assert_eq 检查历史和元数据是否同步。

调用图:调用 3 个内部函数(assistant_message, user_message, make_session_and_context);外部调用 2 个(assert_eq!, vec!)。

reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_incomplete_turn318–409 ↗
async fn reconstruct_history_rollback_keeps_history_and_metadata_in_sync_for_incomplete_turn()

作用:这个测试确认:如果第二轮还没完成就被回滚,系统也会把它从历史和元数据里一起拿掉。这样未完成的半截对话不会污染恢复结果。

数据流:构造第一轮完整对话,再构造第二轮只开始、有用户消息、但没完成 → 加入回滚一轮事件 → 调用重建 → 期望只剩第一轮用户和助手消息,上一轮设置也来自第一轮。

调用关系:它覆盖“未完成轮次回滚”的分支。辅助函数造出消息,reconstruct_history_from_rollout 做真正重建,断言检查结果没有留下第二轮痕迹。

调用图:调用 3 个内部函数(assistant_message, user_message, make_session_and_context);外部调用 2 个(assert_eq!, vec!)。

reconstruct_history_rollback_skips_non_user_turns_for_history_and_metadata412–535 ↗
async fn reconstruct_history_rollback_skips_non_user_turns_for_history_and_metadata()

作用:这个测试确认:回滚按“用户发起的轮次”来算,不应该被没有用户消息的后台轮次消耗掉。这样用户点回滚一轮时,回滚的是用户真正看到的一轮对话。

数据流:构造第一轮用户对话、第二轮用户对话、再加一个没有 UserMessage 的独立助手轮次 → 发出回滚一轮事件 → 调用重建 → 期望第二轮用户对话被回滚,只保留第一轮,元数据也回到第一轮。

调用关系:它测试回滚计数规则。standalone 的非用户轮次被放在最后,用来确认 reconstruct_history_from_rollout 不会把它当成用户轮次来扣数。

调用图:调用 3 个内部函数(assistant_message, user_message, make_session_and_context);外部调用 2 个(assert_eq!, vec!)。

reconstruct_history_rollback_counts_inter_agent_assistant_turns538–636 ↗
async fn reconstruct_history_rollback_counts_inter_agent_assistant_turns()

作用:这个测试确认:由代理间助手指令触发的轮次,在回滚时也要算作可回滚的一轮。多代理系统里,这类轮次虽然不是普通用户输入,但仍会推进对话状态。

数据流:先构造一轮普通用户对话 → 再构造一轮包含 inter_agent_assistant_message 的助手指令轮次和 worker 回复 → 加入回滚一轮 → 调用重建 → 期望只剩普通用户对话,代理指令轮次被移除。

调用关系:它把 inter_agent_assistant_message 造出的特殊消息交给 reconstruct_history_from_rollout。测试重点是确认回滚逻辑能识别这种“助手发起但有轮次意义”的记录。

调用图:调用 3 个内部函数(assistant_message, inter_agent_assistant_message, make_session_and_context);外部调用 2 个(assert_eq!, vec!)。

reconstruct_history_rollback_clears_history_and_metadata_when_exceeding_user_turns639–690 ↗
async fn reconstruct_history_rollback_clears_history_and_metadata_when_exceeding_user_turns()

作用:这个测试确认:如果要求回滚的轮次数超过实际存在的用户轮次,系统会清空历史和相关元数据。也就是“退过头了”时,不留下半吊子的参考信息。

数据流:构造唯一一轮用户对话 → 加入 ThreadRolledBack,要求回滚 99 轮 → 调用重建 → 返回的 history 为空,previous_turn_settings 为空,reference_context_item 也为空。

调用关系:它测试 reconstruct_history_from_rollout 的边界情况。没有调用消息辅助函数,而是直接造 rollout 项,最后用断言确认所有恢复基准都被清掉。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert!, assert_eq!, vec!)。

record_initial_history_resumed_rollback_skips_only_user_turns693–765 ↗
async fn record_initial_history_resumed_rollback_skips_only_user_turns()

作用:这个测试确认:恢复旧会话时,回滚事件只跳过用户轮次,不会因为中间有一个没有用户消息的后台轮次而少回滚。这样恢复后的设置不会被后台任务误导。

数据流:构造一个用户轮次和一个没有 UserMessage 的独立任务轮次 → 加入回滚一轮事件 → 交给 record_initial_history → 查询会话的 previous_turn_settings 和 reference_context_item → 期望都为空,因为唯一用户轮次被回滚了。

调用关系:它测试 record_initial_history 内部调用的重建规则。make_session_and_context 建会话,Resumed 包装旧历史,record_initial_history 负责恢复并更新会话状态。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_rollback_drops_incomplete_user_turn_compaction_metadata768–858 ↗
async fn record_initial_history_resumed_rollback_drops_incomplete_user_turn_compaction_metadata()

作用:这个测试确认:被回滚的未完成用户轮次如果发生过历史压缩,压缩留下的元数据不能影响最终参考上下文。否则系统可能拿被撤销的轮次当新基准。

数据流:先构造一轮已完成的有效对话上下文 → 再构造一轮未完成用户轮次,其中包含 Compacted 压缩记录 → 加入回滚一轮 → 恢复历史 → 期望上一轮设置和参考上下文仍来自第一轮。

调用关系:它走 record_initial_history 的恢复路径,重点盯住压缩记录和回滚记录一起出现时的处理。断言检查会话最终保存的设置没有被未完成轮次覆盖。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_bare_turn_context_does_not_seed_reference_context_item861–875 ↗
async fn record_initial_history_resumed_bare_turn_context_does_not_seed_reference_context_item()

作用:这个测试确认:只有一个孤立的 TurnContextItem 时,不能把它当作 reference_context_item。参考上下文必须来自能证明它属于某个有效轮次的记录。

数据流:把当前 turn_context 转成 TurnContextItem → 单独作为恢复历史传给 record_initial_history → 查询 reference_context_item → 期望为空。

调用关系:它和裸 TurnContext 不填充上一轮设置的测试相呼应,只专门检查 reference_context_item。record_initial_history 是被测入口。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert!, Resumed, vec!)。

record_initial_history_resumed_does_not_seed_reference_context_item_after_compaction878–900 ↗
async fn record_initial_history_resumed_does_not_seed_reference_context_item_after_compaction()

作用:这个测试确认:如果裸 TurnContextItem 后面紧跟历史压缩,系统不会拿压缩前的上下文当参考。压缩相当于重写了聊天记忆,旧基准不能随便沿用。

数据流:构造一个 TurnContextItem,再加一个带 replacement_history 的 Compacted 项 → 恢复到会话 → 查询 previous_turn_settings 和 reference_context_item → 期望都为空。

调用关系:它测试 record_initial_history 对压缩事件的清理效果。Compacted 记录是关键输入,用来确认恢复逻辑不会越过压缩继续信任旧上下文。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

reconstruct_history_legacy_compaction_without_replacement_history_does_not_inject_current_initial_context903–928 ↗
async fn reconstruct_history_legacy_compaction_without_replacement_history_does_not_inject_current_initial_context()

作用:这个测试确认:旧格式的压缩记录没有 replacement_history 时,系统不会偷偷把当前会话的初始上下文塞进历史。它只应该把旧摘要当成一条用户消息保留下来。

数据流:构造压缩前的用户消息和助手回复,再加一个没有 replacement_history 的 legacy Compacted 摘要 → 调用重建 → 期望历史里是原用户消息和摘要用户消息,reference_context_item 为空。

调用关系:它直接测试 reconstruct_history_from_rollout 对旧压缩格式的兼容。这里不用 record_initial_history,避免会话状态干扰,专看重建结果。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert!, assert_eq!, vec!)。

reconstruct_history_legacy_compaction_without_replacement_history_clears_later_reference_context_item931–982 ↗
async fn reconstruct_history_legacy_compaction_without_replacement_history_clears_later_reference_context_item()

作用:这个测试确认:遇到旧格式压缩后,即使后面又出现了 TurnContextItem,也不能建立参考上下文。旧压缩缺少替换历史,说明上下文边界不可靠。

数据流:先放一条用户消息和旧格式 Compacted → 后面再放一轮带 TurnContextItem 的用户轮次 → 调用重建 → 期望 reference_context_item 仍然为空。

调用关系:它测试 reconstruct_history_from_rollout 的保守策略。后面的 TurnContextItem 看似可用,但因为前面有 legacy 压缩,重建逻辑必须避免建立错误基准。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 2 个(assert!, vec!)。

record_initial_history_resumed_turn_context_after_compaction_reestablishes_reference_context_item985–1094 ↗
async fn record_initial_history_resumed_turn_context_after_compaction_reestablishes_reference_context_item()

作用:这个测试确认:带 replacement_history 的现代压缩会先清掉旧基准,但如果同一有效轮次后面又出现 TurnContextItem,它可以重新建立参考上下文。

数据流:构造一个用户轮次:开始、用户消息、现代 Compacted、随后 TurnContextItem、完成 → 恢复到会话 → 期望 previous_turn_settings 和 reference_context_item 都来自压缩后的 TurnContextItem。

调用关系:它测试 record_initial_history 对“压缩后重新建立基准”的处理。Compacted 先让旧参考失效,后面的 TurnContextItem 再成为新的可靠来源。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_aborted_turn_without_id_clears_active_turn_for_compaction_accounting1097–1209 ↗
async fn record_initial_history_resumed_aborted_turn_without_id_clears_active_turn_for_compaction_accounting()

作用:这个测试确认:一个正在进行的轮次如果收到没有 turn_id 的中止事件,系统应把当前活跃轮次清掉。这样后续压缩不会被错误归到这个已经中止的轮次上。

数据流:先构造一轮已完成的有效上下文 → 再构造一轮开始、有用户消息、随后 TurnAborted 但没有 turn_id → 后面放一个 Compacted → 恢复历史 → 期望上一轮设置仍来自已完成轮次,但 reference_context_item 被清空。

调用关系:它测试 record_initial_history 处理异常中止和压缩统计的配合。TurnAborted 没有 id 是关键情况,恢复逻辑必须把活跃轮次状态安全关闭。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_unmatched_abort_preserves_active_turn_for_later_turn_context1212–1336 ↗
async fn record_initial_history_resumed_unmatched_abort_preserves_active_turn_for_later_turn_context()

作用:这个测试确认:如果中止事件带的 turn_id 和当前活跃轮次对不上,不能误把当前轮次关掉。后面出现的 TurnContextItem 仍应归到当前轮次。

数据流:先构造一轮旧的已完成上下文 → 再开始一个 current-turn 用户轮次 → 插入一个指向 other-turn 的 TurnAborted → 随后放 current-turn 的 TurnContextItem 和完成事件 → 恢复历史 → 期望上一轮设置和参考上下文来自 current-turn。

调用关系:它测试 record_initial_history 对中止事件的匹配规则。只有匹配当前 turn_id 的中止才应影响活跃轮次;不匹配的中止应被忽略。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_trailing_incomplete_turn_compaction_clears_reference_context_item1339–1443 ↗
async fn record_initial_history_resumed_trailing_incomplete_turn_compaction_clears_reference_context_item()

作用:这个测试确认:如果日志末尾有一轮未完成用户轮次,并且它发生了压缩,参考上下文要被清空。因为最后状态已经被压缩改写,但没有完整轮次来重新确认基准。

数据流:先构造一轮已完成的有效上下文 → 再构造末尾未完成轮次:开始、用户消息、Compacted → 恢复历史 → 期望 previous_turn_settings 保留前一轮设置,但 reference_context_item 为空。

调用关系:它测试 record_initial_history 面对“日志到这里断了”的情况。压缩发生在未完成轮次里,所以恢复逻辑不能继续信任前一轮参考上下文。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_trailing_incomplete_turn_preserves_turn_context_item1446–1499 ↗
async fn record_initial_history_resumed_trailing_incomplete_turn_preserves_turn_context_item()

作用:这个测试确认:日志末尾的未完成轮次如果已经写下 TurnContextItem,系统仍可以用它作为上一轮设置和参考上下文。未完成不一定无效,关键是有没有可靠上下文记录。

数据流:构造一个开始了、有用户消息、有 TurnContextItem、但没有完成事件的轮次 → 恢复到会话 → 期望 previous_turn_settings 和 reference_context_item 都来自这个 TurnContextItem。

调用关系:它测试 record_initial_history 对尾部未完成轮次的宽容处理。和带压缩的尾部未完成测试相反,这里没有压缩破坏基准,所以 TurnContextItem 可以保留。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 4 个(from, assert_eq!, Resumed, vec!)。

record_initial_history_resumed_replaced_incomplete_compacted_turn_clears_reference_context_item1502–1618 ↗
async fn record_initial_history_resumed_replaced_incomplete_compacted_turn_clears_reference_context_item()

作用:这个测试确认:一个未完成且发生过压缩的轮次,如果后来被新的 TurnStarted 顶替,旧轮次不能继续提供参考上下文。这样可以避免把已经被新轮次替换的半截状态当成有效基准。

数据流:先构造一轮已完成的有效上下文 → 再构造一个未完成用户轮次并加入 Compacted → 随后出现新的 TurnStarted,表示旧未完成轮次被替换 → 恢复历史 → 期望 previous_turn_settings 仍是旧已完成轮次,但 reference_context_item 为空。

调用关系:它测试 record_initial_history 对连续 TurnStarted 的处理。新的轮次开始会让前一个未完成压缩轮次失去资格,恢复逻辑必须清掉参考上下文。

调用图:调用 2 个内部函数(make_session_and_context, default);外部调用 5 个(from, assert!, assert_eq!, Resumed, vec!)。

core/src/session/mcp_tests.rs源码 ↗
testtest

这个文件不负责正式运行功能,而是像验货清单一样,专门检查 MCP 审批相关代码是否按约定工作。MCP 可以理解成一种让外部工具和系统对话的协议;Guardian 是这里用来做安全审批的守门员。测试先造出一些假的“请求用户确认”的消息,比如浏览器插件想访问某个网站来源,然后检查系统能不能把它变成 Guardian 看得懂的工具调用审批请求。它还检查缺省参数、缺少关键标记、请求形状不支持时会怎样处理,避免把不完整或危险的请求放过去。最后,它验证 Guardian 的批准、拒绝、超时、取消这些决定,会被转换成 MCP 要的接受、拒绝或取消响应。简单说,这个文件是在守住“工具调用必须正确走审批”这条安全边界。

函数细节9
meta7–12 ↗
fn meta(value: Value) -> Option<Meta>

作用:这个小工具函数把一段 JSON 值包装成测试里需要的 Meta 元数据。它要求传进来的必须是 JSON 对象,也就是一组键值对;如果不是,就直接让测试失败。

数据流:进去的是一个 JSON 值 → 它先检查这个值是不是对象 → 如果是,就把里面的键值对装进 Meta 并返回 Some;如果不是对象,就触发 panic,让测试立刻报错。

调用关系:它是测试造数据时的基础零件。guardian_meta 会用它来生成标准 Guardian 元数据;一些测试也会直接调用它,故意构造缺字段或形状不完整的元数据,来检查正式逻辑会不会拒绝这些请求。

调用图:被 3 处调用(guardian_elicitation_review_request_declines_unsupported_opt_in_shapes, guardian_elicitation_review_request_requires_opt_in, guardian_meta);外部调用 1 个(panic!)。

guardian_meta14–27 ↗
fn guardian_meta(tool_params: Option<Value>) -> Option<Meta>

作用:这个函数帮测试快速生成一份“这是 Guardian MCP 工具调用审批”的标准元数据。它像填好大部分内容的表格,只允许测试按需补上工具参数。

数据流:进去的是可选的 tool_params,也就是工具调用参数 → 它先创建一份包含审批类型、请求类型、连接器名字、工具名字等字段的 JSON 对象 → 如果传了工具参数,就把它放进 tool_params 字段 → 最后交给 meta 包装成 Meta。

调用关系:多个测试用它来搭建“看起来合法、已经选择走 Guardian 审批”的请求。它内部把真正包装 Meta 的工作交给 meta,然后这些元数据会被 form_request 放进 MCP 表单请求里。

调用图:调用 1 个内部函数(meta);被 3 处调用(guardian_elicitation_review_request_builds_mcp_tool_call, guardian_elicitation_review_request_declines_unsupported_opt_in_shapes, guardian_elicitation_review_request_defaults_missing_tool_params);外部调用 1 个(json!)。

form_request29–41 ↗
fn form_request(meta: Option<Meta>) -> ElicitationReviewRequest

作用:这个函数帮测试生成一个 MCP 表单式审批请求。它把服务器名、请求编号、提示语和元数据拼成一份完整请求,省得每个测试重复写一大段样板。

数据流:进去的是可选的 Meta 元数据 → 它创建一个服务器名为 browser-use、请求编号为 7 的 ElicitationReviewRequest → 请求内容是一个表单确认请求,提示语是“Allow origin?”,并带一个空的表单 schema → 出来的是完整的测试请求对象。

调用关系:它是多条测试的共同造数入口。测试先用 meta 或 guardian_meta 准备元数据,再交给 form_request 生成请求,之后再把请求送进被测的 guardian_elicitation_review_request 等正式函数。

调用图:被 4 处调用(guardian_elicitation_review_request_builds_mcp_tool_call, guardian_elicitation_review_request_declines_unsupported_opt_in_shapes, guardian_elicitation_review_request_defaults_missing_tool_params, guardian_elicitation_review_request_requires_opt_in);外部调用 2 个(builder, Number)。

guardian_elicitation_review_request_builds_mcp_tool_call44–80 ↗
fn guardian_elicitation_review_request_builds_mcp_tool_call()

作用:这个测试确认:当 MCP 请求带着完整的 Guardian 工具调用审批信息时,系统会正确生成 Guardian 的 MCP 工具调用审批请求。它重点检查工具名、参数、连接器信息这些关键字段有没有丢。

数据流:它先用 guardian_meta 造出带 origin 参数的元数据,再用 form_request 做成 MCP 请求 → 然后调用被测逻辑 guardian_elicitation_review_request → 最后逐项检查输出:审批 ID、服务器、工具名、参数、连接器名称和工具标题都必须符合预期。

调用关系:这是主路径测试,也就是最正常、最应该成功的场景。它依赖 guardian_meta 和 form_request 造请求,然后检验正式转换函数能不能产出 GuardianApprovalRequest::McpToolCall。

调用图:调用 2 个内部函数(form_request, guardian_meta);外部调用 3 个(assert_eq!, json!, panic!)。

guardian_elicitation_review_request_defaults_missing_tool_params83–97 ↗
fn guardian_elicitation_review_request_defaults_missing_tool_params()

作用:这个测试确认:如果请求声明了要走 Guardian 工具调用审批,但没有提供工具参数,系统会把参数当成空对象,而不是报错或变成空值。

数据流:它先用 guardian_meta 生成不带 tool_params 的元数据,再用 form_request 包成请求 → 调用 guardian_elicitation_review_request → 从结果里取出 arguments 字段 → 检查它是 Some({}),也就是“有参数,只是空的”。

调用关系:它覆盖主路径里的一个边角情况。和成功构建测试一样,它用 guardian_meta 与 form_request 搭数据,但重点不是所有字段,而是缺少 tool_params 时的默认行为。

调用图:调用 2 个内部函数(form_request, guardian_meta);外部调用 2 个(assert_eq!, panic!)。

plugin_install_elicitation_telemetry_metadata_requires_install_tool_suggestion100–154 ↗
fn plugin_install_elicitation_telemetry_metadata_requires_install_tool_suggestion()

作用:这个测试确认:只有“建议安装插件”的 MCP 提示请求,才会被提取成插件安装遥测信息。遥测可以理解成给系统记录事件用的数据,方便之后统计或排查。

数据流:它先造一个 suggest_type 为 install 的插件建议事件 → 调用 plugin_install_elicitation_telemetry_metadata → 检查能得到插件类型、插件 ID、插件名称。接着它再造一个 suggest_type 为 enable 的事件 → 再次调用同一个函数 → 检查结果是 None,表示这不是安装事件,不该记录成安装遥测。

调用关系:这个测试不走 form_request 那套 Guardian 工具调用路径,而是直接构造 EventMsg::ElicitationRequest。它专门保护遥测提取逻辑,确保只有安装建议会被算作插件安装相关事件。

调用图:外部调用 4 个(String, assert_eq!, json!, ElicitationRequest)。

guardian_elicitation_review_request_requires_opt_in157–167 ↗
fn guardian_elicitation_review_request_requires_opt_in()

作用:这个测试确认:请求光说自己是 MCP 工具调用还不够,还必须明确带上正确的 Guardian 审批请求标记。没有这个“选择加入”标记,系统就不会把它交给 Guardian。

数据流:它用 meta 构造一份缺少 codex_request_type 的元数据,再用 form_request 做成 MCP 请求 → 调用 guardian_elicitation_review_request → 检查结果是 NotRequested,也就是系统认为这不是一个真正要求 Guardian 审批的请求。

调用关系:它测试的是安全入口条件。它调用 meta 和 form_request 来做一个“不完整但看起来有点像”的请求,用来确认正式逻辑不会误判、不会随便启动 Guardian 审批流程。

调用图:调用 2 个内部函数(form_request, meta);外部调用 2 个(assert_eq!, json!)。

guardian_elicitation_review_request_declines_unsupported_opt_in_shapes170–211 ↗
fn guardian_elicitation_review_request_declines_unsupported_opt_in_shapes()

作用:这个测试确认:就算请求声明要走 Guardian 审批,只要请求形状不被支持,系统也会拒绝,而不是勉强处理。这里的“形状”包括请求类型、表单内容、关键字段是否齐全。

数据流:它依次构造三类问题请求:一种是 URL 式请求,不是支持的表单式请求;一种是表单里要求额外字段 confirmed;一种是缺少 tool_name → 每个请求都会被送进 guardian_elicitation_review_request → 测试检查结果都属于 Decline,表示系统明确拒绝处理。

调用关系:它是安全边界测试。它会用 guardian_meta、meta、form_request 以及 schema 构造工具,专门制造不受支持的输入,确认正式转换逻辑在这些情况下会保守地拒绝。

调用图:调用 3 个内部函数(form_request, guardian_meta, meta);外部调用 6 个(new, builder, Boolean, assert!, json!, Number)。

guardian_decisions_map_to_elicitation_responses_without_session_state214–269 ↗
fn guardian_decisions_map_to_elicitation_responses_without_session_state()

作用:这个测试确认:即使没有额外会话状态,Guardian 的审批结果也能被稳定转换成 MCP 响应。比如批准就是接受,拒绝或超时就是拒绝,取消就是取消。

数据流:它分别传入 Approved、Denied、TimedOut、Abort 四种 Guardian 决定,以及可选的拒绝说明 → 调用 mcp_elicitation_response_from_guardian_decision_parts → 检查输出的 ElicitationResponse 是否有正确的 action、content 和 meta;超时时还要带上标准超时说明。

调用关系:它检查的是审批链路的返回方向。前面的测试关注 MCP 请求如何变成 Guardian 请求;这个测试关注 Guardian 决定如何变回 MCP 能理解的响应,保证整条审批闭环能正确结束。

调用图:外部调用 1 个(assert_eq!)。

core/src/state/session_tests.rs源码 ↗
testtest execution

可以把 SessionState 想成一次对话里的“临时账本”:它记着用户选了哪些外部连接器、当前速率限制是多少、自动压缩上下文时预估要塞多少内容等。这个测试文件不负责真正实现这些功能,而是专门检查这些账本规则是否可靠。比如,同一个连接器选两次,最后只能算一次;清空连接器后,不能还偷偷留着旧选择;如果服务端没有给限额编号,系统要默认当成 codex;替换聊天历史时,自动压缩用的预填 token 估算也要清掉。还有一个比较细的规则:从 codex 切到 codex_other 这类限额桶时,账户余额、消费上限、套餐类型这些账号信息不能丢。没有这些测试,状态代码稍微一改,就可能出现界面显示错、限额判断错、旧数据污染新会话的问题。

函数细节6
merge_connector_selection_deduplicates_entries11–24 ↗
async fn merge_connector_selection_deduplicates_entries()

作用:这个测试确认:把连接器选择合并进会话状态时,重复的名字只会保留一份。这样用户或系统重复传入同一个连接器时,不会让状态里出现一堆重复项。

数据流:进去的是一份测试用会话配置,以及三个连接器名字,其中 calendar 出现了两次。测试先用配置创建一个新的 SessionState,然后把这些名字合并进去。出来的结果应该是一个集合,只包含 calendar 和 drive 各一次;测试用断言检查实际结果和预期完全一样。

调用关系:测试运行器启动这个异步测试后,它先调用 make_session_configuration_for_tests 准备一份安全的假配置,再调用 SessionState::new 创建状态对象。核心动作交给状态对象的合并选择逻辑完成,最后用 assert_eq! 做验收。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 1 个(assert_eq!)。

clear_connector_selection_removes_entries28–36 ↗
async fn clear_connector_selection_removes_entries()

作用:这个测试确认:调用清空连接器选择后,之前保存的连接器会全部消失。它防止用户明明取消了选择,系统却还继续带着旧连接器工作。

数据流:进去的是测试会话配置和一个临时加入的 calendar 连接器。测试先建出 SessionState,再把 calendar 合并进去,接着调用清空方法。出来时再读取连接器选择,应该是一个空集合;断言负责确认确实没有残留。

调用关系:它和上一条测试一样,先靠 make_session_configuration_for_tests 和 SessionState::new 搭好测试场景。不同的是,它关注的是清理动作:先制造一条旧数据,再检查 clear_connector_selection 是否把这条数据彻底拿掉。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 1 个(assert_eq!)。

set_rate_limits_defaults_limit_id_to_codex_when_missing39–65 ↗
async fn set_rate_limits_defaults_limit_id_to_codex_when_missing()

作用:这个测试确认:设置速率限制时,如果传入的数据没有写明是哪一种限制,系统会默认把它当作 codex。速率限制就是一段时间内能用多少服务的规则;默认值能避免后续代码因为缺少编号而判断不清。

数据流:进去的是一份没有 limit_id 的 RateLimitSnapshot,也就是一张“限额快照”。里面有主要窗口的使用比例、窗口分钟数、重置时间,但没有说明限制编号。测试把它写入 SessionState 后,再读取 latest_rate_limits,期望看到 limit_id 被补成 codex。

调用关系:测试先调用 make_session_configuration_for_tests 准备配置,再用 SessionState::new 建状态。真正被检查的是 SessionState 的 set_rate_limits 行为;assert_eq! 最后确认缺失的编号有没有被自动补上。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 1 个(assert_eq!)。

replace_history_clears_auto_compact_window_prefill68–81 ↗
async fn replace_history_clears_auto_compact_window_prefill()

作用:这个测试确认:替换整段对话历史时,自动压缩窗口的预填 token 估算会被清空。token 可以理解成模型阅读文本时用的小块计数;历史都换了,旧的估算就不能再拿来用。

数据流:进去的是一个新会话状态,先人为设置 auto compact 的预估预填数量为 100。随后测试用空历史替换当前历史,并且不提供参考上下文项。出来时读取 auto_compact_window_snapshot,预期里面的 prefill_input_tokens 变成 None,表示旧估算已经失效并被清掉。

调用关系:这个测试由测试运行器调用。它先通过 make_session_configuration_for_tests 和 SessionState::new 搭环境,再用设置预填值的方法制造旧状态,然后调用 replace_history 触发清理。最后通过 auto_compact_window_snapshot 观察结果,并用 assert_eq! 对比。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 2 个(new, assert_eq!)。

set_rate_limits_defaults_to_codex_when_limit_id_missing_after_other_bucket84–124 ↗
async fn set_rate_limits_defaults_to_codex_when_limit_id_missing_after_other_bucket()

作用:这个测试确认:即使之前保存过 codex_other 这类别的限额桶,下一次如果新数据没带 limit_id,也仍然要默认成 codex,而不是沿用旧桶。这样可以避免旧状态误导新限额数据。

数据流:进去先是一份明确标成 codex_other 的限额快照,随后又进去一份没有 limit_id 的新限额快照。测试先把 codex_other 写入状态,再写入缺少编号的新快照。出来时读取 latest_rate_limits,预期 limit_id 是 codex,说明系统没有被之前的 codex_other 带偏。

调用关系:它先用 make_session_configuration_for_tests 和 SessionState::new 建好测试对象。整个故事分两步:先放入一个“旧桶”,再放入一个“没写桶名的新数据”。被验证的仍是 set_rate_limits 的默认规则,最后 assert_eq! 检查最终编号。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 1 个(assert_eq!)。

set_rate_limits_carries_account_metadata_from_codex_to_codex_other127–196 ↗
async fn set_rate_limits_carries_account_metadata_from_codex_to_codex_other()

作用:这个测试确认:从 codex 限额切到 codex_other 限额时,如果新快照没有带账户信息,系统会沿用之前已有的账户信息。账户信息包括余额、消费控制上限、套餐类型等,丢了会让界面或判断变得不完整。

数据流:进去先是一份 codex 快照,里面有使用比例、余额 credits、个人消费上限 individual_limit、套餐 plan_type。然后进去一份 codex_other 快照,它有新的限额窗口,但没有余额、消费上限和套餐。测试把两份快照依次写入状态。出来的 latest_rate_limits 应该使用 codex_other 的新限额窗口,同时保留前一份 codex 快照里的账户元数据。

调用关系:测试运行时先通过 make_session_configuration_for_tests 和 SessionState::new 搭出空状态。它连续两次调用 set_rate_limits,模拟服务端先给完整账号信息、后给另一个限额桶的局部信息。最后用 assert_eq! 检查最终快照是不是把“新的桶信息”和“旧的账号信息”正确拼在了一起。

调用图:调用 2 个内部函数(make_session_configuration_for_tests, new);外部调用 1 个(assert_eq!)。

core/src/session_prefix_tests.rs源码 ↗
testtest run

这个测试关心的是一个很实际的问题:如果某个子代理出错了,而且错误文本特别长,系统最后生成的提示消息会不会也跟着变得又长又难处理。文件里故意造了一个很长的错误:把“stream disconnected”重复一千次,模拟日志爆炸的情况。然后它调用生成完成消息的函数,检查两件事:第一,消息的大概 token 数,也就是模型眼里的“文字长度单位”,必须低于规定上限;第二,消息里必须包含下一步该怎么做的固定提示。简单说,它像质检员一样,确认报错提示既不会撑爆页面或触发人工审核阈值,又不会丢掉关键指引。

函数细节1
error_completion_message_stays_below_manual_review_threshold10–20 ↗
fn error_completion_message_stays_below_manual_review_threshold()

作用:这个测试确认:当子代理带着超长错误信息结束时,生成出来的完成消息仍然会被控制在安全长度内,并且还保留告诉用户下一步该做什么的提示。

数据流:进去的是一个根代理路径、一个子代理路径,以及一段被故意放大到很长的错误状态文字。测试把这些交给完成消息生成函数,拿到一段最终消息;然后用近似 token 计数检查它够不够短,再检查里面是否包含固定的错误后续动作提示。出来的结果不是业务数据,而是测试通过或失败:通过表示长度控制和关键提示都正常,失败表示有人改代码时破坏了这个保证。

调用关系:这个函数在测试运行时由测试框架自动调用。它先用 root 和 try_from 准备两个代理路径,再用 Errored 构造一个错误状态,随后把这些交给 format_inter_agent_completion_message 生成实际消息,最后用断言检查消息长度和内容。它不是正常产品流程的一部分,而是给生成提示消息的逻辑加一道防线。

调用图:调用 2 个内部函数(root, try_from);外部调用 3 个(assert!, Errored, format_inter_agent_completion_message)。

转录和上下文塑形

这些文件验证历史、上下文、事件、元数据和压缩如何转换为运行时转录和提示可见状态。

core/src/compact_tests.rs源码 ↗
testtest

聊天记录太长时,系统会把旧内容压缩成更短的历史,像把一摞会议记录整理成摘要。但压缩不能乱来:真正的用户消息要留下,旧的环境说明、过时警告、旧开发者指令要过滤掉;新的权限、模型切换提示等初始上下文还要重新塞回合适位置。这个测试文件就是给这些规则做“安全检查”。它构造各种假消息,比如用户文本、图片、摘要、旧警告、开发者消息,然后调用真实的压缩相关函数,看输出是不是符合预期。这里还测试了超长用户消息会被截断、摘要会放在最后、用户消息的元数据不会丢,以及 Azure 这类模型提供方会走远程压缩任务。简单说,它保证“整理聊天记录”不会把对话弄乱。

函数细节20
process_compacted_history_with_test_session8–25 ↗
async fn process_compacted_history_with_test_session(
    compacted_history: Vec<ResponseItem>,
    previous_turn_settings: Option<&PreviousTurnSettings>,
) -> (Vec<ResponseItem>, Vec<ResponseItem>)

作用:这是测试用的小帮手,用来快速搭一个假的会话环境,然后把一份压缩后的历史交给真实处理函数跑一遍。这样每个测试不用重复写创建会话、设置上一轮参数这些准备工作。

数据流:进去的是一段压缩后的消息列表,以及可选的上一轮设置;它先创建测试会话和上下文,再把上一轮设置放进会话,接着生成系统当前应该有的初始上下文,最后调用压缩历史处理函数;出来的是处理后的历史,以及那份初始上下文,方便测试拿来对比。

调用关系:多个异步测试都会先找它搭舞台。它内部把工作交给 make_session_and_context 创建测试会话,再交给 process_compacted_history 做真正的历史刷新。调用它的测试主要关心旧消息该删什么、新上下文该插到哪里。

调用图:调用 2 个内部函数(process_compacted_history, make_session_and_context);被 6 处调用(process_compacted_history_drops_legacy_warnings, process_compacted_history_drops_non_user_content_messages, process_compacted_history_inserts_context_before_last_real_user_message_only, process_compacted_history_reinjects_full_initial_context, process_compacted_history_reinjects_model_switch_message, process_compacted_history_replaces_developer_messages)。

user_message27–37 ↗
fn user_message(text: &str) -> ResponseItem

作用:这是测试里造“普通用户消息”的小工具。它让测试代码不用每次手写一大段消息结构,只要给一句文本就能得到一条用户消息。

数据流:进去的是一段文字;它把这段文字包成 ResponseItem::Message,角色设为 user,内容设为输入文本;出来的是一条可放进聊天历史里的用户消息,其他字段保持空值。

调用关系:process_compacted_history_drops_legacy_warnings 用它来制造几条旧警告和一条真实用户消息。它只负责造测试数据,不参与真实压缩逻辑。

调用图:被 1 处调用(process_compacted_history_drops_legacy_warnings);外部调用 1 个(vec!)。

compacted_user_message39–44 ↗
fn compacted_user_message(text: &str) -> CompactedUserMessage

作用:这是测试里造“压缩阶段记录的用户消息”的小工具。它把普通文字包装成 CompactedUserMessage,方便测试压缩历史构建函数。

数据流:进去的是一段文字;它把文字放到 message 字段里,并把 metadata 设为空;出来的是一条压缩用的用户消息对象。

调用关系:build_token_limited_compacted_history_truncates_overlong_user_messages 用它制造一条特别长的用户消息,再交给 build_compacted_history_with_limit 检查是否会被截断。

调用图:被 1 处调用(build_token_limited_compacted_history_truncates_overlong_user_messages)。

content_items_to_text_joins_non_empty_segments47–63 ↗
fn content_items_to_text_joins_non_empty_segments()

作用:这个测试确认:把多段文本内容合成一段文字时,空文本会被跳过,非空文本会用换行连起来。

数据流:进去的是一组内容片段,其中有 hello、空字符串和 world;测试调用 content_items_to_text;出来应该是 Some("hello\nworld"),说明空段没参与拼接。

调用关系:它直接检查 content_items_to_text 的行为。这个函数的正确性会影响后面很多测试,因为测试常用它从消息内容里取出可读文字。

调用图:外部调用 2 个(assert_eq!, vec!)。

content_items_to_text_ignores_image_only_content66–75 ↗
fn content_items_to_text_ignores_image_only_content()

作用:这个测试确认:如果一条内容只有图片,没有文字,那么系统不会硬把它当成文本消息。

数据流:进去的是一组只包含图片链接的内容片段;测试调用 content_items_to_text;出来应该是 None,表示没有可提取的文字。

调用关系:它直接约束 content_items_to_text 的边界行为,避免图片内容在压缩或过滤时被误判成用户文本。

调用图:外部调用 2 个(assert_eq!, vec!)。

collect_user_messages_extracts_user_text_only78–104 ↗
fn collect_user_messages_extracts_user_text_only()

作用:这个测试确认:收集用户消息时,只拿用户角色的文字,不拿助手消息,也不拿无关类型的项目。

数据流:进去的是三项历史:一条助手消息、一条用户消息、一个 Other;测试调用 collect_user_messages;出来只应该有用户说的 first。

调用关系:它检查 collect_user_messages 的基本筛选能力。这个能力是构建压缩历史的前置步骤,因为压缩时只应该整理真正的用户输入。

调用图:外部调用 2 个(assert_eq!, vec!)。

collect_user_messages_filters_session_prefix_entries107–146 ↗
fn collect_user_messages_filters_session_prefix_entries()

作用:这个测试确认:系统自动塞进会话开头的说明,比如 AGENTS.md 指令和环境信息,不会被当作用户真正说的话。

数据流:进去的是三条 user 角色消息:项目指令、环境上下文、真实用户消息;测试调用 collect_user_messages;出来只剩 real user message。

调用关系:它检查 collect_user_messages 对“看起来像用户消息、其实是系统上下文”的过滤规则。这能避免压缩历史时把自动说明重复保存。

调用图:外部调用 2 个(assert_eq!, vec!)。

collect_user_messages_filters_legacy_warnings149–166 ↗
fn collect_user_messages_filters_legacy_warnings()

作用:这个测试确认:一些老版本系统自动发出的警告文字,不会被当成用户消息保存进压缩历史。

数据流:进去的是三条旧警告和一条真实用户消息;测试调用 collect_user_messages;出来只应该包含 real user message。

调用关系:它检查 collect_user_messages 对遗留警告的过滤能力。这样旧系统提示不会污染后续对话摘要。

调用图:外部调用 2 个(assert_eq!, vec!)。

build_token_limited_compacted_history_truncates_overlong_user_messages169–209 ↗
fn build_token_limited_compacted_history_truncates_overlong_user_messages()

作用:这个测试确认:如果用户消息长到超过限制,构建压缩历史时会截短它,而不是把超大文本原样塞进去。

数据流:进去的是一个很小的 token 限制、一条重复很多次的超长用户文本,以及摘要 SUMMARY;测试调用 build_compacted_history_with_limit;出来应该有两条消息:第一条是被截断并带有“tokens truncated”提示的用户消息,第二条是完整摘要。

调用关系:它先用 compacted_user_message 造长消息,再把活交给 build_compacted_history_with_limit。它保护的是压缩历史的大小控制,避免长消息继续撑爆上下文。

调用图:调用 1 个内部函数(compacted_user_message);外部调用 6 个(new, assert!, assert_eq!, panic!, from_ref, build_compacted_history_with_limit)。

build_token_limited_compacted_history_appends_summary_message212–231 ↗
fn build_token_limited_compacted_history_appends_summary_message()

作用:这个测试确认:构建压缩历史时,摘要文本会作为最后一条用户消息追加进去。

数据流:进去的是空初始上下文、一条用户消息和 summary text;测试调用 build_compacted_history;出来的历史不应为空,并且最后一项的文字必须等于 summary text。

调用关系:它检查 build_compacted_history 的核心输出形状。摘要放在末尾很重要,因为后续模型读取历史时通常会把最后的总结当作最新压缩结果。

调用图:外部调用 5 个(new, assert!, assert_eq!, panic!, vec!)。

build_compacted_history_preserves_user_message_metadata234–248 ↗
fn build_compacted_history_preserves_user_message_metadata()

作用:这个测试确认:用户消息自带的元数据不会在构建压缩历史时丢失。元数据可以理解为消息的小标签,比如属于哪一轮对话。

数据流:进去的是一条带 turn_id 为 turn-1 的压缩用户消息,以及一段摘要;测试调用 build_compacted_history;出来的第一条历史仍然带 turn-1,而摘要消息没有这个 turn_id。

调用关系:它检查 build_compacted_history 对附加信息的保留。这样后续追踪对话轮次时,不会因为压缩而丢掉线索。

调用图:外部调用 2 个(new, assert_eq!)。

should_use_remote_compact_task_for_azure_provider251–273 ↗
fn should_use_remote_compact_task_for_azure_provider()

作用:这个测试确认:当模型提供方是 Azure 时,系统会选择使用远程压缩任务。

数据流:进去的是一个手工构造的 Azure 模型提供方配置;测试调用 should_use_remote_compact_task;出来应该是真,表示要走远程压缩。

调用关系:它直接检查 should_use_remote_compact_task 的选择规则。这个规则决定压缩任务是在本地做,还是交给远端服务做。

调用图:外部调用 1 个(assert!)。

process_compacted_history_replaces_developer_messages275–320 ↗
async fn process_compacted_history_replaces_developer_messages()

作用:这个测试确认:压缩历史里旧的 developer 消息会被新的初始上下文替换。developer 消息可以理解为给模型看的系统级操作说明。

数据流:进去的是一段历史,里面夹着两条过期 developer 消息和一条用户摘要;测试通过 process_compacted_history_with_test_session 处理;出来应该是当前会话的新初始上下文,再加上那条用户摘要,旧 developer 内容不再保留。

调用关系:它调用测试帮手搭会话,真正的刷新工作由 process_compacted_history 完成。这个测试保证权限、人格等开发者指令不会沿用旧版本。

调用图:调用 1 个内部函数(process_compacted_history_with_test_session);外部调用 2 个(assert_eq!, vec!)。

process_compacted_history_reinjects_full_initial_context323–348 ↗
async fn process_compacted_history_reinjects_full_initial_context()

作用:这个测试确认:即使压缩历史里只有摘要,系统也会重新补上完整的初始上下文。

数据流:进去的是一条用户摘要;测试处理后拿到 refreshed 和 expected 初始上下文;出来应该等于“当前初始上下文 + 摘要消息”。

调用关系:它通过 process_compacted_history_with_test_session 调用真实处理流程。它验证的是压缩恢复时不能只带摘要,还必须带上当前运行所需的规则和环境。

调用图:调用 1 个内部函数(process_compacted_history_with_test_session);外部调用 2 个(assert_eq!, vec!)。

process_compacted_history_drops_non_user_content_messages351–427 ↗
async fn process_compacted_history_drops_non_user_content_messages()

作用:这个测试确认:压缩历史里的项目说明、环境上下文、中断记录、旧开发者指令等自动内容会被丢掉,只留下真正有用的用户摘要。

数据流:进去的是多条看起来像 user 的系统内容、一条 summary、以及一条旧 developer 消息;测试调用处理流程;出来应该是新的初始上下文加 summary,不包含那些自动生成的旧内容。

调用关系:它通过 process_compacted_history_with_test_session 进入真实处理函数。这个测试覆盖的是“清理旧上下文垃圾”的场景,防止恢复后的历史重复或过期。

调用图:调用 1 个内部函数(process_compacted_history_with_test_session);外部调用 2 个(assert_eq!, vec!)。

process_compacted_history_drops_legacy_warnings430–452 ↗
async fn process_compacted_history_drops_legacy_warnings()

作用:这个测试确认:处理压缩历史时,会丢掉旧版本留下的警告消息,但保留最新的真实用户消息。

数据流:进去的是三条旧警告和一条 latest user;测试调用处理流程;出来应该是当前初始上下文加 latest user,不包含警告。

调用关系:它用 user_message 快速造消息,再用 process_compacted_history_with_test_session 跑完整流程。它和收集用户消息的警告过滤测试互相补充,一个测小函数,一个测完整流程。

调用图:调用 2 个内部函数(process_compacted_history_with_test_session, user_message);外部调用 2 个(assert_eq!, vec!)。

process_compacted_history_inserts_context_before_last_real_user_message_only455–522 ↗
async fn process_compacted_history_inserts_context_before_last_real_user_message_only()

作用:这个测试确认:重新插入初始上下文时,要插在最后一条真实用户消息前面,而不是插到摘要前或随便插。

数据流:进去的是 older user、一条带 SUMMARY_PREFIX 的摘要消息、latest user;测试处理后;出来应该保持 older user 和摘要在前,然后插入初始上下文,最后才是 latest user。

调用关系:它通过 process_compacted_history_with_test_session 调真实流程,重点验证插入位置。这个位置很关键,因为最新用户请求前必须有最新规则,模型才能按当前规则回答。

调用图:调用 1 个内部函数(process_compacted_history_with_test_session);外部调用 2 个(assert_eq!, vec!)。

process_compacted_history_reinjects_model_switch_message525–567 ↗
async fn process_compacted_history_reinjects_model_switch_message()

作用:这个测试确认:如果上一轮用的是不同模型,系统会在初始上下文里重新加入模型切换提示。

数据流:进去的是一条摘要,以及 previous_turn_settings,里面写着上一轮模型名;处理后,测试先检查初始上下文第一条 developer 消息含有 <model_switch>,再确认最终历史是初始上下文加摘要。

调用关系:它调用 process_compacted_history_with_test_session,并把上一轮设置传进去。真实流程会根据这些设置生成模型切换说明,让模型知道对话是从另一个模型接过来的。

调用图:调用 1 个内部函数(process_compacted_history_with_test_session);外部调用 4 个(assert!, assert_eq!, panic!, vec!)。

insert_initial_context_before_last_real_user_or_summary_keeps_summary_last570–651 ↗
fn insert_initial_context_before_last_real_user_or_summary_keeps_summary_last()

作用:这个测试确认:当历史末尾是压缩摘要时,插入新的初始上下文不能把摘要挤到中间乱掉;摘要仍然要留在最后。

数据流:进去的是 older user、latest user、summary 三条历史,以及一条新的 developer 上下文;测试调用 insert_initial_context_before_last_real_user_or_summary;出来应该是 older user、developer 上下文、latest user、summary。

调用关系:它直接测试插入初始上下文的辅助函数。这个函数是压缩历史恢复流程里的排版工,负责把新规则放到合适位置,同时保持摘要的特殊末尾位置。

调用图:外部调用 2 个(assert_eq!, vec!)。

insert_initial_context_before_last_real_user_or_summary_keeps_compaction_last654–687 ↗
fn insert_initial_context_before_last_real_user_or_summary_keeps_compaction_last()

作用:这个测试确认:如果历史最后是一条加密压缩内容,插入初始上下文时也不能把这条压缩内容挪走;它仍然留在最后。

数据流:进去的是一条 Compaction 加密压缩记录,以及一条新的 developer 上下文;测试调用 insert_initial_context_before_last_real_user_or_summary;出来应该先是 developer 上下文,最后仍是原来的 Compaction。

调用关系:它直接检查插入辅助函数对特殊 Compaction 项的处理。这样恢复历史时,系统补充新规则的同时,不会破坏压缩记录本身的位置。

调用图:外部调用 2 个(assert_eq!, vec!)。

core/src/context_manager/history_tests.rs源码 ↗
testtest

对话系统要把很多东西记进历史:用户说的话、助手回复、工具调用、命令输出、图片、推理内容等。这个文件专门测试这些历史记录在保存、裁剪、回滚、发给模型前整理时是否可靠。比如:系统消息要过滤掉,工具调用和工具输出要成对保留,太长的命令输出要截短,模型不支持图片时要把图片换成文字提示,多智能体消息要能当作一轮新指令。它还测试 token(大致可理解为模型看文字时的计量单位)估算,避免一张 base64 图片因为原始文本很长而把预算算爆。整体上,这个文件不提供线上功能,而是给历史管理器做“防摔测试”,确保真实运行时上下文不会坏掉。

函数细节77
assistant_msg37–47 ↗
fn assistant_msg(text: &str) -> ResponseItem

作用:造一条助手发出的普通文字消息,方便测试里反复使用。它让测试不用每次手写完整的消息结构。

数据流:输入一段文字 → 包成角色为 assistant、内容为输出文本的 ResponseItem → 返回这条假助手消息,不改动外部状态。

调用关系:多个测试用它搭建历史记录,例如过滤消息、回滚用户轮次、旧版多智能体消息判断等;它只是测试数据工厂,不再把活交给项目里的核心逻辑。

调用图:被 3 处调用(drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns, filters_non_api_messages, legacy_inter_agent_assistant_messages_are_not_turn_boundaries);外部调用 1 个(vec!)。

inter_agent_assistant_msg49–66 ↗
fn inter_agent_assistant_msg(text: &str) -> ResponseItem

作用:造一条“助手发给另一个智能体”的消息,用来测试多智能体协作场景。多智能体就是一个主助手把任务交给另一个助手或 worker。

数据流:输入文字 → 先创建一段带作者、接收者和内容的 InterAgentCommunication,再序列化成 JSON 字符串 → 包成 assistant 消息返回。

调用关系:多智能体边界相关测试会调用它,然后把生成的消息交给 is_user_turn_boundary、for_prompt 或 drop_last_n_user_turns 检查。

调用图:调用 2 个内部函数(root, new);被 3 处调用(drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns, for_prompt_preserves_inter_agent_assistant_messages, inter_agent_assistant_messages_are_turn_boundaries);外部调用 2 个(new, vec!)。

create_history_with_items68–74 ↗
fn create_history_with_items(items: Vec<ResponseItem>) -> ContextManager

作用:用一批假历史项快速创建 ContextManager。ContextManager 可以理解为“对话历史账本”。

数据流:输入 ResponseItem 列表 → 新建历史管理器,并用固定的 10000 token 裁剪策略记录这些项 → 返回装好数据的历史对象。

调用关系:大多数测试都从这里开始搭建场景;它调用 ContextManager::new 和 record_items,把测试数据送进真正的历史记录逻辑。

调用图:调用 1 个内部函数(new);被 38 处调用(drop_last_n_user_turns_clears_reference_context_for_mixed_developer_context_bundles, drop_last_n_user_turns_ignores_session_prefix_user_messages, drop_last_n_user_turns_preserves_prefix, drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns, drop_last_n_user_turns_trims_context_updates_above_rolled_back_turn, estimate_token_count_with_base_instructions_uses_provided_text, for_prompt_clears_image_generation_result_when_images_are_unsupported, for_prompt_preserves_image_generation_calls_when_images_are_supported, for_prompt_preserves_inter_agent_assistant_messages, for_prompt_strips_images_when_model_does_not_support_images (+15 more));外部调用 1 个(Tokens)。

user_msg76–86 ↗
fn user_msg(text: &str) -> ResponseItem

作用:造一条用户发出的普通输出文本消息,供测试使用。

数据流:输入文字 → 包成角色为 user、内容为 OutputText 的 ResponseItem → 返回这条用户消息。

调用关系:过滤、token 追加计算等测试用它构造用户发言,再交给历史管理器记录或估算。

调用图:被 3 处调用(filters_non_api_messages, items_after_last_model_generated_tokens_include_user_and_tool_output, total_token_usage_includes_all_items_after_last_model_generated_item);外部调用 1 个(vec!)。

user_input_text_msg88–98 ↗
fn user_input_text_msg(text: &str) -> ResponseItem

作用:造一条用户输入文本消息,和 user_msg 的内容类型不同,用来覆盖更接近用户输入的格式。

数据流:输入文字 → 包成角色为 user、内容为 InputText 的 ResponseItem → 返回测试消息。

调用关系:回滚用户轮次等测试用它模拟真实用户指令、环境上下文、技能说明等前缀内容。

调用图:被 1 处调用(drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns);外部调用 1 个(vec!)。

developer_msg100–110 ↗
fn developer_msg(text: &str) -> ResponseItem

作用:造一条开发者指令消息。开发者指令可以理解为比普通用户话更像“系统给助手的工作规则”。

数据流:输入文字 → 包成角色为 developer、内容为 InputText 的 ResponseItem → 返回这条开发者消息。

调用关系:主要用于测试回滚时上下文更新和开发者指令是否被正确保留或裁掉。

调用图:外部调用 1 个(vec!)。

developer_msg_with_fragments112–125 ↗
fn developer_msg_with_fragments(texts: &[&str]) -> ResponseItem

作用:造一条由多段文字组成的开发者消息,用来测试一条消息里混有不同性质指令的情况。

数据流:输入多个文字片段 → 每段变成一个 InputText 内容块 → 合成一条 developer 消息返回。

调用关系:混合开发者上下文包的测试会用它,检查回滚时遇到混合内容是否清掉参考上下文。

reference_context_item127–148 ↗
fn reference_context_item() -> TurnContextItem

作用:造一个固定的回合上下文快照。它像拍了一张“当前工作目录、日期、权限、沙箱策略”等运行环境的照片。

数据流:不接收业务输入 → 填好 cwd、日期、审批策略、只读沙箱、模型名等字段 → 返回 TurnContextItem。

调用关系:回滚相关测试把它塞进历史管理器,再验证 drop_last_n_user_turns 后这个参考上下文该保留还是该清空。

调用图:被 2 处调用(drop_last_n_user_turns_clears_reference_context_for_mixed_developer_context_bundles, drop_last_n_user_turns_trims_context_updates_above_rolled_back_turn);外部调用 2 个(from, new_read_only_policy)。

custom_tool_call_output150–157 ↗
fn custom_tool_call_output(call_id: &str, output: &str) -> ResponseItem

作用:造一条自定义工具的输出消息。工具输出就是模型调用外部工具后返回的结果。

数据流:输入调用编号和输出文字 → 把文字包成 FunctionCallOutputPayload → 返回 CustomToolCallOutput。

调用关系:token 使用量相关测试用它放在助手最后一次输出之后,确认这些新工具结果会被补算进总 token。

调用图:调用 1 个内部函数(from_text);被 2 处调用(items_after_last_model_generated_tokens_include_user_and_tool_output, total_token_usage_includes_all_items_after_last_model_generated_item)。

reasoning_msg159–171 ↗
fn reasoning_msg(text: &str) -> ResponseItem

作用:造一条明文推理消息,用来测试历史是否保留模型的 reasoning 项。reasoning 可以理解为模型的思考记录或摘要。

数据流:输入推理文字 → 同时放入固定 summary 和内容正文 → 返回 Reasoning 类型的 ResponseItem。

调用关系:过滤非 API 消息的测试用它确认 Reasoning 不会像系统消息那样被丢掉。

调用图:被 1 处调用(filters_non_api_messages);外部调用 2 个(new, vec!)。

reasoning_with_encrypted_content173–183 ↗
fn reasoning_with_encrypted_content(len: usize) -> ResponseItem

作用:造一条只有加密内容长度的推理消息,用来测试推理 token 的估算。加密内容看不到原文,只能按长度估。

数据流:输入长度 → 生成对应长度的字符串作为 encrypted_content → 返回没有明文 content 的 Reasoning 项。

调用关系:非最后用户轮次推理 token 的测试用它构造多段推理,再检查统计函数如何忽略或计算它们。

调用图:外部调用 2 个(new, vec!)。

truncate_exec_output185–187 ↗
fn truncate_exec_output(content: &str) -> String

作用:把很长的命令执行输出截短到测试规定的 token 上限。这样模型不会被一大坨日志撑爆上下文。

数据流:输入完整输出文本 → 用 2500 token 的裁剪策略调用 truncate_text → 返回可能被加了“truncated”提示的文本。

调用关系:命令输出格式化相关测试都先调用它,再用 assert_truncated_message_matches 验证裁剪标记、保留头尾和删除数量。

调用图:被 4 处调用(format_exec_output_marks_byte_truncation_without_omitted_lines, format_exec_output_prefers_line_marker_when_both_limits_exceeded, format_exec_output_reports_omitted_lines_and_keeps_head_and_tail, format_exec_output_truncates_large_error);外部调用 2 个(truncate_text, Tokens)。

approx_token_count_for_text189–191 ↗
fn approx_token_count_for_text(text: &str) -> i64

作用:用一个很粗略的方法估算文字 token 数,方便测试比较长短差异。

数据流:输入文本 → 按大约每 4 个字符一个 token 计算,并安全转成 i64 → 返回估算值。

调用关系:基础指令 token 估算测试用它算出短指令和长指令之间应有的差值。

调用图:被 1 处调用(estimate_token_count_with_base_instructions_uses_provided_text);外部调用 1 个(try_from)。

filters_non_api_messages194–250 ↗
fn filters_non_api_messages()

作用:测试历史记录会丢掉不该发给 API 的消息,但保留该保留的推理、用户和助手消息。

数据流:先放入 system、reasoning 和 Other,再放入 user、assistant → 读取 raw_items → 断言最终只剩 reasoning、user、assistant。

调用关系:它调用 assistant_msg、reasoning_msg、user_msg 造数据,然后直接验证 ContextManager::record_items 的过滤行为。

调用图:调用 3 个内部函数(assistant_msg, reasoning_msg, user_msg);外部调用 4 个(assert_eq!, default, Tokens, vec!)。

non_last_reasoning_tokens_return_zero_when_no_user_messages253–258 ↗
fn non_last_reasoning_tokens_return_zero_when_no_user_messages()

作用:测试如果历史里没有用户消息,那么“非最后一轮的推理 token”应当是 0。

数据流:输入一条加密推理历史 → 创建历史管理器 → 调 get_non_last_reasoning_items_tokens 并断言返回 0。

调用关系:它通过 create_history_with_items 进入历史逻辑,专门守住没有用户轮次时的边界情况。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

non_last_reasoning_tokens_ignore_entries_after_last_user261–273 ↗
fn non_last_reasoning_tokens_ignore_entries_after_last_user()

作用:测试统计旧推理 token 时,不要把最后一个用户消息之后的新推理算进去。

数据流:构造推理、用户、推理、用户、推理的序列 → 建历史 → 统计非最后轮推理 token → 断言结果只包含应计的旧推理。

调用关系:它用 create_history_with_items 搭场景,验证 ContextManager 的 reasoning token 统计规则。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

items_after_last_model_generated_tokens_include_user_and_tool_output276–294 ↗
fn items_after_last_model_generated_tokens_include_user_and_tool_output()

作用:测试最后一次模型输出之后,新来的用户消息和工具输出都会被视为新增内容。

数据流:构造 assistant 后接 user 和 custom tool output → 找出最后模型生成项之后的项目 → 估算 token 并比对预期。

调用关系:它用 user_msg 和 custom_tool_call_output 造尾部内容,验证 items_after_last_model_generated_item 的范围。

调用图:调用 3 个内部函数(create_history_with_items, custom_tool_call_output, user_msg);外部调用 2 个(assert_eq!, vec!)。

items_after_last_model_generated_tokens_are_zero_without_model_generated_items297–308 ↗
fn items_after_last_model_generated_tokens_are_zero_without_model_generated_items()

作用:测试如果历史里还没有模型生成的内容,就不要把用户消息当成“最后模型输出之后的新增项”来算。

数据流:只放一条用户消息 → 查询最后模型生成项之后的列表并求 token → 断言为 0。

调用关系:它通过 create_history_with_items 检查一个没有助手输出的起步状态。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

inter_agent_assistant_messages_are_turn_boundaries311–315 ↗
fn inter_agent_assistant_messages_are_turn_boundaries()

作用:测试新版多智能体 assistant 消息会被当成一个用户轮次边界。轮次边界就是“从这里开始算一轮新指令”。

数据流:创建多智能体 assistant 消息 → 调 is_user_turn_boundary → 断言结果为真。

调用关系:它用 inter_agent_assistant_msg 造标准格式消息,直接检查边界识别函数。

调用图:调用 1 个内部函数(inter_agent_assistant_msg);外部调用 1 个(assert!)。

for_prompt_preserves_inter_agent_assistant_messages318–324 ↗
fn for_prompt_preserves_inter_agent_assistant_messages()

作用:测试发给模型的 prompt 历史不会丢掉多智能体 assistant 消息。

数据流:创建一条多智能体消息并记录进历史 → 分别读取 raw_items 和 for_prompt → 断言都保留原消息。

调用关系:它连接 create_history_with_items 和 for_prompt,验证整理 prompt 时不会误删协作指令。

调用图:调用 2 个内部函数(create_history_with_items, inter_agent_assistant_msg);外部调用 2 个(assert_eq!, vec!)。

drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns327–342 ↗
fn drop_last_n_user_turns_treats_inter_agent_assistant_messages_as_instruction_turns()

作用:测试回滚最后一轮用户指令时,多智能体 assistant 消息也算一轮可回滚的指令。

数据流:构造普通用户轮次和多智能体轮次 → 删除最后 1 个用户轮次 → 断言只剩第一轮。

调用关系:它用多个消息工厂搭历史,然后把核心动作交给 drop_last_n_user_turns。

调用图:调用 4 个内部函数(assistant_msg, create_history_with_items, inter_agent_assistant_msg, user_input_text_msg);外部调用 2 个(assert_eq!, vec!)。

legacy_inter_agent_assistant_messages_are_not_turn_boundaries345–351 ↗
fn legacy_inter_agent_assistant_messages_are_not_turn_boundaries()

作用:测试旧格式的多智能体文字不会被误认为新版轮次边界。

数据流:创建一条看起来像旧格式协议的普通 assistant 文本 → 调 is_user_turn_boundary → 断言为假。

调用关系:它用 assistant_msg 造旧文本,保护边界识别逻辑不要过度匹配。

调用图:调用 1 个内部函数(assistant_msg);外部调用 1 个(assert!)。

total_token_usage_includes_all_items_after_last_model_generated_item354–375 ↗
fn total_token_usage_includes_all_items_after_last_model_generated_item()

作用:测试总 token 用量会把 API 已报告的用量和最后模型输出后的本地新增项加在一起。

数据流:先记录 assistant 并写入总 token 100 → 再记录用户和工具输出 → 调 get_total_token_usage → 断言等于 100 加新增项估算。

调用关系:它验证 update_token_info、record_items 和新增项估算之间的配合。

调用图:调用 3 个内部函数(create_history_with_items, custom_tool_call_output, user_msg);外部调用 4 个(default, assert_eq!, Tokens, vec!)。

for_prompt_strips_images_when_model_does_not_support_images378–536 ↗
fn for_prompt_strips_images_when_model_does_not_support_images()

作用:测试模型不支持图片输入时,prompt 里的图片会被文字占位提示替换;支持图片时则保留原图。

数据流:构造用户图片、函数输出图片、自定义工具输出图片 → 用纯文本 modality 调 for_prompt → 断言图片变成说明文字;再用默认 modality 断言图片保留。

调用关系:它直接验证 for_prompt 对输入能力的适配,避免把模型看不懂的图片发过去。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 4 个(assert!, assert_eq!, panic!, vec!)。

for_prompt_preserves_image_generation_calls_when_images_are_supported539–580 ↗
fn for_prompt_preserves_image_generation_calls_when_images_are_supported()

作用:测试当模型支持图片时,图片生成调用的结果不会被清空。

数据流:构造 ImageGenerationCall 和用户消息 → 创建历史 → 用默认输入能力生成 prompt → 断言图片生成项完整保留。

调用关系:它验证 for_prompt 在支持图像的模型路径上不破坏图像生成记录。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

for_prompt_clears_image_generation_result_when_images_are_unsupported583–624 ↗
fn for_prompt_clears_image_generation_result_when_images_are_unsupported()

作用:测试当模型不支持图片时,图片生成调用里的图片结果会被清空,只保留调用信息。

数据流:构造用户请求和已完成的图片生成结果 → 用纯文本能力生成 prompt → 断言 result 变成空字符串。

调用关系:它验证 for_prompt 的降级行为,避免把不能处理的图片数据塞给纯文本模型。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

estimate_token_count_with_base_instructions_uses_provided_text627–646 ↗
fn estimate_token_count_with_base_instructions_uses_provided_text()

作用:测试估算 token 时确实使用传入的基础指令文本,而不是固定值或忽略它。

数据流:创建相同历史,分别传短基础指令和长基础指令 → 得到两个估算 → 断言差值等于文本长度带来的估算差。

调用关系:它调用 approx_token_count_for_text 计算预期差异,检查 ContextManager 的基础指令计数入口。

调用图:调用 2 个内部函数(approx_token_count_for_text, create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

remove_first_item_removes_matching_output_for_function_call649–668 ↗
fn remove_first_item_removes_matching_output_for_function_call()

作用:测试删除第一项如果删掉函数调用,也会一起删掉匹配的函数输出。

数据流:构造 FunctionCall 和同 call_id 的 FunctionCallOutput → 删除第一项 → 断言历史为空。

调用关系:它验证 remove_first_item 不会留下孤零零的工具输出。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

remove_first_item_removes_matching_call_for_output671–690 ↗
fn remove_first_item_removes_matching_call_for_output()

作用:测试第一项是函数输出时,也会删除后面匹配的函数调用。

数据流:构造输出在前、调用在后的配对 → 删除第一项 → 断言两者都被移除。

调用关系:它覆盖配对项顺序反过来的情况,仍然走 remove_first_item。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

replace_last_turn_images_replaces_tool_output_images693–732 ↗
fn replace_last_turn_images_replaces_tool_output_images()

作用:测试最后一轮里的工具输出图片可以被替换成错误文字,比如图片无效时给模型一个说明。

数据流:构造用户消息和带图片的函数输出 → 调 replace_last_turn_images("Invalid image") → 断言图片内容变成 InputText。

调用关系:它验证图片修复路径只改最后一轮工具输出中的图片。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 3 个(assert!, assert_eq!, vec!)。

replace_last_turn_images_does_not_touch_user_images735–750 ↗
fn replace_last_turn_images_does_not_touch_user_images()

作用:测试替换最后一轮图片时,不会改用户自己上传的图片。

数据流:构造只有用户图片的历史 → 调 replace_last_turn_images → 返回 false,并断言历史不变。

调用关系:它保护用户原始输入不被工具输出修复逻辑误伤。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 3 个(assert!, assert_eq!, vec!)。

remove_first_item_handles_local_shell_pair753–777 ↗
fn remove_first_item_handles_local_shell_pair()

作用:测试删除本地 shell 调用时,会连同对应输出一起删除。shell 调用就是在本机执行命令。

数据流:构造 LocalShellCall 和同 call_id 的 FunctionCallOutput → 调 remove_first_item → 断言历史为空。

调用关系:它把本地命令这种特殊工具调用也纳入 remove_first_item 的配对删除规则。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

drop_last_n_user_turns_preserves_prefix780–813 ↗
fn drop_last_n_user_turns_preserves_prefix()

作用:测试回滚用户轮次时,会保留会话开头的前缀内容。

数据流:构造前缀 assistant、两轮用户和助手 → 删除最后 1 轮或很多轮 → 断言前缀始终留下,用户轮次按要求删掉。

调用关系:它验证 drop_last_n_user_turns 不会把会话启动时的固定上下文一起清掉。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

drop_last_n_user_turns_ignores_session_prefix_user_messages816–913 ↗
fn drop_last_n_user_turns_ignores_session_prefix_user_messages()

作用:测试某些看起来像用户消息的会话前缀不会被当成普通用户轮次删除。

数据流:构造环境上下文、AGENTS 指令、技能、用户 shell 命令、子代理通知等前缀,再加两轮真实对话 → 回滚 1、2、3 轮 → 断言前缀保留。

调用关系:它验证 drop_last_n_user_turns 能区分“初始化材料”和“真实用户提问”。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

drop_last_n_user_turns_trims_context_updates_above_rolled_back_turn916–951 ↗
fn drop_last_n_user_turns_trims_context_updates_above_rolled_back_turn()

作用:测试回滚上一轮时,会剪掉那一轮上方的临时上下文更新,但保留更早的持久开发者说明。

数据流:构造第一轮、开发者说明、回滚标记、环境差异和第二轮 → 设置参考上下文 → 回滚最后一轮 → 断言只剩早期内容和应保留的开发者说明。

调用关系:它用 reference_context_item 配合 drop_last_n_user_turns,检查回滚时上下文快照是否仍正确。

调用图:调用 3 个内部函数(create_history_with_items, reference_context_item, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

drop_last_n_user_turns_clears_reference_context_for_mixed_developer_context_bundles954–982 ↗
fn drop_last_n_user_turns_clears_reference_context_for_mixed_developer_context_bundles()

作用:测试如果开发者消息里混有临时权限说明和持久插件说明,回滚后会清掉参考上下文,避免上下文含糊。

数据流:构造第一轮、混合开发者消息、环境差异和第二轮 → 设置参考上下文 → 回滚最后一轮 → 断言只剩第一轮且 reference_context_item 为空。

调用关系:它使用 developer_msg_with_fragments 和 reference_context_item,验证保守处理混合上下文的规则。

调用图:调用 3 个内部函数(create_history_with_items, reference_context_item, default_input_modalities);外部调用 3 个(assert!, assert_eq!, vec!)。

remove_first_item_handles_custom_tool_pair985–1005 ↗
fn remove_first_item_handles_custom_tool_pair()

作用:测试删除自定义工具调用时,会一起删除对应的自定义工具输出。

数据流:构造 CustomToolCall 和同 call_id 的 CustomToolCallOutput → 调 remove_first_item → 断言历史为空。

调用关系:它让 remove_first_item 的配对删除规则覆盖自定义工具类型。

调用图:调用 1 个内部函数(create_history_with_items);外部调用 2 个(assert_eq!, vec!)。

normalization_retains_local_shell_outputs1008–1034 ↗
fn normalization_retains_local_shell_outputs()

作用:测试历史规范化不会误删本地 shell 的正常输出。

数据流:构造 LocalShellCall 和对应输出 → 调 for_prompt 触发整理后的视图 → 断言输出仍然存在。

调用关系:它检查 normalize/for_prompt 路径不要把合法命令输出当孤儿项删除。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

record_items_truncates_function_call_output_content1037–1074 ↗
fn record_items_truncates_function_call_output_content()

作用:测试记录函数调用输出时,太长的内容会按 token 限制截短,并保留 turn_id 元数据。

数据流:构造超长 FunctionCallOutput → 用 1000 token 策略 record_items → 断言存入内容被截短、含 truncated 标记,且 turn_id 没丢。

调用关系:它直接测试 ContextManager::record_items 对普通函数输出的保护性裁剪。

调用图:调用 1 个内部函数(new);外部调用 6 个(assert!, assert_eq!, assert_ne!, panic!, Text, Tokens)。

record_items_truncates_custom_tool_call_output_content1077–1107 ↗
fn record_items_truncates_custom_tool_call_output_content()

作用:测试自定义工具输出太长时也会被截短。

数据流:构造超长 CustomToolCallOutput → record_items → 检查保存的文本不同于原文,并包含裁剪提示。

调用关系:它和函数输出裁剪测试成对存在,覆盖自定义工具输出路径。

调用图:调用 2 个内部函数(new, from_text);外部调用 5 个(assert!, assert_eq!, assert_ne!, panic!, Tokens)。

record_items_respects_custom_token_limit1110–1134 ↗
fn record_items_respects_custom_token_limit()

作用:测试 record_items 会尊重调用者给的更小 token 上限。

数据流:用 10 token 策略记录一段很长函数输出 → 读取保存内容 → 断言里面有 tokens truncated 标记。

调用关系:它验证裁剪策略不是写死的,而是由传入的 TruncationPolicy 控制。

调用图:调用 1 个内部函数(new);外部调用 4 个(assert!, panic!, Text, Tokens)。

assert_truncated_message_matches1136–1160 ↗
fn assert_truncated_message_matches(message: &str, line: &str, expected_removed: usize)

作用:检查被截短的文本是否符合统一格式,并确认删除的 token 数正确。

数据流:输入截短消息、预期开头行和预期删除数量 → 生成正则表达式匹配消息 → 验证正文长度和 removed 数字。

调用关系:命令输出裁剪测试都把结果交给它做统一验收;它内部调用 truncated_message_pattern。

调用图:调用 1 个内部函数(truncated_message_pattern);被 4 处调用(format_exec_output_marks_byte_truncation_without_omitted_lines, format_exec_output_prefers_line_marker_when_both_limits_exceeded, format_exec_output_reports_omitted_lines_and_keeps_head_and_tail, format_exec_output_truncates_large_error);外部调用 3 个(new, assert!, assert_eq!)。

truncated_message_pattern1162–1165 ↗
fn truncated_message_pattern(line: &str) -> String

作用:生成一个用来匹配截短提示的正则表达式。正则表达式就是按规则找文字的“小筛子”。

数据流:输入应保留的开头行 → 先转义特殊字符 → 拼出能捕获正文和删除 token 数的匹配模式。

调用关系:只被 assert_truncated_message_matches 使用,帮助测试识别 truncate_text 的输出格式。

调用图:被 1 处调用(assert_truncated_message_matches);外部调用 2 个(format!, escape)。

format_exec_output_truncates_large_error1168–1176 ↗
fn format_exec_output_truncates_large_error()

作用:测试非常长的错误输出会被截短,而不是完整塞进历史。

数据流:生成重复很多次的错误行 → 调 truncate_exec_output → 验证格式和删除数量,并确认结果不同于原文。

调用关系:它通过 truncate_exec_output 测实际裁剪,再交给 assert_truncated_message_matches 检查。

调用图:调用 2 个内部函数(assert_truncated_message_matches, truncate_exec_output);外部调用 1 个(assert_ne!)。

format_exec_output_marks_byte_truncation_without_omitted_lines1179–1188 ↗
fn format_exec_output_marks_byte_truncation_without_omitted_lines()

作用:测试单行过长导致截短时,不应该出现“省略了若干行”的提示。

数据流:生成一条超长单行 → 截短 → 验证 token 删除数量,并断言没有 omitted 字样。

调用关系:它覆盖字节/长度限制触发但没有删行的特殊情况。

调用图:调用 2 个内部函数(assert_truncated_message_matches, truncate_exec_output);外部调用 2 个(assert!, assert_ne!)。

format_exec_output_returns_original_when_within_limits1191–1194 ↗
fn format_exec_output_returns_original_when_within_limits()

作用:测试输出不长时,裁剪函数应该原样返回。

数据流:生成较短内容 → 调截短函数的等价路径 → 断言返回值和输入完全一样。

调用关系:它保护 truncate_text 不要对正常大小的内容做多余修改。

调用图:外部调用 1 个(assert_eq!)。

format_exec_output_reports_omitted_lines_and_keeps_head_and_tail1197–1216 ↗
fn format_exec_output_reports_omitted_lines_and_keeps_head_and_tail()

作用:测试很多行的输出被截短时,会保留开头和结尾,方便读者知道前因后果。

数据流:生成 2000 行内容 → 截短 → 验证截短标记,并断言第一行和最后一行的线索都还在。

调用关系:它确认 truncate_exec_output 的“保头保尾”策略。

调用图:调用 2 个内部函数(assert_truncated_message_matches, truncate_exec_output);外部调用 2 个(assert!, format!)。

format_exec_output_prefers_line_marker_when_both_limits_exceeded1219–1229 ↗
fn format_exec_output_prefers_line_marker_when_both_limits_exceeded()

作用:测试当行数和大小都超限时,裁剪提示采用预期的格式。

数据流:生成既多行又每行很长的内容 → 截短 → 用统一检查函数验证删除 token 数。

调用关系:它覆盖多个限制同时触发时的优先规则。

调用图:调用 2 个内部函数(assert_truncated_message_matches, truncate_exec_output)。

normalize_adds_missing_output_for_function_call1233–1264 ↗
fn normalize_adds_missing_output_for_function_call()

作用:测试发布版里历史规范化会给缺少输出的函数调用补一个 aborted 输出。

数据流:构造只有 FunctionCall 的历史 → normalize_history → 断言后面补上 FunctionCallOutput("aborted")。

调用关系:它在非 debug 构建下运行,验证线上容错会修补不完整工具调用。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_adds_missing_output_for_custom_tool_call1268–1300 ↗
fn normalize_adds_missing_output_for_custom_tool_call()

作用:测试发布版里自定义工具调用缺输出时会自动补 aborted。

数据流:构造只有 CustomToolCall 的历史 → normalize_history → 断言补上 CustomToolCallOutput。

调用关系:它覆盖自定义工具的规范化修补路径,只在非 debug 下启用。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_adds_missing_output_for_local_shell_call_with_id1304–1345 ↗
fn normalize_adds_missing_output_for_local_shell_call_with_id()

作用:测试发布版里本地 shell 调用有 call_id 但没输出时,会补一个 aborted 输出。

数据流:构造只有 LocalShellCall 的历史 → normalize_history → 断言补上对应 FunctionCallOutput。

调用关系:它检查本地命令调用也能被规范化逻辑修复。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_removes_orphan_function_call_output1349–1360 ↗
fn normalize_removes_orphan_function_call_output()

作用:测试发布版里没有对应函数调用的函数输出会被删除。

数据流:构造孤立 FunctionCallOutput → normalize_history → 断言历史为空。

调用关系:它验证规范化会清理孤儿输出,避免发给模型一段没来由的结果。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_removes_orphan_custom_tool_call_output1364–1376 ↗
fn normalize_removes_orphan_custom_tool_call_output()

作用:测试发布版里没有对应调用的自定义工具输出会被删除。

数据流:构造孤立 CustomToolCallOutput → normalize_history → 断言被清空。

调用关系:它让孤儿清理规则覆盖自定义工具输出。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_mixed_inserts_and_removals1380–1475 ↗
fn normalize_mixed_inserts_and_removals()

作用:测试发布版规范化能同时处理缺输出和孤儿输出。

数据流:构造一个缺输出函数调用、一个孤儿输出、一个缺输出自定义工具、一个缺输出 shell 调用 → normalize_history → 断言补该补的、删该删的。

调用关系:它是综合场景,验证 normalize_history 多条规则一起工作时顺序正确。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_adds_missing_output_for_function_call_inserts_output1478–1507 ↗
fn normalize_adds_missing_output_for_function_call_inserts_output()

作用:测试通用规范化路径会给缺少输出的函数调用插入 aborted 输出。

数据流:构造只有 FunctionCall 的历史 → 调 normalize_history → 断言插入对应 FunctionCallOutput。

调用关系:它和条件编译版本类似,用来保证当前构建下这个插入行为存在。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_adds_missing_output_for_tool_search_call1510–1543 ↗
fn normalize_adds_missing_output_for_tool_search_call()

作用:测试工具搜索调用缺少输出时,会补一个空的搜索输出。

数据流:构造 ToolSearchCall → normalize_history → 断言后面出现 ToolSearchOutput,状态和执行端匹配、工具列表为空。

调用关系:它把工具搜索这种调用类型纳入规范化补全规则。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_adds_missing_output_for_custom_tool_call_panics_in_debug1548–1559 ↗
fn normalize_adds_missing_output_for_custom_tool_call_panics_in_debug()

作用:测试 debug 模式下,自定义工具调用缺输出会直接 panic。panic 可以理解为测试期故意报错,逼开发者修正问题。

数据流:构造缺输出 CustomToolCall → 调 normalize_history → 预期程序在测试中崩溃。

调用关系:它只在 debug 构建启用,和发布版自动修复测试形成对照。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

normalize_adds_missing_output_for_local_shell_call_with_id_panics_in_debug1564–1580 ↗
fn normalize_adds_missing_output_for_local_shell_call_with_id_panics_in_debug()

作用:测试 debug 模式下,本地 shell 调用缺输出会 panic。

数据流:构造带 call_id 但无输出的 LocalShellCall → normalize_history → 预期 panic。

调用关系:它帮助开发阶段尽早发现不完整的命令调用记录。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

normalize_removes_orphan_function_call_output_panics_in_debug1585–1593 ↗
fn normalize_removes_orphan_function_call_output_panics_in_debug()

作用:测试 debug 模式下,孤立函数输出会 panic,而不是悄悄删除。

数据流:构造没有匹配调用的 FunctionCallOutput → normalize_history → 预期 panic。

调用关系:它和发布版清理孤儿输出的行为相对,强调开发期严格检查。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

normalize_removes_orphan_custom_tool_call_output_panics_in_debug1598–1607 ↗
fn normalize_removes_orphan_custom_tool_call_output_panics_in_debug()

作用:测试 debug 模式下,孤立自定义工具输出会 panic。

数据流:构造孤立 CustomToolCallOutput → normalize_history → 预期 panic。

调用关系:它确保开发环境不会掩盖自定义工具调用配对错误。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

normalize_removes_orphan_client_tool_search_output1611–1624 ↗
fn normalize_removes_orphan_client_tool_search_output()

作用:测试发布版里客户端执行的孤立工具搜索输出会被删除。

数据流:构造 execution 为 client 的孤立 ToolSearchOutput → normalize_history → 断言历史为空。

调用关系:它验证客户端工具搜索输出必须有对应调用。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_removes_orphan_client_tool_search_output_panics_in_debug1629–1639 ↗
fn normalize_removes_orphan_client_tool_search_output_panics_in_debug()

作用:测试 debug 模式下,客户端工具搜索孤儿输出会 panic。

数据流:构造孤立 client ToolSearchOutput → normalize_history → 预期 panic。

调用关系:它和发布版自动删除形成对照,保证开发期更严格。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

normalize_keeps_server_tool_search_output_without_matching_call1642–1664 ↗
fn normalize_keeps_server_tool_search_output_without_matching_call()

作用:测试服务端执行的工具搜索输出即使没有本地匹配调用,也会保留。

数据流:构造 execution 为 server 的 ToolSearchOutput → normalize_history → 断言原样保留。

调用关系:它说明规范化规则区分 client 和 server,因为服务端结果可能本来就没有本地调用记录。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 2 个(assert_eq!, vec!)。

normalize_mixed_inserts_and_removals_panics_in_debug1669–1708 ↗
fn normalize_mixed_inserts_and_removals_panics_in_debug()

作用:测试 debug 模式下,混合的不完整调用和孤儿输出会触发 panic。

数据流:构造缺输出函数调用、孤儿函数输出、缺输出自定义工具和缺输出 shell → normalize_history → 预期 panic。

调用关系:它是 debug 严格检查的综合场景,防止多种历史损坏被忽略。

调用图:调用 2 个内部函数(create_history_with_items, default_input_modalities);外部调用 1 个(vec!)。

image_data_url_payload_does_not_dominate_message_estimate1711–1747 ↗
fn image_data_url_payload_does_not_dominate_message_estimate()

作用:测试消息里的 base64 图片不会按原始超长字符串完整计入可见字节估算。

数据流:构造带 100000 字符图片 payload 的用户消息 → 算原始 JSON 长度和模型可见估算 → 断言估算用固定图片成本替代原 payload。

调用关系:它验证 estimate_response_item_model_visible_bytes 对普通消息图片的特殊估算。

调用图:外部调用 5 个(assert!, assert_eq!, format!, to_string, vec!)。

image_data_url_payload_does_not_dominate_function_call_output_estimate1750–1773 ↗
fn image_data_url_payload_does_not_dominate_function_call_output_estimate()

作用:测试函数输出里的 base64 图片也不会把估算撑得过大。

数据流:构造含图片内容项的 FunctionCallOutput → 比较原始长度和估算长度 → 断言 payload 被固定图片成本替换。

调用关系:它覆盖函数输出内容项里的图片估算路径。

调用图:调用 1 个内部函数(from_content_items);外部调用 5 个(assert!, assert_eq!, format!, to_string, vec!)。

image_data_url_payload_does_not_dominate_custom_tool_call_output_estimate1776–1800 ↗
fn image_data_url_payload_does_not_dominate_custom_tool_call_output_estimate()

作用:测试自定义工具输出里的 base64 图片同样按图片成本估算,而不是按字符串长度。

数据流:构造含图片的 CustomToolCallOutput → 计算 raw_len 和 estimated → 断言估算低于原始长度且符合公式。

调用关系:它覆盖自定义工具输出内容项的图片估算路径。

调用图:调用 1 个内部函数(from_content_items);外部调用 5 个(assert!, assert_eq!, format!, to_string, vec!)。

non_base64_image_urls_are_unchanged1803–1833 ↗
fn non_base64_image_urls_are_unchanged()

作用:测试普通网址或文件路径图片不会被当成内联 base64 图片改估算。

数据流:构造 https 图片消息和 file 图片函数输出 → 估算可见字节 → 断言等于原始 JSON 长度。

调用关系:它保护估算逻辑只处理真正的 base64 data URL。

调用图:调用 1 个内部函数(from_content_items);外部调用 2 个(assert_eq!, vec!)。

encrypted_function_output_uses_plaintext_byte_estimate1836–1854 ↗
fn encrypted_function_output_uses_plaintext_byte_estimate()

作用:测试加密函数输出会用估算出的明文字节长度替代加密字符串长度。

数据流:构造含 encrypted_content 的 FunctionCallOutput → 计算原始长度、估算长度和预期替换长度 → 断言一致。

调用关系:它验证 estimate_encrypted_function_output_length 和整体字节估算的配合。

调用图:调用 1 个内部函数(from_content_items);外部调用 3 个(assert_eq!, to_string, vec!)。

data_url_without_base64_marker_is_unchanged1857–1873 ↗
fn data_url_without_base64_marker_is_unchanged()

作用:测试 data URL 如果没有 base64 标记,就不会被图片 payload 规则处理。

数据流:构造 data:image/svg+xml 但非 base64 的图片消息 → 估算字节 → 断言等于原始 JSON 长度。

调用关系:它防止估算逻辑误判非 base64 的 data URL。

调用图:外部调用 2 个(assert_eq!, vec!)。

non_image_base64_data_url_is_unchanged1876–1894 ↗
fn non_image_base64_data_url_is_unchanged()

作用:测试虽然是 base64 data URL,但不是 image 类型时,不会套用图片估算规则。

数据流:构造 data:application/octet-stream;base64 的内容 → 估算字节 → 断言等于原始长度。

调用关系:它确保只有图片媒体类型才会被当作图片成本处理。

调用图:调用 1 个内部函数(from_content_items);外部调用 4 个(assert_eq!, format!, to_string, vec!)。

mixed_case_data_url_markers_are_adjusted1897–1916 ↗
fn mixed_case_data_url_markers_are_adjusted()

作用:测试 DATA 和 BASE64 大小写混用时,仍能识别为图片 data URL。

数据流:构造大写标记的 data:image/png;BASE64 URL → 估算字节 → 断言 payload 被替换成固定图片成本。

调用关系:它验证图片 URL 识别大小写不敏感。

调用图:外部调用 4 个(assert_eq!, format!, to_string, vec!)。

multiple_inline_images_apply_multiple_fixed_costs1919–1950 ↗
fn multiple_inline_images_apply_multiple_fixed_costs()

作用:测试一条消息里有多张内联图片时,每张图片都会单独计一次固定成本。

数据流:构造含两张 base64 图片的消息 → 算原始长度、payload 总长和估算 → 断言估算加了两份图片成本。

调用关系:它覆盖多图片场景,防止只处理第一张或少算。

调用图:外部调用 4 个(assert_eq!, format!, to_string, vec!)。

original_detail_images_scale_with_dimensions1953–1983 ↗
fn original_detail_images_scale_with_dimensions()

作用:测试 original 细节等级的图片会按图片尺寸估算成本,而不是固定成本。

数据流:生成 2304x864 PNG 图片并转 base64 → 放进 FunctionCallOutput → 估算字节 → 断言按 32 像素 patch 数得出预期成本。

调用关系:它验证原始细节图片的尺寸解析和 patch 计费启发式。patch 可理解为把图片切成小格来估算成本。

调用图:调用 2 个内部函数(from_content_items, new);外部调用 7 个(from_pixel, new, assert_eq!, format!, Rgba, to_string, vec!)。

original_detail_images_are_capped_at_max_patch_count1986–2016 ↗
fn original_detail_images_are_capped_at_max_patch_count()

作用:测试 original 图片太大时,估算成本会被最大 patch 数封顶。

数据流:生成 3201x3201 PNG → 转 base64 并估算 → 断言成本不超过 ORIGINAL_IMAGE_MAX_PATCHES 对应字节数。

调用关系:它保护超大图片不会让估算无限增长。

调用图:调用 2 个内部函数(from_content_items, new);外部调用 8 个(from_pixel, new, assert_eq!, format!, try_from, Luma, to_string, vec!)。

original_detail_webp_images_scale_with_dimensions2019–2048 ↗
fn original_detail_webp_images_scale_with_dimensions()

作用:测试 WebP 格式的 original 图片也能按尺寸估算成本。

数据流:生成和 PNG 测试同尺寸的 WebP → 放进输出项 → 估算字节 → 断言得到同样的尺寸成本。

调用关系:它确认尺寸估算不只支持 PNG,也支持 WebP。

调用图:调用 2 个内部函数(from_content_items, new);外部调用 7 个(from_pixel, new, assert_eq!, format!, Rgba, to_string, vec!)。

text_only_items_unchanged2051–2066 ↗
fn text_only_items_unchanged()

作用:测试纯文本消息的可见字节估算就是原始 JSON 长度,不会被图片或加密规则影响。

数据流:构造 assistant 纯文本消息 → 估算可见字节并计算原始长度 → 断言两者相等。

调用关系:它作为基准测试,说明特殊估算只作用于图片和加密内容等特殊情况。

调用图:外部调用 3 个(assert_eq!, to_string, vec!)。

core/src/event_mapping_tests.rs源码 ↗
testtest

这个文件像一张“验货清单”。程序会收到很多种 ResponseItem,也就是模型或系统吐出来的原始内容;真正给界面和后续流程使用前,要靠 parse_turn_item 把它们变成 TurnItem,也就是内部统一的“这一轮发生了什么”。这些测试逐个模拟常见和容易出错的情况:普通用户文字加图片、图片旁边自动生成的标签、助手消息、推理摘要、网页搜索动作、钩子提示,以及各种不该给用户看的上下文片段。它还检查一些“兼容旧格式”的行为,比如助手消息里仍然可能出现 InputText。整体目标很直接:保证该显示的留下,不该显示的过滤掉;复杂输入被整理成清楚、稳定的内部格式。

函数细节17
recognizes_skills_instructions_as_contextual_developer_content23–29 ↗
fn recognizes_skills_instructions_as_contextual_developer_content()

作用:这个测试确认“技能说明”会被识别成上下文里的开发者内容,而不是普通用户聊天内容。这样可以避免把系统给模型看的说明误当成用户说的话。

数据流:它准备一段以技能说明开头标记开头的文字 → 交给识别函数判断 → 期望结果为真,表示这段内容确实属于隐藏的上下文说明。

调用关系:测试运行器执行它时,它只做一个断言检查;这个检查围绕 is_contextual_dev_message_content 展开,确保事件翻译流程以后遇到技能说明时能正确归类。

调用图:外部调用 1 个(assert!)。

recognizes_token_budget_as_contextual_developer_content32–40 ↗
fn recognizes_token_budget_as_contextual_developer_content()

作用:这个测试确认“剩余 token 数量提示”会被当成上下文内容,而不是正常聊天内容。token 可以理解成模型读写文字时用的小单位,这类预算提示是给系统看的,不该展示给用户。

数据流:它构造一段 token_budget 标签包起来的文字 → 分别检查它是否属于上下文内容、是否不含普通开发者内容 → 期望前者为真、后者为真。

调用关系:测试运行器执行它时,它会调用上下文识别相关函数,并用断言守住一个边界:预算提示应该被隐藏,不应该混进可见对话。

调用图:外部调用 2 个(assert!, vec!)。

parses_user_message_with_text_and_two_images43–89 ↗
fn parses_user_message_with_text_and_two_images()

作用:这个测试确认用户一条消息里同时有文字和两张图片时,程序能完整保留下来。没有这个保证,图片可能丢失,或者顺序被弄乱。

数据流:它先造出一个用户消息,里面有一段文字和两个图片地址 → 调用 parse_turn_item 做转换 → 得到内部的 UserMessage,并检查内容顺序仍是文字、第一张图、第二张图。

调用关系:测试运行器触发它后,它把模拟的 ResponseItem 交给 parse_turn_item;parse_turn_item 像翻译员一样把外部格式翻成 TurnItem,最后由 assert_eq 检查翻译结果。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

skips_local_image_label_text92–135 ↗
fn skips_local_image_label_text()

作用:这个测试确认本地图片前后那些自动生成的标签文字会被跳过,只保留真正的图片和用户文字。这样界面不会显示类似“图片路径标签”这种用户并没有真正输入的噪音。

数据流:它构造一条用户消息:先有图片开始标签,再有图片数据,再有结束标签,最后有用户真正的话 → 调用 parse_turn_item → 期望输出里只剩图片和“请查看这张图片”这类真实文字。

调用关系:测试运行器执行它时,它专门验证 parse_turn_item 的清理能力;如果清理失败,assert_eq 会指出输出多了不该给用户看的标签。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

parses_assistant_message_input_text_for_backward_compatibility138–172 ↗
fn parses_assistant_message_input_text_for_backward_compatibility()

作用:这个测试确认旧格式里的助手消息即使写成 InputText,也仍然能被当作助手回复读取。向后兼容的意思是:老数据或老版本产生的记录,新代码也要能看懂。

数据流:它准备一条角色为 assistant、内容却是 InputText 的消息 → 调用 parse_turn_item → 期望得到 AgentMessage,并且文本内容原样保留。

调用关系:测试运行器执行它时,它把一个“旧式但仍可能出现”的输入交给 parse_turn_item;这个测试防止后续改代码时只支持新格式,导致历史会话读不出来。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

skips_unnamed_image_label_text175–218 ↗
fn skips_unnamed_image_label_text()

作用:这个测试确认没有名字的图片标签也会被过滤掉。也就是说,不管图片标签有没有文件名,用户真正想看的都只是图片和自己的文字。

数据流:它通过 image_open_tag_text 生成默认图片开始标签,再放入图片、图片结束标签和用户文字 → 调用 parse_turn_item → 检查结果只包含图片和用户文字。

调用关系:测试运行器执行它时,它依赖 image_open_tag_text 生成协议里的标准标签,再让 parse_turn_item 处理;最后用断言确认标签没有混进可见聊天。

调用图:调用 1 个内部函数(image_open_tag_text);外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

skips_user_instructions_and_env221–285 ↗
fn skips_user_instructions_and_env()

作用:这个测试确认用户消息里那些其实是系统上下文的片段会被整条跳过。比如 AGENTS.md 指令、环境信息、技能定义、用户 shell 命令记录,这些都不是普通聊天展示内容。

数据流:它准备多条看起来像用户消息、但内容是说明书或环境上下文的 ResponseItem → 逐条调用 parse_turn_item → 每一条都应该得到空结果,表示不生成可见的 TurnItem。

调用关系:测试运行器执行它时,它用一组输入集中检查过滤规则;parse_turn_item 是被考察的入口,assert 保证这些内部提示不会流到聊天记录里。

调用图:外部调用 3 个(assert!, parse_turn_item, vec!)。

parses_hook_prompt_message_as_distinct_turn_item288–310 ↗
fn parses_hook_prompt_message_as_distinct_turn_item()

作用:这个测试确认“钩子提示”会被解析成专门的 HookPrompt,而不是普通用户消息。钩子可以理解成某个自动步骤插进来的提示,它需要单独标记来源。

数据流:它用 build_hook_prompt_message 和 from_single_hook 造出一条钩子提示消息 → 调用 parse_turn_item → 检查结果是 HookPrompt,并且里面的提示文字和 hook_run_id 都准确保留。

调用关系:测试运行器执行它时,先借助构造函数生成合法的钩子消息,再交给 parse_turn_item;这个测试确保钩子提示在内部流程里有自己的身份。

调用图:调用 1 个内部函数(build_hook_prompt_message);外部调用 4 个(from_single_hook, assert_eq!, panic!, parse_turn_item)。

parses_hook_prompt_and_hides_other_contextual_fragments313–345 ↗
fn parses_hook_prompt_and_hides_other_contextual_fragments()

作用:这个测试确认一条消息里既有环境上下文又有钩子提示时,只把钩子提示拿出来,其他上下文隐藏掉。这样既不丢掉重要提示,也不泄露背景信息。

数据流:它构造一条用户消息,先放环境上下文,再放带 hook_run_id 的 hook_prompt 标签 → 调用 parse_turn_item → 期望得到 HookPrompt,文本里的 HTML 转义也被还原成普通字符。

调用关系:测试运行器执行它时,它把混合内容交给 parse_turn_item;断言检查解析结果只留下该留下的钩子片段,而环境上下文没有变成可见内容。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

internal_model_context_does_not_parse_as_visible_turn_item348–364 ↗
fn internal_model_context_does_not_parse_as_visible_turn_item()

作用:这个测试确认内部模型上下文不会被解析成可见聊天条目。内部模型上下文就是系统悄悄给模型的引导信息,不应出现在用户看到的对话里。

数据流:它用 InternalModelContextFragment 构造一段内部引导文字,并放进用户消息格式里 → 检查解析结果为空 → 表示这段内容被正确隐藏。

调用关系:测试运行器执行它时,它重点守住“内部信息不可见”这条线;断言会在内部上下文被错误转成 TurnItem 时失败。

调用图:外部调用 2 个(assert!, vec!)。

parses_agent_message367–389 ↗
fn parses_agent_message()

作用:这个测试确认助手正常输出的文字会被解析成 AgentMessage。AgentMessage 可以理解成“模型助手说的话”。

数据流:它构造一条 assistant 角色、内容为 OutputText 的消息 → 调用 parse_turn_item → 检查得到的 AgentMessage 第一段文字就是原来的“Hello from Codex”。

调用关系:测试运行器执行它时,它验证最基础的助手回复路径;parse_turn_item 完成格式转换,assert_eq 检查文本没有变形。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

parses_reasoning_summary_and_raw_content392–422 ↗
fn parses_reasoning_summary_and_raw_content()

作用:这个测试确认模型的推理信息能同时保留摘要和原始内容。摘要是简短说明,原始内容是更细的文本记录。

数据流:它构造一个 Reasoning 项,里面有两个摘要片段和一段原始推理文字 → 调用 parse_turn_item → 期望得到 Reasoning,并分别填好 summary_text 和 raw_content。

调用关系:测试运行器执行它时,它把推理类 ResponseItem 交给 parse_turn_item;这个测试保证推理展示或调试所需的两类文本不会互相覆盖。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

parses_reasoning_including_raw_content425–455 ↗
fn parses_reasoning_including_raw_content()

作用:这个测试确认推理原始内容里不同类型的文字都能被收集起来。不管它标成 ReasoningText 还是 Text,只要是可用文字,都应该进入原始内容列表。

数据流:它准备一个 Reasoning 项,摘要是一句,原始内容里有 raw step 和 final thought 两段 → 调用 parse_turn_item → 检查摘要单独保存,两个原始文本按顺序保存。

调用关系:测试运行器执行它时,它继续验证 parse_turn_item 对推理数据的整理规则;assert_eq 保证不同文字类型不会被漏掉。

调用图:外部调用 4 个(assert_eq!, panic!, parse_turn_item, vec!)。

parses_web_search_call458–485 ↗
fn parses_web_search_call()

作用:这个测试确认普通网页搜索动作会被解析成 WebSearch 条目,并把搜索词提取出来。这样聊天记录或界面就能显示“模型搜索了什么”。

数据流:它构造一个已完成的 WebSearchCall,动作是 Search,查询词是 weather → 调用 parse_turn_item → 期望得到 WebSearchItem,id、query 和原始 action 都正确。

调用关系:测试运行器执行它时,它把网页搜索调用交给 parse_turn_item;断言检查搜索动作没有被当成普通消息,也没有丢掉查询词。

调用图:外部调用 3 个(assert_eq!, panic!, parse_turn_item)。

parses_web_search_open_page_call488–513 ↗
fn parses_web_search_open_page_call()

作用:这个测试确认“打开网页”这种网页搜索动作也能变成 WebSearch 条目。这里 query 字段会用网址表示,方便统一展示。

数据流:它构造一个 WebSearchCall,动作是 OpenPage,网址是 https://example.com → 调用 parse_turn_item → 期望得到 WebSearchItem,query 被设置成这个网址。

调用关系:测试运行器执行它时,它验证 parse_turn_item 对网页工具不同动作的兼容;assert_eq 保证打开页面也能走 WebSearch 这条统一通道。

调用图:外部调用 3 个(assert_eq!, panic!, parse_turn_item)。

parses_web_search_find_in_page_call516–543 ↗
fn parses_web_search_find_in_page_call()

作用:这个测试确认“在网页中查找文字”的动作能被整理成容易读的 WebSearch 条目。它会把要找的词和网址合成一句清楚的查询描述。

数据流:它构造一个 FindInPage 动作,网址是 https://example.com,要找的词是 needle → 调用 parse_turn_item → 期望 query 变成“'needle' in https://example.com”。

调用关系:测试运行器执行它时,它检查 parse_turn_item 是否会为复杂网页动作生成可读描述;断言同时确认 action 本身也被原样保留。

调用图:外部调用 3 个(assert_eq!, panic!, parse_turn_item)。

parses_partial_web_search_call_without_action_as_other546–566 ↗
fn parses_partial_web_search_call_without_action_as_other()

作用:这个测试确认网页搜索还没给出具体动作时,程序也不会崩掉,而是把它当成 Other。Other 的意思是“有这么个搜索相关事件,但细节暂时未知”。

数据流:它构造一个状态为 in_progress、action 为空的 WebSearchCall → 调用 parse_turn_item → 期望得到 WebSearchItem,query 是空字符串,action 是 Other。

调用关系:测试运行器执行它时,它验证 parse_turn_item 面对半成品事件的容错能力;这样运行中收到未完成搜索事件时,系统仍能稳定记录。

调用图:外部调用 3 个(assert_eq!, panic!, parse_turn_item)。

core/src/context/contextual_user_message_tests.rs源码 ↗
testtest run

这份文件专门检查“带上下文的用户消息”这套规则。简单说,有些内容虽然放在用户消息里,但其实是系统补充给模型看的信息,比如当前目录、AGENTS.md 里的说明、内部扩展提示、子代理通知、钩子提示等。测试会把这些文字包装成不同格式,然后确认识别函数能认出来;同时也会故意放一些相似但不该隐藏的内容,比如普通文本或随便写的标签,确认系统不会误判。它还检查渲染出来的 AGENTS.md 说明长什么样、内部上下文来源是否合法、动态接口能不能正常使用,以及带特殊字符的钩子提示在生成和解析之间不会被错误转义。可以把它理解成一组“验票员考试题”:只有真正的内部票据能通过,普通纸条不能混进去。

函数细节12
detects_environment_context_fragment12–16 ↗
fn detects_environment_context_fragment()

作用:确认系统能认出环境上下文片段,也就是类似“当前工作目录”这种不是普通用户聊天、而是运行环境说明的内容。

数据流:测试把一段包含 <environment_context><cwd>/tmp</cwd> 的文字放进输入文本里 → 交给识别函数判断它是不是上下文片段 → 期待结果为真,说明这类环境信息会被正确识别。

调用关系:测试运行器调用这个测试;它主要把样本文字交给上下文识别逻辑,然后用断言检查结果,没有再把工作交给别的业务流程。

调用图:外部调用 1 个(assert!)。

detects_agents_instructions_fragment19–28 ↗
fn detects_agents_instructions_fragment()

作用:确认系统能认出 AGENTS.md 指令片段,不管标题里有没有写明目录。

数据流:测试准备两种 AGENTS.md 指令文本:一种写着“for /tmp”,一种没有目录 → 每段都包装成输入文本 → 交给识别函数 → 期待都被判断为上下文片段。

调用关系:测试运行器会执行它;它覆盖的是 AGENTS.md 指令识别规则,靠断言确认两个常见标题格式都能通过。

调用图:外部调用 1 个(assert!)。

renders_agents_instructions_with_legacy_directory_header31–40 ↗
fn renders_agents_instructions_with_legacy_directory_header()

作用:确认带目录的 AGENTS.md 指令会被渲染成旧格式标题,也就是标题里包含“for /tmp”。

数据流:测试创建一个用户指令对象,里面有目录 /tmp 和正文 body → 调用它的渲染方法生成最终文本 → 和预期字符串逐字比较,确认格式没有变。

调用关系:测试运行器调用它;它检查的是 UserInstructions 的输出格式,使用相等断言防止以后改代码时不小心破坏兼容格式。

调用图:外部调用 1 个(assert_eq!)。

renders_agents_instructions_without_directory_header43–52 ↗
fn renders_agents_instructions_without_directory_header()

作用:确认没有目录的 AGENTS.md 指令会渲染成不带目录的标题。

数据流:测试创建一个没有目录、正文为 body 的用户指令对象 → 调用渲染方法 → 得到一段带 <INSTRUCTIONS> 包裹的文本 → 和预期格式比较。

调用关系:测试运行器会执行它;它和带目录版本的测试配套,保证 UserInstructions 在两种情况下都输出稳定格式。

调用图:外部调用 1 个(assert_eq!)。

detects_subagent_notification_fragment_case_insensitively55–59 ↗
fn detects_subagent_notification_fragment_case_insensitively()

作用:确认子代理通知标签的大小写不会影响识别。子代理可以理解成帮主流程干活的“小助手”。

数据流:测试输入一段开始标签是大写、结束标签是小写的通知文本 → 调用 SubagentNotification 的匹配方法 → 期待它仍然返回真,说明识别不挑大小写。

调用关系:测试运行器调用它;它直接检查 SubagentNotification 的文本匹配规则,用断言保护这条兼容行为。

调用图:外部调用 1 个(assert!)。

detects_internal_model_context_fragment62–76 ↗
fn detects_internal_model_context_fragment()

作用:确认内部模型上下文能按正确格式生成,也能被系统认成上下文片段。内部模型上下文就是给模型看的内部提示,不是普通用户消息。

数据流:测试先用 from_static 做出来源名 extension,再用 new 创建内部上下文片段 → 调用渲染得到带 source 属性的 XML 风格文本 → 先检查文本完全符合预期,再把它放进输入文本里检查能否被识别为上下文片段。

调用关系:测试运行器调用它;它把 InternalContextSource 和 InternalModelContextFragment 串起来测,既检查生成格式,也检查生成结果能被总体识别逻辑接住。

调用图:调用 2 个内部函数(from_static, new);外部调用 2 个(assert!, assert_eq!)。

detects_legacy_goal_context_fragment79–84 ↗
fn detects_legacy_goal_context_fragment()

作用:确认旧版的目标上下文标签仍然能被识别,避免老数据或旧流程突然失效。

数据流:测试构造一段 <goal_context> 包住的目标说明文字 → 放入输入文本 → 交给识别函数 → 期待返回真。

调用关系:测试运行器调用它;它专门保护旧格式兼容性,让新的识别规则不会忘掉历史上用过的目标上下文。

调用图:外部调用 1 个(assert!)。

does_not_hide_arbitrary_context_tags87–91 ↗
fn does_not_hide_arbitrary_context_tags()

作用:确认系统不会因为看到某个名字像上下文的标签,就随便把内容当成隐藏上下文。

数据流:测试构造一段 <project_context> 文本 → 放进输入文本 → 交给识别函数 → 期待返回假,说明这种未认可的标签不会被隐藏或特殊处理。

调用关系:测试运行器调用它;它是防误判测试,和那些“应该识别”的测试形成对照,保证识别规则不是过于宽松。

调用图:外部调用 1 个(assert!)。

rejects_invalid_internal_model_context_source94–99 ↗
fn rejects_invalid_internal_model_context_source()

作用:确认内部上下文的来源名必须符合规定大小写,错误来源不会被当成合法内部提示。

数据流:测试输入一段 source 为 Extension 的内部上下文文本,注意首字母大写 → 交给识别函数 → 期待返回假,说明只有合法来源格式才会通过。

调用关系:测试运行器调用它;它保护 InternalModelContextFragment 的来源校验规则,避免看起来相似但不符合规范的内容被误收。

调用图:外部调用 1 个(assert!)。

contextual_user_fragment_is_dyn_compatible102–112 ↗
fn contextual_user_fragment_is_dyn_compatible()

作用:确认上下文片段接口可以作为动态对象使用。动态对象可以理解成“只知道它会 render,不关心它具体是哪种片段”。

数据流:测试创建一个内部模型上下文片段 → 把它装进 Box<dyn ContextualUserFragment> 这种动态接口盒子里 → 调用 render → 检查输出仍然是正确的内部上下文文本。

调用关系:测试运行器调用它;它通过 InternalModelContextFragment 的 new 和 InternalContextSource 的 from_static 创建真实对象,再验证 ContextualUserFragment 这个公共接口能正常承载它。

调用图:调用 2 个内部函数(from_static, new);外部调用 2 个(new, assert_eq!)。

ignores_regular_user_text115–119 ↗
fn ignores_regular_user_text()

作用:确认普通用户输入不会被误认为上下文片段。

数据流:测试把简单的 hello 放进输入文本 → 交给识别函数 → 期待返回假,表示它会按普通聊天内容处理。

调用关系:测试运行器调用它;它是最基础的反例测试,确保识别逻辑不会把所有用户文字都当成特殊内容。

调用图:外部调用 1 个(assert!)。

detects_hook_prompt_fragment_and_roundtrips_escaping122–152 ↗
fn detects_hook_prompt_fragment_and_roundtrips_escaping()

作用:确认钩子提示能被识别,并且里面的引号、&、尖括号这些特殊字符在生成再解析后不会变坏。钩子提示就是外部钩子运行后给模型看的补充提示。

数据流:测试先用一段含有特殊字符的文字和 hook_run_id 创建钩子片段 → 调用 build_hook_prompt_message 生成消息 → 从消息里取出唯一的文本内容 → 确认它是上下文片段 → 再用 parse_visible_hook_prompt_message 解析回来 → 检查解析出的文字和 hook_run_id 与原来一致,并确认原始文本里没有出现错误的转义残留。

调用关系:测试运行器调用它;它把钩子片段创建、消息构建、上下文识别、可见钩子提示解析连成一条完整小流程,中途如果消息形状不对就用 panic 让测试立刻失败。

调用图:调用 1 个内部函数(build_hook_prompt_message);外部调用 4 个(from_single_hook, assert!, assert_eq!, panic!)。

core/src/context/environment_context_tests.rs源码 ↗
testtest run

环境上下文可以理解成系统递给模型的一张“现场说明纸”:当前在哪个文件夹、用什么命令行、今天日期、能不能联网、哪些文件能读写。这个测试文件逐个模拟常见情况,然后把 EnvironmentContext 渲染成类似 XML 的文本,再和手写的标准答案比较。它还测试了权限这块:比如工作区可以写,但 private 目录必须拒绝访问;以及如果一次请求里给了多个 workspace roots,就应该用这些工作区根目录,而不是随便用当前目录。另一个重点是 equals_except_shell:比较两个环境时可以忽略 Shell 名字,但不能忽略工作目录差异。没有这些测试,环境提示一旦格式错、路径选错或权限展开错,模型就可能误以为自己能访问不该访问的地方。

函数细节14
fake_shell_name21–27 ↗
fn fake_shell_name() -> String

作用:造出一个假的 Shell 名字,也就是固定返回 bash,用来让测试不用依赖真实机器上的命令行环境。

数据流:进去时没有业务输入 → 它创建一个 Shell 对象,里面写死类型是 Bash、路径是 /bin/bash,然后取这个 Shell 的显示名称 → 出来一个字符串 bash,不改动外部状态。

调用关系:它是测试里的小道具。调用图里显示它被 turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd 用来准备环境;这样后面的测试重点可以放在路径和权限上,而不是 Shell 检测上。

调用图:被 1 处调用(turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd);外部调用 1 个(from)。

test_abs_path29–31 ↗
fn test_abs_path(unix_path: &str) -> AbsolutePathBuf

作用:把测试里写的 Unix 风格路径,比如 /repo,变成项目内部使用的“绝对路径”对象。

数据流:进去一个字符串路径 → 它先交给 test_path_buf 做成测试用 PathBuf,再调用 abs 标记或转换成 AbsolutePathBuf → 出来一个绝对路径对象,方便后面权限和工作区逻辑使用。

调用关系:它是路径准备工具。serialize_environment_context_with_full_filesystem_profile 和 turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd 会先用它造出 repo、other-repo 这类路径,再交给环境上下文和权限展开代码。

调用图:被 2 处调用(serialize_environment_context_with_full_filesystem_profile, turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd);外部调用 1 个(test_path_buf)。

serialize_workspace_write_environment_context34–59 ↗
fn serialize_workspace_write_environment_context()

作用:测试最基本的环境上下文能不能正确写出当前目录、Shell、日期和时区。

数据流:进去的是测试写死的 /repo、bash、日期和时区 → 它用 EnvironmentContext::new 组装上下文,再调用 render 生成文本 → 最后用 assert_eq! 确认输出正好等于预期字符串。

调用关系:这是基础格式测试,由测试框架运行。它主要检查 EnvironmentContext::new 和 render 这一条主流程,确保最常见的单环境输出没有多字、少字或缩进错误。

调用图:调用 1 个内部函数(new);外部调用 4 个(assert_eq!, test_path_buf, format!, vec!)。

serialize_environment_context_with_network62–91 ↗
fn serialize_environment_context_with_network()

作用:测试环境上下文里带网络规则时,允许访问和禁止访问的网站能不能被正确写出来。

数据流:进去的是允许列表 api.example.com、*.openai.com,以及拒绝列表 blocked.example.com → 它先创建 NetworkContext,再放进 EnvironmentContext → render 后应该多出一个 network 节点,里面写清 enabled、allowed 和 denied。

调用关系:测试框架会运行它。它把活儿交给 NetworkContext::new 和 EnvironmentContext::new,最终验证 render 是否把网络沙盒信息也包含进模型会看到的环境说明里。

调用图:调用 2 个内部函数(new, new);外部调用 3 个(assert_eq!, format!, vec!)。

workspace_write_permission_profile_with_private_denials93–117 ↗
fn workspace_write_permission_profile_with_private_denials() -> PermissionProfile

作用:造出一个测试用的文件权限配置:工作区整体可写,但 private 目录和 private/** 这类路径必须禁止。

数据流:进去没有参数 → 它创建一个受限制的文件系统沙盒策略,加入三条规则:项目根可写、private 子目录拒绝、private/** 通配路径拒绝;网络策略设为受限 → 出来一个 PermissionProfile,供多个测试复用。

调用关系:它是权限测试的固定样板。serialize_environment_context_with_full_filesystem_profile 和 turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd 会拿它来检查权限规则如何展开到每个工作区根目录。

调用图:调用 2 个内部函数(from_runtime_permissions, restricted);被 2 处调用(serialize_environment_context_with_full_filesystem_profile, turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd);外部调用 1 个(vec!)。

serialize_environment_context_with_full_filesystem_profile120–161 ↗
fn serialize_environment_context_with_full_filesystem_profile()

作用:测试完整的文件系统权限说明能不能正确写进环境上下文,尤其是多个工作区根目录和 private 拒绝规则。

数据流:进去的是测试造出的 /repo 和 /other-repo,以及一个“工作区可写、private 拒绝”的权限模板 → 它用 FileSystemContext::from_permission_profile 把抽象规则展开成具体绝对路径和 glob 通配路径 → render 后与预期文本逐字比较。

调用关系:这是文件权限渲染的核心测试。它先调用 test_abs_path 和 workspace_write_permission_profile_with_private_denials 准备材料,再把权限交给 from_permission_profile 展开,最后验证 EnvironmentContext 的输出没有漏掉任何根目录或拒绝项。

调用图:调用 5 个内部函数(new, from_permission_profile, test_abs_path, workspace_write_permission_profile_with_private_denials, resolve_path_against_base);外部调用 4 个(new, assert_eq!, format!, vec!)。

turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd164–212 ↗
fn turn_context_item_filesystem_uses_workspace_roots_instead_of_cwd()

作用:测试从一次对话请求 TurnContextItem 生成环境上下文时,文件权限应该按 workspace_roots 展开,而不是按 cwd 展开。

数据流:进去的是一个 TurnContextItem:cwd 故意设成 /not-the-workspace,但 workspace_roots 设成 /repo 和 /other-repo → 它调用 EnvironmentContext::from_turn_context_item 生成上下文文本 → 结果必须包含两个 workspace root 和 /repo/private,且不能包含 /not-the-workspace/private。

调用关系:这是防错测试,模拟真实请求进入系统后的转换流程。它使用 fake_shell_name、test_abs_path 和权限样板函数准备数据,再检查 from_turn_context_item 有没有把“真正的工作区根目录”传给文件系统权限逻辑。

调用图:调用 4 个内部函数(from_turn_context_item, fake_shell_name, test_abs_path, workspace_write_permission_profile_with_private_denials);外部调用 4 个(new_read_only_policy, assert!, test_path_buf, vec!)。

serialize_read_only_environment_context215–230 ↗
fn serialize_read_only_environment_context()

作用:测试没有工作目录和 Shell 信息时,环境上下文仍然能只输出日期和时区。

数据流:进去的是空环境列表,以及日期、时区 → 它创建 EnvironmentContext 并渲染 → 出来的文本只有 current_date 和 timezone,没有 cwd、shell 等不存在的信息。

调用关系:测试框架会直接运行它。它检查 EnvironmentContext::new 对“信息不完整但合法”的情况是否友好,不会硬塞空字段进输出。

调用图:调用 1 个内部函数(new);外部调用 2 个(new, assert_eq!)。

equals_except_shell_compares_cwd233–257 ↗
fn equals_except_shell_compares_cwd()

作用:测试 equals_except_shell 在两个工作目录相同的情况下会认为环境相同。

数据流:进去是两个新建的 EnvironmentContext,它们 cwd 都是 /repo,Shell 也一样 → 它调用 equals_except_shell 比较 → 结果应该是真,说明至少相同 cwd 不会被误判为不同。

调用关系:这是比较逻辑的正向用例。测试框架运行它时,重点落在 equals_except_shell:这个方法用于判断环境是否实质相同,同时允许忽略 Shell 差别。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert!, vec!)。

equals_except_shell_compares_cwd_differences260–285 ↗
fn equals_except_shell_compares_cwd_differences()

作用:测试 equals_except_shell 不能忽略工作目录差异;/repo1 和 /repo2 应该被看成不同环境。

数据流:进去是两个 EnvironmentContext,一个 cwd 是 /repo1,另一个是 /repo2 → 它调用 equals_except_shell → 出来应该是假,表示工作目录变了就是重要变化。

调用关系:这是比较逻辑的反向用例。它配合 equals_except_shell_compares_cwd,说明这个比较方法只忽略 Shell,不会把所有环境差异都抹平。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert!, vec!)。

equals_except_shell_ignores_shell288–313 ↗
fn equals_except_shell_ignores_shell()

作用:测试 equals_except_shell 确实会忽略 Shell 名字,bash 和 zsh 不应导致比较失败。

数据流:进去是两个 EnvironmentContext,它们 cwd 都是 /repo,但 shell 分别是 bash 和 zsh,id 也不同 → 它调用 equals_except_shell → 出来应该是真,说明这些差别在这个比较里不算关键。

调用关系:这是专门锁定“忽略 Shell”行为的测试。它帮助保证调用 equals_except_shell 的上层逻辑不会因为用户换了命令行外壳就误以为整个环境变了。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert!, vec!)。

serialize_environment_context_with_subagents316–344 ↗
fn serialize_environment_context_with_subagents()

作用:测试有子代理说明时,环境上下文会把这些子代理列表按预期格式写出来。

数据流:进去的是一个普通本地环境、日期时区,以及一段子代理文本 → 它创建 EnvironmentContext 并 render → 输出里应出现 subagents 块,并保留 agent-1、agent-2 这些内容和缩进。

调用关系:测试框架运行它。它验证 EnvironmentContext::new 接收的 subagents 字段能顺利进入最终文本,让模型知道还有哪些协作代理可用。

调用图:调用 1 个内部函数(new);外部调用 3 个(assert_eq!, format!, vec!)。

serialize_environment_context_with_multiple_selected_environments347–389 ↗
fn serialize_environment_context_with_multiple_selected_environments()

作用:测试同时选择多个环境时,输出不再是单个 cwd/shell,而是 environments 列表。

数据流:进去的是两个环境:local 对应 /repo/local,remote 对应 /repo/remote,Shell 都是 bash → 它创建并渲染 EnvironmentContext → 输出应包含两个 environment 节点,每个节点都有自己的 id、cwd 和 shell。

调用关系:这是多环境格式测试。它把多个 EnvironmentContextEnvironment 交给 EnvironmentContext::new,检查 render 是否切换到多环境结构,而不是错误地只输出第一个环境。

调用图:调用 1 个内部函数(new);外部调用 4 个(assert_eq!, test_path_buf, format!, vec!)。

serialize_environment_context_prefers_environment_shell_when_present392–432 ↗
fn serialize_environment_context_prefers_environment_shell_when_present()

作用:测试多环境输出时,每个环境应该使用自己携带的 Shell 名字,而不是被某个默认值覆盖。

数据流:进去的是两个环境:local 的 shell 是 powershell,remote 的 shell 是 cmd → 它渲染上下文 → 输出里 local 必须显示 powershell,remote 必须显示 cmd。

调用关系:这是多环境 Shell 选择规则的测试。它通过 EnvironmentContext::new 和 render 检查每个 EnvironmentContextEnvironment 的 shell 字段是否被原样采用,避免不同环境的命令行信息串台。

调用图:调用 1 个内部函数(new);外部调用 4 个(assert_eq!, test_path_buf, format!, vec!)。

core/src/stream_events_utils_tests.rs源码 ↗
testtest run

可以把这个文件看成质检清单。系统会收到很多种模型输出:普通文字、联网搜索结果、本地工具调用、图片生成结果等。这里的测试逐项确认:哪些输出可能带外部信息,哪些不算;助手文字里的记忆引用和计划块要从用户可见文本里剥掉;扩展插件只有在明确要求时才会改动消息;最终一条助手消息是否会让“邮箱”延后到下一轮投递,也要按消息阶段判断。文件还测试图片生成结果:只接受标准 base64(一种把二进制图片写成文本的编码),拒绝 data URL,并且保存路径要安全,不能被奇怪的调用编号带到别的目录。没有这些测试,改动流式输出处理代码时很容易悄悄破坏用户看到的文字、插件行为或文件安全。

函数细节23
assistant_output_text33–35 ↗
fn assistant_output_text(text: &str) -> ResponseItem

作用:这是测试用的小帮手,用一段普通助手文字快速造出一个模型输出对象。测试里不想每次都手写完整结构时,就用它省事。

数据流:进去一段文字 → 它把阶段留空,转交给 assistant_output_text_with_phase → 出来一个“助手发了一段文字”的 ResponseItem 测试对象。

调用关系:很多测试先用它准备假数据,然后把这个假输出交给被测函数,比如提取最后助手消息、处理非工具输出、判断邮箱是否延后等。它自己只负责把活儿交给 assistant_output_text_with_phase。

调用图:调用 1 个内部函数(assistant_output_text_with_phase);被 9 处调用(completed_item_defers_mailbox_delivery_for_unknown_phase_messages, external_context_pollution_items_exclude_local_tool_calls, finalized_turn_item_defers_mailbox_for_contributed_visible_text, handle_non_tool_response_item_runs_turn_item_contributors_only_when_requested, handle_non_tool_response_item_strips_citations_from_assistant_message, handle_output_item_done_returns_contributed_last_agent_message, last_assistant_message_from_item_returns_none_for_citation_only_message, last_assistant_message_from_item_returns_none_for_plan_only_hidden_message, last_assistant_message_from_item_strips_citations_and_plan_blocks)。

assistant_output_text_with_phase37–47 ↗
fn assistant_output_text_with_phase(text: &str, phase: Option<MessagePhase>) -> ResponseItem

作用:这是更完整的测试造数工具,能造出带指定阶段的助手文字输出。阶段可以理解成消息的状态标签,比如“还在解释中”或“最终回答”。

数据流:进去文字和可选的 MessagePhase 阶段 → 它组装出一个 role 为 assistant、内容为 OutputText 的 ResponseItem → 出来的是可直接喂给测试目标的模型输出对象。

调用关系:assistant_output_text 会调用它来造默认消息;需要测试 commentary 这类特殊阶段时,测试会直接调用它。它不做判断,只负责稳定地产生测试输入。

调用图:被 3 处调用(assistant_output_text, completed_item_keeps_mailbox_delivery_open_for_commentary_messages, finalized_turn_item_keeps_mailbox_open_for_commentary_text);外部调用 1 个(vec!)。

external_context_pollution_items_exclude_local_tool_calls83–133 ↗
fn external_context_pollution_items_exclude_local_tool_calls()

作用:这个测试确认:本地 shell、普通函数调用、自定义工具调用和纯助手文字,不会被误判成“带外部上下文”。这样可以避免系统过度紧张,把正常本地操作当成联网搜索。

数据流:进去的是一组本地工具调用、工具返回值和普通助手文字 → 测试对每个条目调用 response_item_may_include_external_context → 结果要求没有任何一个返回 true。

调用关系:它和 include 测试成对出现,一个测该算的要算,一个测不该算的别算。assistant_output_text 负责提供其中的普通文字样本。

调用图:调用 2 个内部函数(assistant_output_text, from_text);外部调用 3 个(assert!, Exec, vec!)。

handle_non_tool_response_item_strips_citations_from_assistant_message136–172 ↗
async fn handle_non_tool_response_item_strips_citations_from_assistant_message()

作用:这个测试确认:助手消息里夹着的记忆引用标记不会显示给用户,但引用信息本身会被解析并保存。也就是说,用户看到干净文字,系统仍然知道引用来自哪里。

数据流:进去一个带 <oai-mem-citation> 隐藏标记的助手输出,以及测试会话上下文 → handle_non_tool_response_item 把它转成 TurnItem → 出来应是 AgentMessage,文字变成“hello world”,同时 memory_citation 里保留 MEMORY.md 和 rollout id。

调用关系:测试先用 make_session_and_context 建一个临时会话,再用 assistant_output_text 造消息,最后检查 handle_non_tool_response_item 的结果。它验证的是非工具输出进入会话记录前的清洗和解析。

调用图:调用 2 个内部函数(make_session_and_context, assistant_output_text);外部调用 3 个(assert_eq!, panic!, handle_non_tool_response_item)。

TestTurnItemContributor::contribute180–196 ↗
fn contribute(
        &'a self,
        _thread_store: &'a ExtensionData,
        turn_store: &'a ExtensionData,
        item: &'a mut TurnItem,
    ) -> codex_extension_api::ExtensionFuture<'a, Resu

作用:这是测试专用的插件贡献者,用来证明“插件真的被运行过”。它还会给助手消息塞一个空的记忆引用,方便测试观察插件是否改动了消息。

数据流:进去线程级存储、当前轮存储和一个可修改的 TurnItem → 它在当前轮存储里放入 TurnItemContributorRan 标记;如果这是助手消息,就写入空 MemoryCitation → 出来是成功结果,并且输入的消息可能已被改动。

调用关系:handle_non_tool_response_item_runs_turn_item_contributors_only_when_requested 会注册并使用它。被测流程在策略为 Run 时会调用它,在策略为 Skip 时不该调用它。

调用图:调用 1 个内部函数(insert);外部调用 2 个(pin, new)。

RewriteAgentMessageContributor::contribute202–216 ↗
fn contribute(
        &'a self,
        _thread_store: &'a ExtensionData,
        _turn_store: &'a ExtensionData,
        item: &'a mut TurnItem,
    ) -> codex_extension_api::ExtensionFuture<'a, Res

作用:这是测试专用的改写插件,用来模拟扩展把助手回复改成另一段文字。它帮助测试确认后续流程看到的是插件改过的最终文本,而不是原始文本。

数据流:进去一个可修改的 TurnItem → 如果它是助手消息,就把内容替换成“contributed assistant text” → 出来是成功结果,消息正文已被重写。

调用关系:多个测试会把它注册进扩展系统,再调用 finalize_non_tool_response_item 或 handle_output_item_done。它用来检查插件改写能不能影响最后记录的助手消息和邮箱投递判断。

调用图:外部调用 2 个(pin, vec!)。

handle_non_tool_response_item_runs_turn_item_contributors_only_when_requested220–269 ↗
async fn handle_non_tool_response_item_runs_turn_item_contributors_only_when_requested()

作用:这个测试确认:处理普通助手输出时,扩展插件不是默认乱跑,只有策略明确要求 Run 时才会执行。这样可以避免还没最终确定的临时消息被插件提前改坏。

数据流:进去一个带隐藏引用标记的助手输出、测试会话、注册好的 TestTurnItemContributor,以及两种策略 Skip 和 Run → Skip 时生成消息但不写插件标记;Run 时插件标记出现,消息也被加上 memory_citation → 出来通过断言证明两种路径行为不同。

调用关系:它直接围绕 handle_non_tool_response_item 做测试。TestTurnItemContributor 是观察探针,ExtensionData 是插件能写入的小仓库,TurnItemContributorPolicy 决定插件是否参与。

调用图:调用 4 个内部函数(make_session_and_context, assistant_output_text, new, new);外部调用 6 个(new, assert!, assert_eq!, Run, panic!, handle_non_tool_response_item)。

handle_output_item_done_returns_contributed_last_agent_message272–314 ↗
async fn handle_output_item_done_returns_contributed_last_agent_message()

作用:这个测试确认:当一条输出完成时,如果插件改写了助手消息,系统记录的“最后一条助手消息”应当是改写后的文字。否则界面或后续逻辑可能拿到过时内容。

数据流:进去一个原始文字为“original assistant text”的助手输出,以及带 RewriteAgentMessageContributor 的完整处理上下文 → handle_output_item_done 跑完输出完成流程 → 出来的 output.last_agent_message 应是“contributed assistant text”。

调用关系:它搭起接近真实运行的环境:会话、轮次上下文、工具路由器、工具运行时和差异追踪器。然后调用 handle_output_item_done,验证更高层流程会继承插件贡献者的改写结果。

调用图:调用 7 个内部函数(make_session_and_context, assistant_output_text, new, from_turn_context, new, new, new);外部调用 8 个(clone, new, new, default, new, assert_eq!, handle_output_item_done, new)。

finalized_turn_item_defers_mailbox_for_contributed_visible_text317–340 ↗
async fn finalized_turn_item_defers_mailbox_for_contributed_visible_text()

作用:这个测试确认:即使原始助手消息只有隐藏引用,插件补上了可见文字后,系统也应把它当成真正的最终助手消息,并延后邮箱投递到下一轮。

数据流:进去一个原本只有隐藏标记的助手输出,以及会把文本改成可见内容的插件 → finalize_non_tool_response_item 先处理再最终化 → 出来 last_agent_message 是插件文字,并且 defers_mailbox_delivery_to_next_turn 为 true。

调用关系:它检查 finalize_non_tool_response_item 这个最终化步骤是否看到了插件改写后的结果。RewriteAgentMessageContributor 提供可见文字,邮箱延后判断依赖最终可见内容。

调用图:调用 4 个内部函数(make_session_and_context, assistant_output_text, new, new);外部调用 5 个(new, assert!, assert_eq!, Run, finalize_non_tool_response_item)。

finalized_turn_item_keeps_mailbox_open_for_commentary_text343–366 ↗
async fn finalized_turn_item_keeps_mailbox_open_for_commentary_text()

作用:这个测试确认:如果助手消息处在 commentary 阶段,也就是还像“过程说明”而不是最终回答,即使插件改写了文字,也不该关闭当前轮的邮箱投递。

数据流:进去一条阶段为 Commentary 的助手输出和改写插件 → finalize_non_tool_response_item 得到最终对象 → 出来 last_agent_message 是插件文字,但 defers_mailbox_delivery_to_next_turn 为 false。

调用关系:它和上一条测试形成对照:同样有插件改写,但消息阶段不同,所以邮箱行为不同。它验证阶段标签在最终化时仍然起作用。

调用图:调用 4 个内部函数(make_session_and_context, assistant_output_text_with_phase, new, new);外部调用 5 个(new, assert!, assert_eq!, Run, finalize_non_tool_response_item)。

last_assistant_message_from_item_strips_citations_and_plan_blocks369–378 ↗
fn last_assistant_message_from_item_strips_citations_and_plan_blocks()

作用:这个测试确认:提取最后助手文字时,会去掉记忆引用和计划块这种不该直接展示的内容,只留下真正该给用户看的文字。

数据流:进去一条同时包含普通文字、<oai-mem-citation> 引用块和 <proposed_plan> 计划块的助手输出,并开启 plan_mode → last_assistant_message_from_item 清理隐藏部分 → 出来应是“before\nafter”。

调用关系:它直接测试 last_assistant_message_from_item 的清洗能力。assistant_output_text 负责造输入,断言负责保证隐藏块不会混进最后助手消息。

调用图:调用 1 个内部函数(assistant_output_text);外部调用 2 个(assert_eq!, last_assistant_message_from_item)。

last_assistant_message_from_item_returns_none_for_citation_only_message381–388 ↗
fn last_assistant_message_from_item_returns_none_for_citation_only_message()

作用:这个测试确认:如果助手消息只有隐藏的记忆引用,没有真正可见文字,那么系统不应该把它当成最后一条助手回复。

数据流:进去一条内容全是 <oai-mem-citation> 的助手输出 → 提取最后助手消息时隐藏部分被去掉 → 出来应是 None,表示没有可展示文本。

调用关系:它测试 last_assistant_message_from_item 的边界情况。这个行为能避免界面或后续逻辑拿到一条空壳消息。

调用图:调用 1 个内部函数(assistant_output_text);外部调用 1 个(assert_eq!)。

last_assistant_message_from_item_returns_none_for_plan_only_hidden_message391–398 ↗
fn last_assistant_message_from_item_returns_none_for_plan_only_hidden_message()

作用:这个测试确认:在计划模式下,如果消息只有隐藏计划块,也不能算作可见助手回复。

数据流:进去一条只包含 <proposed_plan> 的助手输出,并开启 plan_mode → 清理后没有剩余文字 → 出来应是 None。

调用关系:它补充测试计划块的隐藏规则。和 citation-only 测试一起保证“隐藏内容不能冒充用户可见回复”。

调用图:调用 1 个内部函数(assistant_output_text);外部调用 1 个(assert_eq!)。

completed_item_defers_mailbox_delivery_for_unknown_phase_messages401–407 ↗
fn completed_item_defers_mailbox_delivery_for_unknown_phase_messages()

作用:这个测试确认:没有明确阶段标签的普通最终回答,会让系统把邮箱投递延后到下一轮。可以理解为系统认为这轮回答已经结束,需要等下一轮再处理新消息。

数据流:进去一条没有 phase 的助手文字输出 → completed_item_defers_mailbox_delivery_to_next_turn 判断它是否应延后 → 出来应是 true。

调用关系:它直接测试 completed_item_defers_mailbox_delivery_to_next_turn 的默认行为。assistant_output_text 造出的正是这种无阶段消息。

调用图:调用 1 个内部函数(assistant_output_text);外部调用 1 个(assert!)。

completed_item_keeps_mailbox_delivery_open_for_commentary_messages410–416 ↗
fn completed_item_keeps_mailbox_delivery_open_for_commentary_messages()

作用:这个测试确认:commentary 阶段的消息不会让邮箱投递延后,因为这类消息更像中途说明,还不代表最终结束。

数据流:进去一条 phase 为 Commentary 的助手文字输出 → 延后判断函数检查阶段 → 出来应是 false。

调用关系:它和 unknown phase 测试相对照,说明消息阶段会改变邮箱行为。assistant_output_text_with_phase 用来造出带阶段的样本。

调用图:调用 1 个内部函数(assistant_output_text_with_phase);外部调用 1 个(assert!)。

completed_item_defers_mailbox_delivery_for_image_generation_calls419–431 ↗
fn completed_item_defers_mailbox_delivery_for_image_generation_calls()

作用:这个测试确认:图片生成完成也算一个需要结束当前投递窗口的完成项。否则图片结果可能和下一轮消息交错在一起。

数据流:进去一个状态为 completed、带 base64 结果的 ImageGenerationCall → completed_item_defers_mailbox_delivery_to_next_turn 判断 → 出来应是 true。

调用关系:它把测试范围从文字消息扩展到图片生成输出。这样邮箱延后规则不只覆盖聊天文字,也覆盖生成图片这种特殊输出。

调用图:外部调用 1 个(assert!)。

save_image_generation_result_saves_base64_to_png_in_codex_home434–448 ↗
async fn save_image_generation_result_saves_base64_to_png_in_codex_home()

作用:这个测试确认:图片生成返回的标准 base64 文本会被解码,并保存成 codex home 目录里的 png 文件。codex home 可以理解成这个程序自己的工作文件夹。

数据流:进去临时 codex_home、session id、图片调用 id 和 base64 字符串“Zm9v” → save_image_generation_result 解码并写文件 → 出来保存路径等于预期路径,文件内容是字节 foo。

调用关系:它先用 image_generation_artifact_path 算预期位置,再调用 save_image_generation_result。测试结束还清理文件,避免留下垃圾。

调用图:外部调用 5 个(assert_eq!, remove_file, image_generation_artifact_path, save_image_generation_result, tempdir)。

save_image_generation_result_rejects_data_url_payload451–460 ↗
async fn save_image_generation_result_rejects_data_url_payload()

作用:这个测试确认:保存图片时拒绝 data URL 格式的输入。data URL 是把媒体类型和数据一起塞进一个字符串,系统这里要求只给纯 base64,避免格式混乱或误判。

数据流:进去一个以 data:image/jpeg;base64 开头的结果字符串 → save_image_generation_result 检查格式并拒绝 → 出来应是 CodexErr::InvalidRequest 错误。

调用关系:它验证图片保存函数的防呆逻辑。和成功保存测试一起说明:只接受约定好的干净输入。

调用图:外部调用 3 个(assert!, save_image_generation_result, tempdir)。

save_image_generation_result_overwrites_existing_file463–482 ↗
async fn save_image_generation_result_overwrites_existing_file()

作用:这个测试确认:如果同一个图片输出路径已经有旧文件,新结果会覆盖它。这样重复生成或重试时不会读到旧图片。

数据流:进去一个已预先写入 existing 内容的目标文件,以及新的 base64“Zm9v” → save_image_generation_result 写入同一路径 → 出来路径不变,但文件内容变成 foo。

调用关系:它先用 image_generation_artifact_path 找目标,再用标准文件操作造出旧文件,最后调用 save_image_generation_result 检查覆盖行为。

调用图:外部调用 7 个(assert_eq!, create_dir_all, remove_file, write, image_generation_artifact_path, save_image_generation_result, tempdir)。

save_image_generation_result_sanitizes_call_id_for_codex_home_output_path485–498 ↗
async fn save_image_generation_result_sanitizes_call_id_for_codex_home_output_path()

作用:这个测试确认:图片调用编号里就算带了“../”这种看起来想跳出目录的片段,保存路径也会被安全处理。这样能防止文件被写到 codex home 之外。

数据流:进去 codex_home、session id、危险形状的 call_id“../ig/..”和 base64 数据 → 路径生成和保存逻辑会清理 call_id → 出来文件只落在预期的安全位置,内容是 foo。

调用关系:它同时使用 image_generation_artifact_path 和 save_image_generation_result,确保路径计算和实际保存使用同一套安全规则。

调用图:外部调用 5 个(assert_eq!, remove_file, image_generation_artifact_path, save_image_generation_result, tempdir)。

save_image_generation_result_rejects_non_standard_base64501–508 ↗
async fn save_image_generation_result_rejects_non_standard_base64()

作用:这个测试确认:非标准 base64 字符串会被拒绝。这里特别防止 URL-safe base64 之类变体悄悄通过,保证输入格式统一。

数据流:进去字符串“_-8”这种不符合标准 base64 的图片结果 → save_image_generation_result 尝试校验并失败 → 出来应是 CodexErr::InvalidRequest。

调用关系:它补充图片保存的输入校验测试。这样保存函数不会因为宽松解码而接受不符合协议的内容。

调用图:外部调用 3 个(assert!, save_image_generation_result, tempdir)。

save_image_generation_result_rejects_non_base64_data_urls511–523 ↗
async fn save_image_generation_result_rejects_non_base64_data_urls()

作用:这个测试确认:不是 base64 的 data URL,比如直接塞 SVG 文本的 data URL,也会被拒绝。它防止把带格式头的任意文本当图片结果写进文件。

数据流:进去“data:image/svg+xml,<svg/>”这样的字符串 → save_image_generation_result 识别为不合规输入 → 出来应是 CodexErr::InvalidRequest。

调用关系:它和 data:image/jpeg;base64 的拒绝测试一起覆盖 data URL 的两类情况:带 base64 的不收,不带 base64 的也不收。

调用图:外部调用 3 个(assert!, save_image_generation_result, tempdir)。

core/src/thread_rollout_truncation_tests.rs源码 ↗
testtest

系统和模型对话时,会积累一长串历史记录,代码里叫 rollout,可以理解成聊天流水账。流水账太长时要裁剪,但不能随便从中间砍:用户消息、助手回复、开发者开场提示、子代理之间的通信、以及“回滚事件”(表示前面若干轮已经作废)都会影响该从哪里开始保留。这个测试文件就是给这些边界情况做“防误伤检查”。它先用一些小函数造出用户、助手、开发者、子代理消息,再构造不同的历史记录,调用真正的裁剪函数,最后把结果和手写的正确答案比较。重点检查三类事:从开头按第几个用户消息裁剪;从结尾只保留最近若干个任务轮次;遇到回滚时,已经撤销的轮次不能再算数。

函数细节17
user_msg10–20 ↗
fn user_msg(text: &str) -> ResponseItem

作用:造一条假的用户消息,方便测试里快速搭一段聊天记录。它避免每个测试都手写一大坨消息结构。

数据流:输入一段文字 → 把它放进一个角色为 user 的 ResponseItem::Message 里,并标成输出文本内容 → 返回这条可放进 rollout 的用户消息,不改动外部状态。

调用关系:它是测试造数据的小工具。相关测试在准备聊天流水账时调用它,然后把造出的消息交给裁剪函数,最后用 assert_eq! 比较裁剪结果。

调用图:被 2 处调用(ignores_session_prefix_messages_when_truncating_rollout_from_start, truncates_rollout_from_start_before_nth_user_only);外部调用 1 个(vec!)。

assistant_msg22–32 ↗
fn assistant_msg(text: &str) -> ResponseItem

作用:造一条假的助手回复消息,用来模拟模型或助手已经说过的话。测试需要它来确认裁剪不会只看用户消息,还能保留用户消息后面的助手内容。

数据流:输入一段文字 → 包成一个角色为 assistant 的 ResponseItem::Message,内容是普通文本 → 返回这条助手消息,不保存任何额外信息。

调用关系:它和 user_msg 一起组成测试里的对话片段。测试函数用它搭出“用户说一句、助手回几句”的历史,再检查裁剪结果是否符合预期。

调用图:被 2 处调用(ignores_session_prefix_messages_when_truncating_rollout_from_start, truncates_rollout_from_start_before_nth_user_only);外部调用 1 个(vec!)。

developer_msg34–44 ↗
fn developer_msg(text: &str) -> ResponseItem

作用:造一条假的开发者消息,也就是系统启动时可能塞进上下文的说明或指令。它用来测试这类开场信息在裁剪时会不会被正确丢掉或保留。

数据流:输入一段文字 → 放进角色为 developer 的 ResponseItem::Message,内容类型是输入文本 → 返回这条开发者消息,不影响其他数据。

调用关系:它是测试准备数据的辅助零件。相关测试用它制造“启动前缀”,再检查按最近任务裁剪时,真正任务开始前的前缀是否会被去掉。

调用图:外部调用 1 个(vec!)。

inter_agent_msg46–55 ↗
fn inter_agent_msg(text: &str, trigger_turn: bool) -> ResponseItem

作用:造一条“代理之间通信”的假消息,并把它包装成普通响应项。这里的代理可以理解成主助手把活儿交给子助手时发出的消息。

数据流:输入消息文字和 trigger_turn 标记 → 先建立从 root 到 /root/worker 的代理路径,再创建 InterAgentCommunication;trigger_turn 表示这条通信是否会开启一个新的任务轮次 → 最后把通信转成 ResponseItem 返回。

调用关系:它在测试中用来模拟子代理消息。内部会调用 AgentPath::root、AgentPath::try_from 和 InterAgentCommunication::new 来拼出一条合法通信,然后交给测试中的 rollout 使用。

调用图:调用 3 个内部函数(root, try_from, new);外部调用 1 个(new)。

inter_agent_communication57–65 ↗
fn inter_agent_communication(text: &str, trigger_turn: bool) -> RolloutItem

作用:造一条原始的代理间通信记录,并直接包装成 RolloutItem。它用于测试那些不只看普通聊天消息、还要看 rollout 特殊条目的逻辑。

数据流:输入文字和 trigger_turn 标记 → 创建根代理到 worker 代理的通信对象 → 包成 RolloutItem::InterAgentCommunication 返回,用来放进聊天流水账。

调用关系:它和 inter_agent_msg 类似,但返回的层级不同:这个函数直接产出 RolloutItem。它依赖 AgentPath::root、AgentPath::try_from 和 InterAgentCommunication::new 来生成通信内容。

调用图:调用 3 个内部函数(root, try_from, new);外部调用 2 个(new, InterAgentCommunication)。

truncates_rollout_from_start_before_nth_user_only68–119 ↗
fn truncates_rollout_from_start_before_nth_user_only()

作用:测试“从开头数到第 N 个用户消息前裁剪”时,只把真正的用户消息当成分界点。助手消息、推理记录、工具调用都不应该被错当成用户轮次。

数据流:没有外部输入 → 先造出一串包含用户、助手、推理摘要、工具调用的 rollout → 调用裁剪函数分别按第 1 个和第 2 个用户消息裁剪 → 用 assert_eq! 检查第一次只留下第一个用户轮次前后的内容,第二次因没有更多可裁位置而保留全部。

调用关系:这是一个独立测试入口。它调用 user_msg、assistant_msg 和 vec! 准备数据,再用 assert_eq! 验证真正的裁剪函数结果。

调用图:调用 2 个内部函数(assistant_msg, user_msg);外部调用 2 个(assert_eq!, vec!)。

truncation_max_keeps_full_rollout122–135 ↗
fn truncation_max_keeps_full_rollout()

作用:测试当要求保留的用户消息数量是 usize::MAX 这种极大值时,历史记录不应该被裁掉。简单说,就是“给的额度无限大,就别乱删”。

数据流:没有外部输入 → 构造三条简单的用户和助手消息 → 用最大数调用从开头裁剪的函数 → 得到结果后确认它和原 rollout 完全一样。

调用关系:这是一个边界值测试。它用 vec! 建立输入,用 assert_eq! 做结果比较,目的是防止极端参数导致意外裁剪。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_from_start_applies_thread_rollback_markers138–164 ↗
fn truncates_rollout_from_start_applies_thread_rollback_markers()

作用:测试从开头裁剪时,会把“线程回滚”算进去。回滚就像聊天记录里写了一句“刚才那轮作废”,后续数用户轮次时不能再把作废内容当真。

数据流:没有外部输入 → 构造 u1、u2、回滚 1 轮、u3、u4 这样的历史 → 调用从开头数用户消息的裁剪函数 → 检查它按有效历史 u1、u3、u4 来判断位置,因此裁在正确地方。

调用关系:这是回滚规则的测试入口。它用 vec! 拼出带 ThreadRolledBackEvent 的 rollout,再用 assert_eq! 确认裁剪函数理解了回滚标记。

调用图:外部调用 2 个(assert_eq!, vec!)。

ignores_session_prefix_messages_when_truncating_rollout_from_start167–196 ↗
async fn ignores_session_prefix_messages_when_truncating_rollout_from_start()

作用:测试裁剪用户历史时,不要把会话启动时自动塞进去的前缀消息当成用户真正发起的任务。否则系统可能会从错误位置裁掉上下文。

数据流:没有普通输入,但会异步创建一个测试会话 → 从会话生成初始上下文,再追加用户请求和助手回答 → 调用从开头裁剪函数 → 检查结果只保留会话前缀和第一段真实任务对应内容。

调用关系:这是一个 tokio 异步测试入口,tokio 是 Rust 里跑异步任务的工具。它先调用 make_session_and_context 搭测试会话,再用 user_msg、assistant_msg 补聊天内容,最后交给 assert_eq! 验证。

调用图:调用 3 个内部函数(make_session_and_context, assistant_msg, user_msg);外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_counts_trigger_turn_messages199–224 ↗
fn truncates_rollout_to_last_n_fork_turns_counts_trigger_turn_messages()

作用:测试“只保留最后 N 个分叉任务轮次”时,会把 trigger_turn 为 true 的子代理消息算作一个新轮次。trigger_turn 可以理解成“这条消息会触发下一轮工作”。

数据流:没有外部输入 → 构造包含普通用户消息、助手消息、子代理消息的 rollout,其中一条子代理消息会触发新轮次 → 调用保留最后 2 个轮次的裁剪函数 → 确认结果从触发轮次那条消息开始保留。

调用关系:这是分叉轮次计数规则的测试。它用 vec! 准备数据,用 assert_eq! 比较结果,重点覆盖子代理触发消息如何影响裁剪边界。

调用图:外部调用 2 个(assert_eq!, vec!)。

fork_turn_positions_use_inter_agent_delivery_metadata227–238 ↗
fn fork_turn_positions_use_inter_agent_delivery_metadata()

作用:测试寻找分叉轮次位置时,会读取代理间通信里的 trigger_turn 信息。也就是说,不是所有子代理消息都算新任务,只有带触发标记的才算。

数据流:没有外部输入 → 构造用户消息、普通子代理通信、触发型子代理通信、下一条用户消息 → 调用寻找轮次位置的函数 → 得到位置列表,并检查它只包含真正的轮次起点。

调用关系:这是 fork_turn_positions_in_rollout 的直接测试入口。它通过 assert_eq! 验证函数识别出的索引位置,数据由 vec! 组合而成。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_drops_startup_prefix_even_when_under_limit241–255 ↗
fn truncates_rollout_to_last_n_fork_turns_drops_startup_prefix_even_when_under_limit()

作用:测试即使历史轮次数量没有超过限制,启动时的开发者前缀也会在按最近轮次裁剪时被丢掉。这样留下的是实际任务,而不是开场配置文字。

数据流:没有外部输入 → 构造“开发者启动上下文 + 用户任务 + 助手回答” → 调用保留最后 2 个轮次的裁剪函数 → 确认结果从用户任务开始,不包含开发者前缀。

调用关系:这是启动前缀处理的测试入口。它使用 vec! 准备 rollout,再用 assert_eq! 检查裁剪函数是否把前缀从任务历史里排除。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_applies_thread_rollback_markers258–280 ↗
fn truncates_rollout_to_last_n_fork_turns_applies_thread_rollback_markers()

作用:测试按最后 N 个分叉轮次裁剪时,同样会尊重回滚标记。被回滚的触发轮次不应该继续影响“最近几轮”的判断。

数据流:没有外部输入 → 构造用户消息、触发型子代理消息、回滚 1 轮、再来一个用户消息的历史 → 调用保留最后 2 个轮次的裁剪函数 → 检查在回滚生效后,整段记录仍应被保留。

调用关系:这是最近轮次裁剪与回滚配合的测试。它用 vec! 生成带 ThreadRolledBackEvent 的数据,并用 assert_eq! 对比完整 rollout。

调用图:外部调用 2 个(assert_eq!, vec!)。

fork_turn_positions_ignore_zero_turn_rollback_markers283–297 ↗
fn fork_turn_positions_ignore_zero_turn_rollback_markers()

作用:测试回滚 0 轮的标记不会改变轮次判断。回滚 0 轮等于“什么也没撤销”,不能误删或误改轮次边界。

数据流:没有外部输入 → 构造用户消息、触发型子代理消息、回滚 0 轮、另一个用户消息 → 调用轮次位置识别函数 → 确认返回的位置仍然包含原本该有的三个轮次起点。

调用关系:这是回滚边界值测试。它用 vec! 创建含零回滚事件的 rollout,再用 assert_eq! 确认 fork_turn_positions_in_rollout 不会被无效回滚干扰。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_discards_trigger_boundaries_in_rolled_back_suffix300–324 ↗
fn truncates_rollout_to_last_n_fork_turns_discards_trigger_boundaries_in_rolled_back_suffix()

作用:测试如果一个触发型子代理轮次后来被回滚了,它不应该再作为裁剪边界。否则系统可能会把已经作废的任务当成最近任务来保留。

数据流:没有外部输入 → 构造 u1、u2、触发型子代理消息、助手回复、回滚 1 轮、u3 的历史 → 调用保留最后 2 个轮次的裁剪函数 → 检查结果从 u2 开始,因为被回滚的触发边界已经不算数。

调用关系:这是回滚后缀处理的测试入口。它通过 vec! 构造复杂历史,用 assert_eq! 证明裁剪函数会丢弃已回滚部分里的触发边界。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_discards_rolled_back_assistant_instruction_turns327–353 ↗
fn truncates_rollout_to_last_n_fork_turns_discards_rolled_back_assistant_instruction_turns()

作用:测试被回滚的助手指令轮次会被排除,只保留真正还有效的最新触发轮次。它防止旧的、作废的子任务继续影响当前上下文。

数据流:没有外部输入 → 构造用户消息、第一次触发型子代理任务、回滚、第二次触发型子代理任务 → 调用只保留最后 1 个轮次的裁剪函数 → 确认结果只从第二次触发任务开始。

调用关系:这是对“回滚后的新触发任务”的测试。它用 vec! 组合两次子代理触发和一次回滚,再用 assert_eq! 确认裁剪边界落在新的有效任务上。

调用图:外部调用 2 个(assert_eq!, vec!)。

truncates_rollout_to_last_n_fork_turns_keeps_full_rollout_when_n_is_large356–373 ↗
fn truncates_rollout_to_last_n_fork_turns_keeps_full_rollout_when_n_is_large()

作用:测试如果要求保留的最近轮次数量比实际轮次数还多,整段历史就应该原样保留。它和前面的最大值测试一样,是为了防止过度裁剪。

数据流:没有外部输入 → 构造一段包含用户、助手、触发型子代理消息的短 rollout → 调用保留最后 10 个轮次的裁剪函数 → 检查输出和原始 rollout 完全一致。

调用关系:这是最近轮次裁剪的边界测试。它用 vec! 创建短历史,用 assert_eq! 保证当 n 足够大时,裁剪函数不会动这段数据。

调用图:外部调用 2 个(assert_eq!, vec!)。

core/src/turn_metadata_tests.rs源码 ↗
testtest

这份文件不是真正给用户运行的功能代码,而是给开发者守门的测试。它关注的是 TurnMetadataState,也就是“当前这一轮对话的身份卡”。这张身份卡会被放进发给模型或其他服务的 JSON 元数据里。测试会造出临时目录、临时 Git 仓库、不同的会话来源和子代理来源,然后检查生成出来的 JSON 是否符合规则。比如:普通请求不能带压缩字段;压缩请求才带压缩说明;离线记忆请求不能暴露 turn_id、thread_id 这类身份;客户端自带的字段可以合并,但不能覆盖系统保留字段。文件里还有几个小帮手,专门把元数据转成字符串、造测试用的 MCP 请求上下文、创建干净 Git 仓库。它像质检清单,确保这套“请求随身标签”稳定、干净、不会泄露不该带的信息。

函数细节20
test_mcp_turn_metadata_context26–31 ↗
fn test_mcp_turn_metadata_context() -> McpTurnMetadataContext<'static>

作用:生成一个测试用的 MCP 请求上下文。MCP 可以理解成一种让模型调用外部工具的通道,这里给它固定一个模型名和推理力度,方便后面的测试比较结果。

数据流:进去没有参数 → 它创建一个包含模型名“gpt-5.4”和高推理力度的上下文对象 → 出来一个可直接传给元数据生成函数的测试上下文,不改动外部状态。

调用关系:它是多个测试的配套小工具。测试模型名、推理力度、用户输入标记、客户端元数据合并时,都会先用它造一份稳定输入,再检查 TurnMetadataState 生成的 MCP 元数据。

调用图:被 3 处调用(turn_metadata_state_includes_model_and_reasoning_effort_only_in_request_meta, turn_metadata_state_marks_user_input_requested_during_turn_only_for_mcp_request_meta, turn_metadata_state_merges_client_metadata_without_replacing_reserved_fields)。

test_responses_metadata_json33–46 ↗
fn test_responses_metadata_json(
    state: &TurnMetadataState,
    window_id: &str,
    request_kind: CodexResponsesRequestKind,
) -> String

作用:把某个 TurnMetadataState 转成 Responses API 要用的元数据 JSON 字符串。Responses API 可以理解成“发给模型服务的请求格式”。

数据流:进去一个元数据状态、窗口编号、请求类型 → 它调用状态对象的 to_responses_metadata,加上固定安装编号和窗口编号,再把结果转成 JSON 字符串 → 出来一段可被测试解析和断言的 JSON 文本。

调用关系:它是更具体测试帮手的底层公共步骤。普通轮次和压缩轮次的测试函数都会调用它,用同一套方式生成要检查的请求元数据。

调用图:调用 1 个内部函数(to_responses_metadata);被 2 处调用(test_compaction_responses_metadata_json, test_turn_responses_metadata_json)。

test_turn_responses_metadata_json48–50 ↗
fn test_turn_responses_metadata_json(state: &TurnMetadataState, window_id: &str) -> String

作用:生成“普通对话轮次”请求的元数据 JSON。它让测试不用每次都手写请求类型。

数据流:进去一个状态和窗口编号 → 它把请求类型固定成 Turn,也就是普通对话请求,然后交给 test_responses_metadata_json → 出来普通请求对应的 JSON 字符串。

调用关系:它站在普通模型请求测试的入口位置。客户端元数据合并测试、压缩字段隔离测试会用它确认普通请求只带普通请求该有的内容。

调用图:调用 1 个内部函数(test_responses_metadata_json);被 2 处调用(turn_metadata_state_merges_client_metadata_without_replacing_reserved_fields, turn_metadata_state_overlays_compaction_only_on_compaction_requests)。

test_compaction_responses_metadata_json52–62 ↗
fn test_compaction_responses_metadata_json(
    state: &TurnMetadataState,
    window_id: &str,
    compaction: CompactionTurnMetadata,
) -> String

作用:生成“压缩请求”的元数据 JSON。压缩是把过长上下文整理变短,给模型继续使用的一步。

数据流:进去一个状态、窗口编号和压缩说明 → 它把请求类型包装成 Compaction,也就是压缩请求,再交给 test_responses_metadata_json → 出来带压缩请求标记和压缩详情的 JSON 字符串。

调用关系:它服务于压缩相关测试。测试会通过它生成压缩请求,再和普通请求对比,确认压缩信息只出现在该出现的时候。

调用图:调用 1 个内部函数(test_responses_metadata_json);被 1 处调用(turn_metadata_state_overlays_compaction_only_on_compaction_requests);外部调用 1 个(Compaction)。

test_turn_metadata_header64–69 ↗
fn test_turn_metadata_header(state: &TurnMetadataState) -> String

作用:生成基础的 turn metadata header,也就是还没指定具体请求类型时的元数据头。header 可以理解成随请求带上的一张小纸条。

数据流:进去一个 TurnMetadataState → 它调用 responses_metadata_template 拿到基础模板,再转成 JSON 字符串 → 出来一段用于断言的基础元数据 JSON。

调用关系:这是本文件里最常用的测试帮手。大量测试先通过它拿到基础元数据,再检查会话编号、线程关系、沙箱标签、客户端字段是否正确。

调用图:调用 1 个内部函数(responses_metadata_template);被 11 处调用(turn_metadata_state_ignores_client_reserved_metadata_before_start, turn_metadata_state_includes_forked_thread_spawn_subagent_lineage, turn_metadata_state_includes_known_parent_for_non_thread_spawn_subagents_without_fork, turn_metadata_state_includes_model_and_reasoning_effort_only_in_request_meta, turn_metadata_state_includes_root_fork_lineage, turn_metadata_state_includes_thread_spawn_subagent_parent_without_fork, turn_metadata_state_includes_turn_started_at_unix_ms_after_start, turn_metadata_state_marks_user_input_requested_during_turn_only_for_mcp_request_meta, turn_metadata_state_merges_client_metadata_without_replacing_reserved_fields, turn_metadata_state_preserves_lineage_after_git_enrichment (+1 more))。

create_clean_git_repo71–109 ↗
async fn create_clean_git_repo(repo_name: &str) -> (TempDir, AbsolutePathBuf)

作用:创建一个临时的、干净的 Git 仓库,给需要检查工作区信息的测试使用。Git 是常见的代码版本管理工具,这里用它模拟真实项目目录。

数据流:进去一个仓库名字 → 它创建临时目录,初始化 Git,设置提交用户,写 README.md,提交一次初始版本 → 出来临时目录对象和仓库的绝对路径;临时目录对象活着时,这个仓库就还存在。

调用关系:它给两个异步测试准备现场:一个测试离线记忆请求的工作区元数据,一个测试 Git 信息补充之后线程来源信息是否仍然保留。

调用图:被 2 处调用(detached_memory_responses_metadata_omits_turn_identity, turn_metadata_state_preserves_lineage_after_git_enrichment);外部调用 4 个(new, new, create_dir_all, write)。

detached_memory_responses_metadata_omits_turn_identity112–154 ↗
async fn detached_memory_responses_metadata_omits_turn_identity()

作用:确认“脱离当前对话的记忆请求”不会带上当前轮次身份信息。这样可以避免把 session_id、thread_id、turn_id 这类身份标签误塞进记忆请求。

数据流:进去没有外部参数 → 它先创建一个名字含非 ASCII 字符的干净 Git 仓库,再生成 detached memory 元数据,解析 JSON → 最后确认请求类型是 memory、身份字段不存在、路径和工作区是否有改动的信息正确,并且头部字符串保持 ASCII 安全。

调用关系:这个测试直接验证 detached_memory_responses_metadata 的行为。它借助 create_clean_git_repo 提供真实 Git 仓库,再用 JSON 断言检查输出。

调用图:调用 1 个内部函数(create_clean_git_repo);外部调用 4 个(new, assert!, assert_eq!, from_str)。

detached_memory_responses_metadata_omits_empty_workspace_metadata157–176 ↗
async fn detached_memory_responses_metadata_omits_empty_workspace_metadata()

作用:确认当普通目录没有可用工作区信息时,记忆请求不会硬塞一个空的 workspaces 字段。输出越干净,接收方越不容易误解。

数据流:进去没有外部参数 → 它创建一个临时目录作为当前目录,生成 detached memory 元数据,解析 JSON → 出来被断言为只有 request_kind: memory,没有空工作区块。

调用关系:它和上一个记忆请求测试互补:一个检查有 Git 仓库时写入有用工作区信息,另一个检查没有信息时就不要写废字段。

调用图:外部调用 4 个(new, new, assert_eq!, from_str)。

turn_metadata_state_uses_platform_sandbox_tag179–216 ↗
fn turn_metadata_state_uses_platform_sandbox_tag()

作用:确认元数据里的 sandbox 字段使用平台统一计算出的沙箱标签。沙箱就是一层权限隔离,限制程序能读写什么、能不能联网。

数据流:进去没有外部参数 → 它创建临时目录、只读权限配置和 TurnMetadataState,生成基础 header 并解析 JSON → 最后确认 sandbox、session_id、thread_id 正确,同时不该出现的来源字段没有出现。

调用关系:这个测试会调用 permission_profile_sandbox_tag 算出预期沙箱名,再和 TurnMetadataState 生成的结果比较,确保两边规则一致。

调用图:调用 4 个内部函数(permission_profile_sandbox_tag, new, test_turn_metadata_header, read_only);外部调用 4 个(new, assert!, assert_eq!, from_str)。

turn_metadata_state_includes_root_fork_lineage219–248 ↗
fn turn_metadata_state_includes_root_fork_lineage()

作用:确认从另一个线程 fork 出来的根线程,会在元数据里记录 forked_from_thread_id。fork 可以理解成从原对话分出一条新支线。

数据流:进去没有外部参数 → 它构造一个来源线程编号,创建带 fork 来源的 TurnMetadataState,生成并解析 header → 出来被检查为 fork 来源存在,而 parent_thread_id 和 subagent_kind 不存在。

调用关系:它专门覆盖“有 fork、没有父子代理关系”的场景,帮助区分 fork 线索和子代理父线程线索。

调用图:调用 4 个内部函数(new, test_turn_metadata_header, read_only, from_string);外部调用 4 个(new, assert!, assert_eq!, from_str)。

turn_metadata_state_includes_thread_spawn_subagent_parent_without_fork251–286 ↗
fn turn_metadata_state_includes_thread_spawn_subagent_parent_without_fork()

作用:确认由线程派生出来的子代理,即使不是 fork,也会记录父线程编号和子代理类型。子代理可以理解成主对话派出去干活的小助手。

数据流:进去没有外部参数 → 它创建父线程编号,构造 ThreadSpawn 类型的子代理来源,生成元数据 JSON → 最后确认 parent_thread_id 是父线程,subagent_kind 是 thread_spawn,forked_from_thread_id 不存在。

调用关系:它验证 SessionSource::SubAgent 里的 ThreadSpawn 情况。和 fork 测试放在一起看,可以确认两种“从哪里来”的信息不会混淆。

调用图:调用 4 个内部函数(new, test_turn_metadata_header, read_only, from_string);外部调用 5 个(new, SubAgent, assert!, assert_eq!, from_str)。

turn_metadata_state_includes_forked_thread_spawn_subagent_lineage289–327 ↗
fn turn_metadata_state_includes_forked_thread_spawn_subagent_lineage()

作用:确认一个既是 fork、又是线程派生子代理的轮次,会同时保留两条来源线索。这样后续分析能知道它既分叉自哪里,也由哪个父线程派生。

数据流:进去没有外部参数 → 它用同一个线程编号同时作为 fork 来源和父线程,创建子代理状态并生成 JSON → 出来被断言为 forked_from_thread_id、parent_thread_id、subagent_kind 都正确存在。

调用关系:它覆盖来源信息最复杂的一种组合情况,确保 TurnMetadataState 不会因为写了一个来源字段就丢掉另一个。

调用图:调用 4 个内部函数(new, test_turn_metadata_header, read_only, from_string);外部调用 4 个(new, SubAgent, assert_eq!, from_str)。

turn_metadata_state_includes_known_parent_for_non_thread_spawn_subagents_without_fork330–369 ↗
fn turn_metadata_state_includes_known_parent_for_non_thread_spawn_subagents_without_fork()

作用:确认不是 ThreadSpawn 的子代理,只要知道父线程,也会写入 parent_thread_id,并写出对应的子代理种类。

数据流:进去没有外部参数 → 它准备一个父线程编号,并循环测试 Review、Other 等几种子代理来源 → 每次都生成 JSON,确认没有 fork 字段、有父线程字段,并且 subagent_kind 和来源名称一致。

调用关系:这个测试扩展了子代理来源的覆盖面。它和 ThreadSpawn 测试一起保证各种子代理都能留下可追踪的来源标签。

调用图:调用 4 个内部函数(new, test_turn_metadata_header, read_only, from_string);外部调用 6 个(new, SubAgent, assert!, assert_eq!, Other, from_str)。

turn_metadata_state_includes_turn_started_at_unix_ms_after_start372–398 ↗
fn turn_metadata_state_includes_turn_started_at_unix_ms_after_start()

作用:确认当系统记录了本轮开始时间后,元数据会带上 turn_started_at_unix_ms。Unix 毫秒时间就是从 1970 年开始数到现在的毫秒数。

数据流:进去没有外部参数 → 它创建状态,手动设置一个开始时间戳,再生成并解析 header → 出来被检查为 JSON 中的 turn_started_at_unix_ms 等于设置值。

调用关系:它验证 set_turn_started_at_unix_ms 对最终元数据的影响,确保时间字段是系统写入后才出现。

调用图:调用 3 个内部函数(new, test_turn_metadata_header, read_only);外部调用 3 个(new, assert_eq!, from_str)。

turn_metadata_state_includes_model_and_reasoning_effort_only_in_request_meta401–446 ↗
fn turn_metadata_state_includes_model_and_reasoning_effort_only_in_request_meta()

作用:确认模型名和推理力度只出现在 MCP 请求元数据里,不出现在普通 header 里。这样可以避免把只属于某类请求的信息到处散播。

数据流:进去没有外部参数 → 它创建状态,先检查基础 header 没有 model 和 reasoning_effort,再用 MCP 上下文生成当前请求元数据 → 出来被检查为 MCP 元数据有模型名;有推理力度时写入,没有推理力度时就省略。

调用关系:它使用 test_mcp_turn_metadata_context 准备输入,也使用 test_turn_metadata_header 对比基础 header,重点验证不同出口的字段边界。

调用图:调用 4 个内部函数(new, test_mcp_turn_metadata_context, test_turn_metadata_header, read_only);外部调用 4 个(new, assert!, assert_eq!, from_str)。

turn_metadata_state_marks_user_input_requested_during_turn_only_for_mcp_request_meta449–498 ↗
fn turn_metadata_state_marks_user_input_requested_during_turn_only_for_mcp_request_meta()

作用:确认“本轮中请求过用户输入”这个标记只写进 MCP 请求元数据,不写进普通 header。这个标记说明模型或工具链在运行中曾经需要用户补充信息。

数据流:进去没有外部参数 → 它先生成 header 和 MCP 元数据,确认标记都没有;然后调用 mark_user_input_requested_during_turn;再重新生成两类元数据 → 出来被检查为 header 仍没有该字段,而 MCP 元数据中该字段为 true。

调用关系:它通过 test_mcp_turn_metadata_context 和 test_turn_metadata_header 同时观察两个出口,验证状态变化只影响应该影响的 MCP 请求路径。

调用图:调用 4 个内部函数(new, test_mcp_turn_metadata_context, test_turn_metadata_header, read_only);外部调用 4 个(new, assert!, assert_eq!, from_str)。

turn_metadata_state_ignores_client_reserved_metadata_before_start501–541 ↗
fn turn_metadata_state_ignores_client_reserved_metadata_before_start()

作用:确认客户端在请求开始前传入的保留字段不会被系统采纳。保留字段就是系统自己负责填写、外部不该冒充的字段。

数据流:进去没有外部参数 → 它创建状态,塞入一批客户端自称的 turn_started_at_unix_ms、forked_from_thread_id、parent_thread_id、subagent_kind → 生成 JSON 后确认这些字段都没有被写进去。

调用关系:它验证 set_responsesapi_client_metadata 的过滤规则,特别是还没由系统正式设置这些字段时,客户端不能抢先伪造。

调用图:调用 3 个内部函数(new, test_turn_metadata_header, read_only);外部调用 4 个(from, new, assert!, from_str)。

turn_metadata_state_merges_client_metadata_without_replacing_reserved_fields544–669 ↗
fn turn_metadata_state_merges_client_metadata_without_replacing_reserved_fields()

作用:确认客户端自定义元数据可以合并进 header,但不能覆盖系统保留字段。简单说,客户可以贴便签,但不能改身份证号码。

数据流:进去没有外部参数 → 它创建带 fork 和父线程关系的状态,塞入大量客户端字段,其中既有普通字段也有保留字段,再设置系统开始时间 → 它分别生成基础 header、普通模型请求元数据、MCP 请求元数据 → 最后确认普通客户端字段保留,系统字段仍以系统值为准,安装编号和窗口编号只在模型请求里出现,MCP 里的模型名来自 MCP 上下文。

调用关系:这是本文件最全面的合并规则测试。它调用 test_turn_metadata_header 看基础输出,调用 test_turn_responses_metadata_json 看发模型时的输出,也用 test_mcp_turn_metadata_context 看 MCP 请求出口。

调用图:调用 6 个内部函数(new, test_mcp_turn_metadata_context, test_turn_metadata_header, test_turn_responses_metadata_json, read_only, from_string);外部调用 6 个(from, new, SubAgent, assert!, assert_eq!, from_str)。

turn_metadata_state_overlays_compaction_only_on_compaction_requests672–723 ↗
fn turn_metadata_state_overlays_compaction_only_on_compaction_requests()

作用:确认压缩信息只叠加到压缩请求上,不会污染普通对话请求。压缩信息描述为什么压缩、谁触发、用哪种实现、发生在哪个阶段。

数据流:进去没有外部参数 → 它创建状态,并让客户端也提供一个名为 compaction 的普通字段;然后生成压缩请求 JSON 和普通请求 JSON → 出来被检查为压缩请求的 compaction 被系统结构化信息覆盖,普通请求里没有 compaction 字段。

调用关系:它用 test_compaction_responses_metadata_json 生成压缩出口,用 test_turn_responses_metadata_json 生成普通出口,通过对比确认压缩元数据只在正确路径出现。

调用图:调用 5 个内部函数(new, new, test_compaction_responses_metadata_json, test_turn_responses_metadata_json, read_only);外部调用 5 个(from, new, assert!, assert_eq!, from_str)。

turn_metadata_state_preserves_lineage_after_git_enrichment726–779 ↗
async fn turn_metadata_state_preserves_lineage_after_git_enrichment()

作用:确认后台补充 Git 工作区信息之后,线程来源信息不会被冲掉。Git 补充是异步进行的,像后台有人给身份卡补上一栏“仓库状态”。

数据流:进去没有外部参数 → 它创建干净 Git 仓库和带 fork、父线程、子代理来源的状态,启动 Git 信息补充任务 → 它反复读取 header,直到 workspaces 出现 → 最后确认 forked_from_thread_id、parent_thread_id、subagent_kind 仍然完整。

调用关系:它连接 create_clean_git_repo、spawn_git_enrichment_task 和 test_turn_metadata_header,覆盖异步更新场景,确保后台写工作区信息时不会破坏已有身份线索。

调用图:调用 5 个内部函数(new, create_clean_git_repo, test_turn_metadata_header, read_only, from_string);外部调用 7 个(from_millis, from_secs, SubAgent, assert_eq!, from_str, sleep, timeout)。

core/src/turn_diff_tracker_tests.rs源码 ↗
testtest run

这个测试文件像一套验收题,检查 TurnDiffTracker 记账是不是可靠。TurnDiffTracker 要把一次对话里多次打补丁造成的文件变化合并起来,最后给用户看一份统一 diff(Git 常用的改动说明格式)。这里用临时文件夹造出各种真实场景:先新增再修改要算成一次新增,删了又加回来要算成修改,只改文件名但内容没变就不该显示内容差异,移动文件覆盖已有文件时要分清是删除源文件还是更新目标文件。文件里还有缓存测试,防止每次读取总 diff 都重复做重活;也有大文件重写测试,确认生成的 diff 不但快,而且能被 Git 应用回去并保持内容一字不差。

函数细节17
git_blob_sha1_hex16–18 ↗
fn git_blob_sha1_hex(data: &str) -> String

作用:把一段文字算成 Git blob 的 SHA-1 十六进制编号。测试用它来拼出预期 diff 里的 index 行,避免手写哈希值。

数据流:输入是一段字符串 → 函数按 Git 保存文件内容的方式计算这段内容的哈希 → 输出一个十六进制字符串,供测试拿来和实际 diff 对比。

调用关系:它是很多测试的辅助小工具。新增、删除、移动、覆盖等测试在准备 expected diff 时都会调用它,这样测试关注的是 TurnDiffTracker 生成的 diff 是否符合 Git 习惯。

调用图:被 9 处调用(accumulates_add_then_update_as_single_add, accumulates_delete, accumulates_move_and_update, add_over_existing_file_becomes_update, delete_then_readd_same_path_becomes_update, move_over_existing_destination_with_content_change_deletes_source_and_updates_destination, move_over_existing_destination_without_content_change_deletes_source_only, preserves_committed_change_order_with_delete_then_move_overwrite, tracks_same_absolute_path_across_multiple_environments);外部调用 1 个(format!)。

apply_verified_patch20–47 ↗
async fn apply_verified_patch(root: &Path, patch: &str) -> AppliedPatchDelta

作用:把测试里写好的 apply_patch 文本真正应用到临时目录,并返回这次补丁造成的变化记录。它让测试不是凭空造数据,而是用真实补丁流程产生输入。

数据流:输入是一个目录和一段补丁文本 → 先把目录变成绝对路径,再确认这段命令确实是可验证的补丁操作,然后实际应用补丁 → 输出 AppliedPatchDelta,也就是“这次补丁改了哪些文件、怎么改”的记录;同时磁盘上的临时文件也被改动。

调用关系:大多数测试都会先调用它制造一次真实改动,再把结果交给 TurnDiffTracker.track_delta。它内部把活交给补丁解析和补丁应用函数;如果解析结果不是预期的补丁动作,就直接让测试失败。

调用图:调用 1 个内部函数(from_absolute_path);被 13 处调用(accumulates_add_then_update_as_single_add, accumulates_delete, accumulates_move_and_update, add_over_existing_file_becomes_update, delete_then_readd_same_path_becomes_update, invalidated_tracker_suppresses_existing_diff, move_over_existing_destination_with_content_change_deletes_source_and_updates_destination, move_over_existing_destination_without_content_change_deletes_source_only, preserves_committed_change_order_with_delete_then_move_overwrite, pure_rename_yields_no_diff (+3 more));外部调用 5 个(new, apply_patch, maybe_parse_apply_patch_verified, panic!, vec!)。

tracker_with_root49–51 ↗
fn tracker_with_root(root: &Path) -> TurnDiffTracker

作用:快速创建一个只对应单个根目录的 TurnDiffTracker。测试用它少写重复的初始化代码。

数据流:输入是临时目录路径 → 函数把路径复制成 tracker 需要的格式,并设置显示根目录 → 输出一个新的 TurnDiffTracker。

调用关系:多数测试一开始都会调用它。它把测试的临时目录和 TurnDiffTracker 连接起来,让后续 track_delta 和 get_unified_diff 知道文件路径应该怎样显示。

调用图:调用 1 个内部函数(with_environment_display_roots);被 13 处调用(accumulates_add_then_update_as_single_add, accumulates_delete, accumulates_move_and_update, add_over_existing_file_becomes_update, delete_then_readd_same_path_becomes_update, invalidated_tracker_suppresses_existing_diff, large_rewrite_returns_promptly_and_preserves_exact_content, move_over_existing_destination_with_content_change_deletes_source_and_updates_destination, move_over_existing_destination_without_content_change_deletes_source_only, preserves_committed_change_order_with_delete_then_move_overwrite (+3 more));外部调用 1 个(to_path_buf)。

accumulates_add_then_update_as_single_add54–85 ↗
async fn accumulates_add_then_update_as_single_add()

作用:测试“先新增文件,再修改这个新文件”最后应该显示成一次新增,而不是一条新增加一条修改。这样用户看到的是最终结果,不会被中间步骤干扰。

数据流:测试创建临时目录和 tracker → 应用新增 a.txt 的补丁,再应用给 a.txt 增加一行的补丁 → tracker 合并两次变化 → 输出的 unified diff 应该是一份新文件 diff,内容包含 foo 和 bar。

调用关系:它通过 tracker_with_root 建 tracker,通过 apply_verified_patch 制造两次补丁,通过 git_blob_sha1_hex 计算预期哈希,最后用断言检查 TurnDiffTracker.get_unified_diff 的结果。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 3 个(assert_eq!, format!, tempdir)。

invalidated_tracker_suppresses_existing_diff88–102 ↗
async fn invalidated_tracker_suppresses_existing_diff()

作用:测试 tracker 被标记为失效后,不应该继续吐出旧的 diff。这样可以避免用户看到已经不可信的改动摘要。

数据流:测试先新增一个文件并让 tracker 记住变化 → 调用 invalidate 把 tracker 标成失效 → 再读取 unified diff → 结果应该是 None,也就是没有可展示的 diff。

调用关系:它用 apply_verified_patch 产生一次正常变化,再专门检查 invalidate 对 get_unified_diff 的影响。这个测试覆盖的是异常或不确定状态下的安全行为。

调用图:调用 2 个内部函数(apply_verified_patch, tracker_with_root);外部调用 2 个(assert_eq!, tempdir)。

tracks_same_absolute_path_across_multiple_environments105–139 ↗
async fn tracks_same_absolute_path_across_multiple_environments()

作用:测试同一个真实目录在不同环境名字下出现时,tracker 能按不同显示前缀分别记录。比如同一份文件从 local 和 remote 两个视角看,不能互相覆盖掉。

数据流:测试在临时目录里新增 shared.txt → 创建一个带 local 和 remote 两个显示根的 tracker → 分别用两个环境名记录同一份变化 → 输出 diff 应该有两段,一段路径带 local,一段路径带 remote。

调用关系:它没有用 tracker_with_root,而是直接调用 with_environment_display_roots 建多环境 tracker。它仍然用 apply_verified_patch 产生真实补丁,用 git_blob_sha1_hex 拼预期 diff。

调用图:调用 3 个内部函数(with_environment_display_roots, apply_verified_patch, git_blob_sha1_hex);外部调用 3 个(assert_eq!, format!, tempdir)。

accumulates_delete142–166 ↗
async fn accumulates_delete()

作用:测试删除已有文件时,tracker 能生成正确的删除 diff。没有这个能力,用户就看不清哪些文件被移除了。

数据流:测试先在临时目录写入 b.txt → 应用删除 b.txt 的补丁 → tracker 记录这次删除 → 输出 diff 应该显示 deleted file mode、旧内容 x 被删掉,以及新端是空设备 DEV_NULL。

调用关系:它先用文件系统写入种子文件,再用 apply_verified_patch 删除文件。git_blob_sha1_hex 用来算删除前内容的哈希,最后断言 tracker 的输出。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

accumulates_move_and_update169–194 ↗
async fn accumulates_move_and_update()

作用:测试文件被移动并且内容也改了时,diff 要同时表现出旧路径、新路径和内容变化。这样用户能看出“搬家”和“改内容”是同一件事里发生的。

数据流:测试先写入 src.txt,内容是 line → 应用一个把它移动到 dst.txt 并改成 line2 的补丁 → tracker 记录后生成 diff → 输出应显示 a/src.txt 到 b/dst.txt,并展示 line 变成 line2。

调用关系:它用 tracker_with_root 建 tracker,用 apply_verified_patch 走真实移动补丁流程,用 git_blob_sha1_hex 计算移动前后的内容编号,再比较完整 diff。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

pure_rename_yields_no_diff197–210 ↗
async fn pure_rename_yields_no_diff()

作用:测试只改文件名、内容完全不变时,不显示内容 diff。这里的 TurnDiffTracker 关注的是内容变化,所以纯重命名不会产生可展示差异。

数据流:测试先写 old.txt,内容是 same → 应用移动到 new.txt 但内容不变的补丁 → tracker 记录这次变化 → get_unified_diff 返回 None。

调用关系:它借助 apply_verified_patch 制造纯重命名场景,再检查 tracker 的输出。这个测试说明 tracker 不把“路径名变化但内容不变”当成需要展示的文本改动。

调用图:调用 2 个内部函数(apply_verified_patch, tracker_with_root);外部调用 3 个(assert_eq!, write, tempdir)。

add_over_existing_file_becomes_update213–238 ↗
async fn add_over_existing_file_becomes_update()

作用:测试补丁说“新增文件”,但目标路径其实已经有文件时,tracker 应该把它当成更新已有文件。这样 diff 才符合用户真实看到的结果。

数据流:测试先写 dup.txt,内容是 before → 应用一个 Add File 补丁,把 dup.txt 写成 after → tracker 记录后生成 diff → 输出应是 before 改成 after,而不是新文件从空开始。

调用关系:它结合文件系统预置内容和 apply_verified_patch 的补丁结果,检查 TurnDiffTracker 对“新增覆盖已有文件”这种边界情况的归类是否正确。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

delete_then_readd_same_path_becomes_update241–273 ↗
async fn delete_then_readd_same_path_becomes_update()

作用:测试同一个路径先删除再重新添加时,最终应该看起来像一次内容修改。这样用户看到的是文件从旧内容变成新内容,而不是被拆成两件绕人的事。

数据流:测试先写 cycle.txt,内容是 before → 应用删除补丁并记录 → 再应用重新添加 after 的补丁并记录 → tracker 合并两次变化 → 输出 diff 应显示 before 变成 after。

调用关系:它连续两次调用 apply_verified_patch,并把两次 delta 都交给同一个 tracker。这个测试验证 tracker 能跨多次补丁合并同一路径的生命周期。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

move_over_existing_destination_without_content_change_deletes_source_only276–301 ↗
async fn move_over_existing_destination_without_content_change_deletes_source_only()

作用:测试把 a.txt 移到已经存在且内容相同的 b.txt 时,结果只应该算删除了 a.txt。因为 b.txt 原本就有一样的内容,没有真正变。

数据流:测试先写 a.txt 和 b.txt,内容都是 same → 应用把 a.txt 移到 b.txt 的补丁 → tracker 分析后输出 diff → 只显示 a.txt 被删除,不显示 b.txt 被更新。

调用关系:它用两个种子文件制造“移动覆盖但目标没变”的场景。apply_verified_patch 提供真实 delta,git_blob_sha1_hex 生成删除源文件时需要的旧内容哈希。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

move_over_existing_destination_with_content_change_deletes_source_and_updates_destination304–339 ↗
async fn move_over_existing_destination_with_content_change_deletes_source_and_updates_destination()

作用:测试把源文件移动到已有目标文件上,并且新内容和目标原内容不同的时候,要拆成两件事:源文件被删,目标文件被改。

数据流:测试先写 a.txt 为 from,b.txt 为 existing → 应用把 a.txt 移到 b.txt 且内容变成 new 的补丁 → tracker 输出两段 diff → 第一段删除 a.txt,第二段把 b.txt 从 existing 改成 new。

调用关系:它覆盖移动覆盖里更复杂的一种情况。它调用 apply_verified_patch 得到补丁变化,调用 git_blob_sha1_hex 分别计算源文件旧值、目标旧值和目标新值的哈希。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

preserves_committed_change_order_with_delete_then_move_overwrite342–376 ↗
async fn preserves_committed_change_order_with_delete_then_move_overwrite()

作用:测试当一个补丁里先删除目标文件、再把源文件移动过去时,tracker 最终仍然给出稳定且正确的结果。重点是不要因为内部合并顺序弄错语义。

数据流:测试先准备 a.txt 和 b.txt → 应用一个补丁:先删 b.txt,再把 a.txt 移到 b.txt 并改内容 → tracker 记录后输出 diff → 结果应显示 a.txt 被删除,b.txt 从旧内容更新为新内容。

调用关系:它和前一个移动覆盖测试很像,但把删除目标文件写进同一个补丁里,专门检查 TurnDiffTracker 对补丁内操作顺序的处理。

调用图:调用 3 个内部函数(apply_verified_patch, git_blob_sha1_hex, tracker_with_root);外部调用 4 个(assert_eq!, format!, write, tempdir)。

reuses_rendered_diffs_for_unchanged_paths379–405 ↗
async fn reuses_rendered_diffs_for_unchanged_paths()

作用:测试 tracker 会复用已经渲染好的文件 diff,不会每次读取总 diff 都重新计算。这个缓存能避免文件多时反复做同样的重活。

数据流:测试先新增 a.txt 并记录,渲染计数应为 1 → 再新增 b.txt 并记录,计数应为 2 → 连续读取 unified diff → 内容一样,并且渲染计数仍然是 2,没有额外增加。

调用关系:它通过 rendered_diff_count 观察内部缓存效果。apply_verified_patch 只负责制造新增文件,真正被验证的是 TurnDiffTracker 在 get_unified_diff 时是否复用旧结果。

调用图:调用 2 个内部函数(apply_verified_patch, tracker_with_root);外部调用 2 个(assert_eq!, tempdir)。

repeated_updates_only_rerender_the_touched_path408–428 ↗
async fn repeated_updates_only_rerender_the_touched_path()

作用:测试反复修改一个热点文件时,tracker 只重新生成这个被碰到的文件的 diff,不要连稳定文件也反复重算。这样可以保证多轮更新时性能可控。

数据流:测试先新增 stable.txt 和 hot.txt → 然后把 hot.txt 连续更新 40 次 → tracker 每次只需要重算 hot.txt 的 diff → 最后渲染次数应正好是 42,也就是两个新增加 40 次热点更新。

调用关系:它用循环不断调用 apply_verified_patch 和 track_delta,模拟一个文件被频繁编辑的场景。断言 rendered_diff_count 用来证明缓存粒度是按路径来的。

调用图:调用 2 个内部函数(apply_verified_patch, tracker_with_root);外部调用 3 个(assert_eq!, format!, tempdir)。

large_rewrite_returns_promptly_and_preserves_exact_content431–495 ↗
fn large_rewrite_returns_promptly_and_preserves_exact_content()

作用:测试超大文件整篇重写时,render_diff 既要很快返回,也要生成可被 Git 正确应用的 diff。它防止大改动把系统拖慢,或因为省事生成了不准确的补丁。

数据流:测试创建 Git 仓库并关闭自动换行转换 → 生成 48000 行旧内容和 48000 行新内容 → 调用 tracker.render_diff 生成 diff 并计时 → 用 apply_git_patch 把 diff 应用到真实文件 → 最后确认命令成功,而且文件内容完全等于新内容。

调用关系:这是一个偏性能和正确性的集成测试。它用 tracker_with_root 建 tracker,用 TrackedPath 标记文件路径,直接调用 render_diff 生成补丁,再把补丁交给 Git 工具验证是否真的能落盘。

调用图:调用 2 个内部函数(new, tracker_with_root);外部调用 6 个(now, assert!, assert_eq!, apply_git_patch, write, tempdir)。

core/src/turn_timing_tests.rs源码 ↗
testtest run

这个文件不负责正式运行功能,而是专门“验收”计时逻辑。可以把一轮对话想成一次外卖订单:下单时间、商家第一次接单、开始做菜、骑手被堵住、最后送达,都要记清楚。这里测试的就是类似这些时间点有没有被正确记录。它会检查:第一次文本输出时间,也就是 TTFT(time to first token,第一次看到模型吐出文字的耗时)每轮只记一次;第一次消息时间,也就是 TTFM(time to first message,第一次形成完整消息的耗时)和 TTFT 互不干扰;一轮开始时能保存接近真实系统时间的毫秒时间戳;哪些响应内容算作“已经有输出”;以及 TurnProfileState 能不能把一轮里的模型采样、工具阻塞、重试开销等时间拆开算清楚。这样以后改计时代码时,如果不小心把统计口径弄错,测试会立刻报错。

函数细节6
turn_timing_state_records_ttft_only_once_per_turn20–48 ↗
async fn turn_timing_state_records_ttft_only_once_per_turn()

作用:这个测试确认 TTFT,也就是“本轮第一次看到模型输出文字的时间”,一轮里只会被记录一次。这样统计响应速度时,不会因为后续又来了更多文字而重复算时间。

数据流:一开始创建一个空的 TurnTimingState。还没标记一轮开始时,传入一段输出文字,结果应该什么都不记;标记一轮开始后,先传入 Created 这种还不算文字输出的事件,也不记;再传入第一段文字,应该得到一个计时结果;最后再传入第二段文字,结果又变回 None,表示不会重复记录。

调用关系:这是直接测试 TurnTimingState 的保护规则。它自己构造 ResponseEvent 事件,调用 record_ttft_for_response_event 检查状态变化,用断言确认这套“只记第一次”的行为没有被破坏。

调用图:外部调用 4 个(now, assert!, assert_eq!, default)。

turn_timing_state_records_ttfm_independently_of_ttft51–83 ↗
async fn turn_timing_state_records_ttfm_independently_of_ttft()

作用:这个测试确认 TTFM,也就是“第一次形成消息的时间”,和 TTFT 是分开记录的。即使已经记过第一次文字输出,系统仍然应该能单独记第一次消息。

数据流:测试先创建计时状态并标记一轮开始。然后传入一段输出文字,让 TTFT 被记录;接着传入第一个 AgentMessage,应该记录 TTFM;再传入第二个 AgentMessage,应该返回 None,表示 TTFM 也只记第一次。最终验证两个计时点互不抢占,但各自都只记一次。

调用关系:它承接上一类 TTFT 测试,进一步覆盖 TurnTimingState 的另一条计时线。它把事件交给 record_ttft_for_response_event,把消息交给 record_ttfm_for_turn_item,证明这两个入口在同一轮里能正确配合。

调用图:外部调用 4 个(now, assert!, assert_eq!, default)。

turn_timing_state_records_turn_started_epoch_millis86–104 ↗
async fn turn_timing_state_records_turn_started_epoch_millis()

作用:这个测试确认系统在一轮开始时,会保存一个真实世界时间的毫秒时间戳。这个时间戳适合写日志、做分析,因为人和外部系统都能理解。

数据流:测试先读取当前系统时间,得到 before;然后调用 mark_turn_started 标记一轮开始,并拿到 started_at_unix_ms;再读取一次当前系统时间,得到 after。它检查 started_at_unix_ms 落在 before 和 after 之间,并且 started_at_unix_secs 返回的是这个毫秒值换算成秒后的结果。

调用关系:它测试 TurnTimingState 在“内部计时”和“外部可读时间”之间的桥接。mark_turn_started 用 Instant 记录相对时间,同时也保存 Unix 时间戳;started_at_unix_secs 则给其他统计或日志代码读取秒级开始时间。

调用图:外部调用 5 个(now, now, assert!, assert_eq!, default)。

response_item_records_turn_ttft_for_first_output_signals107–137 ↗
fn response_item_records_turn_ttft_for_first_output_signals()

作用:这个测试确认哪些响应内容应该算作“一轮已经开始有输出了”,从而可以记录 TTFT。比如调用工具、调用自定义工具、或者助手发出非空文字,都算有效输出信号。

数据流:测试分别构造三种 ResponseItem:普通工具调用、定制工具调用、带有文字内容的助手消息。每一种都传给 response_item_records_turn_ttft,期望返回 true,意思是这些内容足够说明模型已经产生了可见动作或输出。

调用关系:它直接测试 response_item_records_turn_ttft 这个判断函数。这个判断会影响上层计时逻辑:当响应项被认为是“首次输出信号”时,系统才会把它用于 TTFT 统计。

调用图:外部调用 1 个(assert!)。

response_item_records_turn_ttft_ignores_empty_non_output_items140–157 ↗
fn response_item_records_turn_ttft_ignores_empty_non_output_items()

作用:这个测试确认空消息或不是模型首次输出的内容,不会误触发 TTFT。这样可以避免把“没有真正输出”的东西算成响应已经开始。

数据流:测试构造两个不该算首次输出的 ResponseItem:一个是文字为空的助手消息,另一个是工具调用的返回结果。它们传入 response_item_records_turn_ttft 后都应该返回 false,表示不会用于记录 TTFT。

调用关系:它和前一个测试配成一对:一个验证该算的会算,另一个验证不该算的不会算。两者一起限定 response_item_records_turn_ttft 的边界,防止统计口径变宽或变窄。

调用图:外部调用 1 个(assert!)。

turn_profile_breaks_down_sampling_blocking_and_retry_overhead160–194 ↗
fn turn_profile_breaks_down_sampling_blocking_and_retry_overhead()

作用:这个测试确认一轮对话的总耗时能被拆成几段有意义的时间:开始到第一次模型采样前、模型采样时间、两次采样之间的额外开销、工具阻塞时间、最后一次采样后的收尾时间,以及采样请求和重试次数。

数据流:测试从一个起点时间开始,手工模拟时间线:100 毫秒后开始采样,600 毫秒结束;接着进入 300 毫秒工具阻塞;记录一次采样重试;1000 毫秒再次开始采样,1200 毫秒结束;最后 1300 毫秒完成整轮。complete 输出一个 TurnProfile,测试把它和预期结果逐项比较,确认每段时间和计数都正确。

调用关系:它测试 TurnProfileState 这台“秒表机器”的完整流程:start 开始计时,begin_sampling 和 begin_tool_blocking 标记阶段开始,end_phase 结束阶段,record_sampling_retry 记录重试,complete 汇总成 TurnProfile。这个结果通常会被分析系统用来解释一轮对话为什么快或慢。

调用图:外部调用 4 个(from_millis, now, assert_eq!, default)。

core/src/user_shell_command_tests.rs源码 ↗
testtest

这是一组自动测试,检查系统如何把用户的终端命令整理成一段固定格式的文本。这里的 shell 命令可以理解成在命令行里输入的指令,比如 echo hi。系统需要把这类命令包在 <user_shell_command> 这样的标签里,像给一份记录贴上清楚的标签,方便后面再识别。文件里先测试普通文本不会被误认为命令记录;然后测试一次成功执行的命令会被格式化成包含命令、退出码、耗时和输出的完整记录;最后还测试当 stdout、stderr 和合并输出都存在时,系统优先使用“合并后的输出”。这很重要,因为合并输出更接近用户实际看到的终端内容,顺序和上下文更完整。

函数细节3
detects_user_shell_command_text_variants11–16 ↗
fn detects_user_shell_command_text_variants()

作用:这个测试确认系统能认出带有 <user_shell_command> 标签的文本,同时不会把普通的 echo hi 误判成一条已记录的用户命令。

数据流:输入是两段文本:一段带命令记录标签,一段只是普通命令文字。测试把它们交给 UserShellCommand::matches_text 判断,然后检查第一段结果必须是真,第二段结果必须是假;它不产生新数据,只验证判断规则是否正确。

调用关系:它直接测试命令记录的“入口识别”规则。调用的断言工具会在结果不符合预期时让测试失败,提醒开发者识别规则被改坏了。

调用图:外部调用 1 个(assert!)。

formats_basic_record19–40 ↗
async fn formats_basic_record()

作用:这个测试确认一条普通执行成功的 shell 命令,会被整理成系统期望的标准记录格式。

数据流:先造出一份假的命令执行结果:退出码是 0,输出是 hi,运行 1 秒,没有超时。接着创建一个测试用会话上下文,把命令 echo hi 和执行结果交给记录生成函数。最后取出生成的消息文本,确认它精确等于预期的 XML 风格记录;如果生成的不是消息或不是文本,测试会直接失败。

调用关系:它模拟一次命令执行后,系统把结果写回对话记录的场景。它会用 make_session_and_context 准备测试环境,再调用实际的记录生成逻辑,最后用断言比较完整文本,确保外层标签、命令、退出码、耗时和输出都没有偏差。

调用图:调用 2 个内部函数(make_session_and_context, new);外部调用 4 个(from_secs, new, assert_eq!, panic!)。

uses_aggregated_output_over_streams43–58 ↗
async fn uses_aggregated_output_over_streams()

作用:这个测试确认当命令结果里同时有 stdout、stderr 和合并输出时,最终记录使用的是合并输出,而不是单独的 stdout 或 stderr。

数据流:测试先准备一份假的执行结果:退出码是 42,stdout 是 stdout-only,stderr 是 stderr-only,合并输出是 combined output wins,耗时 120 毫秒。然后把它和命令 false 交给格式化函数,得到一整段记录文本。最后检查记录里的 Output 部分必须是合并输出,并且耗时被格式化成 0.1200 seconds

调用关系:它测试的是命令记录格式化流程里的一个关键选择:多个输出来源冲突时该信谁。它用测试上下文模拟真实运行环境,直接调用 format_user_shell_command_record,确保下游看到的是最完整的终端输出。

调用图:调用 2 个内部函数(make_session_and_context, new);外部调用 2 个(from_millis, assert_eq!)。

core/src/image_preparation_tests.rs源码 ↗
testtest run

这份文件像是图片处理功能的“质检员”。系统里有些消息会带图片,图片可能是直接塞在文本里的 data URL(一种把图片字节转成字符串的写法),也可能只是普通网页链接。测试先造出假的 PNG 图片,再调用真正的 prepare_response_items,看它有没有按规则做事:小图不能被无故改掉,网页链接不能乱碰,大图要按不同清晰度策略缩小,工具返回的坏图片要换成安全、简短、能提示用户的文字。它还检查错误提示不能泄露太多内部细节,只给可行动的占位文案。没有这些测试,图片入口一改坏,用户可能看到莫名失败,或者系统把不能处理的图片继续往后传。

函数细节6
png_data_url17–25 ↗
fn png_data_url(width: u32, height: u32) -> (String, Vec<u8>)

作用:造一张指定宽高的纯色 PNG 测试图片,并把它包装成 data URL。测试用它来稳定地生成“看起来像真实用户上传”的图片。

数据流:进去的是宽和高 → 它用同一种颜色填满一张图片,把图片编码成 PNG 字节,再把这些字节转成 data URL 字符串 → 出来的是这个 data URL,以及原始 PNG 字节,方便后面比较处理前后有没有变。

调用关系:它是几个测试的造假图片小工厂。小图保留测试、尺寸策略测试、工具图片失败替换测试都会先找它生成样本,再把样本交给图片准备流程去检验。

调用图:调用 1 个内部函数(new);被 3 处调用(detail_policies_apply_the_expected_budgets, preparation_preserves_small_image_bytes_and_non_data_urls, preparation_replaces_only_failed_tool_images_and_preserves_metadata);外部调用 5 个(ImageRgba8, from_pixel, new, data_url_from_bytes, Rgba)。

decoded_image27–32 ↗
fn decoded_image(image_url: &str) -> (Vec<u8>, DynamicImage)

作用:把 data URL 里的图片重新解出来,变回字节和可检查尺寸的图片对象。测试用它确认处理后的图片内容和大小是否符合预期。

数据流:进去的是一个 image_url 字符串 → 它取出逗号后面的 base64 内容,base64 是一种把二进制数据写成普通字符的编码;然后解码成字节,再按图片格式读成图片 → 出来的是图片字节和图片对象。

调用关系:它站在图片准备流程之后,用来验收结果。测试把 prepare_response_items 改过的图片交给它,再比较字节是否没变,或尺寸是否被缩到正确大小。

调用图:外部调用 1 个(load_from_memory)。

preparation_preserves_small_image_bytes_and_non_data_urls35–72 ↗
fn preparation_preserves_small_image_bytes_and_non_data_urls()

作用:确认系统不会乱改不该改的图片。小的 data URL 图片应该原样保留,普通 http 图片链接也应该照旧保留。

数据流:开始时它造一张 64×32 的小 PNG,再准备一个普通网页图片地址 → 把两张图片放进一条用户消息,并调用 prepare_response_items → 最后检查第一张图片解码后的字节和原始字节完全一样,第二个网页链接也还是原来的字符串。

调用关系:这个测试覆盖图片准备流程里“别多手”的部分。它用 png_data_url 生成样本,用 decoded_image 验证结果,中间真正被考察的是 prepare_response_items。

调用图:调用 1 个内部函数(png_data_url);外部调用 3 个(assert_eq!, panic!, vec!)。

detail_policies_apply_the_expected_budgets75–102 ↗
fn detail_policies_apply_the_expected_budgets()

作用:确认不同图片清晰度设置会套用正确的尺寸上限。也就是说,大图进来后,该缩到多大不能凭感觉,必须符合规则。

数据流:进去的是一组测试案例:每个案例都有清晰度设置、输入尺寸和期望输出尺寸 → 它逐个造图,放进消息,调用 prepare_response_items → 再把处理后的图片解码,检查最终宽高是否等于期望值。

调用关系:这个测试集中检查图片准备流程的“尺寸预算”。它反复使用 png_data_url 做不同大小的图,再把结果拿给 decoded_image 看尺寸,保证 High、Original、Auto 和未指定清晰度时的行为都稳定。

调用图:调用 1 个内部函数(png_data_url);外部调用 3 个(assert_eq!, panic!, vec!)。

preparation_replaces_only_failed_tool_images_and_preserves_metadata105–169 ↗
fn preparation_replaces_only_failed_tool_images_and_preserves_metadata()

作用:确认工具返回内容里的图片如果坏了,只替换坏的那几项,别误伤其他文字、成功标记和元数据。它还检查低清晰度图片在这里会被明确拒绝。

数据流:开始时它准备一个工具调用输出,里面混有普通文字、格式坏掉的 data URL、不是图片的 data URL、低清晰度图片和正常高清图片 → 调用 prepare_response_items → 最后整个结果被拿来和预期值比较:坏图片变成通用错误文字,低清晰度图片变成不支持提示,正常高清图片留下,其他字段保持不变。

调用关系:这个测试盯的是工具输出这条分支,而不是普通用户消息。它用 png_data_url 造有效图片,然后考察 prepare_response_items 在复杂列表里逐项处理、只替换该替换内容的能力。

调用图:调用 1 个内部函数(png_data_url);外部调用 2 个(assert_eq!, vec!)。

preparation_errors_use_bounded_actionable_placeholders172–197 ↗
fn preparation_errors_use_bounded_actionable_placeholders()

作用:确认图片处理错误会变成固定、简短、对用户有帮助的占位文案。这样既能说明问题,又不会把内部错误细节直接暴露出去。

数据流:进去的是几种人为构造的错误:不支持低清晰度、图片太大、data URL 无效 → 它调用每个错误的 placeholder 方法 → 出来的是对应的固定提示文字,并逐一检查是否等于预期。

调用关系:这个测试不走完整图片处理流程,而是直接检查错误到用户提示的最后一步。它保证前面任何地方生成这些错误时,最终展示出来的文字都是受控的。

调用图:外部调用 2 个(assert_eq!, Processing)。

core/src/client_common_tests.rs源码 ↗
testtest run

这个文件不是真正跑业务的代码,而是给客户端请求生成逻辑做“体检”。它检查几件容易出错的事:图片输入在使用精简版 Responses API 时,是否会去掉图片清晰度 detail 字段;这个去掉动作是不是只改副本、不碰原始提示词;文本控制里的 verbosity(回答详细程度)和 JSON schema(要求模型按固定 JSON 结构输出)是否能正确变成 JSON;没设置 text 时是否真的不发送 text;以及 service_tier(服务档位)设为 flex 时是否序列化成服务端要的字符串。可以把它理解成发快递前的验单员:它不送包裹,但会确认地址、标签、附加要求都写对,避免真正请求发出去后才出问题。

函数细节7
prompt_with_image_outputs12–49 ↗
fn prompt_with_image_outputs() -> Prompt

作用:这个函数造出一个专门用于测试的 Prompt(一次发给模型的输入包)。这个输入包里同时包含普通用户图片、函数调用返回的图片、自定义工具返回的图片,方便后面的测试一次覆盖多种图片来源。

数据流:进去没有参数 → 它手工拼出一个 Prompt,里面放入三个带图片的输入项,并给每张图片设置不同的 detail(图片细节级别)→ 出来一个可复用的测试 Prompt;它不改外部状态。

调用关系:它是测试用的样品制造器。responses_lite_request_copies_strip_image_details 会先调用它拿到带图片细节的输入,然后再检查格式化请求时这些细节有没有按规则去掉。它内部只用默认值和列表构造来组装数据。

调用图:被 1 处调用(responses_lite_request_copies_strip_image_details);外部调用 2 个(default, vec!)。

responses_lite_request_copies_strip_image_details52–99 ↗
fn responses_lite_request_copies_strip_image_details()

作用:这个测试确认:当使用 Responses Lite(可以理解成精简版请求格式)时,所有图片上的 detail 字段都会被去掉。它还确认这个动作不会偷偷改掉原始 Prompt,只会改一份临时副本。

数据流:进去没有外部输入,由测试框架直接运行 → 它先用 prompt_with_image_outputs 做出带图片细节的 Prompt,并保存原始输入副本;然后调用 get_formatted_input_for_request(true) 得到精简版请求输入 → 它检查输出里的图片 detail 都变成 None,同时检查原 Prompt 仍然没变;最后再用 false 检查非精简版会保留原样。

调用关系:这是围绕 Prompt 请求格式化行为的保护测试。它依赖 prompt_with_image_outputs 提供复杂样本,再用断言 assert_eq! 把实际结果和预期结果逐项对比,防止以后有人改代码时不小心破坏图片处理规则。

调用图:调用 1 个内部函数(prompt_with_image_outputs);外部调用 1 个(assert_eq!)。

serializes_text_verbosity_when_set102–132 ↗
fn serializes_text_verbosity_when_set()

作用:这个测试确认:如果请求里设置了回答详细程度 verbosity,它会被正确写进发给 API 的 JSON 里。这里用的是 Low,也就是要求回答更简短。

数据流:进去没有外部输入 → 它构造一个 ResponsesApiRequest,并在 text 字段里放入 verbosity: Low;然后用 serde_json::to_value 把请求变成 JSON 值 → 最后检查 JSON 里的 text.verbosity 是否正好是字符串 "low"。

调用关系:它测试 ResponsesApiRequest 的序列化规则,也就是 Rust 结构体变成网络请求 JSON 的规则。测试框架运行它;它把检查工作交给 serde_json 做转换,再用 assert_eq! 判断转换后的字段是否符合服务端约定。

调用图:外部调用 3 个(assert_eq!, to_value, vec!)。

serializes_text_schema_with_strict_format135–184 ↗
fn serializes_text_schema_with_strict_format()

作用:这个测试确认:当要求模型按某个 JSON schema 输出,并且设置为 strict(严格模式)时,请求 JSON 里会带上正确的 format 配置。JSON schema 可以理解成“输出格式说明书”。

数据流:进去没有外部输入 → 它先写出一个 schema,要求输出对象里必须有 answer 字符串;再调用 create_text_param_for_request,要求生成严格格式的 text 控制参数;随后把完整 ResponsesApiRequest 转成 JSON → 最后检查 text 里没有 verbosity,并检查 format 的 name、type、strict、schema 都符合预期。

调用关系:它连接了两个关键点:create_text_param_for_request 负责生成 text 控制参数,serde_json::to_value 负责把请求变成真正要发送的 JSON。测试用多个 assert_eq! 和 assert! 来守住格式协议,避免服务端收不到严格 schema 要求。

调用图:外部调用 6 个(assert!, assert_eq!, create_text_param_for_request, json!, to_value, vec!)。

serializes_text_schema_with_non_strict_format187–207 ↗
fn serializes_text_schema_with_non_strict_format()

作用:这个测试确认:当提供 JSON schema 但不要求严格模式时,生成出来的格式配置会保留 schema,同时 strict 标记为 false。也就是说,格式说明还在,但不强制到最严格。

数据流:进去没有外部输入 → 它构造一个 schema,里面有 answer 和 rationale,并声明不允许额外字段;然后调用 create_text_param_for_request,第三个参数传 false → 出来一个 text_controls;测试取出里面的 format,检查 strict 是 false,schema 内容没有被改掉。

调用关系:它专门补上非严格模式这一条分支,和 serializes_text_schema_with_strict_format 形成对照。它主要依赖 create_text_param_for_request 生成结果,再用断言确认生成逻辑没有把 strict 或 schema 搞错。

调用图:外部调用 4 个(assert!, assert_eq!, create_text_param_for_request, json!)。

omits_text_when_not_set210–232 ↗
fn omits_text_when_not_set()

作用:这个测试确认:如果请求没有设置 text 控制参数,转成 JSON 时就不会出现 text 字段。这样可以避免给服务端发送多余字段,造成误解或兼容问题。

数据流:进去没有外部输入 → 它构造一个 ResponsesApiRequest,并明确把 text 设为 None;然后用 serde_json::to_value 转成 JSON → 最后检查 JSON 顶层没有 text 字段。

调用关系:它保护的是“没设置就别发送”的序列化习惯。测试框架运行它;它借助 serde_json 做结构体到 JSON 的转换,再用 assert! 确认 text 字段确实被省略。

调用图:外部调用 3 个(assert!, to_value, vec!)。

serializes_flex_service_tier_when_set235–258 ↗
fn serializes_flex_service_tier_when_set()

作用:这个测试确认:当请求指定 service_tier 为 Flex 时,发出去的 JSON 里会写成字符串 "flex"。service_tier 可以理解成选择服务处理档位的选项。

数据流:进去没有外部输入 → 它构造一个 ResponsesApiRequest,把 service_tier 设置为 ServiceTier::Flex.to_string();然后把请求转成 JSON → 最后读取 JSON 里的 service_tier,检查它是不是 "flex"。

调用关系:它测试服务档位字段的字符串化和序列化是否符合 API 约定。测试框架运行它;它把转换交给 serde_json,再用 assert_eq! 对比最终 JSON,防止枚举名字或大小写变化导致服务端不认。

调用图:外部调用 3 个(assert_eq!, to_value, vec!)。

代理和线程控制

这些测试检验代理编排、注册表和角色行为、委派子代理、执行限制、驻留以及线程生命周期管理。

core/src/agent/control_tests.rs源码 ↗
testtest

可以把 AgentControl 想成调度员:它负责让一个个代理线程开工、收消息、汇报状态、关机,甚至把父代理和子代理串成一棵树。这个测试文件就是给调度员做压力体检。它先搭出临时配置、临时家目录、假的登录凭据和测试用线程管理器,然后模拟很多真实场景:没有管理器时要报错,线程不存在时要说找不到,子代理完成后要通知父代理,超过最大线程数要拦住,重启后要能从保存的对话记录里恢复。里面还特别测试了多代理 v2、历史分叉、匿名子代理、归档记录、关闭整棵代理树等容易出错的边角情况。没有这些测试,用户可能会遇到代理丢失、重复打开、通知发错人、历史恢复错乱这类很难排查的问题。

函数细节64
test_config_with_cli_overrides41–52 ↗
async fn test_config_with_cli_overrides(
    cli_overrides: Vec<(String, TomlValue)>,
) -> (TempDir, Config)

作用:创建一份测试用配置,并允许测试临时改一些命令行配置项。这样每个测试都能在干净的临时目录里运行,不会污染真实用户环境。

数据流:输入是一组配置覆盖项 → 它新建临时 home 目录,用测试配置构建器加载配置,并套上这些覆盖项 → 输出临时目录和 Config,后续测试拿它们启动线程管理器。

调用关系:这是很多限制类测试的地基,比如最大线程数测试会通过它把 agents.max_threads 改成很小;test_config 也会调用它来生成默认配置。

调用图:调用 1 个内部函数(without_managed_config_for_tests);被 6 处调用(resume_agent_releases_slot_after_resume_failure, resume_agent_respects_max_threads_limit, spawn_agent_limit_shared_across_clones, spawn_agent_releases_slot_after_shutdown, spawn_agent_respects_max_threads_limit, test_config);外部调用 1 个(new)。

test_config54–56 ↗
async fn test_config() -> (TempDir, Config)

作用:创建一份不带额外改动的默认测试配置。测试不关心特殊配置时,就用它快速开一个干净环境。

数据流:没有额外输入 → 它调用 test_config_with_cli_overrides,并传入空覆盖列表 → 输出临时目录和默认 Config。

调用关系:它是 AgentControlHarness::new 和多种单测的快捷入口,避免每个测试重复写创建配置的样板代码。

调用图:调用 1 个内部函数(test_config_with_cli_overrides);被 7 处调用(new, ensure_v2_agent_loaded_reloads_registered_unloaded_agent, list_agent_subtree_thread_ids_finds_live_descendants_of_unloaded_root, resume_agent_errors_when_manager_dropped, resume_agent_from_rollout_does_not_reopen_v2_descendants, resume_thread_subagent_restores_stored_nickname_and_role, spawn_agent_errors_when_manager_dropped);外部调用 1 个(new)。

text_input58–64 ↗
fn text_input(text: &str) -> Op

作用:把一段普通文字包装成系统能提交给代理的输入格式。测试里用它模拟用户说了一句话。

数据流:输入一段字符串 → 它生成一个 UserInput::Text,并转成 Op 这种提交操作 → 输出可直接发送给代理线程的输入对象。

调用关系:大部分创建代理和发送任务的测试都会用它,让测试关注“发了什么文字”,不用关心底层输入结构。

调用图:被 31 处调用(encrypted_inter_agent_communication_clears_existing_last_task_message, ensure_v2_agent_loaded_reloads_registered_unloaded_agent, list_agent_subtree_thread_ids_finds_live_descendants_of_unloaded_root, list_agent_subtree_thread_ids_includes_anonymous_and_closed_descendants, multi_agent_v2_completion_ignores_dead_direct_parent, resume_agent_from_rollout_does_not_reopen_closed_descendants, resume_agent_from_rollout_does_not_reopen_v2_descendants, resume_agent_from_rollout_reads_archived_rollout_path, resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown, resume_agent_from_rollout_skips_descendants_when_parent_resume_fails (+15 more));外部调用 1 个(vec!)。

assistant_message66–76 ↗
fn assistant_message(text: &str, phase: Option<MessagePhase>) -> ResponseItem

作用:造一条假的助手回复消息,用来放进历史记录里。测试可以用它模拟代理以前说过什么。

数据流:输入回复文字和可选的消息阶段 → 它包装成 ResponseItem::Message,角色是 assistant → 输出一条可写入对话历史的助手消息。

调用关系:历史分叉相关测试会用它构造父线程历史,随后检查子代理继承历史时有没有过滤掉不该继承的内容。

调用图:被 2 处调用(spawn_agent_can_fork_parent_thread_history_with_sanitized_items, spawn_agent_fork_flushes_parent_rollout_before_loading_history);外部调用 1 个(vec!)。

register_session_root_skips_threads_with_explicit_parent79–85 ↗
fn register_session_root_skips_threads_with_explicit_parent()

作用:确认有明确父线程的会话不会被错误登记成根代理。根代理就像树根,不能把树枝也当树根。

数据流:输入是新建的控制器和两个线程编号 → 它尝试用带父线程的方式登记根会话 → 最后检查根路径没有绑定任何代理。

调用关系:这是针对 AgentControl 内部登记逻辑的独立小测试,防止父子代理树一开始就建错。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert_eq!, default)。

spawn_agent_call87–96 ↗
fn spawn_agent_call(call_id: &str) -> ResponseItem

作用:造一条假的 spawn_agent 函数调用记录。测试用它模拟父代理曾经请求创建子代理。

数据流:输入调用编号 call_id → 它生成一个 ResponseItem::FunctionCall,名字固定为 spawn_agent → 输出可放进历史或 rollout 的调用记录。

调用关系:历史分叉测试用它标记“从父历史的哪个创建点分叉”,之后 spawn_agent_with_metadata 会按这个标记加载父历史。

调用图:被 6 处调用(spawn_agent_can_fork_parent_thread_history_with_sanitized_items, spawn_agent_fork_flushes_parent_rollout_before_loading_history, spawn_agent_fork_last_n_turns_drops_parent_startup_prefix_when_under_limit, spawn_agent_fork_last_n_turns_keeps_only_recent_turns, spawn_agent_fork_last_n_turns_strips_parent_usage_hints, spawn_agent_fork_strips_parent_usage_hints_from_compacted_history)。

AgentControlHarness::new107–110 ↗
async fn new() -> Self

作用:快速搭建一套默认测试环境,包括配置、线程管理器和控制器。它让每个测试不用手工组装一堆对象。

数据流:没有输入 → 它先拿默认测试配置,再交给 new_with_config 完成完整搭建 → 输出一个 AgentControlHarness。

调用关系:绝大多数测试从这里开始;它把 test_config 和 new_with_config 串起来,提供统一的测试入口。

调用图:调用 1 个内部函数(test_config);被 30 处调用(completion_watcher_notifies_parent_when_child_is_missing, encrypted_inter_agent_communication_clears_existing_last_task_message, get_status_returns_not_found_for_missing_thread, get_status_returns_pending_init_for_new_thread, list_agent_subtree_thread_ids_includes_anonymous_and_closed_descendants, multi_agent_v2_completion_ignores_dead_direct_parent, multi_agent_v2_completion_queues_message_for_direct_parent, resume_agent_from_rollout_does_not_reopen_closed_descendants, resume_agent_from_rollout_reads_archived_rollout_path, resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown (+15 more));外部调用 1 个(new_with_config)。

AgentControlHarness::new_with_config112–129 ↗
async fn new_with_config(home: TempDir, config: Config) -> Self

作用:用指定配置搭建测试环境。需要打开某些功能开关或特殊配置时,测试会走这个入口。

数据流:输入临时目录和 Config → 它初始化状态数据库,创建测试用 ThreadManager,再取出 AgentControl → 输出保存这些部件的 harness。

调用关系:多代理 v2 和 SQLite 相关测试会先改配置,再调用它;它把 init_state_db、测试线程管理器和控制器接到一起。

调用图:调用 3 个内部函数(with_models_provider_home_and_state_for_tests, default_for_tests, from_api_key);被 2 处调用(ensure_v2_agent_loaded_reloads_registered_unloaded_agent, resume_agent_from_rollout_does_not_reopen_v2_descendants);外部调用 2 个(init_state_db, new)。

AgentControlHarness::start_thread131–138 ↗
async fn start_thread(&self) -> (ThreadId, Arc<CodexThread>)

作用:在测试环境里启动一个新代理线程。测试需要一个父线程或普通线程时会调用它。

数据流:输入是 harness 自己保存的配置和管理器 → 它用 ThreadManager 启动线程 → 输出线程编号和线程对象。

调用关系:大量父子代理、状态订阅、关闭树测试都从它拿到起始线程,然后再用 AgentControl 操作这个线程。

调用图:调用 1 个内部函数(start_thread);外部调用 1 个(clone)。

has_subagent_notification141–156 ↗
fn has_subagent_notification(history_items: &[ResponseItem]) -> bool

作用:检查一段历史记录里有没有“子代理通知”文本。它帮助测试判断父代理是否收到了子代理完成提醒。

数据流:输入历史消息列表 → 它逐条找用户角色的文字内容,并用 SubagentNotification 的匹配规则判断 → 输出 true 或 false。

调用关系:wait_for_subagent_notification 会反复调用它,直到父线程历史里真的出现通知。

调用图:被 1 处调用(wait_for_subagent_notification);外部调用 1 个(iter)。

history_contains_text159–171 ↗
fn history_contains_text(history_items: &[ResponseItem], needle: &str) -> bool

作用:检查历史消息里是否包含某段文字。测试用它验证某些内容有没有被保留或过滤掉。

数据流:输入历史消息列表和要找的文字 → 它扫描所有文本片段 → 输出是否找到。

调用关系:历史分叉、恢复、通知测试都会用它做断言,比如确认旧提示被删掉、新任务被保留。

调用图:外部调用 1 个(iter)。

history_contains_assistant_inter_agent_communication173–194 ↗
fn history_contains_assistant_inter_agent_communication(
    history_items: &[ResponseItem],
    expected: &InterAgentCommunication,
) -> bool

作用:检查助手消息里有没有一条指定的代理间通信。它不是简单找字符串,而是把文本按 JSON 解析后比较。

数据流:输入历史消息和期望的 InterAgentCommunication → 它只看 assistant 的输出文本,尝试反序列化成通信对象 → 输出是否存在完全匹配的一条。

调用关系:多代理 v2 通知测试用它确认消息没有被错误写到根代理历史里,或者没有触发不该触发的通知。

调用图:外部调用 1 个(iter)。

wait_for_subagent_notification196–215 ↗
async fn wait_for_subagent_notification(parent_thread: &Arc<CodexThread>) -> bool

作用:等待父线程历史里出现子代理通知。因为通知是后台异步写入的,测试不能立刻检查。

数据流:输入父线程对象 → 它循环读取历史,用 has_subagent_notification 判断,中间短暂睡眠,并设置最长等待时间 → 输出是否在超时前等到了通知。

调用关系:子代理完成、子代理缺失等测试会调用它,给后台 completion watcher 留出时间。

调用图:调用 1 个内部函数(has_subagent_notification);外部调用 4 个(from_millis, from_secs, sleep, timeout)。

persist_thread_for_tree_resume217–228 ↗
async fn persist_thread_for_tree_resume(thread: &Arc<CodexThread>, message: &str)

作用:把线程当前对话写到磁盘,方便后面测试“从历史恢复”。没有这一步,恢复测试可能没有可读记录。

数据流:输入线程和一段消息 → 它把消息注入线程历史,确保 rollout 文件生成并刷盘 → 结果是磁盘上有可恢复的线程记录。

调用关系:恢复整棵代理树的测试会先调用它保存父、子、孙线程,再关掉线程并尝试恢复。

调用图:被 9 处调用(resume_agent_from_rollout_does_not_reopen_closed_descendants, resume_agent_from_rollout_does_not_reopen_v2_descendants, resume_agent_from_rollout_reads_archived_rollout_path, resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown, resume_agent_from_rollout_skips_descendants_when_parent_resume_fails, resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale, resume_closed_child_reopens_open_descendants, shutdown_agent_tree_closes_descendants_when_started_at_child, shutdown_agent_tree_closes_live_descendants)。

wait_for_live_thread_spawn_children230–256 ↗
async fn wait_for_live_thread_spawn_children(
    control: &AgentControl,
    parent_thread_id: ThreadId,
    expected_children: &[ThreadId],
)

作用:等待控制器能看到某个父线程的活跃子线程列表。它处理异步登记可能稍晚发生的问题。

数据流:输入控制器、父线程编号和期望子线程编号列表 → 它反复读取 open_thread_spawn_children,排序后比较 → 成功时结束,超时则让测试失败。

调用关系:关闭树和恢复树测试在断言前调用它,确保父子关系已经被系统记录下来。

调用图:调用 1 个内部函数(open_thread_spawn_children);被 8 处调用(resume_agent_from_rollout_does_not_reopen_closed_descendants, resume_agent_from_rollout_does_not_reopen_v2_descendants, resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown, resume_agent_from_rollout_skips_descendants_when_parent_resume_fails, resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale, resume_closed_child_reopens_open_descendants, shutdown_agent_tree_closes_descendants_when_started_at_child, shutdown_agent_tree_closes_live_descendants);外部调用 6 个(from_millis, from_secs, sort_by_key, to_vec, sleep, timeout)。

assert_thread_not_loaded258–264 ↗
async fn assert_thread_not_loaded(manager: &ThreadManager, thread_id: ThreadId)

作用:确认某个线程没有被加载在当前管理器里。它用来证明恢复逻辑没有偷偷打开不该打开的子代理。

数据流:输入线程管理器和线程编号 → 它调用 get_thread → 如果返回 ThreadNotFound 就通过,否则直接让测试失败。

调用关系:resume_agent_from_rollout_does_not_reopen_v2_descendants 用它检查 v2 恢复根代理时没有重开后代线程。

调用图:调用 1 个内部函数(get_thread);被 1 处调用(resume_agent_from_rollout_does_not_reopen_v2_descendants);外部调用 2 个(assert_eq!, panic!)。

send_input_errors_when_manager_dropped267–284 ↗
async fn send_input_errors_when_manager_dropped()

作用:测试控制器背后的线程管理器已经不存在时,发送输入会明确报错。这样调用方不会误以为消息已送达。

数据流:输入是一个默认空控制器、随机线程编号和用户文字 → 它调用 send_input → 输出应是“thread manager dropped”错误。

调用关系:这是无管理器场景的保护测试,直接验证 AgentControl 的错误处理。

调用图:调用 1 个内部函数(new);外部调用 3 个(assert_eq!, default, vec!)。

get_status_returns_not_found_without_manager287–291 ↗
async fn get_status_returns_not_found_without_manager()

作用:测试没有线程管理器时查询状态会返回 NotFound。它避免空控制器产生误导性的运行状态。

数据流:输入默认空控制器和随机线程编号 → 它调用 get_status → 输出应为 AgentStatus::NotFound。

调用关系:和其他 manager dropped 测试一起覆盖 AgentControl 在失去管理器后的安全行为。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert_eq!, default)。

on_event_updates_status_from_task_started294–303 ↗
async fn on_event_updates_status_from_task_started()

作用:确认“回合开始”事件会被翻译成 Running 状态。也就是代理一开工,状态就该显示正在运行。

数据流:输入 TurnStarted 事件 → agent_status_from_event 读取事件类型 → 输出 Some(AgentStatus::Running)。

调用关系:它直接测试事件到状态的转换函数,不需要完整线程环境。

调用图:外部调用 3 个(assert_eq!, agent_status_from_event, TurnStarted)。

on_event_updates_status_from_task_complete306–316 ↗
async fn on_event_updates_status_from_task_complete()

作用:确认“回合完成”事件会变成 Completed 状态,并保留最后一条助手消息。

数据流:输入 TurnComplete 事件和 last_agent_message → 转换函数生成完成状态 → 输出 Completed(Some("done"))。

调用关系:它覆盖状态转换中的成功路径,completion watcher 等功能依赖这个状态判断。

调用图:外部调用 4 个(assert_eq!, agent_status_from_event, Completed, TurnComplete)。

on_event_updates_status_from_error319–327 ↗
async fn on_event_updates_status_from_error()

作用:确认错误事件会变成 Errored 状态,并带上错误信息。这样界面或上层逻辑能看到失败原因。

数据流:输入 Error 事件,消息是 boom → 转换函数提取错误文本 → 输出 AgentStatus::Errored("boom")。

调用关系:它测试事件状态转换的失败路径,和 started、complete、aborted 等测试组成一组。

调用图:外部调用 4 个(assert_eq!, agent_status_from_event, Errored, Error)。

on_event_updates_status_from_turn_aborted330–340 ↗
async fn on_event_updates_status_from_turn_aborted()

作用:确认被中断的回合会显示 Interrupted。用户手动打断或系统中止时不能被误认为成功完成。

数据流:输入 TurnAborted 事件,原因是 Interrupted → 转换函数识别中断 → 输出 AgentStatus::Interrupted。

调用关系:它补齐状态转换里“被打断”这一类事件的覆盖。

调用图:外部调用 3 个(assert_eq!, agent_status_from_event, TurnAborted)。

on_event_updates_status_from_shutdown_complete343–346 ↗
async fn on_event_updates_status_from_shutdown_complete()

作用:确认关闭完成事件会变成 Shutdown 状态。代理关掉后,状态应该清楚显示已经停机。

数据流:输入 ShutdownComplete 事件 → 转换函数识别关闭完成 → 输出 AgentStatus::Shutdown。

调用关系:关闭和状态订阅测试都依赖这种转换能正确发生。

调用图:外部调用 2 个(assert_eq!, agent_status_from_event)。

spawn_agent_errors_when_manager_dropped349–360 ↗
async fn spawn_agent_errors_when_manager_dropped()

作用:测试没有线程管理器时创建代理会失败。否则系统可能假装创建成功,但其实没有线程在运行。

数据流:输入空控制器、测试配置和文字任务 → 它调用 spawn_agent → 输出应是管理器已丢失的错误。

调用关系:它使用 test_config 和 text_input 搭好最小输入,专门验证 AgentControl 的防护分支。

调用图:调用 2 个内部函数(test_config, text_input);外部调用 2 个(assert_eq!, default)。

resume_agent_errors_when_manager_dropped363–374 ↗
async fn resume_agent_errors_when_manager_dropped()

作用:测试没有线程管理器时恢复代理会失败。恢复也需要管理器来重新装载线程。

数据流:输入空控制器、测试配置、随机线程编号和会话来源 → 它调用 resume_agent_from_rollout → 输出管理器已丢失的错误。

调用关系:和 spawn_agent_errors_when_manager_dropped 对称,覆盖恢复入口的错误处理。

调用图:调用 2 个内部函数(test_config, new);外部调用 2 个(assert_eq!, default)。

send_input_errors_when_thread_missing377–393 ↗
async fn send_input_errors_when_thread_missing()

作用:测试给不存在的线程发消息时会返回 ThreadNotFound。消息不能被悄悄丢掉。

数据流:输入正常 harness、随机线程编号和用户文字 → 控制器查不到线程 → 输出带同一线程编号的 ThreadNotFound 错误。

调用关系:它通过 AgentControlHarness 建立真实管理器,验证“管理器存在但线程不存在”的情况。

调用图:调用 2 个内部函数(new, new);外部调用 2 个(assert_matches!, vec!)。

get_status_returns_not_found_for_missing_thread396–400 ↗
async fn get_status_returns_not_found_for_missing_thread()

作用:测试查询不存在的线程状态会得到 NotFound。这样调用方能区分“没这个线程”和“线程还在初始化”。

数据流:输入正常 harness 和随机线程编号 → 调用 get_status → 输出 AgentStatus::NotFound。

调用关系:它和 get_status_returns_pending_init_for_new_thread 一起确认状态查询的基本边界。

调用图:调用 2 个内部函数(new, new);外部调用 1 个(assert_eq!)。

get_status_returns_pending_init_for_new_thread403–408 ↗
async fn get_status_returns_pending_init_for_new_thread()

作用:测试刚启动但还没开始运行的线程状态是 PendingInit。也就是系统知道它存在,但还没准备好。

数据流:输入 harness → 启动一个线程,再查询它的状态 → 输出 AgentStatus::PendingInit。

调用关系:它依赖 AgentControlHarness::start_thread,是状态生命周期的起点测试。

调用图:调用 1 个内部函数(new);外部调用 1 个(assert_eq!)。

subscribe_status_errors_for_missing_thread411–420 ↗
async fn subscribe_status_errors_for_missing_thread()

作用:测试订阅不存在的线程状态会失败。订阅就像等通知,没这个对象就不能订。

数据流:输入 harness 和随机线程编号 → 调用 subscribe_status → 输出 ThreadNotFound 错误。

调用关系:它覆盖状态订阅接口的缺失线程分支。

调用图:调用 2 个内部函数(new, new);外部调用 1 个(assert_matches!)。

subscribe_status_updates_on_shutdown423–440 ↗
async fn subscribe_status_updates_on_shutdown()

作用:测试订阅者能收到线程关闭后的状态变化。这样 UI 或调用方才能及时知道代理停了。

数据流:输入一个新线程 → 先订阅状态,确认初始 PendingInit,再提交 Shutdown → 订阅通道更新为 Shutdown。

调用关系:它把 ThreadManager 启动的线程、AgentControl 的订阅、线程提交关闭操作串起来验证。

调用图:调用 1 个内部函数(new);外部调用 1 个(assert_eq!)。

send_input_submits_user_message443–479 ↗
async fn send_input_submits_user_message()

作用:测试 send_input 会真的把用户消息提交给目标线程。重点不是只返回成功,而是操作被记录为正确的 UserInput。

数据流:输入线程编号和文字 hello from tests → 控制器生成 Op::UserInput 并交给管理器 → 输出非空提交编号,并在 captured_ops 里能找到这条操作。

调用关系:它验证 AgentControl 到 ThreadManager 的提交链路,是发送用户输入的核心测试。

调用图:调用 1 个内部函数(new);外部调用 4 个(default, assert!, assert_eq!, vec!)。

send_inter_agent_communication_without_turn_queues_message_without_triggering_turn482–541 ↗
async fn send_inter_agent_communication_without_turn_queues_message_without_triggering_turn()

作用:测试代理间通信如果标记为不触发回合,就只排队,不立刻让代理开始新一轮工作。

数据流:输入一个 InterAgentCommunication,trigger_turn 为 false → 控制器提交通信操作,线程输入队列出现待处理内容 → 历史里不会立刻出现助手通信消息。

调用关系:它检查 send_inter_agent_communication 的特殊模式,避免后台代理被无意唤醒。

调用图:调用 4 个内部函数(new, root, try_from, new);外部调用 7 个(from_millis, from_secs, new, assert!, assert_eq!, sleep, timeout)。

ensure_v2_agent_loaded_reloads_registered_unloaded_agent544–633 ↗
async fn ensure_v2_agent_loaded_reloads_registered_unloaded_agent()

作用:测试多代理 v2 中,一个已登记但从内存移除的代理可以被重新加载。这样消息发给旧代理时不会因为它不在内存里就失败。

数据流:输入开启 v2 和 SQLite 的配置 → 创建父子代理,持久化子代理,再从管理器移除 → ensure_v2_agent_loaded 重新加载它,随后通信可以正常提交。

调用关系:它串起 spawn_agent_with_metadata、持久化、remove_thread、ensure_v2_agent_loaded 和代理间通信,覆盖 v2 重新装载场景。

调用图:调用 6 个内部函数(new_with_config, test_config, text_input, root, try_from, new);外部调用 7 个(default, new, SubAgent, assert!, assert_eq!, panic!, vec!)。

resume_agent_from_rollout_does_not_reopen_v2_descendants636–723 ↗
async fn resume_agent_from_rollout_does_not_reopen_v2_descendants()

作用:测试多代理 v2 恢复根线程时不会自动重开所有后代代理。v2 的树关系可以记录,但恢复策略更克制。

数据流:输入一棵父、子、孙代理树并保存历史 → 关闭所有线程,用新管理器恢复父线程 → 父线程存在,子和孙仍未加载。

调用关系:它用 wait_for_live_thread_spawn_children 确认树关系,用 assert_thread_not_loaded 检查后代没有被恢复。

调用图:调用 10 个内部函数(new_with_config, assert_thread_not_loaded, persist_thread_for_tree_resume, test_config, text_input, wait_for_live_thread_spawn_children, with_models_provider_home_and_state_for_tests, default_for_tests, from_api_key, root);外部调用 5 个(from_secs, SubAgent, assert_eq!, assert_ne!, new)。

encrypted_inter_agent_communication_clears_existing_last_task_message726–779 ↗
async fn encrypted_inter_agent_communication_clears_existing_last_task_message()

作用:测试加密的代理间任务会清掉旧的明文任务摘要。这样敏感内容不会继续留在元数据里。

数据流:输入一个已有 last_task_message 的子代理和一条加密通信 → 控制器发送通信 → 子代理元数据里的 last_task_message 变成 None。

调用关系:它覆盖 send_inter_agent_communication 对加密内容的隐私保护行为。

调用图:调用 5 个内部函数(new, text_input, root, try_from, new_encrypted);外部调用 4 个(default, new, SubAgent, assert_eq!)。

spawn_agent_creates_thread_and_sends_prompt782–817 ↗
async fn spawn_agent_creates_thread_and_sends_prompt()

作用:测试创建代理时会同时创建线程并发送初始任务。代理不能只被登记而不收到要做的事。

数据流:输入配置和文本 spawned → spawn_agent 返回新线程编号,管理器能取到线程,captured_ops 中有对应 UserInput → 输出证明线程和任务都存在。

调用关系:这是 spawn_agent 最基本的成功路径测试。

调用图:调用 2 个内部函数(new, text_input);外部调用 3 个(default, assert_eq!, vec!)。

spawn_agent_can_fork_parent_thread_history_with_sanitized_items820–1055 ↗
async fn spawn_agent_can_fork_parent_thread_history_with_sanitized_items()

作用:测试子代理从父代理完整历史分叉时,会只继承该继承的内容,并替换成子代理自己的提示。像复印笔记前先把草稿和旧说明擦干净。

数据流:输入一段复杂父历史,包括用户消息、开发者提示、助手评论、最终答案、推理、通信和创建调用 → 创建子代理时选择 FullHistory → 子历史只保留种子上下文、父最终答案和子代理提示,并保留父 diff 基线。

调用关系:它大量使用 assistant_message、spawn_agent_call、history_contains_text,重点验证 spawn_agent_with_metadata 的历史清洗和分叉能力。

调用图:调用 7 个内部函数(new, assistant_message, spawn_agent_call, text_input, root, try_from, new);外部调用 8 个(default, new, SubAgent, assert!, assert_eq!, assert_ne!, TurnContext, vec!)。

spawn_agent_fork_strips_parent_usage_hints_from_compacted_history1058–1176 ↗
async fn spawn_agent_fork_strips_parent_usage_hints_from_compacted_history()

作用:测试父历史经过压缩后再分叉,也会去掉父代理的旧使用提示。压缩历史不能成为旧提示混进子代理的漏洞。

数据流:输入带 compacted replacement_history 的父 rollout,其中含父 root guidance → 子代理按 FullHistory 分叉 → 子历史保留压缩摘要,删除父提示,并加入子代理提示。

调用关系:它覆盖 CompactedItem 这种特殊历史格式,确保历史清洗逻辑不只处理普通消息。

调用图:调用 3 个内部函数(new, spawn_agent_call, text_input);外部调用 8 个(default, new, SubAgent, assert!, Compacted, ResponseItem, TurnContext, vec!)。

spawn_agent_fork_flushes_parent_rollout_before_loading_history1179–1238 ↗
async fn spawn_agent_fork_flushes_parent_rollout_before_loading_history()

作用:测试分叉前会先把父线程未刷盘的历史写出去。否则子代理可能读不到刚发生的父回复。

数据流:输入父线程内存中尚未 flush 的最终答案和 spawn_agent 调用 → 创建 FullHistory 子代理 → 子历史里能看到那条未刷盘前的最终答案。

调用关系:它验证 spawn_agent_with_metadata 在读取父历史前会先做 flush,而不是直接读旧文件。

调用图:调用 4 个内部函数(new, assistant_message, spawn_agent_call, text_input);外部调用 3 个(default, SubAgent, assert!)。

spawn_agent_fork_last_n_turns_keeps_only_recent_turns1241–1377 ↗
async fn spawn_agent_fork_last_n_turns_keeps_only_recent_turns()

作用:测试按最近 N 轮分叉时,只保留最近的相关上下文,并过滤代理间通信。这样子代理不会背上太多旧包袱。

数据流:输入包含旧上下文、排队通信、触发通信和当前任务的父历史 → 创建 LastNTurns(2) 子代理 → 子历史丢掉旧内容和通信,只保留当前父任务,并清空参考上下文。

调用关系:它覆盖 SpawnAgentForkMode::LastNTurns,和 FullHistory 测试形成对比。

调用图:调用 6 个内部函数(new, spawn_agent_call, text_input, root, try_from, new);外部调用 6 个(default, new, SubAgent, assert!, LastNTurns, TurnContext)。

spawn_agent_fork_last_n_turns_drops_parent_startup_prefix_when_under_limit1380–1480 ↗
async fn spawn_agent_fork_last_n_turns_drops_parent_startup_prefix_when_under_limit()

作用:测试即使父历史轮数少于 N,也不会把父代理启动时的开发者上下文塞给子代理。

数据流:输入父启动阶段开发者消息和当前任务 → 创建 LastNTurns(2) 子代理 → 子历史保留当前任务,删除启动前缀,并要求重新建立上下文。

调用关系:它专门防止 LastNTurns 在历史很短时误保留父线程的启动配置。

调用图:调用 3 个内部函数(new, spawn_agent_call, text_input);外部调用 5 个(default, SubAgent, assert!, LastNTurns, vec!)。

spawn_agent_fork_last_n_turns_strips_parent_usage_hints1483–1582 ↗
async fn spawn_agent_fork_last_n_turns_strips_parent_usage_hints()

作用:测试最近 N 轮分叉也会删除父代理的旧使用提示。不是只有完整历史分叉才需要清洗。

数据流:输入带父 root guidance 和父任务的最近历史 → 创建 LastNTurns(2) 子代理 → 子历史保留父任务,但不含父提示。

调用关系:它补充验证 LastNTurns 模式下的提示清洗逻辑。

调用图:调用 3 个内部函数(new, spawn_agent_call, text_input);外部调用 5 个(default, SubAgent, assert!, LastNTurns, vec!)。

spawn_agent_respects_max_threads_limit1585–1634 ↗
async fn spawn_agent_respects_max_threads_limit()

作用:测试创建代理会遵守最大线程数限制。超过限制时必须拒绝,防止系统资源被开爆。

数据流:输入配置覆盖 agents.max_threads=1 → 创建第一个代理成功,再创建第二个 → 输出 AgentLimitReached,并带回看到的最大值。

调用关系:它通过 test_config_with_cli_overrides 设置限制,验证 AgentControl 的并发名额保护。

调用图:调用 5 个内部函数(test_config_with_cli_overrides, text_input, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 4 个(assert_eq!, panic!, new, vec!)。

spawn_agent_releases_slot_after_shutdown1637–1677 ↗
async fn spawn_agent_releases_slot_after_shutdown()

作用:测试代理关闭后会释放线程名额。否则用户关掉代理后仍然不能创建新代理。

数据流:输入最大线程数为 1 的配置 → 创建第一个代理并关闭 → 再创建第二个代理成功,最后关闭第二个。

调用关系:它接着最大线程数测试,确认 shutdown_live_agent 会把占用的名额还回去。

调用图:调用 5 个内部函数(test_config_with_cli_overrides, text_input, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 2 个(new, vec!)。

spawn_agent_limit_shared_across_clones1680–1722 ↗
async fn spawn_agent_limit_shared_across_clones()

作用:测试 AgentControl 的克隆对象共享同一份线程限制。不能一个克隆一个名额,绕过总限制。

数据流:输入最大线程数为 1 的配置和一个 cloned control → 克隆创建第一个代理成功,原 control 创建第二个失败 → 输出 AgentLimitReached。

调用关系:它验证限制守卫存在共享状态里,而不是每个 AgentControl 实例各算各的。

调用图:调用 5 个内部函数(test_config_with_cli_overrides, text_input, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 4 个(assert_eq!, panic!, new, vec!)。

resume_agent_respects_max_threads_limit1725–1778 ↗
async fn resume_agent_respects_max_threads_limit()

作用:测试恢复旧代理也会占用线程名额,并遵守最大线程数。恢复不能绕过创建限制。

数据流:输入最大线程数为 1 的配置 → 先准备一个可恢复代理,再创建另一个活跃代理占满名额 → 尝试恢复旧代理失败,返回 AgentLimitReached。

调用关系:它覆盖 resume_agent_from_rollout 的限流分支,和 spawn_agent 的限制测试对应。

调用图:调用 5 个内部函数(test_config_with_cli_overrides, text_input, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 4 个(assert_eq!, panic!, new, vec!)。

resume_agent_releases_slot_after_resume_failure1781–1809 ↗
async fn resume_agent_releases_slot_after_resume_failure()

作用:测试恢复失败后不会永久占住线程名额。失败也要把临时占用的票退回去。

数据流:输入最大线程数为 1 的配置和不存在的线程编号 → 恢复失败 → 随后创建新代理成功,说明名额已释放。

调用关系:它验证 resume_agent_from_rollout 的错误清理逻辑,防止一次失败导致后续都不能启动。

调用图:调用 6 个内部函数(test_config_with_cli_overrides, text_input, with_models_provider_and_home_for_tests, default_for_tests, from_api_key, new);外部调用 2 个(new, vec!)。

spawn_child_completion_notifies_parent_history1812–1843 ↗
async fn spawn_child_completion_notifies_parent_history()

作用:测试子代理关闭后,父线程历史会收到子代理完成通知。父代理需要知道孩子已经结束。

数据流:输入父线程和一个子代理 → 关闭子代理 → 等待父线程历史出现 SubagentNotification。

调用关系:它通过 wait_for_subagent_notification 等后台 watcher 写入通知。

调用图:调用 2 个内部函数(new, text_input);外部调用 2 个(SubAgent, assert_eq!)。

multi_agent_v2_completion_ignores_dead_direct_parent1846–1953 ↗
async fn multi_agent_v2_completion_ignores_dead_direct_parent()

作用:测试多代理 v2 中,如果直接父代理已经死了,孙代理完成时不要乱发消息给死人或根代理。

数据流:输入 root、worker、tester 三层代理 → 先关掉 worker,再让 tester 发完成事件 → captured_ops 中没有给 worker 的通信,root 历史也没有错误通知。

调用关系:它验证 completion watcher 在直接父代理不可用时会安静退出,而不是越级通知。

调用图:调用 3 个内部函数(new, text_input, root);外部调用 5 个(from_millis, SubAgent, assert!, TurnComplete, sleep)。

multi_agent_v2_completion_queues_message_for_direct_parent1956–2055 ↗
async fn multi_agent_v2_completion_queues_message_for_direct_parent()

作用:测试多代理 v2 中,子代理完成会把消息排到直接父代理那里,而不是写到根代理历史。

数据流:输入 root、worker、tester 三个线程和 tester 完成事件 → watcher 格式化完成消息,并提交给 worker 的输入队列 → root 历史不含这条通信。

调用关系:它手动启动 maybe_start_completion_watcher,并用 format_inter_agent_completion_message 构造期望消息。

调用图:调用 4 个内部函数(new, format_inter_agent_completion_message, root, new);外部调用 9 个(from_millis, from_secs, new, SubAgent, assert!, Completed, TurnComplete, sleep, timeout)。

completion_watcher_notifies_parent_when_child_is_missing2058–2096 ↗
async fn completion_watcher_notifies_parent_when_child_is_missing()

作用:测试 completion watcher 发现子线程不存在时,也会通知父线程“这个子代理找不到”。这比一直等待更清楚。

数据流:输入父线程编号和一个不存在的子线程编号 → 启动 watcher → 父历史出现通知,并包含子编号和 not_found 状态。

调用关系:它覆盖 watcher 的缺失子线程分支,使用 wait_for_subagent_notification 等异步结果。

调用图:调用 2 个内部函数(new, new);外部调用 2 个(SubAgent, assert_eq!)。

spawn_thread_subagent_gets_random_nickname_in_session_source2099–2140 ↗
async fn spawn_thread_subagent_gets_random_nickname_in_session_source()

作用:测试线程型子代理创建时,如果没指定昵称,系统会给它随机分配一个昵称。昵称方便人类区分代理。

数据流:输入父线程和子代理来源,其中 agent_nickname 为 None → 创建子代理 → 子线程配置快照里的 session_source 带有昵称、角色和父线程信息。

调用关系:它验证 spawn_agent 会补全 SubAgentSource::ThreadSpawn 的人类可读元数据。

调用图:调用 2 个内部函数(new, text_input);外部调用 4 个(SubAgent, assert!, assert_eq!, panic!)。

spawn_thread_subagent_uses_role_specific_nickname_candidates2143–2184 ↗
async fn spawn_thread_subagent_uses_role_specific_nickname_candidates()

作用:测试某个角色配置了昵称候选时,子代理会优先用这个候选。比如 researcher 固定可叫 Atlas。

数据流:输入包含 researcher 角色昵称候选 Atlas 的配置 → 创建 researcher 子代理 → 子线程快照中的 agent_nickname 是 Atlas。

调用关系:它在 harness.config.agent_roles 中塞入角色配置,再验证 spawn_agent 的昵称选择逻辑。

调用图:调用 2 个内部函数(new, text_input);外部调用 4 个(SubAgent, assert_eq!, panic!, vec!)。

resume_thread_subagent_restores_stored_nickname_and_role2187–2328 ↗
async fn resume_thread_subagent_restores_stored_nickname_and_role()

作用:测试恢复子代理时,会从持久化数据里找回原来的昵称和角色。重启后代理身份不应变成陌生人。

数据流:输入开启 SQLite 的配置 → 创建带路径和角色的子代理,等待昵称角色写入数据库,关闭后恢复 → 恢复线程的 session_source 保留原父线程、深度、路径、昵称和角色。

调用关系:它把状态数据库、spawn_agent、subscribe_status、shutdown_live_agent 和 resume_agent_from_rollout 串起来,覆盖身份元数据恢复。

调用图:调用 6 个内部函数(test_config, text_input, with_models_provider_home_and_state_for_tests, default_for_tests, from_api_key, from_string);外部调用 10 个(from_millis, from_secs, SubAgent, assert_eq!, init_state_db, matches!, panic!, new, sleep, timeout)。

resume_agent_from_rollout_reads_archived_rollout_path2331–2377 ↗
async fn resume_agent_from_rollout_reads_archived_rollout_path()

作用:测试线程被归档后,恢复逻辑仍能找到归档里的 rollout 文件。归档不应该让历史恢复失效。

数据流:输入一个已保存并关闭的代理线程 → 用 LocalThreadStore 归档它 → resume_agent_from_rollout 仍恢复同一个线程编号。

调用关系:它使用 persist_thread_for_tree_resume 写入历史,再调用线程存储的 archive_thread 验证归档路径读取。

调用图:调用 5 个内部函数(new, persist_thread_for_tree_resume, text_input, new, from_config);外部调用 1 个(assert_eq!)。

list_agent_subtree_thread_ids_includes_anonymous_and_closed_descendants2380–2503 ↗
async fn list_agent_subtree_thread_ids_includes_anonymous_and_closed_descendants()

作用:测试列出代理子树时,会包含没有路径的匿名后代,也包含已经关闭的后代。树结构不能只靠名字路径判断。

数据流:输入一棵含有有路径子代理、匿名子代理、匿名孙代理和另一个分支的树 → 关闭其中一个孙代理 → 查询 worker 子树和匿名子树 → 输出都包含正确后代。

调用关系:它验证 ThreadManager::list_agent_subtree_thread_ids 能根据父子边关系找子树,而不是漏掉匿名或关闭节点。

调用图:调用 3 个内部函数(new, text_input, root);外部调用 3 个(SubAgent, assert_eq!, vec!)。

list_agent_subtree_thread_ids_finds_live_descendants_of_unloaded_root2506–2563 ↗
async fn list_agent_subtree_thread_ids_finds_live_descendants_of_unloaded_root()

作用:测试即使根线程从管理器里卸载了,仍能列出它的活跃后代。树的根不在内存里时,也不能丢掉整棵树。

数据流:输入父、子、孙线程 → 从管理器移除父线程 → 查询父线程子树 → 输出仍包含父、子、孙三个编号。

调用关系:它用没有状态数据库的测试管理器,专门覆盖内存活跃关系的查询能力。

调用图:调用 5 个内部函数(test_config, text_input, with_models_provider_home_and_state_for_tests, default_for_tests, from_api_key);外部调用 4 个(SubAgent, assert_eq!, new, vec!)。

shutdown_agent_tree_closes_live_descendants2566–2648 ↗
async fn shutdown_agent_tree_closes_live_descendants()

作用:测试关闭一棵代理树会关闭根、子、孙所有活跃线程。用户点“关整组”时不能只关根。

数据流:输入父、子、孙代理树并保存历史 → 调用 shutdown_agent_tree(parent) → 三个线程状态都变成 NotFound,captured_ops 里有三条 Shutdown。

调用关系:它依赖 wait_for_live_thread_spawn_children 确认树关系,再验证 shutdown_agent_tree 的递归关闭效果。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 3 个(SubAgent, assert_eq!, vec!)。

shutdown_agent_tree_closes_descendants_when_started_at_child2651–2739 ↗
async fn shutdown_agent_tree_closes_descendants_when_started_at_child()

作用:测试即使中间子代理先被 close,再从父节点关闭整棵树,也会把后代一起处理掉。

数据流:输入父、子、孙代理树 → 先 close_agent(child),再 shutdown_agent_tree(parent) → 父、子、孙最终都 NotFound,并记录对应 Shutdown 操作。

调用关系:它覆盖“子树中有已关闭节点”的关闭路径,防止孙节点因为父节点关闭而被漏掉。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 3 个(SubAgent, assert_eq!, vec!)。

resume_agent_from_rollout_does_not_reopen_closed_descendants2742–2834 ↗
async fn resume_agent_from_rollout_does_not_reopen_closed_descendants()

作用:测试恢复父代理时,不会重新打开之前明确关闭过的子树。用户关掉的后代应该保持关闭。

数据流:输入保存过的父、子、孙树 → close_agent(child),关闭父,再恢复父 → 父恢复成功,子和孙仍是 NotFound。

调用关系:它验证 resume_agent_from_rollout 尊重 close_agent 记录,不把已关闭后代当作可自动恢复对象。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 3 个(SubAgent, assert_eq!, assert_ne!)。

resume_closed_child_reopens_open_descendants2837–2931 ↗
async fn resume_closed_child_reopens_open_descendants()

作用:测试直接恢复一个已关闭的子代理时,它下面仍标记为开放的后代会一起恢复。恢复子树时要把没关的孩子带回来。

数据流:输入父、子、孙树 → close_agent(child),然后直接恢复 child → child 和 grandchild 都重新变为已加载状态。

调用关系:它和“恢复父不重开关闭后代”的测试形成对照,说明恢复入口不同,恢复范围也不同。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 3 个(SubAgent, assert_eq!, assert_ne!)。

resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown2934–3022 ↗
async fn resume_agent_from_rollout_reopens_open_descendants_after_manager_shutdown()

作用:测试线程管理器整体关停后,恢复根代理会重开仍然开放的后代。系统重启后代理树能回来。

数据流:输入保存过的父、子、孙树 → shutdown_all_threads_bounded 关闭全部活跃线程 → 恢复父线程 → 父、子、孙都不再是 NotFound。

调用关系:它模拟进程或管理器停掉后的树恢复,依赖持久化的父子关系和 rollout。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 4 个(from_secs, SubAgent, assert_eq!, assert_ne!)。

resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale3025–3153 ↗
async fn resume_agent_from_rollout_uses_edge_data_when_descendant_metadata_source_is_stale()

作用:测试后代线程自己的元数据过期时,恢复会优先使用父子边记录里的真实关系。这样旧字段不会把树接错。

数据流:输入父、子、孙树 → 人为把孙线程数据库里的 source 改成错误父亲和错误深度 → 关闭后恢复父 → 孙线程恢复时仍指向真正的 child,深度为 2。

调用关系:它验证恢复树时边数据比线程元数据 source 更可信,防止陈旧数据破坏拓扑结构。

调用图:调用 5 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children, new);外部调用 6 个(from_secs, SubAgent, assert_eq!, assert_ne!, panic!, to_string)。

resume_agent_from_rollout_skips_descendants_when_parent_resume_fails3156–3250 ↗
async fn resume_agent_from_rollout_skips_descendants_when_parent_resume_fails()

作用:测试恢复某个子节点失败时,它的后代不会被单独重开。父节点没恢复好,下面的树就不能悬空启动。

数据流:输入保存过的父、子、孙树 → 关闭全部线程后删除 child 的 rollout 文件 → 恢复 parent 成功,但 child 失败,grandchild 也保持 NotFound。

调用关系:它覆盖部分恢复失败的安全策略,确保 resume_agent_from_rollout 不会制造没有父线程的孤儿代理。

调用图:调用 4 个内部函数(new, persist_thread_for_tree_resume, text_input, wait_for_live_thread_spawn_children);外部调用 5 个(from_secs, SubAgent, assert_eq!, assert_ne!, remove_file)。

core/src/agent/control/execution_tests.rs源码 ↗
testtest

这个文件测试的是 AgentControl 里的执行容量保护。可以把它想成一个门卫:某些子代理要开始干活前,必须先问门卫“现在还能进吗”。如果正在干活的人已经满了,门卫就拒绝;等一个任务结束、守卫对象被丢掉后,名额又会还回来。这里重点检查两件事:第一,V2 多代理里的子代理会被计数,而且最大线程数以根会话设置为准,后面子角色想把限制改大也不能覆盖。第二,主会话本身和 V1 版本的子代理不会被这个计数器拦住。测试通过这些场景保证并发限制既不会失效,也不会管得太宽。

函数细节3
control_with_limit8–12 ↗
fn control_with_limit(max_threads: usize) -> AgentControl

作用:这个小帮手用来快速做出一个带指定执行上限的 AgentControl,方便后面的测试不用重复写准备代码。

数据流:进去的是一个数字 max_threads,表示最多允许几个受限制的子代理同时执行;函数先创建默认的 AgentControl,再把它里面的 agent_execution_limiter 初始化成这个上限;出来的是已经设置好限制的 AgentControl,供测试继续使用。

调用关系:它是两个测试的共同准备步骤。execution_guards_count_active_v2_subagent_turns 用它创建上限为 1 的控制器,execution_guards_ignore_root_and_v1_turns 用它创建上限为 0 的控制器。它内部只依赖 AgentControl 的默认创建能力。

调用图:被 2 处调用(execution_guards_count_active_v2_subagent_turns, execution_guards_ignore_root_and_v1_turns);外部调用 1 个(default)。

execution_guards_count_active_v2_subagent_turns15–41 ↗
fn execution_guards_count_active_v2_subagent_turns()

作用:这个测试确认:V2 子代理的执行会被计入并发上限,超过上限会报错;任务结束后,名额会自动释放。

数据流:一开始它用 control_with_limit 做出一个上限为 1 的控制器,然后故意再次初始化成 2,验证后来的子角色配置不能把根会话限制改大。接着它构造一个名叫 worker 的子代理来源,先检查第一次执行有容量,再拿到一个 execution guard(执行守卫,可以理解为占着一个名额的凭证)。当这个凭证还在时,再检查容量就应该失败,并且错误里报告的最大线程数仍是 1。最后它丢掉第一个守卫,名额被释放,再次检查容量就应该成功。

调用关系:这是对执行限制核心行为的完整场景测试。它先调用 control_with_limit 准备控制器,再通过 SubAgent 和 Other 构造一个子代理来源;过程中用 assert_eq! 检查报错里的上限数字是否正确,用 panic! 标出本不该发生的分支。它主要验证 AgentControl 的 ensure_execution_capacity 和 execution_guard 这套配合是否可靠。

调用图:调用 1 个内部函数(control_with_limit);外部调用 4 个(SubAgent, assert_eq!, panic!, Other)。

execution_guards_ignore_root_and_v1_turns44–60 ↗
fn execution_guards_ignore_root_and_v1_turns()

作用:这个测试确认:执行守卫不会错误地限制根会话,也不会限制旧的 V1 子代理会话。

数据流:它先用 control_with_limit 创建一个上限为 0 的控制器,这样如果某类会话会被限制,就一定拿不到名额。然后它分别尝试给 V2 的命令行根会话、V1 的子代理会话创建执行守卫。两次结果都应该是 none,也就是“不需要守卫、不参与计数”。测试用 assert! 确认这两类情况确实被忽略。

调用关系:它补充验证限制规则的边界,避免门卫拦错人。它调用 control_with_limit 来准备一个极端的零容量环境,然后直接检查 AgentControl 的 execution_guard 返回值。和另一个测试相比,它关心的不是“限制是否生效”,而是“哪些情况不该被限制”。

调用图:调用 1 个内部函数(control_with_limit);外部调用 1 个(assert!)。

core/src/agent/control/residency_tests.rs源码 ↗
testtest run

这里测试的是“驻留名额”,可以理解成停车位:一个会话里同时能停放的 V2 子代理数量有限。测试先造一个临时配置和临时目录,启动一个根线程,再手动创建子代理。第一个测试让第一个子代理完成工作并变空闲,然后再申请第二个名额,确认系统会把最早空闲的子代理卸载掉,但根线程和新子代理还在。第二个测试更细:第一个子代理不是正常完成,而是被打断;它被名额回收机制踢掉后,系统不应该再把它当成可恢复的代理加载回来。文件里的几个小工具函数负责创建子代理、伪造“完成”或“中断”的事件,并清掉当前活动轮次,让测试环境像真实运行结束后一样干净。

函数细节6
residency_slot_reservation_unloads_oldest_idle_v2_agent22–65 ↗
async fn residency_slot_reservation_unloads_oldest_idle_v2_agent()

作用:这个测试确认:当 V2 子代理的驻留名额满了,再申请新名额时,系统会卸载最早已经空闲的子代理。它防止旧代理一直占着“停车位”,导致新代理进不来。

数据流:进去的是一份测试配置、临时目录和一个假的登录凭证;测试把多代理 V2 打开,并把同一会话最多线程数设成 2。它启动根线程,申请第一个驻留名额,创建第一个子代理,把它标记为已完成;接着再申请第二个名额。结果应该是第一个子代理已经查不到了,而根线程和第二个子代理都还能查到。

调用关系:这是测试用例的主流程之一。它会调用 spawn_v2_subagent 来创建子代理,调用 mark_thread_completed 来把子代理伪造成已完成状态;随后通过线程管理器查询线程是否还存在,用这些结果判断驻留回收逻辑是否正确。

调用图:调用 6 个内部函数(mark_thread_completed, spawn_v2_subagent, test_config, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 5 个(new, assert!, assert_eq!, panic!, tempdir)。

interrupted_v2_agent_is_lost_after_residency_eviction68–127 ↗
async fn interrupted_v2_agent_is_lost_after_residency_eviction()

作用:这个测试确认:一个被中断的 V2 子代理如果后来因为名额回收被卸载,就应该彻底丢失,不能再被系统重新加载。它防止系统把一个已经不安全或不完整的代理状态误当成可继续使用。

数据流:进去的是测试配置、临时目录和假的认证信息;测试打开多代理 V2,启动根线程,创建第一个子代理并把它标记为“被打断”。然后它申请新的驻留名额,触发旧子代理被卸载,再创建第二个子代理并标记完成。最后它尝试重新加载第一个子代理,期望得到 ThreadNotFound,也就是“这个线程不存在”。

调用关系:这是另一个主测试流程,比正常完成的场景更严格。它先用 spawn_v2_subagent 造子代理,用 mark_thread_interrupted 制造中断状态,再用 mark_thread_completed 让第二个代理结束;最后直接检查 AgentControl 的加载行为,确认被踢掉的中断代理不会复活。

调用图:调用 7 个内部函数(mark_thread_completed, mark_thread_interrupted, spawn_v2_subagent, test_config, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 5 个(new, assert!, assert_eq!, panic!, tempdir)。

spawn_v2_subagent129–151 ↗
async fn spawn_v2_subagent(
    control: &AgentControl,
    state: &Arc<ThreadManagerState>,
    config: Config,
    parent_thread_id: ThreadId,
    label: &str,
) -> crate::thread_manager::NewThread

作用:这个辅助函数专门帮测试创建一个 V2 子代理线程。它把创建子代理时那些重复又容易写错的参数集中到一起,让两个测试都能用同一套造法。

数据流:进去的是代理控制器、线程管理器状态、配置、父线程编号和一个标签;函数把标签包装成“子代理来源”,再告诉线程管理器生成一个挂在父线程下面的新线程。出来的是新建好的线程对象;如果创建失败,测试会直接报错。

调用关系:它被两个测试用例调用,用来准备测试现场里的子代理。它把实际创建线程的工作交给 ThreadManagerState 的 spawn_new_thread_with_source,自己主要负责把“这是一个子代理、属于哪个父线程、叫什么标签”这些信息填好。

调用图:被 2 处调用(interrupted_v2_agent_is_lost_after_residency_eviction, residency_slot_reservation_unloads_oldest_idle_v2_agent);外部调用 3 个(SubAgent, clone, Other)。

mark_thread_completed153–170 ↗
async fn mark_thread_completed(thread: &CodexThread)

作用:这个辅助函数把一个线程伪造成“已经正常完成一轮工作”。测试需要这种状态,才能验证空闲代理会不会被驻留名额机制回收。

数据流:进去的是一个 CodexThread;函数先创建一个默认轮次,然后向会话发送 TurnComplete 事件,意思是“这一轮做完了”,还附上一句最后的代理消息。最后它调用 clear_active_turn,把测试环境里的当前活动轮次清空。

调用关系:它被两个测试用例使用:第一个用它让旧子代理变成可回收的空闲代理,第二个用它结束新子代理。它发送完成事件后,会把收尾工作交给 clear_active_turn,因为这个测试夹具里没有真实任务运行器来自动清理。

调用图:调用 1 个内部函数(clear_active_turn);被 2 处调用(interrupted_v2_agent_is_lost_after_residency_eviction, residency_slot_reservation_unloads_oldest_idle_v2_agent);外部调用 1 个(TurnComplete)。

mark_thread_interrupted172–188 ↗
async fn mark_thread_interrupted(thread: &CodexThread)

作用:这个辅助函数把一个线程伪造成“这一轮被用户或系统打断”。它服务于测试中断代理被卸载后不应再恢复的场景。

数据流:进去的是一个 CodexThread;函数创建一个默认轮次,然后向会话发送 TurnAborted 事件,原因写成 Interrupted,也就是“被中断”。之后它调用 clear_active_turn,把活动轮次清掉,让线程看起来已经结束了这次中断流程。

调用关系:它只被 interrupted_v2_agent_is_lost_after_residency_eviction 这个测试调用。它负责制造关键前提:第一个子代理不是正常完成,而是中断结束;清理活动轮次的细节则交给 clear_active_turn。

调用图:调用 1 个内部函数(clear_active_turn);被 1 处调用(interrupted_v2_agent_is_lost_after_residency_eviction);外部调用 1 个(TurnAborted)。

clear_active_turn190–193 ↗
async fn clear_active_turn(thread: &CodexThread)

作用:这个小工具把线程会话里的“当前正在进行的轮次”清空。它弥补测试环境没有真实任务运行器的缺口,避免线程表面上已经结束、内部却还挂着一个活动任务。

数据流:进去的是一个 CodexThread;函数拿到会话里的 active_turn,并通过异步锁保护后把它设成 None。结果是这个线程不再记录任何正在进行的轮次。

调用关系:它是完成和中断两个辅助函数的共同收尾步骤。mark_thread_completed 和 mark_thread_interrupted 都先发送终止类事件,再调用它做最后清理,保证后续驻留回收判断看到的是一个真正空闲的线程。

调用图:被 2 处调用(mark_thread_completed, mark_thread_interrupted)。

core/src/agent/registry_tests.rs源码 ↗
testtest

这个文件不是真正运行产品功能的代码,而是专门检查 AgentRegistry,也就是“代理登记本”的行为。这个登记本要记住现在有哪些代理线程、最多能开几个、每个代理叫什么昵称、占了哪个路径。测试重点是:预留名额后如果放弃,名额要还回去;如果已经正式创建,就要一直占着名额,直到释放;释放不存在的线程不能误伤;同一个线程释放两次也不能把计数弄乱。它还检查昵称池的规则:用过的昵称不会立刻重复,池子用光后才重置,并自动加上“the 2nd”“the 3rd”这种后缀。最后,它验证代理路径像通讯录地址一样,创建时能查到,释放后查不到。

函数细节17
agent_path6–8 ↗
fn agent_path(path: &str) -> AgentPath

作用:这是测试里用的小工具,把一段普通字符串变成 AgentPath,也就是系统认识的“代理路径”。这样后面的测试不用每次都写转换和报错处理。

数据流:进去的是像“/root/researcher”这样的字符串 → 它调用路径转换函数检查格式并生成 AgentPath → 出来的是可用于注册表查询和预留的路径对象;如果字符串不合法,测试会直接失败。

调用关系:它服务于路径相关的测试。reserved_agent_path_is_released_when_spawn_fails 和 committed_agent_path_is_indexed_until_release 需要构造同一个标准路径时,都会先请它把字符串整理成系统可用的路径。

调用图:调用 1 个内部函数(try_from);被 2 处调用(committed_agent_path_is_indexed_until_release, reserved_agent_path_is_released_when_spawn_fails)。

agent_metadata10–15 ↗
fn agent_metadata(thread_id: ThreadId) -> AgentMetadata

作用:这是测试里用的小工具,用一个线程编号快速做出一份代理资料。它只填最关键的 agent_id,其他字段保持默认。

数据流:进去的是 ThreadId,也就是一个线程的身份号 → 它把这个身份号放进 AgentMetadata,并把没关心的字段设成默认值 → 出来的是可以交给 commit 使用的代理资料。

调用关系:凡是测试需要把“预留名额”变成“真正创建了一个代理”时,都会用它准备资料。commit_holds_slot_until_release、release_ignores_unknown_thread_id 等多个测试都靠它减少重复代码。

调用图:被 6 处调用(agent_nickname_resets_used_pool_when_exhausted, commit_holds_slot_until_release, release_ignores_unknown_thread_id, release_is_idempotent_for_registered_threads, released_nickname_stays_used_until_pool_reset, repeated_resets_advance_the_ordinal_suffix);外部调用 1 个(default)。

format_agent_nickname_adds_ordinals_after_reset18–39 ↗
fn format_agent_nickname_adds_ordinals_after_reset()

作用:这个测试确认昵称在重复使用时会加上正确的序号后缀。比如第一次叫 Plato,重置后再用就变成 Plato the 2nd。

数据流:进去的是同一个基础昵称 Plato 和不同的重置次数 → 它检查格式化函数给出的名字 → 结果必须分别是原名、the 2nd、the 3rd、the 11th、the 21st 这些符合英文习惯的形式。

调用关系:它单独盯住昵称显示规则,不创建注册表。其他昵称池测试会验证什么时候该重置,这个测试则保证重置后显示出来的名字本身是对的。

调用图:外部调用 1 个(assert_eq!)。

session_depth_defaults_to_zero_for_root_sources42–44 ↗
fn session_depth_defaults_to_zero_for_root_sources()

作用:这个测试确认从命令行直接启动的根会话,深度从 0 开始。也就是它不是任何子代理生出来的。

数据流:进去的是 SessionSource::Cli,表示顶层命令行来源 → 它交给 session_depth 计算 → 出来的深度必须是 0。

调用关系:它检查深度计算的最基础情况。后面的 thread_spawn_depth_increments_and_enforces_limit 会在这个基础上检查子代理继续生成子代理时深度怎样增加。

调用图:外部调用 1 个(assert_eq!)。

thread_spawn_depth_increments_and_enforces_limit47–61 ↗
fn thread_spawn_depth_increments_and_enforces_limit()

作用:这个测试确认由线程生成的子代理,再生成下一层时深度会加 1,并且会触发最大深度限制。这样可以防止代理像套娃一样无限生下去。

数据流:先构造一个深度为 1 的线程生成来源 → 计算下一层深度,应该变成 2 → 再用最大深度 1 去检查,结果应该判定已经超限。

调用关系:它验证线程生成链条里的安全刹车。它用 ThreadId::new 做一个父线程身份,再通过深度计算和限制判断函数确认注册逻辑不会放任无限递归。

调用图:调用 1 个内部函数(new);外部调用 3 个(SubAgent, assert!, assert_eq!)。

non_thread_spawn_subagents_default_to_depth_zero64–71 ↗
fn non_thread_spawn_subagents_default_to_depth_zero()

作用:这个测试确认不是“线程继续生成”的子代理,比如 Review 类型,不会被当成已经深入很多层。它们默认深度是 0,下一次线程生成才算第 1 层。

数据流:进去的是一个 Review 子代理来源 → session_depth 给出 0 → next_thread_spawn_depth 给出 1 → 用最大深度 1 检查时不应该超限。

调用关系:它补上了非线程生成来源的情况,避免所有子代理都被误算深度。它和 thread_spawn_depth_increments_and_enforces_limit 一起覆盖深度规则的两条分支。

调用图:外部调用 3 个(SubAgent, assert!, assert_eq!)。

reservation_drop_releases_slot74–81 ↗
fn reservation_drop_releases_slot()

作用:这个测试确认只预留了创建名额、但后来放弃创建时,名额会自动还回去。就像餐厅订位没来,座位不能永远被占着。

数据流:先创建一个注册表,并在最多 1 个线程的限制下预留一个名额 → 把预留对象直接丢掉 → 再次预留时应该成功,说明之前的名额已经释放。

调用关系:它检查预留对象被 drop,也就是离开作用域或被丢弃时的清理动作。这个行为是后面失败创建、路径释放等测试能成立的基础。

调用图:外部调用 2 个(new, default)。

commit_holds_slot_until_release84–104 ↗
fn commit_holds_slot_until_release()

作用:这个测试确认预留名额一旦正式提交成代理线程,就会一直占着名额,直到明确释放。这样最大线程数限制才不会被绕过。

数据流:先预留 1 个名额 → 用 agent_metadata 做出线程资料并 commit → 再想预留第二个名额时必须失败,并返回“达到代理数量上限” → 释放原线程后,再预留就应该成功。

调用关系:它把 agent_metadata 作为准备资料的小助手,然后检查 AgentRegistry 的核心生命周期:预留、提交、阻止超额、释放、重新可用。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 4 个(new, assert_eq!, default, panic!)。

release_ignores_unknown_thread_id107–129 ↗
fn release_ignores_unknown_thread_id()

作用:这个测试确认释放一个注册表不认识的线程编号,不会错误地释放真实线程占用的名额。也就是说,拿错号码牌不能退掉别人的座位。

数据流:先提交一个真实线程占住唯一名额 → 用另一个全新的 ThreadId 调用释放 → 再尝试预留仍然应该失败,说明真实线程还在占位 → 最后释放真实线程,名额才恢复。

调用关系:它沿用 agent_metadata 创建真实代理资料。它专门测试 release_spawned_thread 面对错误输入时的防误伤能力。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 4 个(new, assert_eq!, default, panic!)。

release_is_idempotent_for_registered_threads132–160 ↗
fn release_is_idempotent_for_registered_threads()

作用:这个测试确认同一个线程释放多次也不会把注册表弄乱。“幂等”就是重复做同一件事,结果不会继续变化。

数据流:先提交第一个线程并释放它 → 再提交第二个线程占住名额 → 又去释放已经释放过的第一个线程 → 这不应该影响第二个线程,所以再预留仍然失败 → 释放第二个线程后名额才恢复。

调用关系:它测试 release_spawned_thread 的稳健性。agent_metadata 负责造提交资料,注册表则要证明自己不会因为旧释放请求而误删新线程。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 4 个(new, assert_eq!, default, panic!)。

failed_spawn_keeps_nickname_marked_used163–181 ↗
fn failed_spawn_keeps_nickname_marked_used()

作用:这个测试确认即使代理创建失败,已经拿过的昵称也会被记为用过。这样可以避免失败重试时反复抢同一个名字,造成混乱。

数据流:第一次预留名额并拿到昵称 alpha,然后直接丢弃预留,模拟创建失败 → 第二次再从 alpha 和 beta 里选 → 结果应该选 beta,说明 alpha 仍然被标记为已用。

调用关系:它关注昵称池,而不是线程名额。它依赖预留对象丢弃时不回滚昵称使用记录这个设计,和后面的“昵称池用光才重置”测试连在一起。

调用图:外部调用 3 个(new, assert_eq!, default)。

agent_nickname_resets_used_pool_when_exhausted184–208 ↗
fn agent_nickname_resets_used_pool_when_exhausted()

作用:这个测试确认当可选昵称都已经用过时,昵称池会重置,并给重复昵称加上序号。比如 alpha 再次出现时会变成 alpha the 2nd。

数据流:先创建一个代理并使用 alpha → 再尝试只从 alpha 里选名 → 因为池子已用光,所以系统重置昵称池,返回 alpha the 2nd → 最后检查内部重置次数变成 1。

调用关系:它用 agent_metadata 把第一次预留正式提交,确保 alpha 成为活跃历史的一部分。它验证昵称选择逻辑和注册表内部计数 nickname_reset_count 会同步变化。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 3 个(new, assert_eq!, default)。

released_nickname_stays_used_until_pool_reset211–250 ↗
fn released_nickname_stays_used_until_pool_reset()

作用:这个测试确认代理结束后,它用过的昵称不会立刻变回可选;只有所有候选昵称都用过、昵称池重置后,才允许重复使用并加序号。

数据流:先用 alpha 并释放线程 → 第二次从 alpha、beta 里选时,应避开刚释放的 alpha,选择 beta → 释放 beta 后,alpha 和 beta 都已用过 → 第三次再选时允许重置,返回 alpha the 2nd 或 beta the 2nd,并记录重置次数为 1。

调用关系:它连接了释放线程和昵称池两个规则。agent_metadata 用来提交真实线程,HashSet 用来接受第三次结果的两种合理可能。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 5 个(new, from, assert!, assert_eq!, default)。

repeated_resets_advance_the_ordinal_suffix253–290 ↗
fn repeated_resets_advance_the_ordinal_suffix()

作用:这个测试确认昵称池多次重置时,序号会继续往前走,不会一直停在 the 2nd。这样重复名字仍然能看出第几轮使用。

数据流:连续三次只提供 Plato 这个昵称:第一次得到 Plato,释放后第二次得到 Plato the 2nd,再释放后第三次得到 Plato the 3rd → 最后检查重置次数是 2。

调用关系:它在 format_agent_nickname_adds_ordinals_after_reset 的显示规则基础上,验证真实注册表流程里重置次数会正确累加。agent_metadata 负责让每次预留变成正式代理。

调用图:调用 2 个内部函数(agent_metadata, new);外部调用 3 个(new, assert_eq!, default)。

register_root_thread_indexes_root_path293–303 ↗
fn register_root_thread_indexes_root_path()

作用:这个测试确认根线程注册后,可以通过根路径查到它的线程编号。根路径就像整个代理树的总入口地址。

数据流:创建注册表和一个新的根线程编号 → 调用 register_root_thread 登记根线程 → 再用 AgentPath::root 查询,结果必须返回刚才的线程编号。

调用关系:它测试根代理的路径索引。和后面的子路径测试不同,它不需要预留流程,直接验证根线程登记后能被路径查找功能找到。

调用图:调用 1 个内部函数(new);外部调用 3 个(new, assert_eq!, default)。

reserved_agent_path_is_released_when_spawn_fails306–322 ↗
fn reserved_agent_path_is_released_when_spawn_fails()

作用:这个测试确认如果只预留了代理路径但创建失败,路径会释放出来。否则同一个位置会被一个不存在的代理永久占住。

数据流:第一次预留名额,并预留路径 /root/researcher,然后直接丢弃预留对象,模拟创建失败 → 第二次再预留同一个路径应该成功,说明路径锁已经释放。

调用关系:它用 agent_path 把字符串变成标准路径。它和 reservation_drop_releases_slot 类似,但重点从“线程名额”换成“代理路径”。

调用图:调用 1 个内部函数(agent_path);外部调用 2 个(new, default)。

committed_agent_path_is_indexed_until_release325–350 ↗
fn committed_agent_path_is_indexed_until_release()

作用:这个测试确认代理路径在正式提交后会被登记到查询表里,并且会一直保留到线程释放。释放后,这个路径就不再指向旧线程。

数据流:先预留 /root/researcher 路径 → 提交一份包含线程编号和路径的 AgentMetadata → 查询该路径,应该得到线程编号 → 释放这个线程 → 再查询同一路径,应该得到空结果。

调用关系:它用 agent_path 反复构造同一个路径,并走完整的预留、提交、查询、释放流程。它验证路径索引和线程生命周期是绑在一起更新的。

调用图:调用 2 个内部函数(agent_path, new);外部调用 4 个(new, default, assert_eq!, default)。

core/src/agent/role_tests.rs源码 ↗
testtest

这个文件不是产品运行时会执行的功能代码,而是一组自动测试。它先用临时目录造出一套假的用户环境,再写入各种角色配置文件,检查 apply_role_to_config 这类角色应用逻辑是否稳妥:默认角色不能乱改配置,不存在的角色要报错,坏掉的 TOML 配置文件不能悄悄通过,角色只应该覆盖自己声明的键,没声明的设置要保留。它还测试“spawn 工具说明”里列出的角色文字,确保用户自定义角色和内置角色不会重复,且会提示模型、推理强度、服务档位这些被角色锁定的设置。可以把它理解成角色系统的体检表:每个测试都在模拟一个容易出错的场景。

函数细节22
test_config_with_cli_overrides16–29 ↗
async fn test_config_with_cli_overrides(
    cli_overrides: Vec<(String, TomlValue)>,
) -> (TempDir, Config)

作用:给测试快速造一份干净的配置。调用者可以顺手塞一些“命令行覆盖项”,用来模拟用户在启动时临时指定了配置。

数据流:进去的是一组键值形式的临时覆盖配置;它创建一个临时 home 目录,把这个目录当成项目的配置家目录,再通过 ConfigBuilder 读出完整配置;出来的是临时目录句柄和构建好的 Config,后面的测试可以安全地随便改,不会碰到真实用户文件。

调用关系:很多测试先调用它搭测试舞台,比如测试默认角色、未知角色、沙箱设置、服务档位和技能开关。它内部依赖临时目录创建和 ConfigBuilder 的默认构建流程,把复杂准备工作包成一个小工具。

调用图:被 13 处调用(apply_empty_explorer_role_preserves_current_model_and_reasoning_effort, apply_explorer_role_sets_model_and_adds_session_flags_layer, apply_role_defaults_to_default_and_leaves_config_unchanged, apply_role_does_not_materialize_default_sandbox_workspace_write_fields, apply_role_ignores_agent_metadata_fields_in_user_role_file, apply_role_preserves_existing_service_tier_without_override, apply_role_preserves_unspecified_keys, apply_role_reports_explicit_service_tier, apply_role_returns_error_for_unknown_role, apply_role_returns_unavailable_for_invalid_user_role_toml (+3 more));外部调用 2 个(new, default)。

write_role_config31–37 ↗
async fn write_role_config(home: &TempDir, name: &str, contents: &str) -> PathBuf

作用:在临时目录里写一个角色配置文件。测试用它来假装用户真的写了某个角色的 TOML 文件。

数据流:进去的是临时 home 目录、文件名和文件内容;它把文件名拼到临时目录下,然后异步写入内容;出来的是这个文件的路径,后续会放进 AgentRoleConfig 里给角色应用逻辑读取。

调用关系:需要用户角色文件的测试都会用它,比如坏 TOML、只改推理强度、设置服务档位、设置技能开关等。它把“准备测试文件”的杂活从各个测试里抽出来。

调用图:被 8 处调用(apply_role_does_not_materialize_default_sandbox_workspace_write_fields, apply_role_ignores_agent_metadata_fields_in_user_role_file, apply_role_preserves_existing_service_tier_without_override, apply_role_preserves_unspecified_keys, apply_role_reports_explicit_service_tier, apply_role_returns_unavailable_for_invalid_user_role_toml, apply_role_skills_config_disables_skill_for_spawned_agent, apply_role_takes_precedence_over_existing_session_flags_for_same_key);外部调用 2 个(path, write)。

session_flags_layer_count39–49 ↗
fn session_flags_layer_count(config: &Config) -> usize

作用:数一数当前配置里有多少层来自“会话标志”的配置层。这里的配置层可以理解成一叠透明纸,后放上去的会盖住前面的同名设置。

数据流:进去的是 Config;它读取配置层栈,按从低优先级到高优先级取出所有层,包括禁用层,然后筛出名字是 SessionFlags 的层;出来的是数量,不修改配置。

调用关系:几个测试用它判断应用角色前后有没有新增一层会话级配置。比如 explorer 角色或自定义角色覆盖 model 时,应该新增一层;空角色不该凭空新增。

调用图:被 3 处调用(apply_empty_explorer_role_preserves_current_model_and_reasoning_effort, apply_explorer_role_sets_model_and_adds_session_flags_layer, apply_role_takes_precedence_over_existing_session_flags_for_same_key)。

apply_role_defaults_to_default_and_leaves_config_unchanged52–61 ↗
async fn apply_role_defaults_to_default_and_leaves_config_unchanged()

作用:测试没有指定角色时,系统会走默认角色,而且不会把配置改坏。这个场景很重要,因为大多数用户可能不会显式选择角色。

数据流:它先拿到一份无命令行覆盖的配置并复制一份备份;然后对原配置应用空角色名;最后比较应用前后是否完全一样,确认默认流程没有制造额外变化。

调用关系:测试运行器会调用它。它借助 test_config_with_cli_overrides 准备配置,然后直接检查 apply_role_to_config 的默认行为。

调用图:调用 1 个内部函数(test_config_with_cli_overrides);外部调用 2 个(new, assert_eq!)。

apply_role_returns_error_for_unknown_role64–72 ↗
async fn apply_role_returns_error_for_unknown_role()

作用:测试用户输入一个不存在的角色名时,系统要明确报错,而不是默默使用别的角色。

数据流:它创建一份干净配置,把 missing-role 传给角色应用函数;函数返回错误后,测试检查错误文字必须是 unknown agent_type 'missing-role'。

调用关系:测试运行器调用它。它通过 test_config_with_cli_overrides 搭环境,然后验证 apply_role_to_config 对未知角色的防呆能力。

调用图:调用 1 个内部函数(test_config_with_cli_overrides);外部调用 2 个(new, assert_eq!)。

apply_explorer_role_sets_model_and_adds_session_flags_layer76–87 ↗
async fn apply_explorer_role_sets_model_and_adds_session_flags_layer()

作用:测试 explorer 角色如果有内置默认值,应当设置模型和推理强度,并新增一层会话配置。这个测试目前被标记忽略,因为当前没有需要它的角色。

数据流:它先数应用前的 SessionFlags 层数;应用 explorer 角色后,检查 model 是否变成指定模型、推理强度是否为 Medium,以及 SessionFlags 层数是否增加一个。

调用关系:测试运行器通常会跳过它,因为有 ignore 标记。它使用 session_flags_layer_count 和 test_config_with_cli_overrides 来验证角色是否通过配置层栈生效。

调用图:调用 2 个内部函数(session_flags_layer_count, test_config_with_cli_overrides);外部调用 2 个(new, assert_eq!)。

apply_empty_explorer_role_preserves_current_model_and_reasoning_effort90–103 ↗
async fn apply_empty_explorer_role_preserves_current_model_and_reasoning_effort()

作用:测试一个没有实际覆盖内容的 explorer 角色,不应该把用户已有的模型和推理强度清掉。

数据流:它创建配置后先手动设置 model 和 model_reasoning_effort,再应用 explorer;最后确认这两个值仍然是原来的,并且 SessionFlags 层数没有增加。

调用关系:测试运行器调用它。它用 test_config_with_cli_overrides 准备配置,用 session_flags_layer_count 观察配置层有没有被无意义地新增。

调用图:调用 2 个内部函数(session_flags_layer_count, test_config_with_cli_overrides);外部调用 2 个(new, assert_eq!)。

apply_role_returns_unavailable_for_missing_user_role_file106–122 ↗
async fn apply_role_returns_unavailable_for_missing_user_role_file()

作用:测试用户自定义角色指向一个不存在的配置文件时,系统要返回“角色不可用”的统一错误。

数据流:它创建配置,在 agent_roles 里插入一个 custom 角色,配置文件路径指向不存在的位置;应用 custom 后拿到错误;最后确认错误是 AGENT_TYPE_UNAVAILABLE_ERROR。

调用关系:测试运行器调用它。它重点覆盖 apply_role_to_config 读取用户角色文件失败时的表现。

调用图:调用 1 个内部函数(test_config_with_cli_overrides);外部调用 3 个(from, new, assert_eq!)。

apply_role_returns_unavailable_for_invalid_user_role_toml125–142 ↗
async fn apply_role_returns_unavailable_for_invalid_user_role_toml()

作用:测试用户角色文件内容不是合法 TOML 时,系统不会继续使用半坏的配置,而是把这个角色判为不可用。

数据流:它先写入一个语法坏掉的角色文件,比如 model = [;再把这个文件挂到 custom 角色上;应用角色后检查返回的错误是否为统一的不可用错误。

调用关系:测试运行器调用它。它通过 write_role_config 制造坏文件,验证 apply_role_to_config 的配置解析失败路径。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 2 个(new, assert_eq!)。

apply_role_ignores_agent_metadata_fields_in_user_role_file145–173 ↗
async fn apply_role_ignores_agent_metadata_fields_in_user_role_file()

作用:测试角色文件里的元信息字段不会被当成普通运行配置乱套进去。元信息就是名字、描述、昵称候选这类给人看的资料。

数据流:它写一个包含 name、description、nickname_candidates、developer_instructions 和 model 的角色文件;应用 custom 后,只检查 model 被正确设置为 role-model,说明可用配置仍然生效,而元信息字段不会干扰。

调用关系:测试运行器调用它。它用 test_config_with_cli_overrides 和 write_role_config 准备环境,覆盖用户角色文件中混有说明字段的情况。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 2 个(new, assert_eq!)。

apply_role_preserves_unspecified_keys176–213 ↗
async fn apply_role_preserves_unspecified_keys()

作用:测试角色只改自己写明的设置,不能顺手清掉别的已有设置。这样用户原本的模型、沙箱程序路径等配置才不会莫名消失。

数据流:它先用命令行覆盖设置 base-model,再手动放入两个执行器路径;角色文件只声明 developer_instructions 和 model_reasoning_effort;应用后确认模型仍是 base-model、推理强度变成 High,两个路径也都保留。

调用关系:测试运行器调用它。它使用 test_config_with_cli_overrides 模拟已有配置,用 write_role_config 提供只覆盖部分键的角色文件。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 3 个(from, assert_eq!, vec!)。

apply_role_reports_explicit_service_tier216–243 ↗
async fn apply_role_reports_explicit_service_tier()

作用:测试角色文件明确写了服务档位时,配置里会反映这个选择。服务档位可以理解成请求模型服务时想用的速度或优先级。

数据流:它写一个 service_tier = priority 的角色文件;应用 custom 角色后,检查 Config 里的 service_tier 变成 Fast 对应的请求值。

调用关系:测试运行器调用它。它通过 write_role_config 制造带服务档位的角色,然后验证 apply_role_to_config 能把它翻译到最终配置里。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 2 个(new, assert_eq!)。

apply_role_preserves_existing_service_tier_without_override246–273 ↗
async fn apply_role_preserves_existing_service_tier_without_override()

作用:测试角色没有声明服务档位时,不会覆盖用户已有的服务档位。

数据流:它先把配置里的 service_tier 设置成 Fast;角色文件只写 developer_instructions,不写 service_tier;应用后确认 service_tier 仍然是原值。

调用关系:测试运行器调用它。它和 apply_role_reports_explicit_service_tier 互相补充,一个测“写了要生效”,一个测“没写别乱动”。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 2 个(new, assert_eq!)。

apply_role_does_not_materialize_default_sandbox_workspace_write_fields277–346 ↗
async fn apply_role_does_not_materialize_default_sandbox_workspace_write_fields()

作用:测试角色修改沙箱工作区写入设置时,不会把默认字段也硬塞进角色配置层。沙箱就是限制程序能访问哪些文件和网络的安全围栏。

数据流:它先用命令行设置沙箱模式为 workspace-write,并打开网络访问;角色文件只声明 writable_roots;应用后,它找到新加的 SessionFlags 层,确认里面没有 network_access、exclude_tmpdir_env_var、exclude_slash_tmp 这些默认字段,同时最终沙箱策略里的网络访问仍然保持为 true。

调用关系:测试运行器在非 Windows 平台调用它。它用 test_config_with_cli_overrides 和 write_role_config 搭出沙箱场景,验证角色层只记录用户真正写过的字段。

调用图:调用 2 个内部函数(test_config_with_cli_overrides, write_role_config);外部调用 3 个(assert_eq!, panic!, vec!)。

apply_role_takes_precedence_over_existing_session_flags_for_same_key349–377 ↗
async fn apply_role_takes_precedence_over_existing_session_flags_for_same_key()

作用:测试角色设置和已有会话标志设置同一个键时,角色设置应该赢。这里用 model 这个键做例子。

数据流:它先通过命令行覆盖把 model 设为 cli-model,并记录 SessionFlags 层数;角色文件又把 model 写成 role-model;应用后确认最终模型是 role-model,且 SessionFlags 层数增加一层。

调用关系:测试运行器调用它。它用 session_flags_layer_count 观察层数变化,用 write_role_config 创建会覆盖同名键的角色文件。

调用图:调用 3 个内部函数(session_flags_layer_count, test_config_with_cli_overrides, write_role_config);外部调用 2 个(assert_eq!, vec!)。

apply_role_skills_config_disables_skill_for_spawned_agent381–438 ↗
async fn apply_role_skills_config_disables_skill_for_spawned_agent()

作用:测试角色里的技能配置可以影响被派生出来的代理,并能禁用某个技能。技能可以理解成代理可额外使用的一份说明书或工具包。

数据流:它在临时 home 下创建一个 demo 技能文件;角色文件把这个技能路径配置为 enabled = false;应用角色后,它创建插件管理器和技能管理器,按最终配置重新加载技能;最后找到 demo-skill,并确认它是禁用状态。

调用关系:测试运行器在适合的平台调用它,Windows 上会被忽略。它先用 test_config_with_cli_overrides 和 write_role_config 准备角色,再把结果交给 PluginsManager、SkillsManager 和 skills_load_input_from_config,模拟真实派生代理读取技能的流程。

调用图:调用 4 个内部函数(new, new, test_config_with_cli_overrides, write_role_config);外部调用 8 个(clone, new, new, assert_eq!, skills_load_input_from_config, format!, create_dir_all, write)。

spawn_tool_spec_build_deduplicates_user_defined_built_in_roles441–460 ↗
fn spawn_tool_spec_build_deduplicates_user_defined_built_in_roles()

作用:测试生成 spawn 工具说明时,如果用户自定义角色和内置角色同名,应该显示用户版本,不要重复或混入内置说明。

数据流:它构造两个用户角色,其中 explorer 覆盖了内置 explorer,researcher 是用户新增;调用 spawn_tool_spec::build 生成说明文本;最后检查文本里有用户 researcher、用户 explorer 和内置 default,但没有内置 explorer 的旧描述。

调用关系:测试运行器调用它。它直接验证 spawn_tool_spec::build 这个说明生成器对重名角色的去重规则。

调用图:外部调用 4 个(from, assert!, default, build)。

spawn_tool_spec_lists_user_defined_roles_before_built_ins463–480 ↗
fn spawn_tool_spec_lists_user_defined_roles_before_built_ins()

作用:测试生成给模型或工具看的角色列表时,用户自定义角色排在内置角色前面。这样用户自己加的选项更显眼。

数据流:它构造一个名为 aaa 的用户角色,生成说明文本;然后分别找 aaa 和内置 default 在文本里的位置;最后确认 aaa 出现得更早。

调用关系:测试运行器调用它。它只围绕 spawn_tool_spec::build 的排序结果做检查。

调用图:外部调用 3 个(from, assert!, build)。

spawn_tool_spec_marks_role_locked_model_and_reasoning_effort483–505 ↗
fn spawn_tool_spec_marks_role_locked_model_and_reasoning_effort()

作用:测试如果角色文件锁定了模型和推理强度,生成的角色说明必须把这件事告诉使用者,并说明不能改。

数据流:它创建临时角色文件,里面写 model = gpt-5 和 model_reasoning_effort = high;把这个文件挂到 researcher 角色上;生成说明文本后,检查里面包含“模型和推理强度被设置且不能改变”的提示。

调用关系:测试运行器调用它。它通过真实写文件的方式,让 spawn_tool_spec::build 读取角色配置并生成锁定提示。

调用图:外部调用 5 个(from, new, assert!, write, build)。

spawn_tool_spec_marks_role_locked_reasoning_effort_only508–530 ↗
fn spawn_tool_spec_marks_role_locked_reasoning_effort_only()

作用:测试角色只锁定推理强度时,说明文本要准确提示这一项被锁定,而不是误说模型也被锁定。

数据流:它写一个只包含 model_reasoning_effort = medium 的角色文件;构造 reviewer 角色并生成说明;最后检查说明里有“推理强度为 medium 且不能改变”的文字。

调用关系:测试运行器调用它。它覆盖 spawn_tool_spec::build 对“只锁一部分设置”的文案生成情况。

调用图:外部调用 5 个(from, new, assert!, write, build)。

spawn_tool_spec_marks_role_locked_service_tier533–555 ↗
fn spawn_tool_spec_marks_role_locked_service_tier()

作用:测试角色锁定服务档位时,说明文本会提醒这个档位会优先于 spawn 请求里的服务档位。

数据流:它创建一个 service_tier = priority 的角色文件;把它作为 tiered 角色的配置;生成说明文本后,检查文本包含“服务档位设为 priority,并在模型支持时优先生效”的提示。

调用关系:测试运行器调用它。它验证 spawn_tool_spec::build 会把服务档位这种容易被忽略的限制写进角色说明。

调用图:外部调用 5 个(from, new, assert!, write, build)。

built_in_config_file_contents_resolves_explorer_only558–563 ↗
fn built_in_config_file_contents_resolves_explorer_only()

作用:测试内置角色配置文件查找函数不会对不存在的文件乱返回内容。

数据流:它把 missing.toml 这个路径交给 built_in::config_file_contents;函数返回 None;测试确认结果确实是 None。

调用关系:测试运行器调用它。它覆盖 built_in::config_file_contents 的空结果路径,确保只有受支持的内置配置文件会被解析出来。

调用图:外部调用 1 个(assert_eq!)。

core/src/codex_delegate_tests.rs源码 ↗
testtest

这份文件不是真正给用户运行的功能代码,而是“安全检查清单”。它模拟一个父任务把工作交给子 Codex 去做,然后观察消息有没有正确转发、取消时有没有收尾、权限申请有没有原路返回。这里大量使用异步通道(可以理解成不同任务之间传纸条的管道)、取消令牌(一个“停下来”的信号)和超时检查,目的都是避免后台任务悄悄卡住。测试还特别关注审批场景:比如子任务要执行危险命令,系统应该先发出风险评估;如果用户或守护审查取消了,应该返回拒绝,而不是继续放行。它还验证不同编号的用途没有混淆:工具调用编号、审批回调编号、权限请求编号都必须各走各的路。整体上,这个文件像一套演练剧本,用假会话和假事件把容易出错的极端情况提前跑一遍。

函数细节7
forward_events_cancelled_while_send_blocked_shuts_down_delegate37–112 ↗
async fn forward_events_cancelled_while_send_blocked_shuts_down_delegate()

作用:这个测试确认:当事件转发任务正因为出口通道满了而卡住时,如果外部发出取消信号,它不会永远挂在那里。它应该给子任务发送“中断”和“关闭”指令,干净停下。

数据流:进去的是一个模拟好的 Codex 实例、一个已经被塞满的输出通道、一个输入事件通道,以及一个取消令牌。测试先让输出通道满掉,再往输入通道塞一个事件,让转发逻辑处在可能卡住的位置;随后关闭输入并触发取消。出来的结果是:转发任务能在超时前结束,原本塞在输出通道里的事件还在,同时提交通道里能看到 Interrupt 和 Shutdown 这两个停止用的操作。

调用关系:它直接启动被测的 forward_events,像真实运行时那样让它从 Codex 收事件、往外发事件。测试里通过 make_session_and_context_with_rx 搭出假会话,用 async_channel 的 bounded 通道制造“发送被堵住”的情况,再用 timeout 确认 forward_events 没有挂死。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 15 个(clone, new, new, new, new, new, assert!, assert_eq!, bounded, RawResponseItem (+5 more))。

forward_ops_preserves_submission_trace_context115–157 ↗
async fn forward_ops_preserves_submission_trace_context()

作用:这个测试确认:操作从外部转发进 Codex 时,追踪信息不会丢。追踪信息可以理解成一张快递单号,用来把一次请求在多个系统里的路径串起来。

数据流:进去的是一个带有 trace 字段的 Submission,也就是一条要交给 Codex 的操作请求。测试把它送进 forward_ops 的输入通道;forward_ops 把它转发到 Codex 的提交通道。出来后测试读到转发后的 Submission,并检查 id、op 和 trace 都和原来一样,没有被改掉或漏掉。

调用关系:它启动 forward_ops 来模拟真实的操作转发流程。make_session_and_context_with_rx 提供测试用会话,bounded 创建输入输出通道,spawn 让 forward_ops 在后台跑;最后用 timeout 等它转发完成并正常退出。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 9 个(clone, new, new, from_secs, assert_eq!, bounded, spawn, timeout, channel)。

run_codex_thread_interactive_respects_pre_cancelled_spawn160–183 ↗
async fn run_codex_thread_interactive_respects_pre_cancelled_spawn()

作用:这个测试确认:如果在启动委托子任务之前,取消信号已经被触发,系统应该立刻停止,而不是还傻傻地启动并等待。这样可以避免用户已经取消后后台仍然开新任务。

数据流:进去的是父会话、父上下文、认证和模型管理器,以及一个已经处于“已取消”状态的取消令牌。测试调用 run_codex_thread_interactive,要求它在很短时间内返回。出来的结果应该是错误 CodexErr::TurnAborted,意思是这轮任务被中止了。

调用关系:它测试 run_codex_thread_interactive 这个启动交互式子 Codex 的入口行为。make_session_and_context_with_rx 先造出父会话环境,timeout 保证如果函数错误地卡住,测试会失败。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 5 个(clone, new, from_secs, assert!, timeout)。

handle_request_permissions_uses_tool_call_id_for_round_trip186–282 ↗
async fn handle_request_permissions_uses_tool_call_id_for_round_trip()

作用:这个测试确认:子任务申请权限时,系统会用同一个工具调用编号把问题发给父任务,再把父任务的回答送回子任务。这个编号像取餐号,错了就会把别人的答案送给错误的请求。

数据流:进去的是一个 RequestPermissionsEvent,里面有 call_id、环境编号、工作目录和想申请的网络权限。测试让 handle_request_permissions 把这个申请发到父会话事件流里,然后模拟父会话针对同一个 call_id 给出允许网络权限的回答。出来的结果是子任务提交通道收到 Op::RequestPermissionsResponse,并且里面的 id 正是原来的 call_id,response 也和父任务给的一样。

调用关系:它直接测试 handle_request_permissions 这段桥接逻辑:一边连接子 Codex 的提交通道,另一边连接父 session 的事件和响应等待机制。make_session_and_context_with_rx 准备父会话,notify_request_permissions_response 模拟父侧回复,timeout 用来防止等待响应时卡死。

调用图:调用 2 个内部函数(make_session_and_context_with_rx, default);外部调用 12 个(clone, get_mut, new, new, from_secs, default, assert_eq!, bounded, panic!, spawn (+2 more))。

handle_exec_approval_uses_call_id_for_guardian_review_and_approval_id_for_reply285–395 ↗
async fn handle_exec_approval_uses_call_id_for_guardian_review_and_approval_id_for_reply()

作用:这个测试确认:子任务请求执行命令审批时,风险评估用的是命令本身的 call_id,而回给子任务审批结果时用的是 approval_id。两种编号用途不同,混用会导致审查记录和回调响应对不上。

数据流:进去的是一个执行审批请求,命令是 rm -rf tmp,并带有 call_id 和 approval_id。测试先把父上下文设置成需要自动审查,然后运行 handle_exec_approval。它应该先向父事件流发出 GuardianAssessment,也就是守护审查事件,目标编号指向 call_id;随后测试取消令牌,模拟审查被打断。出来的结果是子任务提交通道收到 Op::ExecApproval,id 使用 approval_id,决定是 Abort,也就是不允许继续。

调用关系:它覆盖 handle_exec_approval 在自动审查模式下的关键路径。测试用 make_session_and_context_with_rx 建立父会话,用配置把 approvals_reviewer 设置成 AutoReview,再监听父事件流中的 GuardianAssessment,最后确认 handle_exec_approval 把取消结果转成给子任务的审批回复。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 14 个(clone, new, try_unwrap, new, from_secs, new, assert!, assert_eq!, bounded, test_path_buf (+4 more))。

delegated_mcp_guardian_abort_returns_synthetic_decline_answer398–454 ↗
async fn delegated_mcp_guardian_abort_returns_synthetic_decline_answer()

作用:这个测试确认:委托子任务请求批准 MCP 工具调用时,如果守护审查已经被取消,系统会自动生成一个“拒绝”的回答。MCP 可以理解成让模型调用外部工具的一套接口,危险工具不能在取消后被默认放行。

数据流:进去的是父会话、父上下文、一个记录待处理 MCP 调用的表、一条用户输入请求事件,以及一个已经取消的取消令牌。待处理表里说明 call-1 对应 custom_server 上的 dangerous_tool;请求事件里有一个工具审批问题。函数 maybe_auto_review_mcp_request_user_input 处理后,出来的是 Some(RequestUserInputResponse),里面对对应问题填入合成的拒绝答案 MCP_TOOL_APPROVAL_DECLINE_SYNTHETIC。

调用关系:它测试 maybe_auto_review_mcp_request_user_input 在自动审查且已取消时的安全兜底行为。测试先把父上下文调成 AutoReview 和 OnRequest,再准备 pending_mcp_invocations 这张“调用编号到工具信息”的表,最后确认函数没有等待人工输入,而是直接返回拒绝。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 7 个(new, try_unwrap, new, from, new, assert_eq!, vec!)。

delegated_mcp_user_reviewer_returns_none_without_metadata457–492 ↗
async fn delegated_mcp_user_reviewer_returns_none_without_metadata()

作用:这个测试确认:当 MCP 工具调用缺少足够的审查元数据时,如果当前不是可自动处理的守护审查场景,函数不会瞎编一个答案。它返回 None,表示这件事还需要走正常的用户输入或其他流程。

数据流:进去的是父会话、父上下文、待处理 MCP 调用表、一个工具审批问题事件,以及未取消的取消令牌。待处理表里有 call-1,对应 Codex apps MCP 服务器上的 dangerous_tool,但没有额外参数或元数据。maybe_auto_review_mcp_request_user_input 检查后不生成审批回答。出来的结果是 None,表示没有自动回答。

调用关系:它同样测试 maybe_auto_review_mcp_request_user_input,但走的是“不应自动决定”的分支。测试通过 pending_mcp_invocations 提供最少的工具调用信息,再用 assert_eq 确认函数没有越权替用户做决定。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 6 个(new, new, from, new, assert_eq!, vec!)。

core/src/thread_manager_tests.rs源码 ↗
test测试运行时,通常在开发或 CI 自动测试阶段活跃

ThreadManager 可以理解成一个聊天会话的调度员:它会开新线程、从历史记录恢复线程、把旧线程分叉成新线程,也会统一关停线程。这个测试文件就是给这个调度员做体检。它先用 user_msg、assistant_msg 这类小工具造出假的对话记录,再检查“截断历史”“处理中断”“恢复 rollout 历史文件”等行为是否符合预期。这里的 rollout 可以理解成会话流水账,记录一段对话发生过什么。文件还测试内部线程不会出现在普通查询里、扩展插件能拿到线程初始化数据、模型列表刷新会用当前配置的服务地址等。很多测试都在临时目录里搭一个干净环境,避免污染真实用户数据。

函数细节28
user_msg37–47 ↗
fn user_msg(text: &str) -> ResponseItem

作用:造一个“用户说了一句话”的假消息,方便测试里快速拼出聊天历史。这样每个测试不用反复写一大段消息结构。

数据流:输入是一段文字 → 它把文字放进 ResponseItem::Message 这种消息对象里,并把角色标成 user → 输出一个可以塞进历史记录的用户消息;它不改动外部状态。

调用关系:它是测试的积木块。像 truncates_before_requested_user_message 和 ignores_session_prefix_messages_when_truncating 这类测试会用它先造历史,再把历史交给被测的截断逻辑检查结果。

调用图:被 2 处调用(ignores_session_prefix_messages_when_truncating, truncates_before_requested_user_message);外部调用 1 个(vec!)。

assistant_msg48–58 ↗
fn assistant_msg(text: &str) -> ResponseItem

作用:造一个“助手回复了一句话”的假消息,和 user_msg 配套使用。测试需要模拟一来一回的对话时会用它。

数据流:输入是一段文字 → 它把文字包装成 ResponseItem::Message,并把角色标成 assistant → 输出一个助手消息对象;不会读写文件或启动线程。

调用关系:它也是测试历史的积木块。truncates_before_requested_user_message 和 ignores_session_prefix_messages_when_truncating 会用它和用户消息一起搭出对话片段,再验证 ThreadManager 的历史处理是否正确。

调用图:被 2 处调用(ignores_session_prefix_messages_when_truncating, truncates_before_requested_user_message);外部调用 1 个(vec!)。

contextual_user_interrupted_marker60–63 ↗
fn contextual_user_interrupted_marker() -> ResponseItem

作用:生成一个“用户上下文导致中断”的历史标记。它用来告诉后续恢复或分叉逻辑:这段对话不是自然结束,而是被打断了。

数据流:没有外部输入 → 它调用 interrupted_turn_history_marker,并指定中断标记类型是 ContextualUser → 输出一个 ResponseItem;如果这个标记功能没启用,测试会直接失败。

调用关系:它把具体造标记的工作交给 interrupted_turn_history_marker。interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_history 和 interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_source 会用它确认分叉后的历史里确实写入了中断边界。

调用图:调用 1 个内部函数(interrupted_turn_history_marker);被 2 处调用(interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_history, interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_source)。

developer_interrupted_marker65–68 ↗
fn developer_interrupted_marker() -> ResponseItem

作用:生成一个“开发者指令形式”的中断标记。它主要用于检查多智能体新版流程里,中断提示是不是写成开发者消息。

数据流:没有外部输入 → 它调用 interrupted_turn_history_marker,并指定类型是 Developer → 输出一个中断用的 ResponseItem;生成失败时测试会报错。

调用关系:它是 multi_agent_v2_interrupted_marker_uses_developer_input_message 的准备步骤。真正的标记内容由 interrupted_turn_history_marker 生成,这个函数只负责选对标记种类。

调用图:调用 1 个内部函数(interrupted_turn_history_marker);被 1 处调用(multi_agent_v2_interrupted_marker_uses_developer_input_message)。

truncates_before_requested_user_message71–141 ↗
fn truncates_before_requested_user_message()

作用:检查“从某个用户消息之前截断历史”这件事是否准确。这个能力用于分叉旧对话时,只保留想要的前半段历史。

数据流:先造出用户消息、助手消息、推理记录、工具调用等一串历史 → 调用 truncate_before_nth_user_message,让它按第几个用户消息来截断 → 最后把结果转成 JSON 比较,确认只留下该留下的项目。

调用关系:这是测试入口,由 Rust 测试框架运行。它用 user_msg 和 assistant_msg 搭历史,然后把历史交给 truncate_before_nth_user_message,最后用断言检查输出。

调用图:调用 2 个内部函数(assistant_msg, user_msg);外部调用 3 个(assert_eq!, Forked, vec!)。

out_of_range_truncation_drops_only_unfinished_suffix_mid_turn144–166 ↗
fn out_of_range_truncation_drops_only_unfinished_suffix_mid_turn()

作用:检查当要求截断的位置超出范围时,如果历史停在半个回合中间,只丢掉未完成的尾巴。这样不会把已经完成的对话也误删。

数据流:输入是一段包含两个用户回合、最后助手回复未完成的历史 → 调用 truncate_before_nth_user_message,并传入一个很大的编号 → 输出应只保留第一个完整回合,未完成的第二回合被丢掉。

调用关系:测试框架直接运行它。它重点验证 truncate_before_nth_user_message 对“编号太大”和“半截回合”同时出现时的保守处理。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

fork_thread_accepts_legacy_usize_snapshot_argument169–185 ↗
fn fork_thread_accepts_legacy_usize_snapshot_argument()

作用:检查旧代码仍然可以用 usize 这种数字参数调用 fork_thread。它是兼容性测试,防止接口升级后老调用点突然编译不过。

数据流:它定义一个小函数,里面用 usize::MAX 调用 manager.fork_thread → 再把这个小函数赋给一个明确的函数类型 → 如果类型不匹配,编译阶段就会失败;运行时基本不做实际工作。

调用关系:这是一个偏“编译期保险”的测试。它不真正等待 fork_thread 完成,只确认 ThreadManager::fork_thread 仍接受旧式快照参数。

out_of_range_truncation_drops_pre_user_active_turn_prefix188–223 ↗
fn out_of_range_truncation_drops_pre_user_active_turn_prefix()

作用:检查如果当前活动回合从 TurnStarted 事件开始,但后面还没完成,截断时会把整个未完成回合都删掉。这样历史不会留下一个孤零零的“回合开始”事件。

数据流:输入是一段含 TurnStarted、用户消息和未完成助手回复的历史 → 先用 snapshot_turn_state 判断它确实停在半截回合 → 再调用 truncate_before_nth_user_message → 输出只剩前一个完整回合。

调用关系:测试框架运行它。它把 snapshot_turn_state 和 truncate_before_nth_user_message 串起来,验证两者对活动回合起点的理解是一致的。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

ignores_session_prefix_messages_when_truncating226–262 ↗
async fn ignores_session_prefix_messages_when_truncating()

作用:检查截断历史时不会把系统自动塞进去的会话前缀消息算成用户真正说的话。否则按“第几个用户消息”截断时会截错位置。

数据流:先通过 make_session_and_context 建一个测试会话 → 读取会话自动生成的初始上下文,再追加真实用户和助手消息 → 调用 truncate_before_nth_user_message → 输出应保留会话前缀和第一轮真实对话。

调用关系:这是异步测试,由测试框架在 Tokio 运行时里执行。它依赖 make_session_and_context 搭出真实一点的会话环境,再用 user_msg、assistant_msg 补充测试数据。

调用图:调用 3 个内部函数(make_session_and_context, assistant_msg, user_msg);外部调用 3 个(assert_eq!, Forked, vec!)。

shutdown_all_threads_bounded_submits_shutdown_to_every_thread265–299 ↗
async fn shutdown_all_threads_bounded_submits_shutdown_to_every_thread()

作用:检查“限时关闭所有线程”会把关闭请求发给每一个线程,并且关闭后管理器里不再列出它们。它防止程序退出时残留后台任务。

数据流:先创建临时配置和 ThreadManager → 启动两个线程 → 调用 shutdown_all_threads_bounded,并给一个 10 秒上限 → 输出的报告应显示两个线程都完成关闭,没有提交失败、没有超时,管理器列表为空。

调用关系:测试框架运行它。它先用 test_config 和测试版 ThreadManager 搭环境,再调用 start_thread 和 shutdown_all_threads_bounded 来检验完整生命周期。

调用图:调用 4 个内部函数(test_config, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 7 个(new, from_secs, assert!, assert_eq!, create_dir_all, tempdir, vec!)。

start_thread_keeps_internal_threads_hidden_from_normal_lookups302–342 ↗
async fn start_thread_keeps_internal_threads_hidden_from_normal_lookups()

作用:检查内部用途的线程不会被普通用户查询到。比如后台做记忆整理的线程,不应该出现在用户可见的线程列表里。

数据流:先创建测试管理器 → 用 StartThreadOptions 启动一个 session_source 为 Internal 的线程 → 调用 list_thread_ids 和 get_thread → 结果应显示普通列表查不到它;最后统一关闭时仍能关闭这个内部线程。

调用关系:这是 ThreadManager 可见性规则的测试。它通过 start_thread_with_options 创建内部线程,再用普通查询和全量关闭两个入口分别确认“隐藏但可管理”。

调用图:调用 4 个内部函数(test_config, with_models_provider_and_home_for_tests, default_for_tests, from_api_key);外部调用 9 个(new, default, from_secs, new, Internal, assert!, assert_eq!, create_dir_all, tempdir)。

start_thread_seeds_extension_data_for_mcp_and_lifecycle_contributors345–524 ↗
async fn start_thread_seeds_extension_data_for_mcp_and_lifecycle_contributors()

作用:检查启动线程时,传给扩展系统的初始化数据能被生命周期扩展和 MCP 扩展同时看到。MCP 可以理解成外部工具服务器配置,这里要确保每个线程拿到自己的插件选择。

数据流:先定义一个记录器扩展,用互斥锁(一把锁,防止两个任务同时改同一份列表)保存它看到的数据 → 启动两个线程,分别传入不同 SelectedCapabilityRoot → 再解析每个线程的 MCP 配置 → 输出应证明两个线程的数据互不串线。

调用关系:这个测试把 ThreadManager::new、扩展注册表、start_thread_with_options 和 runtime_mcp_config 串起来。记录器扩展在 on_thread_start 和 contribute 两个时机被调用,用来证明初始化数据一路传通。

调用图:调用 6 个内部函数(test_config, new, default_for_tests, new, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 7 个(clone, new, new, assert_eq!, create_dir_all, new, tempdir)。

resume_and_fork_do_not_restore_thread_environments_from_rollout527–642 ↗
async fn resume_and_fork_do_not_restore_thread_environments_from_rollout()

作用:检查从历史恢复或分叉线程时,不会把旧历史里记录的工作目录环境直接恢复回来。这样用户当前配置不会被旧会话偷偷覆盖。

数据流:先在一个 selected 目录启动源线程,并把它的 rollout 写到磁盘 → 关闭源线程 → 用默认配置从这个 rollout 恢复和分叉 → 新建回合后检查环境 cwd,结果应是当前默认目录,而不是旧的 selected 目录。

调用关系:它覆盖 resume_thread_from_rollout 和 fork_thread 两条路径。测试先制造一份带环境选择的旧历史,再确认恢复和分叉都重新按当前配置创建环境。

调用图:调用 6 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing, try_from);外部调用 10 个(new, default, new, assert_eq!, assert_ne!, empty_extension_registry, default, create_dir_all, tempdir, vec!)。

explicit_installation_id_skips_codex_home_file645–685 ↗
async fn explicit_installation_id_skips_codex_home_file()

作用:检查如果 ThreadManager 已经拿到了明确的安装 ID,就不会再去 codex_home 目录里创建安装 ID 文件。这样测试或嵌入场景可以完全控制这个身份值。

数据流:先生成一个随机 installation_id,并创建带状态数据库的 ThreadManager → 启动线程 → 检查 codex_home 下没有安装 ID 文件,同时线程会话里的 installation_id 等于传入值 → 最后关闭并移除线程。

调用关系:它测试 ThreadManager::new 和 start_thread 之间关于安装身份的传递。init_state_db 和 thread_store_from_config 提供测试用状态存储。

调用图:调用 5 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 8 个(new, assert!, assert_eq!, empty_extension_registry, init_state_db, create_dir_all, tempdir, new_v4)。

resume_active_thread_from_rollout_returns_running_thread688–743 ↗
async fn resume_active_thread_from_rollout_returns_running_thread()

作用:检查如果要从 rollout 恢复的线程其实还在运行,管理器会直接返回这个正在运行的线程,而不是再开一个副本。这样避免同一个会话同时有两个活实例。

数据流:先启动源线程并把 rollout 落盘 → 不关闭它,直接调用 resume_thread_from_rollout → 输出的线程 ID 应相同,内部 Arc 指针也应指向同一个线程对象 → 最后关闭源线程。

调用关系:它验证 resume_thread_from_rollout 的去重逻辑。这个测试通过 Arc::ptr_eq 确认返回的不是新对象,而是管理器已有的活线程。

调用图:调用 5 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 6 个(new, assert!, assert_eq!, empty_extension_registry, create_dir_all, tempdir)。

resume_stopped_thread_from_rollout_spawns_new_thread746–806 ↗
async fn resume_stopped_thread_from_rollout_spawns_new_thread()

作用:检查如果源线程已经停了,再从 rollout 恢复时会创建一个新的线程对象,但沿用原来的线程 ID。这样会话身份不变,运行实例是新的。

数据流:先启动源线程、写出 rollout,然后关闭它 → 调用 resume_thread_from_rollout → 输出的线程 ID 和原来一样,但 Arc 指针不同 → 最后关闭恢复出来的新线程。

调用关系:它和 resume_active_thread_from_rollout_returns_running_thread 是一组对照测试。一个看“活线程直接复用”,一个看“停线程重新生成”。

调用图:调用 5 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 6 个(new, assert!, assert_eq!, empty_extension_registry, create_dir_all, tempdir)。

resume_stopped_thread_from_rollout_preserves_thread_source809–890 ↗
async fn resume_stopped_thread_from_rollout_preserves_thread_source()

作用:检查停止后的线程从 rollout 恢复时,会保留原来的 thread_source。thread_source 可以理解成线程来源标记,比如是不是用户发起的。

数据流:先用 thread_source 为 User 的选项启动线程 → 写出 rollout、关闭并从管理器移除 → 再从 rollout 恢复 → 读取恢复线程的配置快照,结果应仍然是 ThreadSource::User。

调用关系:它测试 start_thread_with_options 写入的来源信息,能不能通过持久化历史一路传到 resume_thread_from_rollout。状态数据库和 thread_store 用来保存这类元信息。

调用图:调用 5 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 8 个(new, default, new, assert_eq!, empty_extension_registry, init_state_db, create_dir_all, tempdir)。

rollout_path_resume_and_fork_read_history_through_thread_store893–996 ↗
async fn rollout_path_resume_and_fork_read_history_through_thread_store()

作用:检查通过 rollout 路径恢复或分叉时,历史读取会走 ThreadStore,而不是绕开存储层直接读文件。ThreadStore 可以理解成统一的会话仓库接口。

数据流:先把配置改成内存 ThreadStore,并拿到它的调用计数器 → 创建一个带 rollout_path 的恢复历史,写入仓库 → 再分别用 resume_thread_from_rollout 和 fork_thread 读取同一路径 → 最后检查 read_thread_by_rollout_path 被调用了两次。

调用关系:这个测试专门看 ThreadManager 与 ThreadStore 的协作边界。resume_thread_from_rollout 和 fork_thread 都应把按路径查历史的活交给 ThreadStore。

调用图:调用 5 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 10 个(new, assert_eq!, assert_ne!, empty_extension_registry, init_state_db, format!, Resumed, create_dir_all, tempdir, vec!)。

new_uses_active_provider_for_model_refresh999–1029 ↗
async fn new_uses_active_provider_for_model_refresh()

作用:检查 ThreadManager 创建后刷新模型列表时,会使用当前配置里的模型服务地址。否则测试环境或自定义服务地址可能被忽略。

数据流:先启动一个假的 HTTP 服务器,并挂上一次 models 响应 → 把 config.model_provider.base_url 指向这个服务器 → 创建 ThreadManager 后调用 list_models 在线刷新 → 最后确认假的服务器确实收到一次请求。

调用关系:它把 ThreadManager::new 和模型管理器的刷新流程连起来测。mount_models_once 提供假接口,list_models 触发真实的网络请求路径。

调用图:调用 6 个内部函数(test_config, new, mount_models_once, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing);外部调用 7 个(new, start, assert_eq!, empty_extension_registry, create_dir_all, tempdir, vec!)。

interrupted_fork_snapshot_appends_interrupt_boundary1032–1079 ↗
fn interrupted_fork_snapshot_appends_interrupt_boundary()

作用:检查用“中断快照”分叉历史时,会在历史末尾补上中断标记和 TurnAborted 事件。这样新分叉知道上一段不是正常完成的。

数据流:输入是一段已有历史或空历史 → 调用 append_interrupted_boundary,并指定 ContextualUser 标记 → 输出历史应在末尾包含中断消息和“回合被中断”的事件。

调用关系:这是 append_interrupted_boundary 的直接单元测试。它不启动真实线程,只验证历史拼接规则是否正确。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

disabled_interrupted_fork_snapshot_appends_only_interrupt_event1082–1127 ↗
fn disabled_interrupted_fork_snapshot_appends_only_interrupt_event()

作用:检查当中断消息标记被禁用时,分叉历史只追加 TurnAborted 事件,不追加额外文本消息。这样配置关闭的行为不会偷偷写入提示内容。

数据流:输入是一段已有历史或空历史 → 调用 append_interrupted_boundary,并指定 InterruptedTurnHistoryMarker::Disabled → 输出历史只多出“中断事件”,没有中断说明消息。

调用关系:它和 interrupted_fork_snapshot_appends_interrupt_boundary 形成对照。两者共同确认 append_interrupted_boundary 会按标记配置选择不同输出。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

interrupted_snapshot_is_not_mid_turn1130–1151 ↗
fn interrupted_snapshot_is_not_mid_turn()

作用:检查已经写入中断边界的历史,不应再被判断成“停在半个回合中间”。否则再次恢复或分叉时可能重复补中断标记。

数据流:输入是一段用户消息、助手半截回复、中断标记和 TurnAborted 事件组成的历史 → 调用 snapshot_turn_state → 输出应表示 ends_mid_turn 为 false,且没有活动回合 ID。

调用关系:它直接测试 snapshot_turn_state 的判断。这个判断会影响后续 fork_thread 是否需要补中断边界。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

multi_agent_v2_interrupted_marker_uses_developer_input_message1154–1169 ↗
fn multi_agent_v2_interrupted_marker_uses_developer_input_message()

作用:检查新版多智能体中断标记使用 developer 角色和 InputText 内容。也就是说,这个提示是给系统/开发者层面的指导,不是普通用户发言。

数据流:先调用 developer_interrupted_marker 生成标记 → 拆开 ResponseItem 检查角色和内容类型 → 输出通过断言证明 role 是 developer,内容里包含预期的中断指导文字;如果不是消息类型就直接 panic。

调用关系:它依赖 developer_interrupted_marker 生成测试对象。这个测试保护 interrupted_turn_history_marker 在 Developer 模式下的消息格式不被改错。

调用图:调用 1 个内部函数(developer_interrupted_marker);外部调用 3 个(assert!, assert_eq!, panic!)。

completed_legacy_event_history_is_not_mid_turn1172–1197 ↗
fn completed_legacy_event_history_is_not_mid_turn()

作用:检查老格式事件历史里,如果有用户消息也有助手完成回复,就不应被认为是半截回合。这样旧数据不会被误判为中断。

数据流:输入是一段旧格式 UserMessage 事件加 AgentMessage 事件 → 调用 snapshot_turn_state → 输出应表示回合已完成,不在 mid-turn 状态。

调用关系:它测试 snapshot_turn_state 对 legacy event,也就是老事件格式的兼容。恢复旧会话时会依赖这个判断。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

mixed_response_and_legacy_user_event_history_is_mid_turn1200–1221 ↗
fn mixed_response_and_legacy_user_event_history_is_mid_turn()

作用:检查混合了新格式响应消息和老格式用户事件、但没有助手完成回复的历史,会被判断为半截回合。这样不完整历史能被正确识别。

数据流:输入是一段 ResponseItem 用户消息加 legacy UserMessage 事件 → 调用 snapshot_turn_state → 输出应表示 ends_mid_turn 为 true。

调用关系:它也是 snapshot_turn_state 的兼容性测试。它覆盖新旧格式混在一起时的边界情况。

调用图:外部调用 3 个(assert_eq!, Forked, vec!)。

interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_history1224–1328 ↗
async fn interrupted_fork_snapshot_does_not_synthesize_turn_id_for_legacy_history()

作用:检查从没有明确 turn_id 的旧历史做中断分叉时,不会凭空编一个 turn_id。这样历史记录不会出现伪造的回合编号。

数据流:先用一段旧式半截历史创建源线程并读回 rollout → 确认 snapshot_turn_state 认为它是半截回合但 active_turn_id 是 None → 调用 fork_thread 做中断分叉 → 读分叉后的历史,检查中断标记和 TurnAborted 事件各出现一次,且事件里的 turn_id 仍是 None。

调用关系:这个测试串起 resume_thread_with_history、RolloutRecorder::get_rollout_history、snapshot_turn_state 和 fork_thread。contextual_user_interrupted_marker 用来构造预期的中断标记。

调用图:调用 7 个内部函数(test_config, new, contextual_user_interrupted_marker, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing, get_rollout_history);外部调用 13 个(new, assert!, assert_eq!, empty_extension_registry, init_state_db, TurnAborted, Forked, EventMsg, ResponseItem, to_value (+3 more))。

interrupted_fork_snapshot_preserves_explicit_turn_id1331–1425 ↗
async fn interrupted_fork_snapshot_preserves_explicit_turn_id()

作用:检查如果源历史里明确写了 turn_id,中断分叉时会保留这个 ID。这样追踪工具和日志还能把中断事件对应回原来的回合。

数据流:先创建一段带 TurnStarted(turn-explicit) 的半截历史 → 写入并读回 rollout,确认 active_turn_id 是 turn-explicit → 调用 fork_thread 做中断分叉 → 读分叉历史,确认 TurnAborted 事件里仍然是这个 turn_id。

调用关系:它测试 fork_thread 在中断快照下如何使用 snapshot_turn_state 给出的活动回合 ID。RolloutRecorder 负责把分叉后的真实历史读出来供断言。

调用图:调用 6 个内部函数(test_config, new, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing, get_rollout_history);外部调用 9 个(new, assert!, assert_eq!, empty_extension_registry, init_state_db, Forked, create_dir_all, tempdir, vec!)。

interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_source1428–1562 ↗
async fn interrupted_fork_snapshot_uses_persisted_mid_turn_history_without_live_source()

作用:检查即使源线程已经不在管理器里,中断分叉也能根据持久化的 rollout 历史正确补中断边界。它保证恢复能力不依赖内存里的活线程。

数据流:先用半截历史创建源线程并写出 rollout → 从管理器移除源线程 → 用 rollout 路径做中断分叉 → 读新历史确认不再是半截回合,并且中断标记只出现一次;随后再对这个已中断历史重新分叉,确认不会重复追加中断标记和中断事件。

调用关系:它覆盖 fork_thread 在没有 live source,也就是没有活源线程时的路径。它会调用 RolloutRecorder::get_rollout_history 读持久化历史,并用 contextual_user_interrupted_marker 对比预期标记。

调用图:调用 7 个内部函数(test_config, new, contextual_user_interrupted_marker, default_for_tests, from_auth_for_testing, create_dummy_chatgpt_auth_for_testing, get_rollout_history);外部调用 11 个(new, assert!, assert_eq!, empty_extension_registry, init_state_db, Forked, ResponseItem, to_value, create_dir_all, tempdir (+1 more))。

策略和审批行为

这些文件锁定不同平台和审批模式下的执行策略、安全决策、guardian 审查行为、MCP 暴露和沙盒标签。

core/src/guardian/tests.rs源码 ↗
testtest run

Guardian 可以理解成“自动安全审查员”:主程序要做敏感动作前,先把上下文、动作内容和规则交给它判断。这个测试文件不负责线上功能本身,而是专门验证那套判断机器不会走偏。它会搭假会话、假模型服务器、假历史记录,再检查生成给 Guardian 的提示词、JSON 格式、模型选择、重试策略、错误上报、会话复用和配置隔离。比如,它确认 Guardian 不会把父会话里的记忆、插件、MCP 服务等危险或无关内容带进审查;也确认连续拒绝太多次会触发“断路器”,避免程序陷入无限申请。没有这些测试,审批系统很容易在边界情况里误放行、误拒绝,或把敏感上下文泄进审查请求。

函数细节73
fixed_guardian_parent_session_id81–84 ↗
fn fixed_guardian_parent_session_id() -> ThreadId

作用:提供一个固定的父会话编号,方便测试稳定地比较输出。会话编号是 UUID,一种常见的全局唯一字符串。

数据流:进去没有参数 → 它把写死的字符串解析成 ThreadId → 出来一个固定的父会话 ID;如果字符串不是合法 UUID,测试会直接失败。

调用关系:多个搭建 Guardian 测试会话的函数会用它,比如 guardian_test_session_and_turn_with_base_urlguardian_test_session_turn_and_rx,这样后面的提示词快照和断言不会因为随机 ID 变化而抖动。

调用图:调用 1 个内部函数(from_string);被 4 处调用(build_guardian_prompt_includes_parent_turn_denied_reads, guardian_review_request_layout_matches_model_visible_request_snapshot, guardian_test_session_and_turn_with_base_url, guardian_test_session_turn_and_rx)。

GuardianMemoryContextProbe::on_thread_start97–106 ↗
fn on_thread_start(
        &'a self,
        input: codex_extension_api::ThreadStartInput<'a, Config>,
    ) -> codex_extension_api::ExtensionFuture<'a, ()>

作用:在测试用的扩展启动线程时,记下当前配置里“记忆功能是否开启”。这是一个探针,用来确认 Guardian 审查会话不会错误继承父会话的记忆上下文。

数据流:进去的是线程启动输入,里面有配置和线程存储区 → 它读取 memories.use_memories,把布尔值塞进线程存储区 → 出来没有返回有意义的数据,但线程存储被写入了测试标记。

调用关系:它属于 GuardianMemoryContextProbe 这个测试扩展,在线程开始时由扩展框架调用;后续 GuardianMemoryContextProbe::contribute 会读取它写下的标记。

调用图:外部调用 1 个(pin)。

GuardianMemoryContextProbe::contribute110–127 ↗
fn contribute(
        &'a self,
        _session_store: &'a codex_extension_api::ExtensionData,
        thread_store: &'a codex_extension_api::ExtensionData,
    ) -> codex_extension_api::ExtensionFu

作用:根据前面记录的“记忆是否开启”,决定是否往提示词里加一段测试标记文字。测试借此检查 Guardian 请求里有没有不该出现的记忆内容。

数据流:进去的是会话存储和线程存储 → 它查看线程存储里的 GuardianMemoryContextEnabled → 如果为真就输出一个开发者策略片段,否则输出空列表。

调用关系:它由扩展框架在组装提示词时调用;guardian_review_request_layout_matches_model_visible_request_snapshot 会验证 Guardian 审查请求没有注入这段探针文字。

调用图:外部调用 3 个(pin, new, vec!)。

guardian_rejection_circuit_breaker_interrupts_after_three_consecutive_denials131–152 ↗
fn guardian_rejection_circuit_breaker_interrupts_after_three_consecutive_denials()

作用:测试“拒绝断路器”:同一轮里连续被 Guardian 拒绝三次后,系统应该中断当前轮次,别再继续申请。

数据流:进去是一个新断路器和多次拒绝记录 → 它连续记录同一 turn 的拒绝 → 前两次返回继续,第三次返回中断,第四次重新回到继续。

调用关系:这是直接测试 GuardianRejectionCircuitBreaker 的基础行为,给后面更复杂的自动审查流程提供安全底线。

调用图:外部调用 2 个(assert_eq!, default)。

guardian_rejection_circuit_breaker_resets_consecutive_denials_on_non_denial155–177 ↗
fn guardian_rejection_circuit_breaker_resets_consecutive_denials_on_non_denial()

作用:确认只要中间出现一次“不是拒绝”的结果,连续拒绝计数就会清零。这样系统不会把断开的拒绝误算成连续风险。

数据流:进去是一个新断路器 → 先记一次拒绝,再记一次非拒绝,再继续记拒绝 → 连续计数重算,但近期拒绝总数仍保留。

调用关系:它和连续三次拒绝测试一起覆盖断路器的计数规则,避免 Guardian 因旧状态误中断。

调用图:外部调用 2 个(assert_eq!, default)。

auto_review_rejection_circuit_breaker_interrupts_after_ten_recent_denials180–196 ↗
fn auto_review_rejection_circuit_breaker_interrupts_after_ten_recent_denials()

作用:测试另一条保护规则:即使拒绝不是连续的,最近累计拒绝达到十次也要中断。它防止程序绕过连续拒绝限制,反复尝试。

数据流:进去是新断路器 → 它反复记录“拒绝后接非拒绝”九次,再记录第十次拒绝 → 输出中断动作,并带上连续拒绝数和近期拒绝数。

调用关系:它直接检验 Guardian 自动审查的“近期失败太多就停手”逻辑。

调用图:外部调用 2 个(assert_eq!, default)。

auto_review_rejection_circuit_breaker_forgets_denials_outside_recent_review_window199–215 ↗
fn auto_review_rejection_circuit_breaker_forgets_denials_outside_recent_review_window()

作用:确认断路器只看最近一段窗口里的拒绝,不会永远记仇。旧拒绝过了窗口后,不应继续触发中断。

数据流:进去是新断路器 → 先制造九次近期拒绝,再加入很多非拒绝把旧记录挤出窗口,最后再拒绝一次 → 输出继续,而不是中断。

调用关系:它补齐断路器窗口机制的测试,防止历史太久的失败影响当前正常操作。

调用图:外部调用 2 个(assert_eq!, default)。

guardian_test_session_and_turn217–221 ↗
async fn guardian_test_session_and_turn(
    server: &wiremock::MockServer,
) -> (Arc<Session>, Arc<TurnContext>)

作用:快速创建一套指向假模型服务器的 Guardian 测试会话和当前轮次。很多网络相关测试都用它省去重复搭环境。

数据流:进去是假服务器 → 取服务器地址 → 调用 guardian_test_session_and_turn_with_base_url → 出来父会话和 turn 上下文。

调用关系:它是常用测试夹具;模型选择、重试、会话复用等测试都会先通过它得到可控的会话环境。

调用图:调用 1 个内部函数(guardian_test_session_and_turn_with_base_url);被 7 处调用(guardian_request_model_for_auto_review, guardian_reused_trunk_ignores_stale_prior_turn_completion, guardian_reuses_prompt_cache_key_and_appends_prior_reviews, guardian_review_does_not_retry_missing_assessment_payload, guardian_review_does_not_retry_valid_denial, guardian_review_retries_transient_session_failure_then_approves, guardian_review_retries_two_parse_failures_then_approves);外部调用 1 个(uri)。

guardian_test_session_turn_and_rx223–254 ↗
async fn guardian_test_session_turn_and_rx(
    server: &wiremock::MockServer,
) -> (
    Arc<Session>,
    Arc<TurnContext>,
    async_channel::Receiver<Event>,
)

作用:创建测试会话、当前轮次,并额外返回事件接收器。事件接收器可以理解成“消息收件箱”,测试用它检查 Guardian 发出了哪些状态事件。

数据流:进去是假服务器 → 创建带事件通道的会话 → 固定父会话 ID,改模型服务地址,替换模型管理器和 provider → 出来 session、turn 和事件接收器。

调用关系guardian_review_exhausts_three_failures_with_one_terminal_event 用它观察失败重试后只发出一次终态事件。

调用图:调用 3 个内部函数(fixed_guardian_parent_session_id, make_session_and_context_with_rx, models_manager_with_provider);被 1 处调用(guardian_review_exhausts_three_failures_with_one_terminal_event);外部调用 5 个(clone, get_mut, new, create_model_provider, format!)。

guardian_shell_request256–265 ↗
fn guardian_shell_request(id: &str) -> GuardianApprovalRequest

作用:生成一个标准的“执行 git push 命令”的 Guardian 审批请求。它是多个测试共用的样板危险动作。

数据流:进去是请求 ID → 组装命令、工作目录、沙箱权限和理由 → 出来一个 Shell 类型的 GuardianApprovalRequest

调用关系:多个重试和拒绝测试调用它,避免每个测试都重复手写同样的 shell 请求。

调用图:被 5 处调用(guardian_review_does_not_retry_missing_assessment_payload, guardian_review_does_not_retry_valid_denial, guardian_review_exhausts_three_failures_with_one_terminal_event, guardian_review_retries_transient_session_failure_then_approves, guardian_review_retries_two_parse_failures_then_approves);外部调用 2 个(test_path_buf, vec!)。

guardian_test_session_and_turn_with_base_url267–286 ↗
async fn guardian_test_session_and_turn_with_base_url(
    base_url: &str,
) -> (Arc<Session>, Arc<TurnContext>)

作用:用指定的模型服务地址创建 Guardian 测试会话和 turn。它让测试可以把真实模型调用改到本地假服务器。

数据流:进去是 base URL 字符串 → 创建普通测试会话,固定线程 ID,把模型 provider 的地址改成该 URL 下的 /v1,重建模型管理器和 provider → 出来共享引用包装的 session 和 turn。

调用关系guardian_test_session_and_turn 会转调它;构建提示词的多项测试也直接用它准备环境。

调用图:调用 3 个内部函数(fixed_guardian_parent_session_id, make_session_and_context, models_manager_with_provider);被 7 处调用(build_guardian_prompt_delta_mode_handles_empty_delta, build_guardian_prompt_delta_mode_preserves_original_numbering, build_guardian_prompt_full_mode_preserves_initial_review_format, build_guardian_prompt_items_explains_network_access_review_scope, build_guardian_prompt_stale_delta_cursor_falls_back_to_full_prompt, build_guardian_prompt_stale_delta_version_falls_back_to_full_prompt, guardian_test_session_and_turn);外部调用 4 个(clone, new, create_model_provider, format!)。

seed_guardian_parent_history288–331 ↗
async fn seed_guardian_parent_history(session: &Arc<Session>, turn: &Arc<TurnContext>)

作用:往父会话里塞一段固定历史:用户请求、工具查询、工具结果、助手说明。这样 Guardian 审查提示词有真实上下文可用。

数据流:进去是 session 和 turn → 写入四条对话/工具记录 → 出来没有直接返回,但会话历史变成测试所需状态。

调用关系:大量提示词、模型请求、重试测试都会先调用它;后续 Guardian 构造审查请求时会读取这些父会话历史。

调用图:调用 1 个内部函数(from_text);被 16 处调用(build_guardian_prompt_delta_mode_handles_empty_delta, build_guardian_prompt_delta_mode_preserves_original_numbering, build_guardian_prompt_full_mode_preserves_initial_review_format, build_guardian_prompt_includes_parent_turn_denied_reads, build_guardian_prompt_items_explains_network_access_review_scope, build_guardian_prompt_stale_delta_cursor_falls_back_to_full_prompt, build_guardian_prompt_stale_delta_version_falls_back_to_full_prompt, guardian_request_model_for_auto_review, guardian_reuses_prompt_cache_key_and_appends_prior_reviews, guardian_review_does_not_retry_missing_assessment_payload (+6 more));外部调用 1 个(vec!)。

rollout_item_contains_message_text333–338 ↗
fn rollout_item_contains_message_text(item: &RolloutItem, needle: &str) -> bool

作用:检查一个 rollout 记录里是否包含某段消息文字。rollout 可以理解成会话保存下来的历史条目。

数据流:进去是 rollout 条目和要找的字符串 → 如果条目不是响应项就返回 false,否则交给 response_item_contains_message_text 查内容 → 出来布尔值。

调用关系guardian_reuses_prompt_cache_key_and_appends_prior_reviews 用它确认跟进提醒确实被保存进 Guardian 分支历史。

调用图:调用 1 个内部函数(response_item_contains_message_text)。

response_item_contains_message_text340–348 ↗
fn response_item_contains_message_text(item: &ResponseItem, needle: &str) -> bool

作用:检查一条模型响应项是不是消息,并且消息文本里是否包含指定片段。

数据流:进去是响应项和搜索词 → 只处理 Message 类型,遍历输入文本和输出文本 → 出来是否命中;图片内容会被忽略。

调用关系:它是 rollout_item_contains_message_text 的底层小工具,专门帮测试查历史文本。

调用图:被 1 处调用(rollout_item_contains_message_text)。

guardian_snapshot_options350–354 ↗
fn guardian_snapshot_options() -> ContextSnapshotOptions

作用:生成 Guardian 快照测试用的格式选项。快照测试就是把一次请求的文本保存下来,以后对比有没有意外变化。

数据流:进去没有参数 → 从默认选项开始,去掉能力说明和 AGENTS.md 用户上下文等噪声 → 出来一份快照格式配置。

调用关系:请求布局快照测试会用它,让快照只关注 Guardian 真正重要的请求内容。

调用图:调用 1 个内部函数(default)。

normalize_guardian_snapshot_paths356–373 ↗
fn normalize_guardian_snapshot_paths(text: String) -> String

作用:把不同操作系统上的路径格式统一成固定写法,避免 Windows、macOS、Linux 的路径差异让快照测试失败。

数据流:进去是一段快照文本 → 把平台路径和 JSON 转义后的平台路径都替换成 /repo/... 这类标准路径 → 出来标准化后的文本。

调用关系:多个快照断言在保存或比较前调用它,保证测试关注内容变化,而不是路径分隔符变化。

调用图:外部调用 2 个(test_path_buf, to_string)。

guardian_prompt_text375–383 ↗
fn guardian_prompt_text(items: &[codex_protocol::user_input::UserInput]) -> String

作用:从 Guardian 提示词输入项里抽出所有纯文本,拼成一个字符串,方便测试查里面有没有某句话。

数据流:进去是一组用户输入项 → 只取 Text 项的 text,忽略图片等其他类型 → 出来拼接后的大文本。

调用关系:构建 Guardian prompt 的多项测试都用它做断言,比如检查全量模式、增量模式、网络审查说明等。

调用图:被 7 处调用(build_guardian_prompt_delta_mode_handles_empty_delta, build_guardian_prompt_delta_mode_preserves_original_numbering, build_guardian_prompt_full_mode_preserves_initial_review_format, build_guardian_prompt_includes_parent_turn_denied_reads, build_guardian_prompt_items_explains_network_access_review_scope, build_guardian_prompt_stale_delta_cursor_falls_back_to_full_prompt, build_guardian_prompt_stale_delta_version_falls_back_to_full_prompt);外部调用 1 个(iter)。

last_user_message_text_from_body385–398 ↗
fn last_user_message_text_from_body(body: &serde_json::Value) -> String

作用:从发送给模型的 JSON 请求体里找最后一条用户消息文本。它用于确认跟进审查请求里放了正确的增量上下文。

数据流:进去是 JSON 请求体 → 找 input 数组里最后一个 role 为 user 的内容,取其中所有 input_text 片段并拼接 → 出来最后用户消息文本。

调用关系guardian_ephemeral_retry_preserves_parallel_trunk_and_fork_history 用它检查并行分支的 Guardian 请求只带该带的 transcript delta。

build_guardian_transcript_keeps_original_numbering401–427 ↗
fn build_guardian_transcript_keeps_original_numbering()

作用:确认渲染对话记录时编号不会因为截取前几条而乱掉。编号稳定能帮助 Guardian 准确引用上下文。

数据流:进去是三条对话条目,但只渲染前两条 → 渲染函数输出带 [1][2] 的文本 → 测试确认没有遗漏提示。

调用关系:它直接测试 render_guardian_transcript_entries 的基本输出格式。

调用图:外部调用 2 个(assert!, assert_eq!)。

build_guardian_prompt_full_mode_preserves_initial_review_format430–458 ↗
async fn build_guardian_prompt_full_mode_preserves_initial_review_format() -> anyhow::Result<()>

作用:测试第一次完整审查时,Guardian 提示词仍是全量格式,而不是增量格式。

数据流:进去是带固定历史的会话和一个 git push 请求 → 构建 Full 模式提示词 → 出来文本应包含完整 transcript 起止标记、动作说明,并记录 4 条 transcript 游标。

调用关系:它使用 guardian_test_session_and_turn_with_base_urlseed_guardian_parent_historyguardian_prompt_text,验证提示词生成主流程。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, assert_eq!, test_path_buf, vec!)。

build_guardian_prompt_includes_parent_turn_denied_reads461–516 ↗
async fn build_guardian_prompt_includes_parent_turn_denied_reads() -> anyhow::Result<()>

作用:确认如果父 turn 的权限明确拒绝读取某些路径,Guardian 审查提示词会提醒不要批准为了读这些路径的升级请求。

数据流:进去是带拒绝路径规则的 turn、父历史和一个 cat 私密文件请求 → 构建 Full 模式提示词 → 出来文本包含父 turn 权限上下文、拒绝路径和 glob 规则。

调用关系:它手动搭权限配置并调用提示词构建函数,确保父会话的文件沙箱规则会传达给 Guardian。

调用图:调用 6 个内部函数(fixed_guardian_parent_session_id, guardian_prompt_text, seed_guardian_parent_history, make_session_and_context, from_runtime_permissions, restricted);外部调用 4 个(new, assert!, test_path_buf, vec!)。

build_guardian_prompt_delta_mode_preserves_original_numbering519–579 ↗
async fn build_guardian_prompt_delta_mode_preserves_original_numbering() -> anyhow::Result<()>

作用:测试跟进审查的增量模式只展示新增对话,但编号仍沿用原始完整历史编号。

数据流:进去是已有 4 条历史后又追加 2 条新消息的会话,以及游标指向前 4 条 → 构建 Delta 模式提示词 → 出来只包含 [5][6],不包含旧的 [1] 内容。

调用关系:它验证 Guardian 会话复用时的提示词瘦身逻辑,依赖测试会话和历史播种工具。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, assert_eq!, test_path_buf, vec!)。

build_guardian_prompt_delta_mode_handles_empty_delta582–613 ↗
async fn build_guardian_prompt_delta_mode_handles_empty_delta() -> anyhow::Result<()>

作用:确认增量模式下如果没有新增对话,也会明确告诉 Guardian 没有保留的新增条目,而不是生成空白含糊内容。

数据流:进去是已有 4 条历史且游标也指向 4 条的会话 → 构建 Delta 提示词 → 出来包含 <no retained transcript delta entries>,游标仍为 4。

调用关系:它覆盖跟进审查中“没有新上下文”的边界情况。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, assert_eq!, test_path_buf, vec!)。

build_guardian_prompt_stale_delta_cursor_falls_back_to_full_prompt616–648 ↗
async fn build_guardian_prompt_stale_delta_cursor_falls_back_to_full_prompt() -> anyhow::Result<()>

作用:测试如果增量游标里的条目数量不可信,比如超过当前历史长度,系统会退回完整提示词。

数据流:进去是只有 4 条历史但游标说已有 99 条的会话 → 构建提示词 → 出来是 Full 格式,不包含 Delta 标记,游标修正为 4。

调用关系:它确保游标异常不会让 Guardian 漏看上下文。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, assert_eq!, test_path_buf, vec!)。

build_guardian_prompt_stale_delta_version_falls_back_to_full_prompt651–736 ↗
async fn build_guardian_prompt_stale_delta_version_falls_back_to_full_prompt() -> anyhow::Result<()>

作用:测试父历史被压缩或替换后,旧版本增量游标会失效,系统必须重新发完整上下文。

数据流:进去是先有历史、再替换历史版本、再追加新消息的会话,以及旧版本游标 → 构建提示词 → 出来是 Full 格式,包含压缩后的新编号,游标版本更新为 1。

调用关系:它验证历史压缩和 Guardian 增量审查之间的安全衔接。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, assert_eq!, test_path_buf, vec!)。

collect_guardian_transcript_entries_skips_contextual_user_messages739–771 ↗
fn collect_guardian_transcript_entries_skips_contextual_user_messages()

作用:确认收集给 Guardian 的对话记录时,会跳过环境上下文这类系统塞给用户角色的消息。

数据流:进去是一个环境上下文 user 消息和一个 assistant 消息 → 收集 transcript 条目 → 出来只保留 assistant 的 hello。

调用关系:它直接测试 collect_guardian_transcript_entries 的过滤规则,避免 Guardian 被无关环境块干扰。

调用图:外部调用 2 个(assert_eq!, vec!)。

collect_guardian_transcript_entries_keeps_manual_approval_developer_message774–807 ↗
fn collect_guardian_transcript_entries_keeps_manual_approval_developer_message()

作用:确认普通 developer 消息会被过滤,但手动批准相关的 developer 消息会保留。

数据流:进去是普通开发者上下文和一条带自动审查拒绝后手动批准前缀的消息 → 收集条目 → 出来只保留手动批准消息。

调用关系:它保护一种重要上下文:用户或开发者明确覆盖先前拒绝时,Guardian 跟进审查需要知道这件事。

调用图:外部调用 3 个(assert_eq!, format!, vec!)。

collect_guardian_transcript_entries_includes_recent_tool_calls_and_output810–864 ↗
fn collect_guardian_transcript_entries_includes_recent_tool_calls_and_output()

作用:确认 transcript 会包含最近的工具调用和工具输出。Guardian 判断风险时,经常需要看到工具到底查了什么、返回了什么。

数据流:进去是 user 消息、工具调用、工具输出和 assistant 消息 → 收集条目 → 出来四条都保留,并把工具调用标成 call、工具输出标成 result。

调用关系:它测试 collect_guardian_transcript_entries 对工具证据的保留能力。

调用图:外部调用 2 个(assert_eq!, vec!)。

guardian_truncate_text_keeps_prefix_suffix_and_xml_marker867–876 ↗
fn guardian_truncate_text_keeps_prefix_suffix_and_xml_marker()

作用:测试长文本截断时会保留开头和结尾,并插入清楚的截断标记。这样 Guardian 既能看到上下文两端,又知道中间被省略了。

数据流:进去是一段很长文本和很小的 token 上限,token 可以粗略理解为模型读文本的计量单位 → 截断函数处理 → 出来文本含前缀、后缀和 <truncated ...> 标记,并标明发生了截断。

调用关系:它验证长 patch 或长工具输出进入 Guardian 前的压缩策略。

调用图:外部调用 1 个(assert!)。

format_guardian_action_pretty_truncates_large_string_fields879–895 ↗
fn format_guardian_action_pretty_truncates_large_string_fields() -> serde_json::Result<()>

作用:确认把审批动作格式化成漂亮 JSON 时,超大的字符串字段会被截断,避免请求过长。

数据流:进去是包含巨大 patch 文本的 ApplyPatch 请求 → 格式化函数转换成 JSON 文本并截断大字段 → 出来文本包含 apply_patch 工具名、截断标记,并报告 truncated 为真。

调用关系:它测试 Guardian 动作展示层,防止超大补丁撑爆提示词。

调用图:外部调用 3 个(new, assert!, test_path_buf)。

format_guardian_action_pretty_reports_no_truncation_for_small_payload898–912 ↗
fn format_guardian_action_pretty_reports_no_truncation_for_small_payload() -> serde_json::Result<()>

作用:确认小的审批动作不会被误报为截断。这样测试能区分真实截断和普通格式化。

数据流:进去是只有一行 patch 的 ApplyPatch 请求 → 格式化 → 出来文本包含工具名,truncated 为 false。

调用关系:它和大字段截断测试成对,验证格式化函数的两种分支。

调用图:外部调用 3 个(new, assert!, test_path_buf)。

guardian_approval_request_to_json_renders_mcp_tool_call_shape915–953 ↗
fn guardian_approval_request_to_json_renders_mcp_tool_call_shape() -> serde_json::Result<()>

作用:测试 MCP 工具调用审批请求会被转成 Guardian 期望的 JSON 形状。MCP 是一种让模型调用外部工具的协议。

数据流:进去是带服务器、工具名、参数、连接器名、工具标题和注解的 MCP 请求 → 转 JSON → 出来字段名和值应与预期完全一致,并省略没有值的字段。

调用关系:它验证 guardian_approval_request_to_json 对 MCP 工具调用的序列化规则。

调用图:外部调用 2 个(assert_eq!, json!)。

guardian_approval_request_to_json_renders_network_access_trigger956–997 ↗
fn guardian_approval_request_to_json_renders_network_access_trigger() -> serde_json::Result<()>

作用:测试网络访问审批请求转 JSON 时,会包含触发这次联网的命令信息。

数据流:进去是访问 example.com:443 的网络请求,并带触发命令 curl → 转 JSON → 出来包含 target、host、protocol、port 和 trigger 里的命令、目录、理由等。

调用关系:它验证网络审批的 JSON 证据足够完整,让 Guardian 能判断联网是否是命令的合理后果。

调用图:外部调用 3 个(assert_eq!, test_path_buf, vec!)。

build_guardian_prompt_items_explains_network_access_review_scope1000–1066 ↗
async fn build_guardian_prompt_items_explains_network_access_review_scope() -> anyhow::Result<()>

作用:确认网络访问审查提示词会清楚告诉 Guardian:重点看触发命令是否被授权,而不是要求用户逐字批准具体连接。

数据流:进去是父历史、网络被策略阻止的原因和一个网络访问请求 → 构建提示词 → 出来文本包含网络审查说明和 Network access JSON,但不包含普通动作审查的旧标题或 retry reason。

调用关系:它使用快照保存网络审查提示词布局,防止以后无意改坏审查口径。

调用图:调用 3 个内部函数(guardian_prompt_text, guardian_test_session_and_turn_with_base_url, seed_guardian_parent_history);外部调用 4 个(assert!, test_path_buf, clone_current, vec!)。

guardian_assessment_action_redacts_apply_patch_patch_text1069–1088 ↗
fn guardian_assessment_action_redacts_apply_patch_patch_text()

作用:确认记录 Guardian 评估动作时,不会把 apply_patch 的完整补丁正文放进去。这里是为了减少敏感内容或大文本外泄。

数据流:进去是包含 patch 文本的 ApplyPatch 请求 → 生成评估用动作摘要并序列化 → 出来只包含类型、工作目录和文件列表,不包含 patch 内容。

调用关系:它验证 analytics 或事件中使用的动作摘要会脱敏。

调用图:外部调用 3 个(assert_eq!, test_path_buf, vec!)。

guardian_request_turn_id_prefers_network_access_owner_turn1091–1117 ↗
fn guardian_request_turn_id_prefers_network_access_owner_turn()

作用:测试网络访问请求会优先使用自己携带的 owner turn ID,其他请求才用外部传入的 fallback turn ID。

数据流:进去是一个 NetworkAccess 请求、一个 ApplyPatch 请求和 fallback 字符串 → 分别取 turn ID → 网络请求输出 owner-turn,补丁请求输出 fallback-turn。

调用关系:它验证 guardian_request_turn_id 对网络审批的归属处理,避免事件记到错误 turn 上。

调用图:外部调用 3 个(assert_eq!, test_path_buf, vec!)。

guardian_request_target_item_id_omits_network_access_trigger_call_id1120–1141 ↗
fn guardian_request_target_item_id_omits_network_access_trigger_call_id()

作用:确认网络访问审批不会把触发命令的 call_id 当作审批目标项 ID。因为这次审批目标是网络访问本身,不是原工具调用。

数据流:进去是带 trigger call_id 的 NetworkAccess 请求 → 查询目标项 ID → 出来 None。

调用关系:它测试 guardian_request_target_item_id 的特殊规则,避免 UI 或事件把网络请求误挂到 shell 调用上。

调用图:外部调用 3 个(assert_eq!, test_path_buf, vec!)。

cancelled_guardian_review_emits_terminal_abort_without_warning1144–1186 ↗
async fn cancelled_guardian_review_emits_terminal_abort_without_warning()

作用:测试 Guardian 审查一开始就被取消时,应返回 Abort,并发出“进行中→已中止”的事件,而不是误报警告。

数据流:进去是带事件通道的会话、已取消的取消令牌和一个补丁请求 → 调用可取消审查 → 出来决策为 Abort;事件收件箱里只有 InProgress 和 Aborted,没有 warning。

调用关系:它覆盖外部取消流程,确保取消不是错误,也不会被当成拒绝。

调用图:调用 1 个内部函数(make_session_and_context_with_rx);外部调用 6 个(new, new, assert!, assert_eq!, test_path_buf, vec!)。

guardian_timeout_message_distinguishes_timeout_from_policy_denial1189–1194 ↗
fn guardian_timeout_message_distinguishes_timeout_from_policy_denial()

作用:确认 Guardian 超时提示说的是“没在截止前完成”,而不是“风险不可接受”。超时和策略拒绝含义不同。

数据流:进去没有参数 → 生成超时消息 → 出来文本应包含 deadline 和 retry once,不包含 unacceptable risk。

调用关系:它测试用户可见错误文案,避免把临时故障解释成安全拒绝。

调用图:外部调用 1 个(assert!)。

routes_approval_to_guardian_requires_guardian_reviewer1197–1209 ↗
async fn routes_approval_to_guardian_requires_guardian_reviewer()

作用:确认只有配置为 AutoReview 审查员时,审批才会走 Guardian;如果配置为用户审查,就不走。

数据流:进去是测试 turn → 先把 approvals_reviewer 设为 User,检查返回 false;再设为 AutoReview,检查返回 true。

调用关系:它测试审批路由入口,决定请求交给人还是 Guardian。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 2 个(new, assert!)。

routes_approval_to_guardian_can_use_app_reviewer_override1212–1223 ↗
async fn routes_approval_to_guardian_can_use_app_reviewer_override()

作用:测试应用层传入的审查员覆盖值也能决定是否走 Guardian。

数据流:进去是测试 turn 和不同 reviewer 参数 → 用 User 覆盖时返回 false,用 AutoReview 覆盖时返回 true。

调用关系:它测试 routes_approval_to_guardian_with_reviewer,补充配置路由之外的覆盖路径。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 1 个(assert!)。

routes_approval_to_guardian_allows_granular_review_policy1226–1242 ↗
async fn routes_approval_to_guardian_allows_granular_review_policy()

作用:确认使用细粒度审批策略时,只要审查员是 AutoReview,仍允许走 Guardian。

数据流:进去是配置成 AutoReview 的 turn,并把审批策略设成 Granular → 调用路由判断 → 出来 true。

调用关系:它验证新版更细的审批配置不会绕开 Guardian。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(new, Granular, assert!)。

build_guardian_transcript_reserves_separate_budget_for_tool_evidence1245–1283 ↗
fn build_guardian_transcript_reserves_separate_budget_for_tool_evidence()

作用:测试 transcript 截断时,会给普通对话和工具证据分配不同空间,不让大量工具文本挤掉关键用户/助手消息。

数据流:进去是两条重要人类对话加十二条超长工具记录 → 渲染 transcript → 出来保留前两条用户/助手内容,省略早期工具条目,并报告有省略。

调用关系:它验证 render_guardian_transcript_entries 的预算分配策略。

调用图:外部调用 2 个(assert!, vec!)。

build_guardian_transcript_preserves_recent_tool_context_when_user_history_is_large1286–1331 ↗
fn build_guardian_transcript_preserves_recent_tool_context_when_user_history_is_large()

作用:确认即使用户历史很大,最近的工具调用和工具输出仍会保留。最近工具证据通常最接近当前审批风险。

数据流:进去是多条巨大用户文本和两条最近工具记录 → 渲染 transcript → 出来仍能看到 curl 命令和网络被阻止结果,并标明省略了部分对话。

调用关系:它补充测试 transcript 裁剪时“最近工具证据优先”的行为。

调用图:外部调用 4 个(assert!, assert_eq!, Tool, json!)。

parse_guardian_assessment_extracts_embedded_json1334–1349 ↗
fn parse_guardian_assessment_extracts_embedded_json()

作用:测试 Guardian 返回内容里即使有前言,只要嵌着合法 JSON,也能解析出评估结果。

数据流:进去是一段含 JSON 的字符串 → 解析函数提取 JSON → 出来 GuardianAssessment,包含 medium 风险、low 授权、allow 结果和理由。

调用关系:它验证 parse_guardian_assessment 对模型输出不完全规整时的容错。

调用图:外部调用 1 个(assert_eq!)。

parse_guardian_assessment_treats_bare_allow_as_low_risk1352–1365 ↗
fn parse_guardian_assessment_treats_bare_allow_as_low_risk()

作用:确认 Guardian 只返回 outcome: allow 时,系统会补上合理默认值:低风险、授权未知和默认理由。

数据流:进去是只有 outcome 的 allow JSON → 解析 → 出来完整 GuardianAssessment,risk_level 为 Low,user_authorization 为 Unknown。

调用关系:它测试最小合法输出的 allow 分支。

调用图:外部调用 1 个(assert_eq!)。

parse_guardian_assessment_treats_bare_deny_as_high_risk1368–1381 ↗
fn parse_guardian_assessment_treats_bare_deny_as_high_risk()

作用:确认 Guardian 只返回 outcome: deny 时,系统会把它视为高风险拒绝,并补上默认拒绝理由。

数据流:进去是只有 outcome 的 deny JSON → 解析 → 出来 risk_level 为 High,授权未知,结果为 Deny。

调用关系:它测试最小合法输出的 deny 分支,确保拒绝不会被轻描淡写。

调用图:外部调用 1 个(assert_eq!)。

guardian_output_schema_requires_only_outcome_and_allows_optional_details1384–1412 ↗
fn guardian_output_schema_requires_only_outcome_and_allows_optional_details()

作用:测试要求 Guardian 输出的 JSON schema:只强制 outcome,风险等级、授权程度和理由可选。schema 是给模型看的“输出格式说明书”。

数据流:进去没有参数 → 生成 schema → 出来 JSON 要求对象不能有额外字段,outcome 必填,其余字段受枚举或字符串限制。

调用关系:它验证 guardian_output_schema,后续模型请求布局测试也会检查请求里带的是这份 schema。

调用图:外部调用 1 个(assert_eq!)。

guardian_request_model_for_auto_review1419–1504 ↗
async fn guardian_request_model_for_auto_review(
    auto_review_model_override: Option<String>,
    catalog: GuardianTestCatalog,
) -> anyhow::Result<(
    String,
    String,
    String,
    codex_a

作用:搭建一次自动审查,返回 Guardian 实际请求使用的模型、父模型、首选审查模型和埋点结果。它是多个模型选择测试的共用助手。

数据流:进去是可选的自动审查模型覆盖值,以及模型目录类型 → 启动假服务器,挂一次 allow 响应,创建会话,按目录情况调整模型管理器,运行 Guardian 审查 → 出来请求模型、父模型、首选模型和 analytics 元数据。

调用关系:三个模型选择测试调用它,分别检查有覆盖、无覆盖、目录缺少审查模型时的行为。

调用图:调用 6 个内部函数(guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_once, sse, start_mock_server, new);被 3 处调用(guardian_review_records_missing_auto_review_model_in_analytics_metadata, guardian_review_uses_model_catalog_override_when_preferred_review_model_exists, guardian_review_uses_preferred_review_model_without_model_catalog_override);外部调用 7 个(clone, get_mut, new, test_path_buf, panic!, json!, vec!)。

guardian_review_uses_model_catalog_override_when_preferred_review_model_exists1507–1544 ↗
async fn guardian_review_uses_model_catalog_override_when_preferred_review_model_exists() -> anyhow::Result<()>

作用:确认如果模型目录里有首选审查模型,并且配置了审查模型覆盖值,Guardian 会使用覆盖模型。

数据流:进去是测试运行环境 → 调用 guardian_request_model_for_auto_review 传入覆盖模型 → 出来断言请求模型等于覆盖值,且埋点记录覆盖发生。

调用关系:它依赖共用助手创建完整审查流程,专门检查模型覆盖优先级。

调用图:调用 1 个内部函数(guardian_request_model_for_auto_review);外部调用 3 个(assert_eq!, assert_ne!, skip_if_no_network!)。

guardian_review_uses_preferred_review_model_without_model_catalog_override1547–1582 ↗
async fn guardian_review_uses_preferred_review_model_without_model_catalog_override() -> anyhow::Result<()>

作用:确认没有覆盖值时,Guardian 会使用 provider 建议的首选审查模型,而不是父会话正在用的模型。

数据流:进去是测试环境 → 用无 override 的参数跑自动审查 → 出来断言请求模型等于 preferred_model,埋点显示未覆盖。

调用关系:它和覆盖测试一起定义 Guardian 模型选择顺序。

调用图:调用 1 个内部函数(guardian_request_model_for_auto_review);外部调用 3 个(assert_eq!, assert_ne!, skip_if_no_network!)。

guardian_review_records_missing_auto_review_model_in_analytics_metadata1585–1620 ↗
async fn guardian_review_records_missing_auto_review_model_in_analytics_metadata() -> anyhow::Result<()>

作用:确认模型目录里没有首选审查模型时,Guardian 会退回父模型,并把“目录缺失”写进埋点。

数据流:进去是 ParentOnly 模型目录配置 → 运行自动审查 → 出来请求模型等于父模型,analytics 里 guardian_catalog_contains_auto_review 为 false。

调用关系:它验证降级路径和可观测性,方便以后排查为什么没用专用审查模型。

调用图:调用 1 个内部函数(guardian_request_model_for_auto_review);外部调用 3 个(assert_eq!, assert_ne!, skip_if_no_network!)。

guardian_review_request_layout_matches_model_visible_request_snapshot1623–1820 ↗
async fn guardian_review_request_layout_matches_model_visible_request_snapshot() -> anyhow::Result<()>

作用:用快照检查真正发给模型的 Guardian 请求长什么样。它特别确认不会注入父会话的记忆内容或技能正文。

数据流:进去是测试假服务器、开启记忆和技能的父配置、父历史和一个 git push 请求 → 运行 Guardian 审查 → 出来检查审查允许、Guardian 线程 ID 独立、schema 和模型元数据正确,并保存请求快照。

调用关系:它串起会话、扩展、技能、模型请求和 analytics,是本文件里最完整的端到端布局测试之一。

调用图:调用 8 个内部函数(fixed_guardian_parent_session_id, seed_guardian_parent_history, make_session_and_context, models_manager_with_provider, mount_sse_once, sse, start_mock_server, from_string);外部调用 17 个(clone, new, new, assert!, assert_eq!, assert_ne!, new, create_model_provider, test_path_buf, format! (+7 more))。

build_guardian_prompt_items_includes_parent_session_id1823–1858 ↗
async fn build_guardian_prompt_items_includes_parent_session_id() -> anyhow::Result<()>

作用:确认 Guardian 提示词会在 transcript 后写出被审查的父会话 ID,便于追踪它评估的是哪个主会话。

数据流:进去是一个会话和 shell status 请求 → 构建 Full 提示词 → 拼接文本后检查里面包含 Reviewed Codex session id 和 session.thread_id。

调用关系:它直接测试提示词内容,补充快照测试中对会话可追踪性的要求。

调用图:调用 1 个内部函数(make_session_and_context);外部调用 3 个(assert!, test_path_buf, vec!)。

guardian_reuses_prompt_cache_key_and_appends_prior_reviews1861–2154 ↗
async fn guardian_reuses_prompt_cache_key_and_appends_prior_reviews() -> anyhow::Result<()>

作用:测试多次 Guardian 审查会复用同一个提示词缓存键,并把先前审查结果作为上下文追加到后续请求里。

数据流:进去是假服务器三次 allow 响应、父历史和三次 shell 请求 → 依次运行三次审查,中间追加父会话消息 → 出来确认 Guardian 线程复用、后续请求使用增量 transcript、包含先前理由、提醒只追加一次、缓存键一致。

调用关系:它验证 Guardian trunk 会话复用机制,是跟进审查性能和上下文连续性的核心测试。

调用图:调用 5 个内部函数(guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_sequence, start_mock_server, from_string);外部调用 8 个(clone, assert!, assert_eq!, test_path_buf, panic!, clone_current, skip_if_no_network!, vec!)。

guardian_reused_trunk_ignores_stale_prior_turn_completion2157–2263 ↗
async fn guardian_reused_trunk_ignores_stale_prior_turn_completion() -> anyhow::Result<()>

作用:确认复用 Guardian trunk 时,如果收到了过期的旧 turn 完成事件,不会把它误当成当前审查结果。

数据流:进去是假服务器两次 allow 响应 → 第一次审查完成后,手动塞入一个 stale 的 deny 完成事件,再跑第二次审查 → 出来第二次仍采用真实第二个响应,而不是旧事件。

调用关系:它测试 Guardian 复用会话里的事件匹配,避免并发或残留事件污染当前结果。

调用图:调用 3 个内部函数(guardian_test_session_and_turn, mount_sse_sequence, start_mock_server);外部调用 8 个(clone, assert!, assert_eq!, test_path_buf, panic!, TurnComplete, skip_if_no_network!, vec!)。

guardian_review_surfaces_responses_api_errors_in_rejection_reason2266–2374 ↗
async fn guardian_review_surfaces_responses_api_errors_in_rejection_reason() -> anyhow::Result<()>

作用:测试模型接口返回 400 错误时,Guardian 会把底层错误信息展示在警告和拒绝理由里,而不是只给泛泛的失败说明。

数据流:进去是假服务器返回 invalid_request_error、带事件通道的会话和一个 git push 请求 → 调用审查 → 出来决策为 Denied,事件 warning 和 denial rationale 都包含接口错误,拒绝记录挂在 review ID 上。

调用关系:它验证错误传播链路:HTTP/API 错误 → Guardian warning → 拒绝理由 → guardian_rejection_message

调用图:调用 5 个内部函数(seed_guardian_parent_history, make_session_and_context_with_rx, models_manager_with_provider, mount_response_sequence, start_mock_server);外部调用 11 个(clone, get_mut, new, new, assert!, assert_eq!, create_model_provider, test_path_buf, format!, skip_if_no_network! (+1 more))。

guardian_review_retries_transient_session_failure_then_approves2377–2430 ↗
async fn guardian_review_retries_transient_session_failure_then_approves() -> anyhow::Result<()>

作用:确认 Guardian 遇到临时会话失败会重试,并在第二次成功后批准。

数据流:进去是假服务器先返回过载失败,再返回 allow JSON → 运行最多 3 次尝试的审查 → 出来 assessment 为 allow,attempt_count 为 2,请求数为 2。

调用关系:它测试 run_guardian_review_session_for_test 的临时故障重试逻辑。

调用图:调用 5 个内部函数(guardian_shell_request, guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_sequence, start_mock_server);外部调用 7 个(clone, assert!, assert_eq!, panic!, json!, skip_if_no_network!, vec!)。

guardian_review_does_not_retry_missing_assessment_payload2433–2460 ↗
async fn guardian_review_does_not_retry_missing_assessment_payload() -> anyhow::Result<()>

作用:确认如果模型响应完成但没有给出 Guardian 评估内容,系统不会盲目重试。

数据流:进去是假服务器只发 created 和 completed,没有 assistant assessment → 调用普通审查 → 出来 Denied,请求数只有 1。

调用关系:它定义“缺少评估 payload”属于不可重试的终止失败。

调用图:调用 5 个内部函数(guardian_shell_request, guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_sequence, start_mock_server);外部调用 3 个(assert_eq!, skip_if_no_network!, vec!)。

guardian_review_retries_two_parse_failures_then_approves2463–2521 ↗
async fn guardian_review_retries_two_parse_failures_then_approves() -> anyhow::Result<()>

作用:确认 Guardian 解析模型输出失败时可以重试,连续两次无效 JSON 后第三次有效就批准。

数据流:进去是假服务器两次返回不可解析文本,第三次返回 allow JSON → 运行最多 3 次尝试 → 出来 allow,attempt_count 为 3,请求数为 3。

调用关系:它测试模型格式错误的可恢复路径。

调用图:调用 5 个内部函数(guardian_shell_request, guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_sequence, start_mock_server);外部调用 7 个(clone, assert!, assert_eq!, panic!, json!, skip_if_no_network!, vec!)。

guardian_review_exhausts_three_failures_with_one_terminal_event2524–2577 ↗
async fn guardian_review_exhausts_three_failures_with_one_terminal_event() -> anyhow::Result<()>

作用:确认三次解析失败耗尽重试后,只发出一个最终拒绝事件。这样 UI 不会收到多个互相冲突的终态。

数据流:进去是假服务器三次返回无效评估文本、带事件接收器的会话 → 调用审查 → 出来 Denied,请求数 3,事件状态只有 InProgress 和 Denied。

调用关系:它结合 guardian_test_session_turn_and_rx 观察事件流,验证重试失败后的事件收尾。

调用图:调用 5 个内部函数(guardian_shell_request, guardian_test_session_turn_and_rx, seed_guardian_parent_history, mount_sse_sequence, start_mock_server);外部调用 4 个(new, assert_eq!, skip_if_no_network!, vec!)。

guardian_review_does_not_retry_valid_denial2580–2615 ↗
async fn guardian_review_does_not_retry_valid_denial() -> anyhow::Result<()>

作用:确认模型给出合法 deny 时,系统马上拒绝,不会把有效拒绝当失败去重试。

数据流:进去是假服务器返回一份合法高风险 deny JSON → 调用审查 → 出来 Denied,请求数为 1。

调用关系:它和解析失败重试测试形成对照:格式错误可重试,明确拒绝不可重试。

调用图:调用 5 个内部函数(guardian_shell_request, guardian_test_session_and_turn, seed_guardian_parent_history, mount_sse_sequence, start_mock_server);外部调用 4 个(assert_eq!, json!, skip_if_no_network!, vec!)。

guardian_ephemeral_retry_preserves_parallel_trunk_and_fork_history2618–2872 ↗
async fn guardian_ephemeral_retry_preserves_parallel_trunk_and_fork_history() -> anyhow::Result<()>

作用:测试并行 Guardian 审查时,临时分支重试不会破坏主干历史,也不会提前看到还没完成的主干审查结果。

数据流:进去是一个分段流式假服务器:先完成一次审查,第二次审查被闸门卡住,第三次临时分支先失败再重试成功 → 测试同时跑第二和第三次审查 → 出来确认缓存键一致、分支包含已提交的第一条理由、不包含尚未完成的第二条理由,且增量 transcript 正确。

调用关系:它是复杂并发场景测试,保护 Guardian trunk/fork 会话模型在并行审批和重试时不串线。

调用图:外部调用 2 个(anyhow!, new)。

guardian_review_session_config_preserves_parent_network_proxy2874–2918 ↗
async fn guardian_review_session_config_preserves_parent_network_proxy()

作用:确认构建 Guardian 审查会话配置时,会保留父配置里的网络代理规则,同时把审批策略锁成不再请求批准、权限变成只读。

数据流:进去是带 github.com 允许规则的父配置、活动模型和推理强度 → 构建 Guardian 配置 → 出来网络配置保留,模型和 reasoning effort 正确,审批策略为 Never,权限 profile 为 read-only。

调用关系:它测试 build_guardian_review_session_config_for_test 的基础配置隔离和继承规则。

调用图:调用 2 个内部函数(from_config_and_constraints, test_config);外部调用 4 个(default, assert_eq!, default, from)。

guardian_review_session_config_clears_parent_developer_instructions2921–2939 ↗
async fn guardian_review_session_config_clears_parent_developer_instructions()

作用:确认父会话的 developer instructions 不会覆盖 Guardian 自己的安全策略提示。

数据流:进去是带父 developer_instructions 的配置 → 构建 Guardian 配置 → 出来 developer_instructions 为 None,base_instructions 是 Guardian policy prompt。

调用关系:它保护 Guardian 审查提示词的权威性,防止父配置改写审查员规则。

调用图:调用 1 个内部函数(test_config);外部调用 1 个(assert_eq!)。

guardian_review_session_config_clears_legacy_notify2942–2958 ↗
async fn guardian_review_session_config_clears_legacy_notify()

作用:确认 Guardian 审查会话不会继承旧的 notify 命令。notify 是外部通知钩子,审查子会话不应该额外触发它。

数据流:进去是带 notify 数组的父配置 → 构建 Guardian 配置 → 出来 notify 为 None。

调用关系:它测试配置清理,避免嵌套审查产生多余通知副作用。

调用图:调用 1 个内部函数(test_config);外部调用 2 个(assert_eq!, vec!)。

guardian_review_session_config_uses_live_network_proxy_state2961–3002 ↗
async fn guardian_review_session_config_uses_live_network_proxy_state()

作用:确认如果有实时网络代理状态,Guardian 会用实时状态,而不是父配置里旧的网络规则。

数据流:进去是父配置允许 parent.example、实时网络允许 github.com → 构建 Guardian 配置 → 出来网络 spec 来自 live_network,并按只读权限重新计算。

调用关系:它验证运行时网络状态优先,保证 Guardian 看见的是当前真实联网限制。

调用图:调用 2 个内部函数(from_config_and_constraints, test_config);外部调用 3 个(assert_eq!, default, vec!)。

guardian_review_session_config_disables_mcp_apps_plugins_and_memories3005–3039 ↗
async fn guardian_review_session_config_disables_mcp_apps_plugins_and_memories()

作用:确认 Guardian 子会话会关掉 MCP 服务器、Apps、Plugins 和 Memories。它们是外部工具、应用或记忆能力,审查员不该被这些额外能力影响。

数据流:进去是开启 MCP、Apps、Plugins、应用说明和记忆的父配置 → 构建 Guardian 配置 → 出来 MCP 为空,相关 feature 和记忆开关全关。

调用关系:它测试 Guardian 配置沙箱化,和请求布局测试里的“不要注入技能/记忆内容”互相呼应。

调用图:调用 1 个内部函数(test_config);外部调用 3 个(from, assert!, from_str)。

guardian_review_session_config_allows_pinned_disabled_feature3042–3066 ↗
async fn guardian_review_session_config_allows_pinned_disabled_feature()

作用:确认即使配置里钉住了某个目前禁用的 feature,Guardian 配置构建也不会失败。

数据流:进去是带 feature requirements 的父配置 → 构建 Guardian 配置 → 出来仍成功,Collab feature 可用,同时 MCP 和应用说明仍被清掉。

调用关系:它覆盖配置管理的兼容性边界,避免 workspace 要求让 Guardian 启动失败。

调用图:调用 2 个内部函数(from_configured, test_config);外部调用 2 个(from, assert!)。

guardian_review_session_config_uses_parent_active_model_instead_of_hardcoded_slug3069–3082 ↗
async fn guardian_review_session_config_uses_parent_active_model_instead_of_hardcoded_slug()

作用:确认 Guardian 使用父 turn 当前实际活动模型,而不是父配置文件里写的模型名或硬编码模型。

数据流:进去是父配置 model 为 configured-model,但传入 active-model → 构建 Guardian 配置 → 出来 model 是 active-model。

调用关系:它测试模型传递规则,保证审查会话和当前运行模型状态对齐。

调用图:调用 1 个内部函数(test_config);外部调用 1 个(assert_eq!)。

guardian_review_session_config_keeps_bedrock_provider_for_bedrock_gpt_5_43085–3115 ↗
async fn guardian_review_session_config_keeps_bedrock_provider_for_bedrock_gpt_5_4()

作用:确认当父会话使用 Amazon Bedrock 的 GPT-5.4 模型时,Guardian 配置仍保留 Bedrock provider,而不是切到别的 provider。

数据流:进去是 Bedrock provider 父配置、Bedrock GPT-5.4 模型和低 reasoning effort → 构建 Guardian 配置 → 出来模型、provider ID、provider 信息都匹配 Bedrock,并把重试次数设为 1。

调用关系:它覆盖非 OpenAI provider 的配置路径,防止专用云模型审查被错误改道。

调用图:调用 2 个内部函数(test_config, create_amazon_bedrock_provider);外部调用 1 个(assert_eq!)。

guardian_review_session_config_uses_requirements_guardian_policy_config3118–3160 ↗
async fn guardian_review_session_config_uses_requirements_guardian_policy_config()

作用:确认 workspace requirements 里提供的 Guardian policy 配置会被用来生成审查员基础指令,并会去掉首尾空白。

数据流:进去是临时 codex_home、workspace 和带 guardian_policy_config 的配置层 → 加载父配置,再构建 Guardian 配置 → 出来 base_instructions 是带 workspace 管理策略的 Guardian prompt,developer_instructions 为空。

调用关系:它测试配置层需求对 Guardian 策略的覆盖路径。

调用图:调用 1 个内部函数(new);外部调用 6 个(default, new, load_config_with_layer_stack, assert_eq!, default, tempdir)。

guardian_review_session_config_uses_default_guardian_policy_without_requirements_override3163–3196 ↗
async fn guardian_review_session_config_uses_default_guardian_policy_without_requirements_override()

作用:确认没有 requirements 覆盖时,Guardian 使用默认安全策略提示。

数据流:进去是没有 guardian_policy_config 的配置层 → 加载父配置并构建 Guardian 配置 → 出来 base_instructions 等于默认 guardian_policy_prompt(),developer_instructions 为空。

调用关系:它和上一条 requirements 覆盖测试成对,定义默认策略和 workspace 覆盖策略的选择规则。

调用图:调用 1 个内部函数(new);外部调用 6 个(default, new, load_config_with_layer_stack, assert_eq!, default, tempdir)。

core/src/exec_policy_tests.rs源码 ↗
testtest

可以把这个文件看成执行策略系统的“安全演习场”。执行策略就是一套规则:哪些命令可以直接跑,哪些必须问用户,哪些绝对不能跑;沙箱则像一个隔离房间,用来限制命令能碰哪些文件和网络。这个测试文件会临时造目录、写配置、写 .rules 规则文件,再让策略加载器和审批判断器去跑一遍。它覆盖很多容易出错的情况:规则目录不存在、规则文件写坏、项目不受信任、用户配置被忽略、bash -lc 里藏着真正命令、heredoc 多行脚本、绝对路径程序、Windows/PowerShell 差异、沙箱提权、自动建议新增规则等。测试里的辅助函数负责搭临时配置、生成平台相关路径、把规则字符串转好、统一断言结果。整体目标很明确:保证安全判断既不太松,也不无故太严。

函数细节88
config_stack_for_dot_codex_folder42–55 ↗
fn config_stack_for_dot_codex_folder(dot_codex_folder: &Path) -> ConfigLayerStack

作用:给测试快速造一个只包含某个项目 .codex 文件夹的配置层栈。配置层栈可以理解成多张配置纸叠在一起,系统按顺序读取。

数据流:输入一个 .codex 文件夹路径 → 把它转成绝对路径,做成一个项目配置层,内容为空表 → 输出一个 ConfigLayerStack,供加载执行策略时使用。

调用关系:多个规则加载测试会先调用它搭好最小配置环境,然后把这个配置交给 load_exec_policy 或 ExecPolicyManager::load 去验证规则是否被读取。

调用图:调用 3 个内部函数(new, new, from_absolute_path);被 6 处调用(format_exec_policy_error_with_source_renders_range, ignores_policies_outside_policy_dir, ignores_policy_files_when_config_stack_disables_exec_policy_rules, loads_policies_from_policy_subdirectory, returns_empty_policy_when_no_policy_files_exist, rules_path_file_returns_read_dir_error);外部调用 5 个(default, Table, default, default, vec!)。

host_absolute_path57–67 ↗
fn host_absolute_path(segments: &[&str]) -> String

作用:按当前操作系统拼出一个主机上的绝对路径字符串。这样测试在 Windows 和类 Unix 系统上都能用同一套写法。

数据流:输入路径片段数组 → 先选择 C:\ 或 / 作为根,再逐段拼接 → 输出平台对应的绝对路径字符串。

调用关系:它被 host_program_path 和绝对路径命令测试使用,用来模拟真实机器上的程序路径。

调用图:被 3 处调用(absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths, host_program_path, preserves_host_executables_when_requirements_overlay_is_present);外部调用 2 个(from, cfg!)。

host_program_path69–76 ↗
fn host_program_path(name: &str) -> String

作用:生成某个程序在 /usr/bin 或 Windows 对应路径下的完整路径。Windows 上会自动补 .exe。

数据流:输入程序名 → 根据系统决定是否加 .exe,再交给 host_absolute_path 拼成 /usr/bin/程序名 → 输出完整路径字符串。

调用关系:绝对路径执行策略测试用它模拟用户直接运行 /usr/bin/git 这类命令,再检查策略能不能识别成 git。

调用图:调用 1 个内部函数(host_absolute_path);被 2 处调用(absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths, absolute_path_exec_approval_requirement_matches_host_executable_rules);外部调用 2 个(cfg!, format!)。

starlark_string78–80 ↗
fn starlark_string(value: &str) -> String

作用:把普通字符串转成可以安全写进 Starlark 规则文件的字符串内容。Starlark 是这里规则文件使用的一种小脚本语言。

数据流:输入原始字符串 → 把反斜杠和双引号转义,避免破坏规则文件语法 → 输出可嵌入规则文件的字符串。

调用关系:写 host_executable 规则时会用它保护路径字符串,避免 Windows 路径里的反斜杠或引号让规则解析失败。

调用图:被 3 处调用(absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths, absolute_path_exec_approval_requirement_matches_host_executable_rules, preserves_host_executables_when_requirements_overlay_is_present)。

write_project_trust_config82–107 ↗
async fn write_project_trust_config(
    codex_home: &Path,
    trusted_projects: &[(&Path, TrustLevel)],
) -> std::io::Result<()>

作用:给测试写一份项目信任配置,说明哪些项目可信、哪些不可信。执行策略只应该接受可信项目里的规则。

数据流:输入 codex_home 路径和项目信任列表 → 生成 config.toml 内容并异步写入磁盘 → 输出写文件结果,同时磁盘上多出一份信任配置。

调用关系:项目信任相关测试会先调用它布置信任状态,再让 ConfigBuilder 加载配置,最后检查规则是否被采纳或忽略。

调用图:被 3 处调用(exec_policies_only_load_from_trusted_project_layers, exec_policies_require_project_trust_without_config_toml, exec_policy_warnings_ignore_untrusted_project_rules_without_config_toml);外部调用 5 个(default, iter, join, write, to_string)。

test_config109–117 ↗
async fn test_config() -> (TempDir, Config)

作用:快速创建一份默认测试配置和临时主目录,减少重复样板代码。

数据流:不接收业务输入 → 创建临时目录,用测试专用 ConfigBuilder 加载默认配置 → 输出临时目录和 Config。

调用关系:父子配置是否能共用执行策略的几项测试都用它取得基准配置。

调用图:调用 1 个内部函数(without_managed_config_for_tests);被 4 处调用(child_does_not_use_parent_exec_policy_when_ignore_rules_differs, child_does_not_use_parent_exec_policy_when_requirements_exec_policy_differs, child_uses_parent_exec_policy_when_layer_stack_matches, child_uses_parent_exec_policy_when_non_exec_policy_layers_differ);外部调用 1 个(new)。

child_uses_parent_exec_policy_when_layer_stack_matches120–125 ↗
async fn child_uses_parent_exec_policy_when_layer_stack_matches()

作用:测试子配置和父配置完全一样时,子任务可以复用父任务的执行策略。

数据流:先创建父配置并克隆成子配置 → 调用判断函数 → 断言结果为可以复用。

调用关系:这是 child_uses_parent_exec_policy 复用逻辑的最基本正例。

调用图:调用 1 个内部函数(test_config);外部调用 1 个(assert!)。

child_uses_parent_exec_policy_when_non_exec_policy_layers_differ128–152 ↗
async fn child_uses_parent_exec_policy_when_non_exec_policy_layers_differ()

作用:测试只有非执行策略相关的配置层不同,不应该影响执行策略复用。

数据流:创建父子配置 → 给子配置额外加一个空的会话标记层 → 断言仍然可以复用父策略。

调用关系:它说明复用判断不是简单比较全部配置,而是只关心会影响执行策略的部分。

调用图:调用 3 个内部函数(new, new, test_config);外部调用 3 个(default, Table, assert!)。

child_does_not_use_parent_exec_policy_when_ignore_rules_differs155–168 ↗
async fn child_does_not_use_parent_exec_policy_when_ignore_rules_differs()

作用:测试如果子配置改变了“忽略用户和项目规则”的开关,就不能复用父策略。

数据流:创建父子配置 → 子配置开启忽略规则 → 调用复用判断 → 输出断言为不能复用。

调用关系:它保护一种安全边界:规则来源被改变时必须重新算策略。

调用图:调用 1 个内部函数(test_config);外部调用 1 个(assert!)。

child_does_not_use_parent_exec_policy_when_requirements_exec_policy_differs171–209 ↗
async fn child_does_not_use_parent_exec_policy_when_requirements_exec_policy_differs()

作用:测试如果配置要求里额外加入执行策略,子任务不能继续沿用父任务的旧策略。

数据流:创建父子配置 → 给子配置要求里加一条禁止 rm 的策略 → 断言不能复用。

调用关系:它覆盖来自 requirements 的策略叠加场景,保证策略内容变化会触发重新加载。

调用图:调用 4 个内部函数(new, new, new, test_config);外部调用 3 个(default, assert!, empty)。

returns_empty_policy_when_no_policy_files_exist212–233 ↗
async fn returns_empty_policy_when_no_policy_files_exist()

作用:测试没有任何规则文件时,系统会得到一个空策略,而不是报错或自动创建目录。

数据流:创建空临时目录和配置栈 → 加载策略 → 用 rm 命令检查结果走默认启发式放行,并确认规则目录没有被创建。

调用关系:它验证 ExecPolicyManager::load 对“没有规则”这种正常情况的处理。

调用图:调用 2 个内部函数(load, config_stack_for_dot_codex_folder);外部调用 4 个(assert!, assert_eq!, tempdir, vec!)。

rules_path_file_returns_read_dir_error236–253 ↗
async fn rules_path_file_returns_read_dir_error()

作用:测试 rules 路径如果是文件而不是目录,会明确返回读目录错误。

数据流:创建一个名为 rules 的普通文件 → 加载策略 → 得到错误并确认错误指向这个路径。

调用关系:它检查 load_exec_policy 的错误报告,避免把坏目录结构悄悄吞掉。

调用图:调用 1 个内部函数(config_stack_for_dot_codex_folder);外部调用 3 个(assert!, write, tempdir)。

collect_policy_files_returns_empty_when_dir_missing256–265 ↗
async fn collect_policy_files_returns_empty_when_dir_missing()

作用:测试规则目录不存在时,收集规则文件会返回空列表。

数据流:输入一个不存在的 rules 目录 → 调用 collect_policy_files → 输出空文件列表。

调用关系:它直接验证底层收集函数,支持上层“没有规则不是错误”的行为。

调用图:外部调用 2 个(assert!, tempdir)。

format_exec_policy_error_with_source_renders_range268–291 ↗
async fn format_exec_policy_error_with_source_renders_range()

作用:测试规则解析失败时,格式化后的错误信息会带上文件名和大致行号。

数据流:写入一个语法错误的 broken.rules → 加载失败 → 格式化错误 → 检查文字里包含 broken.rules 和第 1 行提示。

调用关系:它保证用户写坏规则时,提示能指向出错位置,而不是只说解析失败。

调用图:调用 1 个内部函数(config_stack_for_dot_codex_folder);外部调用 4 个(assert!, create_dir_all, write, tempdir)。

parse_starlark_line_from_message_extracts_path_and_line294–302 ↗
fn parse_starlark_line_from_message_extracts_path_and_line()

作用:测试能从 Starlark 错误文本里拆出文件路径和行号。

数据流:输入一段包含 /tmp/default.rules:143:1 的错误消息 → 解析 → 输出路径和 143 行。

调用关系:它验证错误美化功能里的小解析器。

调用图:外部调用 1 个(assert_eq!)。

parse_starlark_line_from_message_rejects_zero_line305–310 ↗
fn parse_starlark_line_from_message_rejects_zero_line()

作用:测试行号为 0 的错误消息会被拒绝,因为真实源码行号应从 1 开始。

数据流:输入带 :0: 的错误消息 → 解析器判断不合理 → 输出 None。

调用关系:它防止错误定位功能生成无意义的第 0 行提示。

调用图:外部调用 1 个(assert_eq!)。

loads_policies_from_policy_subdirectory313–340 ↗
async fn loads_policies_from_policy_subdirectory()

作用:测试项目 rules 子目录里的 .rules 文件会被加载并生效。

数据流:写入禁止 rm 的规则文件 → 加载策略 → 检查 rm 命令被判为 Forbidden。

调用关系:这是规则文件正常加载路径的核心正例。

调用图:调用 1 个内部函数(config_stack_for_dot_codex_folder);外部调用 5 个(assert_eq!, create_dir_all, write, tempdir, vec!)。

merges_requirements_exec_policy_network_rules343–375 ↗
async fn merges_requirements_exec_policy_network_rules() -> anyhow::Result<()>

作用:测试配置要求里的网络规则会合并进最终执行策略。

数据流:创建一个禁止访问 blocked.example.com 的 requirements 策略 → 加载最终策略 → 读取编译后的网络域名,确认它在拒绝列表里。

调用关系:它覆盖 requirements 与文件规则叠加的路径,重点是网络访问限制。

调用图:调用 5 个内部函数(new, new, new, new, from_absolute_path);外部调用 9 个(default, Table, default, assert!, assert_eq!, default, empty, tempdir, vec!)。

preserves_host_executables_when_requirements_overlay_is_present378–427 ↗
async fn preserves_host_executables_when_requirements_overlay_is_present() -> anyhow::Result<()>

作用:测试即使叠加了 requirements 策略,规则文件里声明的主机可执行程序映射也不会丢。

数据流:写入 git 的 host_executable 规则,再加入一个网络禁止规则 → 加载策略 → 检查 git 路径仍保存在策略里。

调用关系:它防止合并策略时只保留新规则、误删原有 host_executable 信息。

调用图:调用 7 个内部函数(new, new, new, new, host_absolute_path, starlark_string, from_absolute_path);外部调用 11 个(default, Table, default, assert_eq!, default, empty, format!, create_dir_all, write, tempdir (+1 more))。

ignores_policies_outside_policy_dir430–453 ↗
async fn ignores_policies_outside_policy_dir()

作用:测试放在 .codex 根目录而不是 rules 子目录里的 .rules 文件不会被加载。

数据流:在错误位置写 root.rules → 加载策略 → 检查 ls 没有被该规则影响,仍按默认启发式放行。

调用关系:它明确规则文件的有效位置,避免随便一个 .rules 文件都改变安全策略。

调用图:调用 1 个内部函数(config_stack_for_dot_codex_folder);外部调用 4 个(assert_eq!, write, tempdir, vec!)。

ignores_policy_files_when_config_stack_disables_exec_policy_rules456–480 ↗
async fn ignores_policy_files_when_config_stack_disables_exec_policy_rules()

作用:测试当配置栈要求忽略用户和项目规则时,这些规则文件不会生效。

数据流:写入允许 curl 的项目规则 → 开启忽略开关 → 加载策略 → 用默认 Forbidden 回调检查 curl 仍被禁止。

调用关系:它验证忽略开关真正绕过用户/项目规则,而不是只影响配置文件。

调用图:调用 1 个内部函数(config_stack_for_dot_codex_folder);外部调用 4 个(assert_eq!, create_dir_all, write, tempdir)。

ignore_user_project_rules_keeps_system_policy_files483–520 ↗
async fn ignore_user_project_rules_keeps_system_policy_files()

作用:测试忽略用户和项目规则时,系统级规则仍然保留。

数据流:创建系统配置层和允许 curl 的系统规则 → 开启忽略用户/项目规则 → 加载策略 → curl 仍被允许。

调用关系:它说明忽略开关不是全局关掉所有规则,系统管理员级别的规则仍有效。

调用图:调用 3 个内部函数(new, new, from_absolute_path);外部调用 9 个(default, Table, default, assert_eq!, default, create_dir_all, write, tempdir, vec!)。

ignores_rules_from_untrusted_project_layers523–559 ↗
async fn ignores_rules_from_untrusted_project_layers() -> anyhow::Result<()>

作用:测试不受信任的项目配置层里的规则不会被执行。

数据流:创建一个被标记 disabled 的项目层,并写禁止 ls 的规则 → 加载策略 → ls 仍按默认规则放行。

调用关系:它保护项目信任边界:不可信项目不能偷偷写规则影响命令审批。

调用图:调用 2 个内部函数(new, from_absolute_path);外部调用 7 个(default, assert_eq!, default, create_dir_all, write, tempdir, vec!)。

loads_policies_from_multiple_config_layers562–631 ↗
async fn loads_policies_from_multiple_config_layers() -> anyhow::Result<()>

作用:测试用户层和项目层的规则可以一起加载。

数据流:用户层写禁止 rm,项目层写提示 ls → 构造两层配置 → 加载策略 → 分别检查 rm 被禁、ls 需要确认。

调用关系:它验证多层配置叠加时,不会只读其中一层。

调用图:调用 2 个内部函数(new, from_absolute_path);外部调用 7 个(default, assert_eq!, default, create_dir_all, write, tempdir, vec!)。

evaluates_bash_lc_inner_commands634–653 ↗
async fn evaluates_bash_lc_inner_commands()

作用:测试 bash -lc 这种外壳命令里真正执行的 rm 会被策略看见。

数据流:输入 bash -lc 'rm -rf ...' 和禁止 rm 的规则 → 计算审批要求 → 输出 Forbidden。

调用关系:它通过通用断言助手检查 create_exec_approval_requirement_for_command 的 shell 拆解能力。

调用图:调用 1 个内部函数(assert_exec_approval_requirement_for_command);外部调用 1 个(vec!)。

commands_for_exec_policy_falls_back_for_empty_shell_script656–667 ↗
fn commands_for_exec_policy_falls_back_for_empty_shell_script()

作用:测试 bash -lc 后面的脚本为空时,不强行解析,直接用原始命令。

数据流:输入 bash -lc '' → commands_for_exec_policy 发现没有可解析内容 → 输出原始命令和未使用复杂解析标记。

调用关系:它覆盖 shell 命令解析器的空输入兜底路径。

调用图:外部调用 2 个(assert_eq!, vec!)。

commands_for_exec_policy_falls_back_for_whitespace_shell_script670–685 ↗
fn commands_for_exec_policy_falls_back_for_whitespace_shell_script()

作用:测试脚本只有空白字符时,也会退回原始命令。

数据流:输入 bash -lc 加空格换行制表符 → 解析后没有真实命令 → 输出原始命令。

调用关系:它和空脚本测试一起防止空白脚本被误判或崩溃。

调用图:外部调用 2 个(assert_eq!, vec!)。

ignore_user_config_keeps_user_policy_files688–724 ↗
async fn ignore_user_config_keeps_user_policy_files() -> std::io::Result<()>

作用:测试忽略用户 config.toml 时,用户 rules 文件仍然会加载。

数据流:写一个坏的用户配置文件和一个禁止 curl 的规则 → 设置 ignore_user_config → 构建配置并加载策略 → curl 仍被规则禁止。

调用关系:它区分“忽略用户配置内容”和“忽略用户规则文件”这两件事。

调用图:外部调用 6 个(default, assert_eq!, default, create_dir_all, write, tempdir)。

evaluates_heredoc_script_against_prefix_rules727–749 ↗
async fn evaluates_heredoc_script_against_prefix_rules()

作用:测试 heredoc 多行脚本里的 python3 会按前缀规则匹配。heredoc 是 shell 里把多行文本喂给命令的写法。

数据流:输入 bash -lc 的 python3 <<'PY' 脚本和允许 python3 的规则 → 审批结果为跳过确认并绕过沙箱。

调用关系:它检查复杂 shell 解析能识别 heredoc 的实际执行命令。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

omits_auto_amendment_for_heredoc_fallback_prompts752–772 ↗
async fn omits_auto_amendment_for_heredoc_fallback_prompts()

作用:测试 heredoc 解析走兜底并需要确认时,不自动建议新增规则。

数据流:输入无匹配策略的 heredoc 命令 → 审批需要用户确认 → 输出里 proposed_execpolicy_amendment 为 None。

调用关系:它避免系统给复杂 heredoc 生成可能不准确的自动规则建议。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

drops_requested_amendment_for_heredoc_fallback_prompts_when_it_wont_match775–799 ↗
async fn drops_requested_amendment_for_heredoc_fallback_prompts_when_it_wont_match()

作用:测试用户请求的前缀规则和 heredoc 实际兜底命令不匹配时,会丢弃这个建议。

数据流:输入 heredoc 命令和 python3 -m pip 前缀请求 → 判断它不能可靠覆盖命令 → 输出确认需求但不带规则建议。

调用关系:它保护自动修正规则功能,避免批准一个实际上套不住命令的规则。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

drops_requested_amendment_for_heredoc_fallback_prompts_when_it_matches802–822 ↗
async fn drops_requested_amendment_for_heredoc_fallback_prompts_when_it_matches()

作用:测试即使请求前缀看起来匹配 heredoc,也不会在兜底场景下生成建议。

数据流:输入 heredoc 命令和 python3 前缀请求 → 因为 heredoc 兜底不可靠 → 输出不带规则建议的确认需求。

调用关系:它进一步强调复杂 heredoc 场景下不自动写规则。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

heredoc_with_variable_assignment_is_not_reduced_to_allowed_prefix826–850 ↗
async fn heredoc_with_variable_assignment_is_not_reduced_to_allowed_prefix()

作用:测试带环境变量赋值的 heredoc 不会被简单缩减成允许的 cat 命令。

数据流:输入 PATH=/tmp/evil:$PATH cat <<EOF 这类命令和允许 cat 的规则 → 审批不绕过沙箱,并建议原始完整命令。

调用关系:它防止攻击者通过改 PATH 把看似安全的 cat 换成恶意程序。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

heredoc_redirect_without_escalation_runs_inside_sandbox853–883 ↗
async fn heredoc_redirect_without_escalation_runs_inside_sandbox()

作用:测试 heredoc 重定向写文件但没有要求提权时,可以在沙箱里运行。

数据流:输入 zsh heredoc 写文件命令,权限为工作区可写 → 审批结果跳过用户确认,但不绕过沙箱。

调用关系:它检查写文件场景下,系统优先依赖沙箱限制,而不是一律要求确认。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, workspace_write);外部调用 2 个(new, vec!)。

heredoc_redirect_with_escalation_requires_approval886–916 ↗
async fn heredoc_redirect_with_escalation_requires_approval()

作用:测试同样的 heredoc 写文件命令如果要求沙箱提权,就必须问用户。

数据流:输入 zsh heredoc 写文件命令,沙箱权限为要求提权 → 输出 NeedsApproval,并带完整命令建议。

调用关系:它验证沙箱权限请求会影响最终审批结果。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, workspace_write);外部调用 2 个(new, vec!)。

justification_is_included_in_forbidden_exec_approval_requirement919–947 ↗
async fn justification_is_included_in_forbidden_exec_approval_requirement()

作用:测试禁止规则里的说明文字会出现在最终拒绝原因里。

数据流:写一条禁止 rm 且理由为 destructive command 的规则 → 检查 rm -rf → 输出 Forbidden,原因包含该说明。

调用关系:它保证规则作者写的解释能传给用户,而不是只显示生硬的 blocked。

调用图:调用 1 个内部函数(assert_exec_approval_requirement_for_command);外部调用 1 个(vec!)。

exec_approval_requirement_prefers_execpolicy_match950–966 ↗
async fn exec_approval_requirement_prefers_execpolicy_match()

作用:测试如果执行策略明确匹配并要求确认,最终结果优先使用这个策略判断。

数据流:写 rm 需要 prompt 的规则 → 检查 rm → 输出 NeedsApproval,理由说明由策略要求确认。

调用关系:它确认策略规则的优先级高于其他兜底判断。

调用图:调用 1 个内部函数(assert_exec_approval_requirement_for_command);外部调用 1 个(vec!)。

absolute_path_exec_approval_requirement_matches_host_executable_rules969–993 ↗
async fn absolute_path_exec_approval_requirement_matches_host_executable_rules()

作用:测试用绝对路径运行 git 时,如果规则声明这个路径就是 git,仍能匹配 git 规则。

数据流:生成 /usr/bin/git 之类路径,写 host_executable 和允许 git 的规则 → 检查绝对路径 git status → 输出跳过确认并绕过沙箱。

调用关系:它依赖 host_program_path 和 starlark_string 搭规则,验证主机程序映射功能。

调用图:调用 4 个内部函数(assert_exec_approval_requirement_for_command, host_program_path, starlark_string, read_only);外部调用 2 个(format!, vec!)。

absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths996–1029 ↗
async fn absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths()

作用:测试没有被 host_executable 允许的绝对路径,不会被当成 git 来匹配策略。

数据流:规则只允许一个 git 路径,却输入另一个 git 路径 → 策略不按 git prompt 处理 → 输出在沙箱内跳过,并建议原始绝对路径命令。

调用关系:它防止攻击者用另一个同名程序冒充被允许的主机程序。

调用图:调用 5 个内部函数(assert_exec_approval_requirement_for_command, host_absolute_path, host_program_path, starlark_string, read_only);外部调用 4 个(new, cfg!, format!, vec!)。

requested_prefix_rule_can_approve_absolute_path_commands1032–1055 ↗
async fn requested_prefix_rule_can_approve_absolute_path_commands()

作用:测试用户请求的前缀规则可以把绝对路径 cargo 命令归并成 cargo install 建议。

数据流:输入绝对路径 cargo install cargo-insta,并给出 cargo install 前缀请求 → 审批需要确认,建议新增 cargo install 规则。

调用关系:它覆盖人工请求规则与绝对路径命令归一化的配合。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

exec_approval_requirement_respects_approval_policy1058–1073 ↗
async fn exec_approval_requirement_respects_approval_policy()

作用:测试当全局审批策略是 Never 时,原本需要确认的命令会变成禁止。

数据流:写 rm 需要 prompt 的规则,审批策略设为 Never → 检查 rm → 输出 Forbidden 和冲突原因。

调用关系:它保证“永不询问用户”的模式不会偷偷弹确认,而是直接拒绝需要确认的命令。

调用图:调用 1 个内部函数(assert_exec_approval_requirement_for_command);外部调用 1 个(vec!)。

unmatched_granular_policy_still_prompts_for_restricted_sandbox_escalation1076–1099 ↗
fn unmatched_granular_policy_still_prompts_for_restricted_sandbox_escalation()

作用:测试细粒度审批模式下,未知命令如果要求沙箱提权,仍会提示用户。

数据流:输入 madeup-cmd 和要求提权的上下文 → 调用未匹配命令决策函数 → 输出 Prompt。

调用关系:它直接测试 render_decision_for_unmatched_command 的沙箱提权分支。

调用图:外部调用 2 个(assert_eq!, vec!)。

unmatched_on_request_uses_permission_profile_file_system_policy_for_escalation_prompts1102–1119 ↗
fn unmatched_on_request_uses_permission_profile_file_system_policy_for_escalation_prompts()

作用:测试 OnRequest 模式下,未知命令提权会参考权限配置并提示。

数据流:输入未知命令、只读权限和要求提权 → 决策函数判断需要用户确认 → 输出 Prompt。

调用关系:它验证普通请求审批模式和权限配置之间的联动。

调用图:外部调用 2 个(assert_eq!, vec!)。

known_safe_on_request_still_prompts_for_restricted_sandbox_escalation1122–1139 ↗
fn known_safe_on_request_still_prompts_for_restricted_sandbox_escalation()

作用:测试即使是 echo 这种看起来安全的命令,在受限 Windows 沙箱提权时也要提示。

数据流:输入 echo hello、工作区写权限、受限令牌沙箱和提权请求 → 输出 Prompt。

调用关系:它覆盖“命令安全”和“沙箱提权”同时存在时,提权要求不能被忽略。

调用图:外部调用 2 个(assert_eq!, vec!)。

managed_cwd_write_profile_has_filesystem_restrictions1142–1165 ↗
fn managed_cwd_write_profile_has_filesystem_restrictions()

作用:测试只允许项目目录写入的权限配置会被识别为有文件系统限制。

数据流:构造根目录只读、项目根可写的文件系统策略 → 转成 PermissionProfile → 判断结果为有限制。

调用关系:它验证 profile_has_managed_filesystem_restrictions 对常见工作区写权限的识别。

调用图:调用 2 个内部函数(from_runtime_permissions, restricted);外部调用 2 个(assert!, vec!)。

managed_unresolvable_write_profile_has_filesystem_restrictions1168–1194 ↗
fn managed_unresolvable_write_profile_has_filesystem_restrictions()

作用:测试包含未来未知特殊路径的写权限,也会保守地认为有文件系统限制。

数据流:构造根目录只读、未知特殊路径可写的策略 → 转成权限配置 → 判断为有限制。

调用关系:它防止系统因为不认识新特殊路径就误判为无限制。

调用图:调用 2 个内部函数(from_runtime_permissions, restricted);外部调用 2 个(assert!, vec!)。

managed_full_disk_write_profile_has_no_filesystem_restrictions1197–1213 ↗
fn managed_full_disk_write_profile_has_no_filesystem_restrictions()

作用:测试根目录可写等于几乎全盘可写,不应被当作有文件系统限制。

数据流:构造根目录写权限策略 → 转成权限配置 → 判断结果为没有受控文件限制。

调用关系:它给 profile_has_managed_filesystem_restrictions 提供反例。

调用图:调用 2 个内部函数(from_runtime_permissions, restricted);外部调用 2 个(assert!, vec!)。

exec_approval_requirement_prompts_for_inline_additional_permissions_under_on_request1216–1239 ↗
async fn exec_approval_requirement_prompts_for_inline_additional_permissions_under_on_request()

作用:测试命令请求额外权限时,在 OnRequest 模式下需要用户确认。

数据流:输入 touch 文件命令,只读权限,并声明有额外权限请求 → 输出 NeedsApproval,并建议 touch 命令规则。

调用关系:它覆盖 inline additional permissions 对审批结果的影响。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

exec_approval_requirement_prompts_for_known_safe_escalation_under_on_request1242–1261 ↗
async fn exec_approval_requirement_prompts_for_known_safe_escalation_under_on_request()

作用:测试安全命令如果要求沙箱提权,在 OnRequest 模式下也需要确认。

数据流:输入 echo hello、工作区写权限、要求提权 → 输出 NeedsApproval,并建议 echo hello 规则。

调用关系:它和未匹配命令测试一起保证提权不是小事。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, workspace_write);外部调用 2 个(new, vec!)。

exec_approval_requirement_rejects_known_safe_escalation_when_granular_sandbox_is_disabled1264–1286 ↗
async fn exec_approval_requirement_rejects_known_safe_escalation_when_granular_sandbox_is_disabled()

作用:测试细粒度审批里如果关闭沙箱审批,安全命令的提权请求也会被拒绝。

数据流:输入 echo hello,细粒度配置 sandbox_approval=false → 输出 Forbidden 和拒绝沙箱审批原因。

调用关系:它验证 GranularApprovalConfig 的 sandbox_approval 开关会被严格执行。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, workspace_write);外部调用 2 个(Granular, vec!)。

exec_approval_requirement_rejects_unmatched_sandbox_escalation_when_granular_sandbox_is_disabled1289–1311 ↗
async fn exec_approval_requirement_rejects_unmatched_sandbox_escalation_when_granular_sandbox_is_disabled()

作用:测试未知命令提权时,如果细粒度沙箱审批关闭,会直接拒绝。

数据流:输入 madeup-cmd 和 sandbox_approval=false → 审批器返回 Forbidden。

调用关系:它是上一项的未知命令版本,确保不同命令类型都遵守同一开关。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(Granular, vec!)。

mixed_rule_and_sandbox_prompt_prioritizes_rule_for_rejection_decision1314–1348 ↗
async fn mixed_rule_and_sandbox_prompt_prioritizes_rule_for_rejection_decision()

作用:测试命令同时触发规则确认和沙箱提权确认时,规则确认这条线会优先进入审批结果。

数据流:写 git prompt 规则,输入 bash 脚本里 git status && madeup-cmd,并要求提权 → 结果为 NeedsApproval。

调用关系:它直接构造 ExecPolicyManager,检查混合场景下的优先级。

调用图:调用 3 个内部函数(new, new, read_only);外部调用 4 个(new, Granular, assert!, vec!)。

mixed_rule_and_sandbox_prompt_rejects_when_granular_rules_are_disabled1351–1387 ↗
async fn mixed_rule_and_sandbox_prompt_rejects_when_granular_rules_are_disabled()

作用:测试混合场景中,如果细粒度配置关闭规则审批,会因为规则确认被禁而拒绝。

数据流:同样输入 git prompt 加沙箱提权,但 rules=false → 输出 Forbidden,原因是规则审批被关闭。

调用关系:它说明在多个确认原因同时存在时,禁用规则审批会压过沙箱审批允许。

调用图:调用 3 个内部函数(new, new, read_only);外部调用 4 个(new, Granular, assert_eq!, vec!)。

exec_approval_requirement_falls_back_to_heuristics1390–1412 ↗
async fn exec_approval_requirement_falls_back_to_heuristics()

作用:测试没有显式策略时,系统会用启发式规则判断命令。启发式就是内置经验规则。

数据流:输入 cargo build、空策略、UnlessTrusted 和只读权限 → 审批结果需要确认,并建议 cargo build 规则。

调用关系:它验证 ExecPolicyManager::default 的兜底路径。

调用图:调用 2 个内部函数(default, read_only);外部调用 2 个(assert_eq!, vec!)。

empty_bash_lc_script_falls_back_to_original_command1415–1437 ↗
async fn empty_bash_lc_script_falls_back_to_original_command()

作用:测试空 bash -lc 脚本在审批时会按原始命令处理。

数据流:输入 bash -lc '' → 解析没有内部命令 → 输出 NeedsApproval,建议原始 bash -lc 命令。

调用关系:它把 commands_for_exec_policy 的空脚本兜底行为放到完整审批流程里验证。

调用图:调用 2 个内部函数(default, read_only);外部调用 2 个(assert_eq!, vec!)。

whitespace_bash_lc_script_falls_back_to_original_command1440–1466 ↗
async fn whitespace_bash_lc_script_falls_back_to_original_command()

作用:测试只有空白的 bash -lc 脚本在审批时也按原始命令处理。

数据流:输入 bash -lc 加空白字符串 → 审批器回退到原始命令 → 输出 NeedsApproval 和原始命令建议。

调用关系:它是完整审批流程中的空白脚本兜底测试。

调用图:调用 2 个内部函数(default, read_only);外部调用 2 个(assert_eq!, vec!)。

request_rule_uses_prefix_rule1469–1498 ↗
async fn request_rule_uses_prefix_rule()

作用:测试用户指定的前缀规则会用于生成审批建议。

数据流:输入 cargo install cargo-insta,并请求 cargo install 前缀 → 输出 NeedsApproval,建议新增 cargo install。

调用关系:它验证 prefix_rule 参数会影响 proposed_execpolicy_amendment。

调用图:调用 2 个内部函数(default, read_only);外部调用 2 个(assert_eq!, vec!)。

request_rule_falls_back_when_prefix_rule_does_not_approve_all_commands1501–1531 ↗
async fn request_rule_falls_back_when_prefix_rule_does_not_approve_all_commands()

作用:测试用户请求的前缀规则不能覆盖脚本里所有命令时,会改用真正未覆盖的命令。

数据流:输入 cargo install && rm -rf 脚本,请求 cargo install 前缀 → cargo 部分可覆盖,但 rm 不行 → 建议 rm -rf 规则。

调用关系:它防止一个窄规则被误用来批准整段危险脚本。

调用图:调用 1 个内部函数(default);外部调用 2 个(assert_eq!, vec!)。

heuristics_apply_when_other_commands_match_policy1534–1565 ↗
async fn heuristics_apply_when_other_commands_match_policy()

作用:测试脚本里一部分命令命中策略时,另一部分仍会走启发式判断。

数据流:策略允许 apple,输入 apple | orange → apple 匹配策略,orange 无匹配 → 输出需要确认并建议 orange。

调用关系:它验证多命令脚本不是只要一个命中策略就全部放行。

调用图:调用 1 个内部函数(new);外部调用 3 个(new, assert_eq!, vec!)。

append_execpolicy_amendment_updates_policy_and_file1568–1598 ↗
async fn append_execpolicy_amendment_updates_policy_and_file()

作用:测试追加一条执行策略修正后,内存策略和磁盘规则文件都会更新。

数据流:输入 echo hello 修正 → manager 写入默认规则文件并更新当前策略 → 检查 echo hello world 被允许,文件内容也正确。

调用关系:它验证 append_amendment_and_update 的两个结果:立即生效和持久保存。

调用图:调用 2 个内部函数(from, default);外部调用 5 个(assert!, assert_eq!, read_to_string, tempdir, vec!)。

append_execpolicy_amendment_rejects_empty_prefix1601–1616 ↗
async fn append_execpolicy_amendment_rejects_empty_prefix()

作用:测试不能追加空前缀规则,因为空规则没有明确含义且可能过宽。

数据流:输入空 Vec 作为修正 → append_amendment_and_update 返回错误 → 断言错误类型是 EmptyPrefix。

调用关系:它保护规则写入入口,避免生成危险或无效规则。

调用图:调用 2 个内部函数(from, default);外部调用 3 个(assert!, tempdir, vec!)。

proposed_execpolicy_amendment_is_present_for_single_command_without_policy_match1619–1637 ↗
async fn proposed_execpolicy_amendment_is_present_for_single_command_without_policy_match()

作用:测试单个命令没有匹配策略时,会给出可添加的规则建议。

数据流:输入 cargo build 和空策略 → 审批需要确认 → 输出 proposed_execpolicy_amendment 为 cargo build。

调用关系:它验证系统能帮用户把确认操作转成未来可复用的规则。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

proposed_execpolicy_amendment_is_omitted_when_policy_prompts1640–1656 ↗
async fn proposed_execpolicy_amendment_is_omitted_when_policy_prompts()

作用:测试如果已有策略明确要求确认,就不会再建议新增规则。

数据流:写 rm prompt 规则 → 检查 rm → 输出 NeedsApproval,原因来自策略,规则建议为空。

调用关系:它避免对已经被策略覆盖的命令重复建议。

调用图:调用 1 个内部函数(assert_exec_approval_requirement_for_command);外部调用 1 个(vec!)。

proposed_execpolicy_amendment_is_present_for_multi_command_scripts1659–1682 ↗
async fn proposed_execpolicy_amendment_is_present_for_multi_command_scripts()

作用:测试多命令脚本没有策略匹配时,会建议第一个需要处理的命令。

数据流:输入 cargo build && echo ok → 解析成多个命令 → 输出 NeedsApproval,建议 cargo build。

调用关系:它验证多段 shell 脚本的建议选择规则。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

proposed_execpolicy_amendment_uses_first_no_match_in_multi_command_scripts1685–1710 ↗
async fn proposed_execpolicy_amendment_uses_first_no_match_in_multi_command_scripts()

作用:测试多命令脚本中前面命令已被允许时,会建议第一个没有匹配的命令。

数据流:策略允许 cat,输入 cat && apple → cat 跳过,apple 无匹配 → 输出建议 apple。

调用关系:它保证规则建议对准真正缺规则的那一段。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

proposed_execpolicy_amendment_is_present_when_heuristics_allow1713–1731 ↗
async fn proposed_execpolicy_amendment_is_present_when_heuristics_allow()

作用:测试即使命令被内置启发式认为安全,也可以给出规则建议。

数据流:输入 echo safe,OnRequest 和只读权限 → 审批跳过确认但不绕过沙箱,同时建议 echo safe 规则。

调用关系:它让用户有机会把内置判断固化成显式策略。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 2 个(new, vec!)。

proposed_execpolicy_amendment_is_suppressed_when_policy_matches_allow1734–1754 ↗
async fn proposed_execpolicy_amendment_is_suppressed_when_policy_matches_allow()

作用:测试已有 allow 策略匹配时,不再建议新增规则。

数据流:策略允许 python3,输入 python3 -c print(1) → 输出跳过确认、绕过沙箱、无规则建议。

调用关系:它确认显式允许规则已经足够,不需要重复生成 amendment。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

multi_segment_shell_requires_policy_allow_for_every_segment_to_bypass_sandbox1757–1785 ↗
async fn multi_segment_shell_requires_policy_allow_for_every_segment_to_bypass_sandbox()

作用:测试多段 shell 脚本只有部分命令被 allow 时,不能绕过沙箱。

数据流:策略只允许 cat,脚本还有 curl 和 bash → 在 OnRequest 与 Never 下检查 → 输出跳过确认但不绕过沙箱。

调用关系:它确保绕过沙箱必须非常严格:每一段都要被明确允许。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, workspace_write);外部调用 1 个(vec!)。

multi_segment_shell_bypasses_sandbox_when_every_segment_matches_policy_allow1788–1815 ↗
async fn multi_segment_shell_bypasses_sandbox_when_every_segment_matches_policy_allow()

作用:测试多段 shell 脚本每一段都被 allow 策略覆盖时,才可以绕过沙箱。

数据流:策略允许 cat、curl、bash,输入三段脚本 → 审批结果跳过确认并绕过沙箱。

调用关系:它是上一项的正例,说明绕过沙箱的条件是什么。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, read_only);外部调用 1 个(vec!)。

derive_requested_execpolicy_amendment_for_test1817–1833 ↗
fn derive_requested_execpolicy_amendment_for_test(
    prefix_rule: Option<&Vec<String>>,
    matched_rules: &[RuleMatch],
) -> Option<ExecPolicyAmendment>

作用:测试专用的小包装,用更少参数调用“根据用户请求前缀生成规则建议”的真实函数。

数据流:输入可选前缀规则和已匹配规则列表 → 准备默认命令、空策略、默认匹配选项 → 输出可能的 ExecPolicyAmendment。

调用关系:后面一组 derive_requested_execpolicy_amendment 测试都通过它间接测试真实推导逻辑。

调用图:外部调用 2 个(empty, default)。

derive_requested_execpolicy_amendment_returns_none_for_missing_prefix_rule1836–1841 ↗
fn derive_requested_execpolicy_amendment_returns_none_for_missing_prefix_rule()

作用:测试用户没有提供前缀规则时,不会生成请求型规则建议。

数据流:输入 None 和空匹配列表 → 调用测试包装 → 输出 None。

调用关系:它覆盖规则建议推导的无输入情况。

调用图:外部调用 1 个(assert_eq!)。

derive_requested_execpolicy_amendment_returns_none_for_empty_prefix_rule1844–1849 ↗
fn derive_requested_execpolicy_amendment_returns_none_for_empty_prefix_rule()

作用:测试空前缀规则不会生成建议。

数据流:输入空 Vec 作为前缀 → 推导函数拒绝 → 输出 None。

调用关系:它和追加空规则测试一起防止无意义规则进入系统。

调用图:外部调用 1 个(assert_eq!)。

derive_requested_execpolicy_amendment_returns_none_for_exact_banned_prefix_rule1852–1860 ↗
fn derive_requested_execpolicy_amendment_returns_none_for_exact_banned_prefix_rule()

作用:测试某些危险的精确前缀,比如 python -c,不会被自动建议。

数据流:输入 python -c 前缀 → 推导函数识别为禁用模式 → 输出 None。

调用关系:它防止自动批准可执行任意代码的解释器入口。

调用图:外部调用 1 个(assert_eq!)。

derive_requested_execpolicy_amendment_returns_none_for_windows_and_pypy_variants1863–1877 ↗
fn derive_requested_execpolicy_amendment_returns_none_for_windows_and_pypy_variants()

作用:测试 py、pythonw、pypy 等 Python 变体也不会被轻易建议为规则。

数据流:逐个输入这些前缀 → 每次推导 → 都输出 None。

调用关系:它补齐不同平台和不同 Python 命令名的风险覆盖。

调用图:外部调用 2 个(assert_eq!, vec!)。

derive_requested_execpolicy_amendment_returns_none_for_shell_and_powershell_variants1880–1903 ↗
fn derive_requested_execpolicy_amendment_returns_none_for_shell_and_powershell_variants()

作用:测试 bash、sh、zsh、PowerShell 等 shell 入口不会被自动建议成允许规则。

数据流:逐个输入各种 shell 或 powershell 前缀 → 推导函数判断太宽泛或危险 → 输出 None。

调用关系:它避免生成“允许 shell”这种几乎等于允许任意命令的规则。

调用图:外部调用 2 个(assert_eq!, vec!)。

derive_requested_execpolicy_amendment_allows_non_exact_banned_prefix_rule_match1906–1917 ↗
fn derive_requested_execpolicy_amendment_allows_non_exact_banned_prefix_rule_match()

作用:测试虽然 python -c 本身被禁,但更具体到完整代码的前缀可以生成建议。

数据流:输入 python -c print('hi') → 推导函数认为足够具体 → 输出对应 ExecPolicyAmendment。

调用关系:它说明禁用名单不是一刀切,而是防止过宽规则。

调用图:外部调用 2 个(assert_eq!, vec!)。

derive_requested_execpolicy_amendment_returns_none_when_policy_matches1920–1959 ↗
fn derive_requested_execpolicy_amendment_returns_none_when_policy_matches()

作用:测试只要已有策略匹配,无论是 prompt、allow 还是 forbidden,都不生成请求规则建议。

数据流:输入 cargo build 前缀,并分别提供三种已匹配规则 → 每次推导都输出 None。

调用关系:它避免用户请求规则覆盖或重复已有策略判断。

调用图:外部调用 2 个(assert_eq!, vec!)。

dangerous_rm_rf_requires_approval_in_danger_full_access1962–1980 ↗
async fn dangerous_rm_rf_requires_approval_in_danger_full_access()

作用:测试 rm -rf 这种危险命令在无沙箱的高风险配置下仍需要用户确认。

数据流:输入 rm -rf /tmp/nonexistent、OnRequest、禁用权限沙箱 → 输出 NeedsApproval,并建议该命令规则。

调用关系:它验证危险命令启发式不会因为全权限模式而直接放行。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, vec_str);外部调用 1 个(new)。

vec_str1982–1984 ↗
fn vec_str(items: &[&str]) -> Vec<String>

作用:把字符串切片快速转换成 Vec<String>,让测试命令写起来更短。

数据流:输入 &[&str] → 每个元素转成 String → 输出 Vec<String>。

调用关系:危险命令和 PowerShell 测试用它构造命令数组。

调用图:被 4 处调用(dangerous_command_allowed_when_sandbox_is_explicitly_disabled, dangerous_command_forbidden_in_external_sandbox_when_policy_matches, dangerous_rm_rf_requires_approval_in_danger_full_access, verify_approval_requirement_for_unsafe_powershell_command)。

verify_approval_requirement_for_unsafe_powershell_command1989–2086 ↗
async fn verify_approval_requirement_for_unsafe_powershell_command()

作用:测试 PowerShell 里看似 echo、实则可能执行表达式的命令,在不同平台上的审批行为。

数据流:如果机器没有 pwsh 就跳过 → 构造可疑 PowerShell 命令和危险 rm 命令 → 分别检查 Windows、非 Windows、AskForApproval::Never 下的结果。

调用关系:它直接用 ExecPolicyManager 检查跨平台安全差异,并用 vec_str 生成命令。

调用图:调用 2 个内部函数(new, vec_str);外部调用 6 个(new, new, assert_eq!, cfg!, empty, which)。

dangerous_command_allowed_when_sandbox_is_explicitly_disabled2089–2110 ↗
async fn dangerous_command_allowed_when_sandbox_is_explicitly_disabled()

作用:测试当权限配置表示使用外部沙箱时,危险命令在没有策略匹配时可以跳过内置审批。

数据流:输入 rm -rf,审批策略 Never,权限为 External → 输出 Skip,并带该命令建议。

调用关系:它覆盖外部沙箱模式下的特殊信任路径。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, vec_str)。

dangerous_command_forbidden_in_external_sandbox_when_policy_matches2113–2131 ↗
async fn dangerous_command_forbidden_in_external_sandbox_when_policy_matches()

作用:测试即使使用外部沙箱,只要显式策略要求确认而审批策略又是 Never,就必须拒绝。

数据流:写 rm prompt 规则,输入 rm -rf,审批策略 Never,权限为 External → 输出 Forbidden。

调用关系:它说明外部沙箱不能绕过明确的执行策略规则。

调用图:调用 2 个内部函数(assert_exec_approval_requirement_for_command, vec_str)。

policy_from_src2143–2152 ↗
fn policy_from_src(policy_src: Option<&str>) -> Arc<Policy>

作用:把测试里的规则源码字符串变成 Policy 对象;没有源码就返回空策略。

数据流:输入 Option<&str> → 有内容时用 PolicyParser 解析并 build,没有内容时创建空 Policy → 输出 Arc<Policy> 共享指针。

调用关系:exec_approval_requirement_for_command 用它统一准备策略,避免每个测试重复解析代码。

调用图:调用 1 个内部函数(new);被 1 处调用(exec_approval_requirement_for_command);外部调用 2 个(new, empty)。

exec_approval_requirement_for_command2154–2178 ↗
async fn exec_approval_requirement_for_command(
    test: ExecApprovalRequirementScenario,
) -> ExecApprovalRequirement

作用:测试专用执行器:给一组场景参数,算出这个命令最终需要什么审批。

数据流:输入 ExecApprovalRequirementScenario → 解析策略,创建 ExecPolicyManager,组装 ExecApprovalRequest → 输出 ExecApprovalRequirement。

调用关系:assert_exec_approval_requirement_for_command 调它,众多审批测试通过这个助手保持写法一致。

调用图:调用 2 个内部函数(new, policy_from_src);被 1 处调用(assert_exec_approval_requirement_for_command)。

assert_exec_approval_requirement_for_command2180–2186 ↗
async fn assert_exec_approval_requirement_for_command(
    test: ExecApprovalRequirementScenario,
    expected_requirement: ExecApprovalRequirement,
)

作用:测试专用断言:计算命令审批要求,并和期望值比较。

数据流:输入测试场景和期望结果 → 调用 exec_approval_requirement_for_command → 用 assert_eq 检查实际等于期望。

调用关系:大多数审批行为测试都用它,像一个统一裁判,减少重复代码。

调用图:调用 1 个内部函数(exec_approval_requirement_for_command);被 29 处调用(absolute_path_exec_approval_requirement_ignores_disallowed_host_executable_paths, absolute_path_exec_approval_requirement_matches_host_executable_rules, dangerous_command_allowed_when_sandbox_is_explicitly_disabled, dangerous_command_forbidden_in_external_sandbox_when_policy_matches, dangerous_rm_rf_requires_approval_in_danger_full_access, drops_requested_amendment_for_heredoc_fallback_prompts_when_it_matches, drops_requested_amendment_for_heredoc_fallback_prompts_when_it_wont_match, evaluates_bash_lc_inner_commands, evaluates_heredoc_script_against_prefix_rules, exec_approval_requirement_prefers_execpolicy_match (+15 more));外部调用 1 个(assert_eq!)。

exec_policies_only_load_from_trusted_project_layers2189–2234 ↗
async fn exec_policies_only_load_from_trusted_project_layers() -> std::io::Result<()>

作用:测试嵌套项目里,只会加载被信任项目层的执行策略。

数据流:创建项目根和 nested 两套 rules,信任 nested → 构建配置并加载策略 → rm 来自根规则不生效,mv 来自 nested 规则生效。

调用关系:它用 write_project_trust_config 设置可信项目,验证项目层选择逻辑。

调用图:调用 1 个内部函数(write_project_trust_config);外部调用 5 个(assert_eq!, default, create_dir_all, write, tempdir)。

exec_policies_require_project_trust_without_config_toml2237–2292 ↗
async fn exec_policies_require_project_trust_without_config_toml() -> std::io::Result<()>

作用:测试即使项目没有 config.toml,项目规则也必须在项目被信任后才会加载。

数据流:创建项目规则禁止 rm,然后分别设置 unknown、untrusted、trusted 三种信任状态 → 加载策略 → 只有 trusted 时 rm 被禁止。

调用关系:它验证项目信任不是依赖 config.toml 是否存在,而是独立安全要求。

调用图:调用 1 个内部函数(write_project_trust_config);外部调用 8 个(new, assert_eq!, default, format!, create_dir_all, write, tempdir, vec!)。

exec_policy_warnings_ignore_untrusted_project_rules_without_config_toml2295–2342 ↗
async fn exec_policy_warnings_ignore_untrusted_project_rules_without_config_toml() -> std::io::Result<()>

作用:测试不可信项目里的坏规则不会产生警告,可信项目里的坏规则才会报告解析错误。

数据流:写一个语法错误的 broken.rules,分别设置 unknown、untrusted、trusted → 调用警告检查 → 只有 trusted 情况返回解析警告。

调用关系:它和项目信任加载测试配套,确保警告系统也遵守同一信任边界。

调用图:调用 1 个内部函数(write_project_trust_config);外部调用 8 个(new, assert_eq!, default, format!, create_dir_all, write, tempdir, vec!)。

core/src/exec_policy_windows_tests.rs源码 ↗
testtest

这是一组测试,像安检演练一样,拿不同 Windows 命令去试执行策略。执行策略就是系统决定一条命令是直接放行、需要用户批准,还是直接禁止的规则。Windows 上麻烦的一点是,很多命令会藏在 powershell.exe -Command ... 里面;如果只看见 PowerShell 本身,就可能放过里面的 Remove-Item 这类删除命令。这个文件验证系统会把 PowerShell 外壳拆开,看里面真正要跑什么;也验证“允许规则”和“询问规则”能正确作用到里面的命令。它还检查没有匹配到规则时的默认行为:安全的 PowerShell 读文件命令可以放行;有 Windows 沙箱(一种把程序关在受限环境里的保护层)时,未知命令可在沙箱里跑;没有沙箱又不允许询问用户时,就要禁止。整体上,这个文件是在保护 Windows 执行安全规则不被回归改坏。

函数细节8
evaluates_powershell_inner_commands_against_prompt_rules5–25 ↗
async fn evaluates_powershell_inner_commands_against_prompt_rules()

作用:这个测试确认:如果策略说某个命令前缀要“询问用户”,但当前设置又是不允许询问,那么藏在 PowerShell 里的这条命令必须被禁止。它防止系统因为命令外面包了 powershell.exe 就绕过提示规则。

数据流:测试先构造一条命令:外层是 powershell.exe -Command,内层是真正的 echo blocked。再给它一条策略:遇到 echo 要提示用户。因为审批设置是“永不询问”,提示无法发生,所以期望结果从“待判断的命令”变成“禁止执行,并说明是提示规则冲突”。

调用关系:它把完整场景交给测试辅助流程 assert_exec_approval_requirement_for_command 去跑,自己只准备输入和期望结果。构造命令列表时使用 vec! 这样的 Rust 列表宏;真正的策略判断发生在被测的执行策略代码里。

调用图:外部调用 1 个(vec!)。

evaluates_powershell_inner_commands_against_allow_rules28–49 ↗
async fn evaluates_powershell_inner_commands_against_allow_rules()

作用:这个测试确认:如果策略明确允许某个命令,那么即使它藏在 PowerShell 的 -Command 后面,也应该被识别出来并放行。它防止系统误把安全白名单命令当成陌生命令。

数据流:测试输入是一条 PowerShell 包装命令,里面实际运行 echo blocked。同时提供一条允许 echo 的规则、一个只读权限配置,以及“除非可信否则要问”的审批模式。判断之后,期望输出是跳过审批并允许执行,而且可以绕过沙箱,因为规则已经明确放行。

调用关系:它会调用 PermissionProfile::read_only 准备只读权限环境,再把场景交给 assert_exec_approval_requirement_for_command 检查。这个测试和前一个测试形成一正一反:一个验证提示规则会生效,一个验证允许规则也会生效。

调用图:调用 1 个内部函数(read_only);外部调用 1 个(vec!)。

commands_for_exec_policy_parses_powershell_shell_wrapper52–68 ↗
fn commands_for_exec_policy_parses_powershell_shell_wrapper()

作用:这个测试确认命令解析器能看懂 PowerShell 外壳,把 powershell.exe -Command "echo blocked" 拆成真正要执行的 echo blocked。这很重要,因为安全规则应该判断里面的命令,而不是只判断外面的 PowerShell 程序。

数据流:进去的是一个字符串列表,表示用户要启动 powershell.exe 并传入 -Command。函数 commands_for_exec_policy 会把它解析成执行策略真正要检查的命令列表。出来的期望结果是:命令变成 echoblocked 两个词,来源标记为 PowerShell,并且说明没有用到复杂解析。

调用关系:它直接调用被测解析函数 commands_for_exec_policy,再用 assert_eq! 比较实际结果和预期结果。这个测试为其他审批测试打基础:只有先能拆出内层命令,后面的允许、禁止、审批判断才有意义。

调用图:外部调用 2 个(assert_eq!, vec!)。

unmatched_safe_powershell_words_are_allowed71–88 ↗
fn unmatched_safe_powershell_words_are_allowed()

作用:这个测试确认:某些安全的 PowerShell 命令即使没有命中专门规则,也可以在只读场景下放行。这里的例子是 Get-Content Cargo.toml,大体相当于读取一个文件内容。

数据流:测试把 Get-Content Cargo.toml 作为待判断命令,并提供上下文:审批策略是“除非可信否则询问”、权限是只读、Windows 沙箱关闭、命令来源是 PowerShell。判断函数根据这些信息认为它是安全读操作,输出结果是允许执行。

调用关系:它直接调用 render_decision_for_unmatched_command,这是处理“没有匹配到明确规则的命令”的判断入口,然后用 assert_eq! 确认结果是 Decision::Allow。它补充验证了默认规则不是一刀切禁止,而是会区分安全读操作。

调用图:外部调用 2 个(assert_eq!, vec!)。

read_only_windows_sandbox_runs_unmatched_commands_under_sandbox91–113 ↗
fn read_only_windows_sandbox_runs_unmatched_commands_under_sandbox()

作用:这个测试确认:在 Windows 沙箱可用时,只读策略下的陌生命令可以被允许,因为它会被限制在沙箱里运行。沙箱可以理解成一个隔离房间,命令即使运行也不能随便改外面的东西。

数据流:测试使用 cmd.exe /c dir 这个没有专门匹配规则的命令,并分别放到两种 Windows 沙箱级别里检查。输入上下文包含“永不询问用户”、只读权限、沙箱启用。判断结果应当都是允许,因为系统可以依赖沙箱来限制风险。

调用关系:它在循环里两次调用 render_decision_for_unmatched_command,分别覆盖 RestrictedTokenElevated 两种沙箱级别,并用 assert_eq! 验证两者都允许。它和后面“没有沙箱时禁止”的测试形成对照。

调用图:外部调用 2 个(assert_eq!, vec!)。

read_only_windows_policy_without_sandbox_backend_still_requires_approval116–134 ↗
fn read_only_windows_policy_without_sandbox_backend_still_requires_approval()

作用:这个测试确认:如果 Windows 沙箱不可用,即使权限配置是只读,陌生命令也不能在“永不询问”的模式下直接放行。它防止系统以为有只读策略就安全,但实际上没有底层沙箱来执行这个限制。

数据流:测试输入是 cmd.exe /c dir,上下文是只读权限、审批策略为永不询问、Windows 沙箱关闭。判断函数发现没有明确规则,也没有可依赖的沙箱保护,而用户审批又不允许发生,于是输出结果是禁止。

调用关系:它调用 render_decision_for_unmatched_command 做默认决策,再用 assert_eq! 检查结果是 Decision::Forbidden。它紧接着前一个沙箱放行测试,说明“只读策略”必须有实际沙箱后端支撑,否则不能盲目信任。

调用图:外部调用 2 个(assert_eq!, vec!)。

writable_windows_policy_without_sandbox_backend_still_requires_approval137–172 ↗
fn writable_windows_policy_without_sandbox_backend_still_requires_approval()

作用:这个测试确认:如果权限里允许写项目目录,但 Windows 沙箱不可用,那么陌生命令更不能直接放行。它防止可写权限在没有隔离保护时变成安全漏洞。

数据流:测试先搭出一个文件系统沙箱策略:根目录只读,项目目录可写;再把它转换成运行时权限配置。随后把 cmd.exe /c dir 放进判断函数,审批策略是永不询问,Windows 沙箱关闭。因为没有明确规则,也没有沙箱保证写权限边界,最终结果应是禁止执行。

调用关系:它先调用 FileSystemSandboxPolicy::restricted 创建受限文件系统规则,再调用 PermissionProfile::from_runtime_permissions 生成权限配置,最后交给 render_decision_for_unmatched_command 判断,并用 assert_eq! 验证禁止。这个测试覆盖了比只读更危险的“有写权限”情况。

调用图:调用 2 个内部函数(from_runtime_permissions, restricted);外部调用 2 个(assert_eq!, vec!)。

unmatched_dangerous_powershell_inner_commands_require_approval175–202 ↗
async fn unmatched_dangerous_powershell_inner_commands_require_approval()

作用:这个测试确认:PowerShell 里面的危险命令如果没有命中任何规则,就应该要求用户批准,而不是自动放行。例子里的 Remove-Item test -Force 类似强制删除文件,风险明显更高。

数据流:测试先准备内层危险命令 Remove-Item test -Force,再构造外层 PowerShell 调用。没有提供额外策略,审批模式是“按请求询问”,权限配置是禁用沙箱。判断后,期望结果是需要审批,并且给出一个建议的执行策略补充项,意思是以后可以把这条命令作为规则记录下来。

调用关系:它通过 ExecPolicyAmendment::new 生成建议规则,再把完整场景交给 assert_exec_approval_requirement_for_command。它依赖 PowerShell 内层命令解析能力,也验证危险未匹配命令会进入审批流程,而不是被默认允许。

调用图:外部调用 2 个(new, vec!)。

core/src/safety_tests.rs源码 ↗
testtest

这个文件不是真正给用户运行的功能代码,而是给开发者用的“安全闸门检查表”。它用临时目录假装成一个项目,再制造各种补丁操作,比如在项目里新增文件、在项目外新增文件、改受保护的目录等。然后它把这些操作交给安全判断函数,看结果是不是符合预期。这里反复验证几类规则:工作区内能不能写、项目外要不要审批、只读模式是否必须拒绝、外部沙盒是否可以自动放行,以及某些明确标成不可写或只读的路径会不会挡住自动批准。可以把它理解成门禁系统的演练:有人要进门,有的人能直接进,有的人要保安确认,有的人绝对不能进。这个测试文件确保门禁规则不会被后续改代码时不小心弄坏。

函数细节8
test_writable_roots_constraint15–61 ↗
fn test_writable_roots_constraint()

作用:这个测试检查“只能写工作区”的规则是否真的生效。它确认项目目录里的文件可以改,项目外面的文件不可以改,除非那个外部目录被明确加入可写名单。

数据流:进去的是一个临时项目目录、两个准备新增文件的补丁:一个在项目里,一个在项目父目录里。测试先创建只允许写当前工作区的文件系统策略,然后检查内部补丁被允许、外部补丁被拦下。接着它把父目录加入可写范围,再确认外部补丁也能通过。出来的结果不是业务数据,而是一组断言:安全判断必须和预期一致。

调用关系:它主要验证底层的写路径约束函数 is_write_patch_constrained_to_writable_paths。测试中通过 workspace_write 构造文件系统策略,用临时目录隔离真实文件系统,并用断言把安全规则固定下来,防止以后改动把“项目外不能随便写”这条规则破坏掉。

调用图:调用 1 个内部函数(workspace_write);外部调用 3 个(new, assert!, from_ref)。

external_sandbox_auto_approves_in_on_request64–89 ↗
fn external_sandbox_auto_approves_in_on_request()

作用:这个测试确认在“外部沙盒”模式下,如果补丁写的是项目内部文件,并且审批策略是按需询问,那么系统可以自动批准,不必打扰用户。沙盒可以理解成一个隔离笼子,用来限制程序能碰哪些东西。

数据流:进去的是一个临时项目目录、一个在项目内新增文件的补丁、一个外部沙盒权限配置,以及“需要时再问用户”的审批模式。测试把这些交给 assess_patch_safety 做安全评估。出来的结果必须是 AutoApprove,也就是自动放行,并且说明没有额外沙盒包装、用户也没有显式批准。

调用关系:它直接测试 assess_patch_safety 的决策结果。补丁由 new_add_for_test 制造,文件系统策略由 external_sandbox 生成;最后用 assert_eq! 比较安全评估结果,确保外部沙盒模式不会对安全的项目内写入过度弹窗。

调用图:调用 2 个内部函数(new_add_for_test, external_sandbox);外部调用 2 个(new, assert_eq!)。

granular_with_all_flags_true_matches_on_request_for_out_of_root_patch92–134 ↗
fn granular_with_all_flags_true_matches_on_request_for_out_of_root_patch()

作用:这个测试检查“细粒度审批”在所有开关都打开时,是否和普通的“按需询问”表现一样。这里关注的是:如果补丁想写到项目外,系统应该问用户,而不是直接放行。

数据流:进去的是一个临时项目目录、一个写到项目父目录的补丁、工作区可写权限配置,以及两种审批模式:OnRequest 和 Granular。Granular 是更细的审批设置,里面每个开关代表一类事情是否允许弹出审批。测试分别把两种模式交给 assess_patch_safety。出来的结果都必须是 AskUser,表示需要用户确认。

调用关系:它把 granular 审批模式和老的 OnRequest 模式放在同一个场景里对照。权限配置由 workspace_write_with 创建,补丁由 new_add_for_test 创建,核心判断交给 assess_patch_safety;这个测试保证新审批模型在全开时不会改变已有安全行为。

调用图:调用 2 个内部函数(new_add_for_test, workspace_write_with);外部调用 2 个(new, assert_eq!)。

granular_sandbox_approval_false_rejects_out_of_root_patch137–170 ↗
fn granular_sandbox_approval_false_rejects_out_of_root_patch()

作用:这个测试确认如果细粒度审批里关闭了“沙盒审批”,那么写项目外文件不能再弹窗请求用户同意,而是要直接拒绝。这样可以防止某些配置明确禁止越界请求时,程序还绕去问用户。

数据流:进去的是一个临时项目目录、一个写到项目外的新增文件补丁、工作区写权限配置,以及一个 sandbox_approval 设为 false 的 Granular 审批配置。测试把这些输入交给 assess_patch_safety。出来的结果必须是 Reject,并带有“补丁在项目外被拒绝”的原因文字。

调用关系:它专门覆盖 assess_patch_safety 在细粒度审批关闭沙盒批准时的分支。workspace_write_with 负责制造只允许工作区写入的权限环境,new_add_for_test 负责制造越界补丁;最后断言系统不是 AskUser,而是直接拒绝。

调用图:调用 2 个内部函数(new_add_for_test, workspace_write_with);外部调用 2 个(new, assert_eq!)。

read_only_policy_rejects_patch_with_read_only_reason173–199 ↗
fn read_only_policy_rejects_patch_with_read_only_reason()

作用:这个测试检查只读模式是否真的禁止写文件。即使补丁写的是项目内部文件,只读策略下也必须拒绝,并且拒绝理由要说清楚是因为只读。

数据流:进去的是一个临时项目目录、一个在项目内新增文件的补丁,以及 read_only 创建的只读权限配置。测试先检查这个补丁不在可写范围内,然后把它交给 assess_patch_safety,并使用“永不请求批准”的审批模式。出来的结果必须是 Reject,原因必须是只读模式对应的拒绝说明。

调用关系:它先用 is_write_patch_constrained_to_writable_paths 验证底层路径可写判断,再用 assess_patch_safety 验证最终安全决策。read_only 提供权限配置,new_add_for_test 创建写入动作;这个测试保证只读模式不会被项目内路径这个条件误放行。

调用图:调用 2 个内部函数(new_add_for_test, read_only);外部调用 3 个(new, assert!, assert_eq!)。

explicit_unreadable_paths_prevent_auto_approval_for_external_sandbox201–241 ↗
fn explicit_unreadable_paths_prevent_auto_approval_for_external_sandbox()

作用:这个测试确认:即使外部沙盒总体允许写很多地方,只要某个具体文件被明确标成禁止访问,系统就不能自动批准写它。明确禁止的规则应该压过宽泛允许的规则。

数据流:进去的是一个临时项目目录、一个准备写 blocked.txt 的补丁、外部沙盒权限配置,以及一个自定义文件系统策略。这个策略先说根目录可写,又单独说 blocked.txt 禁止访问。测试先确认这个补丁不算安全可写,再交给 assess_patch_safety。出来的结果必须是 AskUser,而不是自动批准。

调用关系:它验证 restricted 构造出的细节权限规则会影响 assess_patch_safety 的自动批准判断。new_add_for_test 创建要写受阻文件的补丁,vec! 装入两条权限规则;测试通过断言确保“具体禁止路径”会阻止外部沙盒的自动放行。

调用图:调用 2 个内部函数(new_add_for_test, restricted);外部调用 4 个(new, assert!, assert_eq!, vec!)。

explicit_read_only_subpaths_prevent_auto_approval_for_external_sandbox244–285 ↗
fn explicit_read_only_subpaths_prevent_auto_approval_for_external_sandbox()

作用:这个测试检查一个更细的情况:项目整体可写,但项目里的某个子目录被标成只读时,写这个子目录下面的文件不能自动批准。它防止“上层允许写”不小心盖过“下层只读”。

数据流:进去的是一个临时项目目录、docs/blocked.txt 这个目标路径、外部沙盒权限配置,以及一个自定义文件系统策略。策略先允许项目根目录写入,再把 docs 子目录设为只读。测试用 resolve_path_against_base 算出 docs 的绝对路径,然后检查写 blocked.txt 不在可写范围内,并让 assess_patch_safety 做最终判断。出来的结果必须是 AskUser。

调用关系:它和前一个测试类似,但重点从“明确禁止某个文件”变成“某个子目录只读”。restricted 提供规则列表,resolve_path_against_base 保证子目录路径按项目目录正确解析,assess_patch_safety 负责给出最终是否自动批准的结论。

调用图:调用 3 个内部函数(new_add_for_test, restricted, resolve_path_against_base);外部调用 4 个(new, assert!, assert_eq!, vec!)。

missing_project_dot_codex_config_requires_approval288–325 ↗
fn missing_project_dot_codex_config_requires_approval()

作用:这个测试确认写入项目里的 .codex/config.toml 这类配置文件时,如果 .codex 目录被规则标成只读,就必须请求用户批准。配置文件通常会影响工具行为,所以不能因为它在项目内就随便自动改。

数据流:进去的是一个临时项目目录、一个准备新增 .codex/config.toml 的补丁、工作区可写权限配置,以及一条额外规则:把项目里的 .codex 目录设成只读。测试先确认该补丁不满足可写约束,再交给 assess_patch_safety。出来的结果必须是 AskUser,表示需要用户确认。

调用关系:它在 workspace_write_with 生成的默认工作区策略上追加一条更具体的只读规则,然后分别测试路径约束函数和最终安全评估函数。这个测试保证项目级配置目录的特殊限制会被尊重,不会被“工作区可写”这条大规则冲掉。

调用图:调用 2 个内部函数(new_add_for_test, workspace_write_with);外部调用 3 个(new, assert!, assert_eq!)。

core/src/mcp_tool_exposure_test.rs源码 ↗
testtest run

MCP 可以理解成“外部工具接口”,让模型能调用日历、搜索或其他服务。这个测试文件关心一个很实际的问题:哪些工具应该直接摆到模型面前,哪些不该出现,哪些应该放进“工具搜索”里以后再找。文件先准备假连接器和假工具,就像搭一套临时舞台;再用不同配置检查曝光结果。它覆盖了几种关键情况:工具数量少时直接展示,数量多时改为延后搜索;带有“只给 app 看”的工具不能暴露给模型;应用自己的开关配置能单独启用或禁用某个工具;还有一个功能开关会强制所有 MCP 工具都延后展示。这样可以保证模型看到的工具既不过多,也不会越权看到不该看的工具。

函数细节10
make_connector20–36 ↗
fn make_connector(id: &str, name: &str) -> AppInfo

作用:造一个假的应用连接器信息,供测试使用。连接器可以理解成“某个外部应用的入口”,比如日历应用。

数据流:输入一个连接器 id 和显示名称 → 把它们填进 AppInfo,并把其他不重要的字段留空或设成默认可用 → 输出一个测试用的 AppInfo,不改动外部状态。

调用关系:它是测试里的造数小工具。需要模拟某个应用存在时,测试会拿它做出连接器,再交给 MCP 工具曝光流程判断哪些应用工具能被展示。

调用图:外部调用 1 个(new)。

make_mcp_tool38–62 ↗
fn make_mcp_tool(
    server_name: &str,
    tool_name: &str,
    callable_namespace: &str,
    callable_name: &str,
    connector_id: Option<&str>,
    connector_name: Option<&str>,
) -> ToolInfo

作用:造一个假的 MCP 工具,省得每个测试都手写一大堆字段。MCP 工具就是模型可能调用的外部能力,比如“读取日历”。

数据流:输入服务器名、工具名、可调用的命名空间和函数名,以及可选的连接器信息 → 组装成 ToolInfo,里面带有工具描述和空的参数格式 → 输出一个完整的测试工具对象。

调用关系:它服务于多个测试场景,特别是 applies_per_tool_app_policy_across_the_exposure_build 和 excludes_tools_hidden_from_model_exposure。测试先用它造出候选工具,再把这些工具交给曝光构建流程,看最后哪些留下。

调用图:被 2 处调用(applies_per_tool_app_policy_across_the_exposure_build, excludes_tools_hidden_from_model_exposure);外部调用 5 个(new, default, new, format!, new)。

numbered_mcp_tools64–78 ↗
fn numbered_mcp_tools(count: usize) -> Vec<ToolInfo>

作用:批量造出一串编号工具,比如 tool_0、tool_1。它主要用来测试“工具数量多不多”会不会改变展示方式。

数据流:输入想要的数量 → 从 0 开始循环生成对应数量的工具名 → 每个编号都变成一个 ToolInfo → 输出一组测试工具。

调用关系:directly_exposes_small_effective_tool_sets 和 searches_large_effective_tool_sets 会用它制造刚好少于或达到阈值的工具集合,用来验证系统在小集合和大集合下走不同路径。

调用图:被 2 处调用(directly_exposes_small_effective_tool_sets, searches_large_effective_tool_sets)。

tool_names80–85 ↗
fn tool_names(tools: &[ToolInfo]) -> HashSet<ToolName>

作用:把一组工具转换成一组标准化工具名,方便测试比较结果。这样比较时不用关心工具对象里其他字段。

数据流:输入一组 ToolInfo → 逐个读取它们的规范名称 → 放进 HashSet,也就是不关心顺序、只关心有没有的集合 → 输出这组工具名集合。

调用关系:它常在断言前使用,帮助测试把“预期工具”和“实际曝光工具”变成同一种可比较的形式。always_defer_feature_defers_apps_too 会用它检查延后工具里是否包含指定工具。

调用图:被 1 处调用(always_defer_feature_defers_apps_too);外部调用 1 个(iter)。

with_visibility87–95 ↗
fn with_visibility(mut tool: ToolInfo, visibility: &[&str]) -> ToolInfo

作用:给一个测试工具加上可见性标记,模拟工具声明自己能给谁看。比如只给应用界面看,或者也给模型看。

数据流:输入一个 ToolInfo 和一组可见性字符串 → 把这些字符串写进工具的元数据 meta 字段 → 输出带有新可见性设置的 ToolInfo。

调用关系:excludes_tools_hidden_from_model_exposure 用它造出“隐藏给模型”和“允许给模型”的工具,然后验证曝光流程会尊重这些标记。

调用图:被 1 处调用(excludes_tools_hidden_from_model_exposure);外部调用 2 个(Meta, json!)。

directly_exposes_small_effective_tool_sets98–108 ↗
async fn directly_exposes_small_effective_tool_sets()

作用:测试工具数量少的时候,系统会把 MCP 工具直接展示给模型,而不是让模型先搜索。

数据流:先读取测试配置 → 生成比直接展示阈值少 1 个的工具 → 调用曝光构建流程 → 检查直接展示列表正好包含这些工具,并且没有延后工具。

调用关系:这是“小工具集”的基准测试。它调用 test_config 准备配置,调用 numbered_mcp_tools 准备工具,然后用断言确认 build_mcp_tool_exposure 的结果符合预期。

调用图:调用 2 个内部函数(test_config, numbered_mcp_tools);外部调用 2 个(assert!, assert_eq!)。

excludes_tools_hidden_from_model_exposure111–186 ↗
async fn excludes_tools_hidden_from_model_exposure()

作用:测试带有“不给模型看”标记的工具不会被暴露给模型。它防止用户界面专用工具误出现在模型可调用列表里。

数据流:先准备测试配置 → 造出普通可见工具、隐藏工具、空可见性工具、应用可见工具和应用隐藏工具 → 加上日历连接器 → 调用曝光构建流程 → 检查结果只剩明确可给模型用的工具。

调用关系:它调用 make_mcp_tool 造工具,调用 with_visibility 写入可见性元数据,再把这些工具交给曝光流程。最后用 tool_names 和断言确认隐藏规则真的生效。

调用图:调用 3 个内部函数(test_config, make_mcp_tool, with_visibility);外部调用 3 个(assert!, assert_eq!, vec!)。

applies_per_tool_app_policy_across_the_exposure_build189–237 ↗
async fn applies_per_tool_app_policy_across_the_exposure_build()

作用:测试应用级配置能精确控制单个工具是否启用。比如日历默认关闭所有工具,但单独打开“创建事件”。

数据流:先创建一个临时配置目录 → 写入配置文件,说明 calendar 默认工具关闭、events/create 单独开启 → 读取这份配置 → 造出一个启用工具和一个禁用工具 → 调用曝光构建流程 → 检查最后只展示被配置允许的工具。

调用关系:它用 make_mcp_tool 构造两个应用工具,用临时文件模拟真实配置,再验证曝光构建流程会同时考虑 MCP 工具列表、连接器和应用策略。

调用图:调用 1 个内部函数(make_mcp_tool);外部调用 6 个(assert!, assert_eq!, default, write, tempdir, vec!)。

searches_large_effective_tool_sets240–254 ↗
async fn searches_large_effective_tool_sets()

作用:测试工具数量达到阈值时,系统不会把所有工具一股脑塞给模型,而是放进延后搜索列表。

数据流:读取测试配置 → 生成刚好达到直接展示阈值数量的工具 → 调用曝光构建流程 → 检查直接工具为空,并确认所有工具都进入 deferred_tools,也就是可通过工具搜索发现的列表。

调用关系:它和 directly_exposes_small_effective_tool_sets 配成一对:一个验证少量工具直接展示,另一个验证大量工具改走搜索,避免模型一次看到太多工具。

调用图:调用 2 个内部函数(test_config, numbered_mcp_tools);外部调用 2 个(assert!, assert_eq!)。

always_defer_feature_defers_apps_too257–301 ↗
async fn always_defer_feature_defers_apps_too()

作用:测试一个特殊功能开关:只要开启,就连普通 MCP 工具和应用工具都必须延后展示。这样可以强制模型通过工具搜索来发现工具。

数据流:先拿到测试配置 → 打开 ToolSearchAlwaysDeferMcpTools 功能开关 → 准备一个普通 MCP 工具和一个日历应用工具 → 调用曝光构建流程 → 检查直接列表为空,并确认两个工具都在延后列表里。

调用关系:它调用 test_config 准备可修改的配置,用 tool_names 检查结果集合。这个测试保证全局“总是延后”开关的优先级足够高,不会漏掉应用类工具。

调用图:调用 2 个内部函数(test_config, tool_names);外部调用 2 个(assert!, vec!)。

core/src/sandbox_tags_tests.rs源码 ↗
testtest run

这份文件不是真正执行沙箱的代码,而是像“验货清单”。项目里有不同权限档位:比如完全不限制、外部沙箱、只读、受管理的文件系统权限、网络受限等。系统会把这些复杂配置压成简短标签,比如“none”“external”或某个平台沙箱名字,方便统计和判断。这里的测试逐个确认:危险的完全访问不会被误标成沙箱;外部沙箱会保留 external;默认 Linux 沙箱会按当前平台能力打标签;启用“强制管理网络”时,即使文件系统不受限,也应算作沙箱。最后一个测试还检查新权限配置能被翻译成接近旧版模式的标签,比如 workspace-write。没有这些测试,改权限逻辑时很容易把“没保护”和“有保护”混在一起,安全统计就会失真。

函数细节8
danger_full_access_is_untagged_even_when_linux_sandbox_defaults_apply19–26 ↗
fn danger_full_access_is_untagged_even_when_linux_sandbox_defaults_apply()

作用:这个测试确认:当权限档位是完全关闭保护时,标签必须是“none”。也就是说,即使平台上有默认沙箱能力,也不能把“危险的全权限”误说成“已经进沙箱”。

数据流:输入是一份 Disabled 权限配置、关闭的 Windows 沙箱级别,以及“不强制管理网络”的开关。测试把这些交给 permission_profile_sandbox_tag 算标签,然后用 assert_eq! 检查结果。最后期望输出是字符串“none”,文件本身不改动任何长期数据。

调用关系:它直接测试 permission_profile_sandbox_tag 的一个边界情况,并把结果交给 assert_eq! 做核对。这个测试通常在自动测试套件运行时被测试框架调用,用来守住“完全访问不能被伪装成沙箱”的规则。

调用图:外部调用 2 个(assert_eq!, permission_profile_sandbox_tag)。

external_sandbox_keeps_external_tag_when_linux_sandbox_defaults_apply29–38 ↗
fn external_sandbox_keeps_external_tag_when_linux_sandbox_defaults_apply()

作用:这个测试确认:如果权限配置明确说使用外部沙箱,标签就应该保持为“external”。外部沙箱可以理解成“不是本程序内置的保险箱,而是外面另有一套保护”。

数据流:输入是一份 External 权限配置,其中网络策略是 Enabled,再加上关闭的 Windows 沙箱级别和不强制管理网络。测试调用 permission_profile_sandbox_tag 得到标签,然后用 assert_eq! 比较。期望结果是“external”,不会因为 Linux 默认沙箱规则而被改成别的名字。

调用关系:它把一份外部沙箱配置送进 permission_profile_sandbox_tag,再用 assert_eq! 验证输出。它和前一个测试一起区分两件事:完全无保护是 none,外部保护是 external。

调用图:外部调用 2 个(assert_eq!, permission_profile_sandbox_tag)。

default_linux_sandbox_uses_platform_sandbox_tag41–51 ↗
fn default_linux_sandbox_uses_platform_sandbox_tag()

作用:这个测试确认:普通只读权限在没有特殊 Windows 沙箱时,会使用当前平台真正支持的沙箱标签。简单说,就是标签要跟机器上实际能用的保护方式一致。

数据流:输入是一份 read_only 只读权限配置、关闭的 Windows 沙箱级别,以及不强制管理网络。测试先用 permission_profile_sandbox_tag 算实际标签;再用 get_platform_sandbox 查询当前平台沙箱,如果有就转成指标标签,没有就用“none”。最后用 assert_eq! 确认两边一致。

调用关系:它同时碰到 read_only、get_platform_sandbox 和 permission_profile_sandbox_tag:前者造出测试用权限,中间查询平台能力,后者给权限打标签。assert_eq! 负责最后验收,保证权限标签没有脱离真实平台环境。

调用图:调用 1 个内部函数(read_only);外部调用 3 个(assert_eq!, get_platform_sandbox, permission_profile_sandbox_tag)。

profile_sandbox_tag_distinguishes_disabled_from_external54–73 ↗
fn profile_sandbox_tag_distinguishes_disabled_from_external()

作用:这个测试把“关闭保护”和“外部沙箱”放在一起比,确认它们不会被打成同一个标签。这样统计时就能看清:到底是真没沙箱,还是用了外部沙箱。

数据流:测试准备两种权限配置:Disabled 和 External。它分别计算沙箱标签,并用 assert_eq! 检查 Disabled 对应“none”,External 对应“external”。结果只体现在测试是否通过,不会写入外部状态。

调用关系:它在同一个测试里连续检查两个分支,最终由 assert_eq! 判断是否符合预期。它是前面两个单独测试的浓缩版,强调这两个状态必须被清楚地区分。

调用图:外部调用 1 个(assert_eq!)。

unrestricted_managed_profile_with_enabled_network_is_untagged76–90 ↗
fn unrestricted_managed_profile_with_enabled_network_is_untagged()

作用:这个测试确认:受管理权限配置里,如果文件系统不受限制、网络也允许,并且没有强制网络管理,那么它仍然应该被看作“无沙箱”,标签是“none”。

数据流:输入是一份 Managed 权限配置:文件系统 Unrestricted,网络 Enabled。测试把这份配置连同关闭的 Windows 沙箱级别、不强制管理网络开关一起用于计算标签,然后用 assert_eq! 验证结果是“none”。它只检查判断结果,不改变配置对象。

调用关系:它关注 Managed 配置里最宽松的情况。assert_eq! 是最后的裁判,用来保证“名字叫 Managed”不等于“一定有沙箱保护”。

调用图:外部调用 1 个(assert_eq!)。

root_write_managed_profile_with_enabled_network_is_untagged93–115 ↗
fn root_write_managed_profile_with_enabled_network_is_untagged()

作用:这个测试确认:如果受管理权限允许对根目录写入,实际效果也几乎等于全权限,所以标签应该还是“none”。根目录可以理解成整台文件系统的最上层入口,能写这里就很宽松。

数据流:测试先用 vec! 造出一条文件系统规则:特殊路径 Root,访问模式 Write。然后把它放进 Managed 权限配置里,网络设置为 Enabled。接着计算沙箱标签,并用 assert_eq! 检查结果是“none”。输出是测试通过或失败,没有持久副作用。

调用关系:它专门覆盖一种容易误判的权限:看起来是 Restricted,但因为允许写根目录,实际并不受限。vec! 帮它组装规则列表,assert_eq! 负责确认标签没有被误标成受保护。

调用图:外部调用 2 个(assert_eq!, vec!)。

managed_network_enforcement_tags_unrestricted_profiles_as_sandboxed118–135 ↗
fn managed_network_enforcement_tags_unrestricted_profiles_as_sandboxed()

作用:这个测试确认:一旦打开“强制管理网络”,即使文件系统本身不受限制,也应该按平台沙箱来打标签。因为这时网络已经进入受控流程,不能再简单说成“none”。

数据流:输入是一份文件系统 Unrestricted、网络 Enabled 的 Managed 配置,但这次 enforce_managed_network 开关是 true。测试用 get_platform_sandbox 查询当前平台对应的沙箱标签,查不到就退回“none”。然后比较实际标签和这个期望值。

调用关系:它和 unrestricted_managed_profile_with_enabled_network_is_untagged 形成对照:同样的权限配置,只改“强制管理网络”开关,标签含义就会变。get_platform_sandbox 提供平台基准,assert_eq! 做最终检查。

调用图:外部调用 2 个(assert_eq!, get_platform_sandbox)。

profile_policy_tag_reports_closest_legacy_mode138–160 ↗
fn profile_policy_tag_reports_closest_legacy_mode()

作用:这个测试确认:新的详细权限配置,仍然能被概括成旧系统认识的模式标签。这里期望它被归类为“workspace-write”,也就是“可以写工作区”的模式。

数据流:测试先用 Path::new 和 from_absolute_path 准备当前目录 /tmp/codex,以及可写目录 /tmp/codex/work。然后构造一个受限文件系统策略:只给这个可写目录 Write 权限,同时网络 Restricted。接着用 from_runtime_permissions 生成 PermissionProfile,再调用 permission_profile_policy_tag,看它面对当前目录会给出什么旧版标签。最后 assert_eq! 要求结果是“workspace-write”。

调用关系:它测试的是权限配置到旧版策略标签的翻译。Path::new 和 from_absolute_path 负责准备绝对路径,vec! 负责放入文件规则,from_runtime_permissions 把运行时策略包装成权限档案,最后 assert_eq! 检查 permission_profile_policy_tag 的归类是否正确。

调用图:调用 2 个内部函数(from_runtime_permissions, from_absolute_path);外部调用 3 个(new, assert_eq!, vec!)。

运行时环境和实时辅助工具

这些测试涵盖面向文件系统和 shell 的辅助工具、AGENTS.md 和 personality 迁移行为、Git 元数据,以及实时上下文/对话支持。

core/src/agents_md_tests.rs源码 ↗
testtest

AGENTS.md 可以理解成项目给 AI 助手看的“使用说明书”。这个测试文件就是在反复模拟各种真实情况:说明文件不存在、太大、编码坏了、在仓库根目录或子目录里、同时有全局说明和项目说明、多个运行环境各有说明、还有本地覆盖文件和备用文件名。文件里先做了一些测试工具,比如 TestConfig 用来快速造一份测试配置,FailingFileSystem 用来假装文件系统出错,好检查错误会不会被正确处理。后面的大量测试像验收清单一样,确认读取逻辑不会误读目录或特殊文件,不会把技能、应用功能之类无关内容塞进 AGENTS.md,也会按顺序保留说明来源。没有这些测试,项目说明很容易在边界情况里丢失、重复、顺序错乱,甚至把不该读的东西交给模型。

函数细节57
FailingFileSystem::canonicalize128–134 ↗
fn canonicalize(
        &'a self,
        path: &'a PathUri,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, PathUri>

作用:这是测试用假文件系统里的“规范化路径”入口,但这些测试不应该走到这里。它的作用是如果代码意外调用了它,就立刻暴露问题。

数据流:进去的是一个路径和可选的沙箱信息(一层限制文件访问范围的保护壳)→ 它不真正处理路径,而是直接触发“这里不该被调用”的失败 → 没有正常输出,只用于抓测试里的意外行为。

调用关系:它属于 FailingFileSystem 这套假文件系统。相关测试主要想检查读文件和查元数据的错误,所以如果主流程把活儿交到这个函数,说明读取流程走偏了。

调用图:外部调用 2 个(pin, unreachable!)。

FailingFileSystem::read_file136–142 ↗
fn read_file(
        &'a self,
        path: &'a PathUri,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, Vec<u8>>

作用:这个函数模拟“读某个文件时失败”。测试用它来确认读取 AGENTS.md 时,权限错误会传出去,文件突然消失则能被温和处理。

数据流:进去的是要读的路径和沙箱信息 → 它先把路径转成绝对路径,若正好是预设要失败的文件并且失败类型是读取失败,就返回指定错误;否则交给真实本地文件系统读取 → 出来要么是文件字节内容,要么是人为注入的错误。

调用关系:read_agents_md_propagates_read_errors 和 read_agents_md_ignores_files_removed_after_discovery 这类测试通过它制造读文件异常。它在假文件系统里替代真实读文件动作,帮助验证上层 read_agents_md 的反应。

调用图:调用 1 个内部函数(to_abs_path);外部调用 2 个(pin, new)。

FailingFileSystem::read_file_stream144–155 ↗
fn read_file_stream(
        &'a self,
        _path: &'a PathUri,
        _sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, FileSystemReadStream>

作用:这个函数表示测试假文件系统不支持“流式读取”。流式读取就是边读边处理大文件,这里不需要。

数据流:进去的是路径和沙箱信息 → 它不打开文件,而是马上返回“不支持”的错误 → 出来是一个错误,说明这个测试替身不能用流式方式读。

调用关系:它补齐 ExecutorFileSystem 这个文件系统接口要求的方法。当前这些 AGENTS.md 测试没有靠它读文件;如果有人改代码后走到这里,会得到明确的不支持提示。

调用图:外部调用 2 个(pin, new)。

FailingFileSystem::write_file157–164 ↗
fn write_file(
        &'a self,
        path: &'a PathUri,
        contents: Vec<u8>,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, ()>

作用:这是测试假文件系统里的写文件入口,但 AGENTS.md 读取测试不应该写文件。它用来防止测试悄悄做了不该做的修改。

数据流:进去的是路径、要写入的内容和沙箱信息 → 它不保存任何东西,而是直接报“这里不该被调用” → 没有正常输出,也不会改磁盘。

调用关系:它作为文件系统接口的一部分存在。读取 AGENTS.md 的流程如果调用它,就说明读说明文件的逻辑混入了写操作,测试会立刻失败。

调用图:外部调用 2 个(pin, unreachable!)。

FailingFileSystem::create_directory166–175 ↗
fn create_directory(
        &'a self,
        path: &'a PathUri,
        options: CreateDirectoryOptions,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a,

作用:这是测试假文件系统里的建目录入口,但这些测试只读项目说明,不应该创建目录。它用于抓住意外的副作用。

数据流:进去的是目录路径、创建选项和沙箱信息 → 它不创建目录,而是直接触发失败 → 出来没有正常结果,测试会因此暴露异常调用。

调用关系:它补齐文件系统接口。AGENTS.md 读取流程正常只需要查找和读取文件,所以这个函数被调用就代表流程不干净。

调用图:外部调用 2 个(pin, unreachable!)。

FailingFileSystem::get_metadata177–183 ↗
fn get_metadata(
        &'a self,
        path: &'a PathUri,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, FileMetadata>

作用:这个函数模拟“查看文件信息时失败”。文件信息包括它是不是普通文件、是否存在等。

数据流:进去的是路径和沙箱信息 → 它把路径转成绝对路径,如果命中预设路径并且失败类型是元数据失败,就返回指定错误;否则交给真实本地文件系统查询 → 出来是文件信息,或人为注入的查询错误。

调用关系:read_agents_md_propagates_metadata_errors 用它制造权限错误,检查上层是否把这类严重错误传出来。它是测试 AGENTS.md 发现阶段的重要故障开关。

调用图:调用 1 个内部函数(to_abs_path);外部调用 2 个(pin, new)。

FailingFileSystem::read_directory185–191 ↗
fn read_directory(
        &'a self,
        path: &'a PathUri,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, Vec<ReadDirectoryEntry>>

作用:这是测试假文件系统里的读目录入口,但这些测试不希望通过它遍历目录。它用来防止读取逻辑走到非预期路径。

数据流:进去的是目录路径和沙箱信息 → 它不列出目录内容,而是直接报“这里不该被调用” → 没有正常输出。

调用关系:它只是为了实现完整文件系统接口。当前 AGENTS.md 查找逻辑通过检查候选文件路径工作,不应把任务交给这个函数。

调用图:外部调用 2 个(pin, unreachable!)。

FailingFileSystem::remove193–200 ↗
fn remove(
        &'a self,
        path: &'a PathUri,
        options: RemoveOptions,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> ExecutorFileSystemFuture<'a, ()>

作用:这是测试假文件系统里的删除入口,但读取 AGENTS.md 不应该删除任何东西。它防止测试流程出现危险副作用。

数据流:进去的是路径、删除选项和沙箱信息 → 它不删除文件,而是立即失败 → 没有正常输出,磁盘不会被改动。

调用关系:它补齐文件系统接口。若 AGENTS.md 读取流程调用删除,测试会马上失败,提醒开发者逻辑出了大问题。

调用图:外部调用 2 个(pin, unreachable!)。

FailingFileSystem::copy202–216 ↗
fn copy(
        &'a self,
        source_path: &'a PathUri,
        destination_path: &'a PathUri,
        options: CopyOptions,
        sandbox: Option<&'a FileSystemSandboxContext>,
    ) -> Execut

作用:这是测试假文件系统里的复制入口,但说明文件读取不该复制文件。它负责把这种意外行为变成明显的测试失败。

数据流:进去的是源路径、目标路径、复制选项和沙箱信息 → 它不复制任何内容,而是直接触发“不可达”的失败 → 没有正常输出。

调用关系:它作为 ExecutorFileSystem 接口的一部分存在。AGENTS.md 测试只关心发现和读取文件,因此任何复制调用都说明上层流程不符合预期。

调用图:外部调用 2 个(pin, unreachable!)。

TestConfig::deref227–229 ↗
fn deref(&self) -> &Self::Target

作用:这个函数让 TestConfig 可以像普通 Config 一样被读取。这样测试代码少写一层 .config,更顺手。

数据流:进去的是一个 TestConfig 引用 → 它取出里面真正的 config 字段 → 出来是 Config 的只读引用,不改任何数据。

调用关系:很多测试 helper 和断言会直接访问配置字段。这个函数把 TestConfig 伪装成 Config,让测试代码更像在用真实配置。

TestConfig::deref_mut233–235 ↗
fn deref_mut(&mut self) -> &mut Self::Target

作用:这个函数让 TestConfig 可以像普通 Config 一样被修改。测试经常要改当前目录、开关功能或调整限制。

数据流:进去的是一个可修改的 TestConfig → 它拿出里面真正的 config 字段 → 出来是 Config 的可修改引用,后续修改会直接落在 TestConfig 里的配置上。

调用关系:测试如切换 cwd、开启功能标志时会依赖这种便利写法。它和 TestConfig::deref 配合,让包装类型不妨碍测试操作配置。

get_user_instructions238–240 ↗
async fn get_user_instructions(config: &TestConfig) -> Option<String>

作用:这是测试里最常用的快捷函数:给它一份测试配置,它返回最终会给模型看的说明文字。测试用它避免每次都手动拆 LoadedAgentsMd。

数据流:进去的是 TestConfig → 它调用 load_agents_md 读取并合并说明 → 如果有结果,就取出纯文本;如果没有任何说明,就返回 None。

调用关系:大量测试从这里开始,比如检查文件缺失、截断、合并、覆盖文件和功能开关。它把底层加载细节藏起来,让测试只关心最后文本对不对。

调用图:调用 1 个内部函数(load_agents_md);被 18 处调用(agents_local_md_preferred, agents_md_directory_is_ignored, agents_md_paths_preserve_symlinked_cwd, agents_md_preferred_over_fallbacks, agents_md_special_file_is_ignored, apps_feature_does_not_append_to_agents_md_user_instructions, apps_feature_does_not_emit_user_instructions_by_itself, doc_larger_than_limit_is_truncated, doc_smaller_than_limit_is_returned, finds_doc_in_repo_root (+8 more))。

load_agents_md242–251 ↗
async fn load_agents_md(config: &TestConfig) -> Option<LoadedAgentsMd>

作用:这个 helper 用测试配置加载完整的 AGENTS.md 结果,不只拿文字,也保留来源和分段信息。需要检查来源顺序或内部结构的测试会用它。

数据流:进去的是 TestConfig → 它先把当前目录包装成一个本地运行环境,再调用真正的 load_project_instructions → 出来是 LoadedAgentsMd,里面有全局说明、项目说明条目和来源信息;没有说明则是 None。

调用关系:get_user_instructions 会调用它取纯文本;更细的测试如 concatenates_root_and_cwd_docs 和 instruction_sources_include_global_before_agents_md_docs 会直接用它检查结构。

调用图:调用 1 个内部函数(resolved_local_environments);被 7 处调用(child_agents_message_after_global_instructions_uses_plain_separator, child_agents_message_after_project_docs_is_not_an_instruction_source, concatenates_root_and_cwd_docs, get_user_instructions, instruction_sources_include_global_before_agents_md_docs, project_doc_invalid_utf8_uses_lossy_text, total_byte_limit_truncates_later_project_docs)。

agents_md_paths253–255 ↗
async fn agents_md_paths(config: &TestConfig) -> std::io::Result<Vec<AbsolutePathBuf>>

作用:这个 helper 返回系统会发现哪些 AGENTS.md 路径。它让测试能单独检查“找文件”这一步,而不必真的关心文件内容。

数据流:进去的是 TestConfig → 它把配置里的真实 Config、当前目录和本地文件系统交给生产代码里的路径发现函数 → 出来是按读取顺序排列的绝对路径列表,或文件系统错误。

调用关系:覆盖文件、本地符号链接、目录被忽略、备用文件名和项目根标记等测试都会调用它。它位于“发现路径”和“读取内容”之间,专门验证发现规则。

调用图:被 8 处调用(agents_local_md_preferred, agents_md_directory_is_ignored, agents_md_paths_preserve_symlinked_cwd, agents_md_preferred_over_fallbacks, agents_md_special_file_is_ignored, override_directory_falls_back_to_agents_md_file, project_layers_do_not_override_project_root_markers, project_root_markers_are_honored_for_agents_discovery);外部调用 1 个(agents_md_paths)。

resolved_local_environments257–276 ↗
fn resolved_local_environments(
    environments: [(&str, AbsolutePathBuf); N],
) -> TurnEnvironmentSnapshot

作用:这个函数把若干个环境名和目录变成测试用的环境快照。环境快照可以理解成“这轮对话能访问哪些工作目录”的清单。

数据流:进去的是一组环境编号和绝对目录 → 它为每个目录创建本地执行环境,并记录对应的根路径 URI → 出来是 TurnEnvironmentSnapshot,供加载项目说明时按环境读取。

调用关系:load_agents_md 用它创建单环境;多环境测试也直接用它创建 primary、secondary 等环境,检查说明是否按环境分组和保序。

调用图:被 8 处调用(child_agents_guidance_is_appended_once_after_environment_groups, load_agents_md, multiple_environment_docs_use_labeled_layout_and_preserve_source_order, multiple_environments_can_exceed_single_environment_project_doc_limit, primary_only_project_doc_preserves_legacy_layout_with_multiple_bound_environments, project_doc_byte_limit_is_applied_independently_per_environment, secondary_environment_invalid_utf8_does_not_suppress_other_docs, secondary_only_project_doc_uses_single_contributor_layout);外部调用 1 个(into_iter)。

project_provenance278–284 ↗
fn project_provenance(path: AbsolutePathBuf, cwd: AbsolutePathBuf) -> InstructionProvenance

作用:这个函数帮测试造出“这段说明来自哪个项目文件”的来源记录。来源记录用于确认系统不只是拼了文字,还记住文字从哪里来。

数据流:进去的是说明文件路径和当前工作目录 → 它打包成 Project 类型的 InstructionProvenance,并固定环境编号为 local → 出来是一份可用于比较的来源对象。

调用关系:需要精确比较 LoadedAgentsMd 结构的测试会用它生成期望值。它让来源字段的构造保持一致,避免每个测试手写重复结构。

make_config291–310 ↗
async fn make_config(root: &TempDir, limit: usize, instructions: Option<&str>) -> TestConfig

作用:这是创建测试配置的主工具。它把临时目录设成项目目录,并设置 AGENTS.md 最大读取字节数和可选的全局说明。

数据流:进去的是临时项目目录、字节上限和可选说明文字 → 它创建一个临时 codex_home,构建默认配置,改掉当前目录和项目说明大小限制,并把可选全局说明包装起来 → 出来是 TestConfig。

调用关系:绝大多数测试都先调用它准备现场。后续 get_user_instructions、load_agents_md 或 agents_md_paths 都依赖这份配置运行。

调用图:被 33 处调用(agents_local_md_preferred, agents_md_directory_is_ignored, agents_md_paths_preserve_symlinked_cwd, agents_md_special_file_is_ignored, apps_feature_does_not_append_to_agents_md_user_instructions, apps_feature_does_not_emit_user_instructions_by_itself, child_agents_guidance_is_appended_once_after_environment_groups, child_agents_message_after_global_instructions_uses_plain_separator, child_agents_message_after_project_docs_is_not_an_instruction_source, concatenates_root_and_cwd_docs (+15 more));外部调用 3 个(abs, new, default)。

make_config_with_fallback312–324 ↗
async fn make_config_with_fallback(
    root: &TempDir,
    limit: usize,
    instructions: Option<&str>,
    fallbacks: &[&str],
) -> TestConfig

作用:这个函数创建带备用说明文件名的测试配置。备用文件名用于测试 AGENTS.md 不存在时是否会尝试读别的文件。

数据流:进去的是临时目录、字节上限、可选全局说明和备用文件名列表 → 它先调用 make_config,再把备用文件名写进配置 → 出来是带 fallback 规则的 TestConfig。

调用关系:uses_configured_fallback_when_agents_missing 和 agents_md_preferred_over_fallbacks 用它验证备用文件只在合适时候生效。它是在基础配置上加一小块规则。

调用图:调用 1 个内部函数(make_config);被 2 处调用(agents_md_preferred_over_fallbacks, uses_configured_fallback_when_agents_missing)。

make_config_with_project_root_markers326–359 ↗
async fn make_config_with_project_root_markers(
    root: &TempDir,
    limit: usize,
    instructions: Option<&str>,
    markers: &[&str],
) -> TestConfig

作用:这个函数创建带自定义项目根标记的测试配置。项目根标记就是用某些文件或目录告诉系统“这里是项目顶层”。

数据流:进去的是临时目录、字节上限、可选全局说明和标记名列表 → 它通过命令行覆盖项写入 project_root_markers,构建配置,再设置当前目录和字节限制 → 出来是 TestConfig。

调用关系:project_root_markers_are_honored_for_agents_discovery 用它确认自定义根标记会影响 AGENTS.md 查找范围。它专门覆盖默认的 .git 识别规则。

调用图:被 1 处调用(project_root_markers_are_honored_for_agents_discovery);外部调用 4 个(abs, new, default, vec!)。

no_doc_file_returns_none363–374 ↗
async fn no_doc_file_returns_none()

作用:这个测试确认没有 AGENTS.md、也没有全局说明时,系统不会凭空生成说明。没有文件就应该返回空。

数据流:它创建空临时目录 → 用 make_config 生成无全局说明的配置,再调用 get_user_instructions → 期望输出是 None,不产生任何说明文字。

调用关系:它走最基础的 get_user_instructions 路径,是其他复杂场景的基线:先证明空项目不会误报有说明。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 2 个(assert!, tempdir)。

empty_loaded_instructions_are_empty377–397 ↗
fn empty_loaded_instructions_are_empty()

作用:这个测试确认空字符串或只有空白字符的说明会被当作“没有说明”。这样不会把无意义空段落交给模型。

数据流:它构造空文本、空白文本和测试用 LoadedAgentsMd → 调用相等性检查与默认空对象比较 → 期望它们都等同于空结果。

调用关系:它直接检查 LoadedAgentsMd 的空值规则,不经过文件读取流程。后续文本合并能依赖这个规则过滤无内容说明。

调用图:调用 1 个内部函数(from_absolute_path);外部调用 1 个(assert_eq!)。

loaded_instructions_with_only_empty_or_whitespace_entries_are_empty400–418 ↗
fn loaded_instructions_with_only_empty_or_whitespace_entries_are_empty()

作用:这个测试确认如果说明条目里只有空内容或空白内容,整体也算空。它防止内部列表看似有条目但实际没有信息。

数据流:它手动造两个 LoadedAgentsMd,一个条目为空,一个条目只有空白 → 调用 is_empty → 期望两者都返回 true。

调用关系:它补充验证 LoadedAgentsMd 的判空逻辑。和 empty_loaded_instructions_are_empty 一起保证空说明不会进入最终提示。

调用图:外部调用 2 个(assert!, vec!)。

doc_smaller_than_limit_is_returned422–435 ↗
async fn doc_smaller_than_limit_is_returned()

作用:这个测试确认小于字节上限的 AGENTS.md 会原样返回。正常小文件不该被改写或截断。

数据流:它在临时目录写入“hello world” → 创建足够大的读取限制并调用 get_user_instructions → 输出应完全等于原文件内容。

调用关系:它通过 make_config 和 get_user_instructions 走完整读取流程,是项目说明最普通、最成功的路径。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

project_doc_invalid_utf8_uses_lossy_text438–447 ↗
async fn project_doc_invalid_utf8_uses_lossy_text()

作用:这个测试确认 AGENTS.md 里有非法 UTF-8 字节时,系统不会崩溃,而是用替换符号显示坏字节。UTF-8 是常见文本编码,这里保证坏文件也能尽量读。

数据流:它写入包含非法字节的文件 → 调用 load_agents_md 读取 → 输出文本中非法字节变成 U+FFFD 这个替代字符。

调用关系:它直接检查加载后的文本。这个测试保证读取项目说明时,编码问题不会让其他正常内容完全丢掉。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

doc_larger_than_limit_is_truncated451–464 ↗
async fn doc_larger_than_limit_is_truncated()

作用:这个测试确认太大的 AGENTS.md 会被截到配置允许的字节数。这样可以防止巨大的项目说明把提示塞爆。

数据流:它写入两倍于限制大小的 A 字符串 → 用限制值创建配置并读取说明 → 输出长度应正好等于限制,并且内容是原文件开头部分。

调用关系:它走 get_user_instructions 的普通读取路径,验证 project_doc_max_bytes 这个安全阀确实生效。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

total_byte_limit_truncates_later_project_docs467–498 ↗
async fn total_byte_limit_truncates_later_project_docs()

作用:这个测试确认同一个环境里有多个项目说明时,总字节上限会按顺序消耗,后面的文件可能被截短。

数据流:它在仓库根目录和嵌套目录各写一个 AGENTS.md,并把总限制设为 7 → 加载时先读 root,再读 nested,root 用掉 4 字节,nested 只剩 3 字节 → 输出结构和文本应是 root 加 abc。

调用关系:它调用 load_agents_md 并用 project_provenance 构造期望来源。它验证从项目根到当前目录的多文件合并和总限制规则。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 5 个(assert_eq!, create_dir, write, tempdir, vec!)。

read_agents_md_propagates_metadata_errors501–516 ↗
async fn read_agents_md_propagates_metadata_errors()

作用:这个测试确认查询文件信息时遇到权限错误,系统会把错误交出去,而不是悄悄忽略。权限错误通常代表真实问题。

数据流:它创建配置,并让 FailingFileSystem 在检查 .git 元数据时返回 PermissionDenied → 调用 read_agents_md → 期望得到同样类型的权限错误。

调用关系:它绕过 get_user_instructions,直接测 read_agents_md 的错误处理。FailingFileSystem::get_metadata 是这个测试的故障来源。

调用图:调用 1 个内部函数(make_config);外部调用 3 个(assert_eq!, Metadata, tempdir)。

read_agents_md_propagates_read_errors519–534 ↗
async fn read_agents_md_propagates_read_errors()

作用:这个测试确认真正读取 AGENTS.md 时遇到权限错误,会被报告出来。不能把“没权限读”和“没有文件”混为一谈。

数据流:它写入 AGENTS.md,再让 FailingFileSystem 对这个文件的读取返回 PermissionDenied → 调用 read_agents_md → 输出是权限错误。

调用关系:它用 FailingFileSystem::read_file 制造故障,检查 read_agents_md 是否保留严重读文件错误。

调用图:调用 1 个内部函数(make_config);外部调用 4 个(assert_eq!, Read, write, tempdir)。

read_agents_md_ignores_files_removed_after_discovery537–552 ↗
async fn read_agents_md_ignores_files_removed_after_discovery()

作用:这个测试确认如果 AGENTS.md 被发现后又突然消失,系统会把它当作没有文件,而不是失败。现实里文件可能被别的进程删掉。

数据流:它先写入 AGENTS.md,再让假文件系统在读取时返回 NotFound → 调用 read_agents_md → 输出是 Ok(None),表示没有可用说明。

调用关系:它和读权限错误测试形成对比:NotFound 是可恢复情况,PermissionDenied 是要报告的情况。

调用图:调用 1 个内部函数(make_config);外部调用 4 个(assert_eq!, Read, write, tempdir)。

finds_doc_in_repo_root557–580 ↗
async fn finds_doc_in_repo_root()

作用:这个测试确认当前目录在仓库深处时,系统能找到仓库根目录的 AGENTS.md。.git 文件用来标识仓库根。

数据流:它创建一个带 .git 的临时仓库,在根目录写 AGENTS.md,又把 cwd 改到深层子目录 → 调用 get_user_instructions → 输出应是根目录说明。

调用关系:它验证路径发现逻辑会向上找项目根。make_config 准备配置,get_user_instructions 触发完整读取。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 5 个(assert_eq!, write, create_dir_all, write, tempdir)。

zero_byte_limit_disables_docs584–594 ↗
async fn zero_byte_limit_disables_docs()

作用:这个测试确认把项目说明字节上限设为 0 会完全关闭项目文档读取。0 在这里是明确的禁用开关。

数据流:它写入 AGENTS.md,但创建配置时限制为 0 → 调用 get_user_instructions → 输出应为 None。

调用关系:它测试 project_doc_max_bytes 的特殊值。即使文件存在,读取流程也不应返回项目说明。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 3 个(assert!, write, tempdir)。

merges_existing_instructions_with_agents_md599–612 ↗
async fn merges_existing_instructions_with_agents_md()

作用:这个测试确认全局说明和项目 AGENTS.md 同时存在时,会按规定拼在一起。全局说明先出现,项目说明跟在后面。

数据流:它写入项目 AGENTS.md,并在配置里放入 base instructions → 调用 get_user_instructions → 输出应是全局说明、分隔符、项目说明。

调用关系:它验证合并规则和 AGENTS_MD_SEPARATOR。get_user_instructions 把 load_agents_md 的结果转成最终文本。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 4 个(assert_eq!, format!, write, tempdir)。

multiple_environment_docs_use_labeled_layout_and_preserve_source_order615–675 ↗
async fn multiple_environment_docs_use_labeled_layout_and_preserve_source_order()

作用:这个测试确认多个环境都有说明时,输出会带环境标签,并且来源顺序不会乱。环境标签告诉读者每段说明属于哪个工作目录。

数据流:它创建 primary 和 secondary 两个目录,primary 还有根和子目录两份说明,再加入全局说明 → 调用 load_project_instructions → 期望文本按全局、primary 根、primary 子目录、secondary 的顺序排列,并检查 render 和 sources。

调用关系:它直接使用 resolved_local_environments 创建多环境现场。这个测试覆盖多环境布局、渲染外壳和来源列表,是本文件里较完整的集成检查。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 5 个(assert_eq!, format!, create_dir, write, tempdir)。

secondary_only_project_doc_uses_single_contributor_layout678–701 ↗
async fn secondary_only_project_doc_uses_single_contributor_layout()

作用:这个测试确认只有一个环境真正贡献了项目说明时,即使绑定了多个环境,也使用简单的单来源排版。这样输出不会无端变复杂。

数据流:它让 primary 没有 AGENTS.md,secondary 有一份,并加入全局说明 → 加载项目说明 → 输出应使用旧式拼接文本和针对 secondary 路径的标题。

调用关系:它和多环境标签测试互补:不是环境多就一定加标签,而是多个贡献者才需要分组。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 4 个(assert_eq!, format!, write, tempdir)。

primary_only_project_doc_preserves_legacy_layout_with_multiple_bound_environments704–727 ↗
async fn primary_only_project_doc_preserves_legacy_layout_with_multiple_bound_environments()

作用:这个测试确认只有主环境有项目说明时,会保留老式简单布局。这样老用户看到的格式不会因为额外环境绑定而变化。

数据流:它创建 primary 和 secondary,但只在 primary 写 AGENTS.md,并加入全局说明 → 加载说明 → 输出应是全局说明加 primary 项目说明,不使用多环境标签格式。

调用关系:它和 secondary_only_project_doc_uses_single_contributor_layout 一起证明:单个贡献环境走 legacy_text,多贡献环境才走 labeled layout。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 4 个(assert_eq!, format!, write, tempdir)。

project_doc_byte_limit_is_applied_independently_per_environment730–754 ↗
async fn project_doc_byte_limit_is_applied_independently_per_environment()

作用:这个测试确认项目说明大小限制是按每个环境分别应用的。一个环境被截短,不会吃掉另一个环境的额度。

数据流:它在 primary 写 ABCDE,在 secondary 写 VWXYZ,限制设为 3 → 加载多环境说明 → 输出应包含 primary 的 ABC 和 secondary 的 VWX。

调用关系:它用 resolved_local_environments 创建两个环境,验证 load_project_instructions 对每个环境单独读和截断。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 3 个(assert_eq!, write, tempdir)。

multiple_environments_can_exceed_single_environment_project_doc_limit757–791 ↗
async fn multiple_environments_can_exceed_single_environment_project_doc_limit()

作用:这个测试记录一个当前行为:多个环境合起来的项目说明总量可以超过单环境限制。代码注释也提示未来可能会加总上限。

数据流:它给 primary 和 secondary 各写满 LIMIT 字节的说明 → 加载多环境说明 → 统计项目条目字节数,期望总数是 LIMIT 的两倍,并且超过配置里的单环境限制。

调用关系:它不是在宣扬理想规则,而是在固定现有行为,避免改动时无意改变。它直接检查 LoadedAgentsMd 的 entries。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 4 个(assert!, assert_eq!, write, tempdir)。

secondary_environment_invalid_utf8_does_not_suppress_other_docs794–815 ↗
async fn secondary_environment_invalid_utf8_does_not_suppress_other_docs()

作用:这个测试确认某个环境的说明含坏编码时,不会影响其他环境的正常说明。坏字节会被替换,但整体结果仍保留。

数据流:它让 primary 写正常文本,secondary 写含非法字节的文本 → 加载多环境说明 → 输出同时包含 primary 文本和 secondary 中带替换字符的文本。

调用关系:它扩展了单文件非法 UTF-8 测试到多环境场景,保证一个环境的问题不会吞掉另一个环境的说明。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 3 个(assert!, write, tempdir)。

child_agents_guidance_is_appended_once_after_environment_groups818–841 ↗
async fn child_agents_guidance_is_appended_once_after_environment_groups()

作用:这个测试确认开启 ChildAgentsMd 功能后,层级 AGENTS.md 的提示只追加一次,而且放在所有环境分组之后。

数据流:它给两个环境都写说明,并开启 ChildAgentsMd 功能 → 加载项目说明 → 检查特殊提示出现次数是 1,且文本最后以它结尾。

调用关系:它测试功能开关和多环境布局的组合。load_project_instructions 完成正文分组后,才追加这段内部提示。

调用图:调用 2 个内部函数(make_config, resolved_local_environments);外部调用 4 个(assert!, assert_eq!, write, tempdir)。

keeps_existing_instructions_when_doc_missing846–854 ↗
async fn keeps_existing_instructions_when_doc_missing()

作用:这个测试确认没有项目 AGENTS.md 时,已有全局说明会原样保留。项目说明缺失不应该抹掉用户配置的说明。

数据流:它创建空目录,但配置里放入 some instructions → 调用 get_user_instructions → 输出应正好是这段全局说明。

调用关系:它和 no_doc_file_returns_none 对照:没有全局说明则为空,有全局说明则返回全局说明。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 2 个(assert_eq!, tempdir)。

concatenates_root_and_cwd_docs859–903 ↗
async fn concatenates_root_and_cwd_docs()

作用:这个测试确认仓库根目录和当前工作目录都有 AGENTS.md 时,会从根到当前目录依次拼接。越靠近当前目录的说明越后出现。

数据流:它创建带 .git 的仓库,根目录写 root doc,子目录写 crate doc,并把 cwd 指到子目录 → 调用 load_agents_md → 输出条目应是 root doc 再 crate doc,来源也按这个顺序。

调用关系:它直接检查 LoadedAgentsMd 的结构、text 和 sources。project_provenance 用来构造期望来源。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 6 个(assert_eq!, write, create_dir_all, write, tempdir, vec!)。

project_root_markers_are_honored_for_agents_discovery906–933 ↗
async fn project_root_markers_are_honored_for_agents_discovery()

作用:这个测试确认自定义项目根标记会被 AGENTS.md 查找逻辑尊重。比如 .codex-root 可以比嵌套的 .git 更外层地定义项目根。

数据流:它在父目录放 .codex-root 和 AGENTS.md,在子目录放 .git 和另一份 AGENTS.md → 用自定义标记配置读取路径 → 期望发现父、子两份说明,并最终拼成 parent doc 加 child doc。

调用关系:它调用 make_config_with_project_root_markers 设置规则,再分别用 agents_md_paths 和 get_user_instructions 检查发现和读取两步。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config_with_project_root_markers);外部调用 4 个(assert_eq!, create_dir_all, write, tempdir)。

project_layers_do_not_override_project_root_markers936–978 ↗
async fn project_layers_do_not_override_project_root_markers()

作用:这个测试确认项目层配置不会覆盖全局确定的 project_root_markers。项目层配置可以理解成项目目录里的局部配置。

数据流:它创建根和嵌套目录说明,并人为塞入两个项目层配置,里面写了应被忽略的根标记 → 调用 agents_md_paths → 期望仍按默认规则发现根和嵌套 AGENTS.md。

调用关系:它直接测试配置层级和路径发现之间的关系。ConfigLayerStack 用来模拟项目层配置,agents_md_paths 验证最终效果。

调用图:调用 3 个内部函数(new, agents_md_paths, make_config);外部调用 7 个(default, assert_eq!, default, create_dir, write, tempdir, vec!)。

agents_md_paths_preserve_symlinked_cwd981–998 ↗
async fn agents_md_paths_preserve_symlinked_cwd()

作用:这个测试确认当前目录是符号链接时,发现到的 AGENTS.md 路径会保留链接路径,而不是偷偷换成真实目标路径。符号链接就像文件夹快捷方式。

数据流:它创建 target 目录和 linked 符号链接,把 cwd 设为 linked → 调用 agents_md_paths → 期望路径是 linked/AGENTS.md;再读取说明,内容应正常。

调用关系:它同时检查路径发现和最终读取。create_directory_symlink 负责搭建快捷方式场景。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config);外部调用 5 个(assert_eq!, create_directory_symlink, create_dir, write, tempdir)。

child_agents_message_after_global_instructions_uses_plain_separator1001–1024 ↗
async fn child_agents_message_after_global_instructions_uses_plain_separator()

作用:这个测试确认只有全局说明、没有项目说明时,开启 ChildAgentsMd 后会用普通空行分隔追加内部提示。格式要简洁,不带项目来源标题。

数据流:它创建带 global doc 的配置并开启功能 → 调用 load_agents_md → 期望结果包含全局说明和一条内部层级提示,并且文本是 global doc、空行、提示。

调用关系:它测试 ChildAgentsMd 和全局说明的组合。因为没有项目文件,内部提示不应被当成项目来源。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 3 个(assert_eq!, tempdir, vec!)。

instruction_sources_include_global_before_agents_md_docs1027–1059 ↗
async fn instruction_sources_include_global_before_agents_md_docs()

作用:这个测试确认来源列表里,全局说明排在项目 AGENTS.md 前面。来源顺序要和最终文本顺序一致,方便追踪每段话从哪里来。

数据流:它写入项目说明,也在 codex_home 写入全局说明文件 → 调用 load_agents_md → 期望 LoadedAgentsMd 同时记录全局和项目来源,sources 返回 global 再 project。

调用关系:它直接检查 user_instructions、sources 和 text。这个测试保证来源跟踪不只对项目文件有效,也包含全局文件。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 5 个(assert_eq!, create_dir_all, write, tempdir, vec!)。

child_agents_message_after_project_docs_is_not_an_instruction_source1062–1100 ↗
async fn child_agents_message_after_project_docs_is_not_an_instruction_source()

作用:这个测试确认 ChildAgentsMd 追加的内部提示不会出现在“来源文件”列表里。因为它不是从磁盘文件读来的。

数据流:它写入全局和项目说明,并开启 ChildAgentsMd → 调用 load_agents_md → 期望 entries 里有项目说明和内部提示,但 sources 只包含全局文件和项目文件。

调用关系:它和 instruction_sources_include_global_before_agents_md_docs 相连,进一步区分真实文件来源和系统内部追加内容。

调用图:调用 2 个内部函数(load_agents_md, make_config);外部调用 5 个(assert_eq!, create_dir_all, write, tempdir, vec!)。

agents_local_md_preferred1104–1123 ↗
async fn agents_local_md_preferred()

作用:这个测试确认 AGENTS.override.md 会优先于 AGENTS.md。这个本地覆盖文件适合放不想提交到版本库的个人或机器特定说明。

数据流:它同时写入默认 AGENTS.md 和本地覆盖文件 → 调用 get_user_instructions → 输出应是 local;再检查发现路径只有覆盖文件。

调用关系:它测试文件名优先级。agents_md_paths 验证发现阶段就选中了覆盖文件,get_user_instructions 验证最终内容一致。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

uses_configured_fallback_when_agents_missing1127–1144 ↗
async fn uses_configured_fallback_when_agents_missing()

作用:这个测试确认 AGENTS.md 不存在时,可以使用配置里指定的备用文件名。这样项目可以把说明放在别的文件里。

数据流:它只写 EXAMPLE.md,并把它设为 fallback → 调用 get_user_instructions → 输出应是 EXAMPLE.md 的内容。

调用关系:它通过 make_config_with_fallback 设置备用规则,验证备用文件在主文件缺失时生效。

调用图:调用 2 个内部函数(get_user_instructions, make_config_with_fallback);外部调用 3 个(assert_eq!, write, tempdir)。

agents_md_preferred_over_fallbacks1148–1176 ↗
async fn agents_md_preferred_over_fallbacks()

作用:这个测试确认只要 AGENTS.md 存在,就优先使用它,而不是备用文件。备用文件只能兜底,不能抢主文件。

数据流:它同时写 AGENTS.md 和 EXAMPLE.md,并配置多个 fallback → 调用 get_user_instructions → 输出应是 primary;再检查发现路径指向 AGENTS.md。

调用关系:它和 uses_configured_fallback_when_agents_missing 成对验证优先级:主文件存在读主文件,主文件缺失才读备用。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config_with_fallback);外部调用 4 个(assert!, assert_eq!, write, tempdir)。

agents_md_directory_is_ignored1179–1190 ↗
async fn agents_md_directory_is_ignored()

作用:这个测试确认名叫 AGENTS.md 的目录会被忽略。系统只应该读取普通文件,不能把目录当说明文件。

数据流:它创建一个 AGENTS.md 目录而不是文件 → 调用 get_user_instructions 和 agents_md_paths → 期望没有说明,也发现不到路径。

调用关系:它检查文件类型过滤。读取逻辑在真正读内容前,应通过元数据判断这不是普通文件。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config);外部调用 3 个(assert_eq!, create_dir, tempdir)。

agents_md_special_file_is_ignored1194–1213 ↗
async fn agents_md_special_file_is_ignored()

作用:这个 Unix 专用测试确认名叫 AGENTS.md 的特殊文件会被忽略。特殊文件比如 FIFO 管道,不是普通文本文件,贸然读取可能卡住。

数据流:它用 mkfifo 创建一个 AGENTS.md 命名管道 → 调用 get_user_instructions 和 agents_md_paths → 期望没有说明,也没有发现路径。

调用关系:它补充 agents_md_directory_is_ignored,覆盖另一类非普通文件。这个测试只在 Unix 系统上运行。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config);外部调用 4 个(new, assert_eq!, mkfifo, tempdir)。

override_directory_falls_back_to_agents_md_file1216–1237 ↗
async fn override_directory_falls_back_to_agents_md_file()

作用:这个测试确认如果 AGENTS.override.md 只是目录而不是文件,系统会退回读取普通 AGENTS.md。无效覆盖不该遮住有效主文件。

数据流:它创建一个同名覆盖目录,再写入正常 AGENTS.md → 调用 get_user_instructions → 输出应是主文件内容;发现路径也应指向 AGENTS.md。

调用关系:它扩展了覆盖文件优先级规则:只有覆盖项是普通文件时才优先,否则继续检查默认文件。

调用图:调用 3 个内部函数(agents_md_paths, get_user_instructions, make_config);外部调用 4 个(assert_eq!, create_dir, write, tempdir)。

skills_are_not_appended_to_agents_md1240–1255 ↗
async fn skills_are_not_appended_to_agents_md()

作用:这个测试确认技能说明不会自动追加到 AGENTS.md 说明里。技能是另一个功能,不能污染项目说明文本。

数据流:它写入项目 AGENTS.md,又用 create_skill 创建一个技能文件 → 调用 get_user_instructions → 输出仍然只等于 base doc。

调用关系:它调用 create_skill 搭建技能目录。这个测试划清 AGENTS.md 读取和技能系统之间的边界。

调用图:调用 3 个内部函数(create_skill, get_user_instructions, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

apps_feature_does_not_emit_user_instructions_by_itself1258–1267 ↗
async fn apps_feature_does_not_emit_user_instructions_by_itself()

作用:这个测试确认只开启 Apps 功能,不会凭空生成用户说明。功能开关本身不应该变成提示内容。

数据流:它创建空项目配置并开启 Apps → 调用 get_user_instructions → 期望输出 None。

调用关系:它验证 Apps 功能和 AGENTS.md 加载互不干扰。没有文件、没有全局说明时仍应为空。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 2 个(assert_eq!, tempdir)。

apps_feature_does_not_append_to_agents_md_user_instructions1270–1283 ↗
async fn apps_feature_does_not_append_to_agents_md_user_instructions()

作用:这个测试确认开启 Apps 功能也不会往 AGENTS.md 说明后面追加内容。项目说明应保持原样。

数据流:它写入 AGENTS.md,再开启 Apps 功能 → 调用 get_user_instructions → 输出应只等于 base doc。

调用关系:它和 apps_feature_does_not_emit_user_instructions_by_itself 一起证明 Apps 开关不会改变用户说明加载结果。

调用图:调用 2 个内部函数(get_user_instructions, make_config);外部调用 3 个(assert_eq!, write, tempdir)。

create_skill1285–1290 ↗
fn create_skill(codex_home: PathBuf, name: &str, description: &str)

作用:这个 helper 在测试用的 codex_home 里创建一个技能文件。它不是测试 AGENTS.md 的主体,只是给“技能不会被追加”这个场景搭道具。

数据流:进去的是 codex_home 路径、技能名和描述 → 它创建 skills/<name> 目录,并写入带简单元数据和正文的 SKILL.md → 出来没有返回值,但磁盘上多了一个技能文件。

调用关系:skills_are_not_appended_to_agents_md 调用它制造技能存在的环境。随后 get_user_instructions 读取 AGENTS.md,以确认技能文件没有参与合并。

调用图:被 1 处调用(skills_are_not_appended_to_agents_md);外部调用 4 个(join, format!, create_dir_all, write)。

core/src/personality_migration_tests.rs源码 ↗
testtest

这是一组自动化测试。它先在临时文件夹里假装搭出一个用户的 Codex 主目录,再造出几种现实情况:有普通会话、有归档会话、已经迁移过、用户自己明确选过个性、完全没有会话。然后它调用真正的迁移函数 maybe_migrate_personality,看结果是不是符合预期。这里的“迁移”可以理解成搬家时补一张新表格:如果发现你是老住户而且没填过“助手性格”,系统就帮你填成 Pragmatic;如果你已经填过,或者已经贴了“处理过”的标记,就不能再动。文件里的辅助函数会写出假的会话 JSONL 文件,JSONL 就是一行一个 JSON 记录,像流水账一样记录一次会话的元信息和用户发言。测试最后会检查状态、标记文件、config.toml 里的个性值,确保迁移既不漏做,也不多做。

函数细节9
read_config_toml18–21 ↗
async fn read_config_toml(codex_home: &Path) -> io::Result<ConfigToml>

作用:读取临时用户目录里的 config.toml,并把它变成程序能直接检查的配置对象。测试用它来确认迁移之后配置文件到底被写成了什么样。

数据流:输入是一个 Codex 主目录路径。它拼出 config.toml 的位置,异步读取这个文本文件,再用 TOML 解析器把文本转成 ConfigToml;如果文件读不到或内容格式不对,就返回错误;成功时返回解析好的配置。

调用关系:它是测试里的“验收工具”。applies_when_sessions_exist_and_no_personality、applies_when_only_archived_sessions_exist_and_no_personality 和 skips_when_personality_explicit 会在迁移动作之后调用它,拿到落盘后的配置,再检查 personality 字段是不是预期值。

调用图:被 3 处调用(applies_when_only_archived_sessions_exist_and_no_personality, applies_when_sessions_exist_and_no_personality, skips_when_personality_explicit);外部调用 3 个(join, read_to_string, from_str)。

write_session_with_user_event23–31 ↗
async fn write_session_with_user_event(codex_home: &Path) -> io::Result<()>

作用:在临时目录里伪造一条普通的历史会话。这样测试就能模拟“这个用户以前用过 Codex,但还没有个性配置”的场景。

数据流:输入是 Codex 主目录路径。它先生成一个新的 ThreadId,也就是会话编号;再拼出 sessions/2025/01/01 这样的普通会话目录;最后把具体写文件的活交给 write_rollout_with_user_event。输出是成功或失败的 IO 结果,并会在磁盘上留下一个假的会话文件。

调用关系:它服务于 applies_when_sessions_exist_and_no_personality。那个测试需要先制造“有普通会话”的证据,再去跑迁移函数,看系统是否因此决定写入默认个性。

调用图:调用 2 个内部函数(write_rollout_with_user_event, new);被 1 处调用(applies_when_sessions_exist_and_no_personality);外部调用 1 个(join)。

write_archived_session_with_user_event33–37 ↗
async fn write_archived_session_with_user_event(codex_home: &Path) -> io::Result<()>

作用:在临时目录里伪造一条归档的历史会话。它用来确认系统不只看当前会话目录,也会把已经归档的老会话算作“用户曾经用过”。

数据流:输入是 Codex 主目录路径。它生成一个新的会话编号,拼出 archived sessions 目录,然后调用 write_rollout_with_user_event 写入同样格式的假会话流水账。结果是在归档目录里出现一个可被迁移逻辑识别的会话文件。

调用关系:它服务于 applies_when_only_archived_sessions_exist_and_no_personality。这个测试用它搭出“只有归档会话,没有普通会话”的环境,再验证迁移仍然会执行。

调用图:调用 2 个内部函数(write_rollout_with_user_event, new);被 1 处调用(applies_when_only_archived_sessions_exist_and_no_personality);外部调用 1 个(join)。

write_rollout_with_user_event39–87 ↗
async fn write_rollout_with_user_event(dir: &Path, thread_id: ThreadId) -> io::Result<()>

作用:真正负责写假会话文件。它会写入会话的基本信息和一条用户消息,让这个文件看起来像系统真实保存过的一次对话。

数据流:输入是目标目录和一个会话编号。它先创建目录,再生成 rollout-时间-会话编号.jsonl 文件;随后构造两行记录:第一行是 SessionMeta,也就是会话的身份证明;第二行是 UserMessage,也就是用户说了“hello”。它把这两条记录序列化成 JSON,一行一条写进文件,最后返回写入是否成功。

调用关系:它是两个造数函数的共同底层工具。write_session_with_user_event 和 write_archived_session_with_user_event 只负责决定文件放在哪,真正把会话内容写成 JSONL 的工作都交给它。

调用图:被 2 处调用(write_archived_session_with_user_event, write_session_with_user_event);外部调用 10 个(default, join, new, format!, UserMessage, EventMsg, SessionMeta, from, create, create_dir_all)。

applies_when_sessions_exist_and_no_personality90–103 ↗
async fn applies_when_sessions_exist_and_no_personality() -> io::Result<()>

作用:测试最典型的迁移场景:用户有历史会话,但配置里没有写过 personality。预期结果是系统自动补上默认的 Pragmatic 个性。

数据流:它先创建一个临时目录,再调用 write_session_with_user_event 写入一条普通会话;接着准备一个空的默认配置,运行 maybe_migrate_personality。运行之后,它检查返回状态必须是 Applied,检查迁移标记文件存在,再用 read_config_toml 读回 config.toml,确认 personality 已经变成 Pragmatic。

调用关系:这是对迁移主流程的正向验收。它先请 write_session_with_user_event 做测试数据,再把场景交给 maybe_migrate_personality,最后请 read_config_toml 帮忙核对结果。

调用图:调用 2 个内部函数(read_config_toml, write_session_with_user_event);外部调用 4 个(new, assert!, assert_eq!, default)。

applies_when_only_archived_sessions_exist_and_no_personality106–119 ↗
async fn applies_when_only_archived_sessions_exist_and_no_personality() -> io::Result<()>

作用:测试只有归档会话时也应该迁移。也就是说,系统不能因为会话被搬到归档目录,就误以为用户从没用过。

数据流:它创建临时目录,调用 write_archived_session_with_user_event 写入一条归档会话;然后用默认配置运行 maybe_migrate_personality。之后它确认状态是 Applied,确认迁移标记文件出现,并读回 config.toml,检查 personality 被写成 Pragmatic。

调用关系:它和普通会话测试互相补充。它把造数工作交给 write_archived_session_with_user_event,再用 read_config_toml 验证迁移结果,重点保护“归档目录也要算历史使用记录”这个规则。

调用图:调用 2 个内部函数(read_config_toml, write_archived_session_with_user_event);外部调用 4 个(new, assert!, assert_eq!, default)。

skips_when_marker_exists122–132 ↗
async fn skips_when_marker_exists() -> io::Result<()>

作用:测试如果迁移标记文件已经存在,系统就应该直接跳过。这个标记像门口贴的“已处理”纸条,防止同一件事反复做。

数据流:它先创建临时目录,并在里面创建 PERSONALITY_MIGRATION_FILENAME 这个标记文件;然后拿默认配置运行 maybe_migrate_personality。结果应该是 SkippedMarker,并且不应该新建 config.toml,因为既然已经标记处理过,就不该再改配置。

调用关系:它验证迁移函数的第一道保险。测试本身创建标记,再调用 maybe_migrate_personality,最后用断言确认迁移没有继续写配置。

调用图:外部调用 4 个(new, assert!, assert_eq!, default)。

skips_when_personality_explicit135–155 ↗
async fn skips_when_personality_explicit() -> io::Result<()>

作用:测试用户已经明确选择过个性时,迁移不能覆盖用户自己的选择。这里用户选的是 Friendly,迁移后也必须保持 Friendly。

数据流:它创建临时目录,用 ConfigEditsBuilder 写入一个带 personality=Friendly 的 config.toml;再读回配置作为迁移函数的输入,运行 maybe_migrate_personality。结果应该是 SkippedExplicitPersonality;同时迁移标记文件会被创建,表示以后不用再检查;最后再次读回配置,确认 Friendly 没被改成 Pragmatic。

调用关系:它保护“尊重用户设置”这条规则。它先用配置编辑工具造出明确个性的配置,再通过 read_config_toml 读取,交给 maybe_migrate_personality 判断,最后再次读取文件确认没有被覆盖。

调用图:调用 2 个内部函数(new, read_config_toml);外部调用 3 个(new, assert!, assert_eq!)。

skips_when_no_sessions158–167 ↗
async fn skips_when_no_sessions() -> io::Result<()>

作用:测试没有任何历史会话时不应该迁移。因为系统没有证据说明这是需要补默认个性的老用户。

数据流:它创建一个空的临时目录,准备默认配置,然后运行 maybe_migrate_personality。预期状态是 SkippedNoSessions;迁移标记文件会出现,表示这个判断已经做过;但 config.toml 不应该被创建,因为没有必要写入 personality。

调用关系:它验证迁移函数的“不要凭空改配置”行为。这个测试不造任何会话文件,直接调用 maybe_migrate_personality,再检查状态、标记文件和配置文件是否符合跳过逻辑。

调用图:外部调用 4 个(new, assert!, assert_eq!, default)。

core/src/git_info_tests.rs源码 ↗
testtest run

这份文件不像正式业务代码那样给用户直接用,而是专门“验货”的。它会临时建一个 Git 仓库,写文件、提交、加远端、切分支、制造未提交改动,甚至模拟 worktree(Git 的一个仓库派生出多个工作目录)和特殊的 .git 指针文件。然后它调用真正的 Git 工具函数,看返回结果是不是符合预期。比如:普通文件夹不该被当成 Git 仓库;干净仓库不该显示有改动;未跟踪的新文件也应该算改动;脱离分支的提交不应该硬说自己在某个分支上。它还特别检查了一个安全细节:查询改动时不能触发用户配置的 Git hook(钩子脚本,也就是 Git 操作时自动运行的小脚本),否则光是“看状态”就可能执行外部代码。

函数细节26
create_test_git_repo22–77 ↗
async fn create_test_git_repo(temp_dir: &TempDir) -> PathBuf

作用:创建一个最小但真实可用的临时 Git 仓库,给其他测试当“样板仓库”。它会初始化仓库、配置提交人、写入一个文件并做第一次提交。

数据流:进去的是一个临时目录;函数在里面新建 repo 文件夹,执行 git init、git config、git add、git commit,并写入 test.txt;出来的是这个新仓库的路径,同时磁盘上多了一个有首个提交的 Git 仓库。

调用关系:这是很多测试的地基。测试需要真实仓库时会先调用它;带远端仓库的辅助函数 create_test_git_repo_with_remote 也先靠它建本地仓库,再继续加远端。

调用图:被 12 处调用(create_test_git_repo_with_remote, resolve_root_git_project_for_trust_detects_worktree_and_returns_main_root, resolve_root_git_project_for_trust_regular_repo_returns_repo_root, test_collect_git_info_detached_head, test_collect_git_info_git_repository, test_collect_git_info_with_branch, test_collect_git_info_with_remote, test_get_has_changes_clean_repo_returns_false, test_get_has_changes_ignores_configured_hooks_path, test_get_has_changes_with_tracked_change_returns_true (+2 more));外部调用 5 个(path, new, create_dir, write, vec!)。

test_recent_commits_non_git_directory_returns_empty80–84 ↗
async fn test_recent_commits_non_git_directory_returns_empty()

作用:确认在普通文件夹里查询最近提交时,不会报错或编造提交记录,而是返回空列表。

数据流:进去的是一个刚创建、没有 Git 信息的临时目录;测试把它交给 recent_commits;出来应该是空结果,断言会检查这一点。

调用关系:这是 recent_commits 的边界测试。测试框架运行它时,它直接调用 recent_commits,验证“不是仓库”的情况能被温和处理。

调用图:外部调用 3 个(new, assert!, recent_commits)。

test_recent_commits_orders_and_limits87–152 ↗
async fn test_recent_commits_orders_and_limits()

作用:确认最近提交列表既按时间从新到旧排列,也会遵守调用者要求的数量上限。

数据流:先创建一个测试仓库,再连续写文件并提交三次,中间等待一下让时间顺序更清楚;然后请求最近 3 条提交;结果应依次是第三次、第二次、第一次提交,并且每条都有像样的提交编号。

调用关系:它先借 create_test_git_repo 准备仓库,再调用 recent_commits 检查真正的查询结果。它属于对提交历史展示功能的完整场景测试。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 8 个(from_millis, new, assert!, assert_eq!, new, recent_commits, write, skip_if_sandbox!)。

create_test_git_repo_with_remote154–187 ↗
async fn create_test_git_repo_with_remote(temp_dir: &TempDir) -> (PathBuf, String)

作用:创建一个带远端的测试仓库,用来测试“本地仓库和远端仓库相比有什么差别”这类功能。

数据流:进去的是临时目录;它先创建本地仓库,再创建一个裸仓库作为远端 origin,读取当前分支名,并把初始提交推送过去;出来的是本地仓库路径和分支名。

调用关系:它建立在 create_test_git_repo 之上,专门服务 git_diff_to_remote 相关测试。那些测试需要远端分支作为参照物,就会先调用它。

调用图:调用 1 个内部函数(create_test_git_repo);被 4 处调用(test_get_git_working_tree_state_branch_fallback, test_get_git_working_tree_state_clean_repo, test_get_git_working_tree_state_unpushed_commit, test_get_git_working_tree_state_with_changes);外部调用 3 个(from_utf8, path, new)。

test_collect_git_info_non_git_directory190–194 ↗
async fn test_collect_git_info_non_git_directory()

作用:确认 collect_git_info 遇到普通文件夹时会返回“没有 Git 信息”,而不是误判。

数据流:进去的是一个没有 Git 仓库的临时目录;测试调用 collect_git_info;出来应该是 None,也就是没有可收集的仓库信息。

调用关系:这是 collect_git_info 的基本防错测试。它直接调用被测函数,验证外部传错目录时结果安全、清楚。

调用图:外部调用 3 个(new, assert!, collect_git_info)。

test_collect_git_info_git_repository197–218 ↗
async fn test_collect_git_info_git_repository()

作用:确认 collect_git_info 在正常 Git 仓库里能读到提交编号和当前分支。

数据流:先用 create_test_git_repo 造出仓库;再调用 collect_git_info;结果应包含 40 位十六进制提交哈希,并包含 main 或 master 这样的当前分支名。

调用关系:它把辅助函数造出的仓库交给 collect_git_info,检查最常见的成功路径:一个普通本地仓库的信息能被正确采集。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 4 个(new, assert!, assert_eq!, collect_git_info)。

test_collect_git_info_with_remote221–257 ↗
async fn test_collect_git_info_with_remote()

作用:确认仓库配置了远端 origin 时,collect_git_info 能把远端地址也读出来。

数据流:先创建本地仓库,再给它添加 origin 远端地址;随后调用 collect_git_info,并另外用 git remote get-url 读出 Git 实际保存的地址;最后比较两者是否一致。

调用关系:它覆盖 collect_git_info 读取 repository_url 的部分。因为有些开发环境会改写远端地址,所以测试会以 Git 实际报告的地址为准。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 5 个(from_utf8, new, assert_eq!, new, collect_git_info)。

test_collect_git_info_detached_head260–289 ↗
async fn test_collect_git_info_detached_head()

作用:确认仓库处在 detached HEAD 状态时,也就是当前不在任何分支上时,函数不会硬填一个分支名。

数据流:先创建仓库并取出当前提交哈希;然后直接 checkout 到这个提交,让仓库脱离分支;调用 collect_git_info 后,结果应该有提交编号,但 branch 应该是 None。

调用关系:它测试 collect_git_info 对特殊 Git 状态的理解。这个场景常见于 CI 或手动检出某个提交时。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 5 个(from_utf8, new, assert!, new, collect_git_info)。

test_collect_git_info_with_branch292–310 ↗
async fn test_collect_git_info_with_branch()

作用:确认切到新分支后,collect_git_info 能准确返回这个新分支名。

数据流:先创建仓库,再执行 git checkout -b feature-branch;调用 collect_git_info;结果里的 branch 应该正好是 feature-branch。

调用关系:它直接验证 collect_git_info 的分支读取逻辑,和 detached HEAD 测试一起覆盖“有分支”和“无分支”两种情况。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 4 个(new, assert_eq!, new, collect_git_info)。

test_get_has_changes_non_git_directory_returns_none313–316 ↗
async fn test_get_has_changes_non_git_directory_returns_none()

作用:确认在非 Git 目录里检查是否有改动时,结果是 None,表示“这个问题不适用”。

数据流:进去的是普通临时目录;测试调用 get_has_changes;出来应是 None,而不是 true 或 false。

调用关系:这是 get_has_changes 的边界测试。测试框架运行它时,它验证函数能先识别“这里根本不是仓库”。

调用图:外部调用 2 个(new, assert_eq!)。

test_get_has_changes_clean_repo_returns_false319–323 ↗
async fn test_get_has_changes_clean_repo_returns_false()

作用:确认一个刚提交完、没有任何新改动的仓库会被判断为干净。

数据流:先创建一个测试 Git 仓库;不再修改任何文件;调用 get_has_changes;结果应是 Some(false),意思是“这是仓库,而且没有改动”。

调用关系:它借 create_test_git_repo 准备干净状态,然后检查 get_has_changes 的正常无改动路径。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 2 个(new, assert_eq!)。

test_get_has_changes_with_tracked_change_returns_true326–332 ↗
async fn test_get_has_changes_with_tracked_change_returns_true()

作用:确认已经被 Git 跟踪的文件被修改后,会被识别为有改动。

数据流:先创建仓库;再改写已经提交过的 test.txt;调用 get_has_changes;结果应是 Some(true),表示仓库里有未提交变化。

调用关系:它测试 get_has_changes 对“已跟踪文件被改了”的识别能力,这是最常见的工作区改动。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 3 个(new, assert_eq!, write)。

test_get_has_changes_with_untracked_change_returns_true335–341 ↗
async fn test_get_has_changes_with_untracked_change_returns_true()

作用:确认新建但还没 git add 的文件,也会被算作仓库有改动。

数据流:先创建仓库;再写入一个 Git 从未见过的新文件 new_file.txt;调用 get_has_changes;结果应是 Some(true)。

调用关系:它补上 get_has_changes 的另一类常见变化:未跟踪文件。和 tracked change 测试一起保证改动判断不漏项。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 3 个(new, assert_eq!, write)。

test_get_has_changes_ignores_configured_hooks_path345–385 ↗
async fn test_get_has_changes_ignores_configured_hooks_path()

作用:确认检查仓库改动时不会触发用户配置的 Git hook 脚本,避免只是读取状态就执行外部代码。

数据流:先创建仓库;再配置一个自定义 hooks 目录,并放入会写 marker 文件的 post-index-change 脚本;随后调用 get_has_changes;结果应显示无改动,并且 marker 文件不应该出现。

调用关系:这是 get_has_changes 的安全测试,只在 Unix 系统上运行。它验证底层 Git 调用应该避开会触发 hook 的方式。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 9 个(new, assert!, assert_eq!, new, format!, create_dir_all, metadata, set_permissions, write)。

test_get_git_working_tree_state_clean_repo388–408 ↗
async fn test_get_git_working_tree_state_clean_repo()

作用:确认本地仓库和远端完全一致时,git_diff_to_remote 返回远端提交编号,并且差异内容为空。

数据流:先创建带远端的仓库;读取 origin/当前分支 的提交哈希;调用 git_diff_to_remote;结果里的 sha 应等于远端哈希,diff 应为空。

调用关系:它使用 create_test_git_repo_with_remote 准备远端参照,然后测试 git_diff_to_remote 的干净仓库路径。

调用图:调用 1 个内部函数(create_test_git_repo_with_remote);外部调用 7 个(from_utf8, new, assert!, assert_eq!, new, git_diff_to_remote, format!)。

test_get_git_working_tree_state_with_changes411–436 ↗
async fn test_get_git_working_tree_state_with_changes()

作用:确认本地有已修改文件和未跟踪文件时,git_diff_to_remote 能把这些变化写进差异文本里。

数据流:先创建带远端的仓库;修改 test.txt,并新增 untracked.txt;读取远端提交编号;调用 git_diff_to_remote;结果应保留远端 sha,同时 diff 文本里应提到两个文件。

调用关系:它验证 git_diff_to_remote 不只看提交历史,也会把当前工作区里还没提交的变化纳入比较。

调用图:调用 1 个内部函数(create_test_git_repo_with_remote);外部调用 8 个(from_utf8, new, assert!, assert_eq!, new, git_diff_to_remote, format!, write)。

test_get_git_working_tree_state_branch_fallback439–478 ↗
async fn test_get_git_working_tree_state_branch_fallback()

作用:确认当前本地分支没有对应远端时,git_diff_to_remote 能退而求其次找到合适的远端分支作为比较基准。

数据流:先创建带远端的仓库;再创建并推送 feature 分支;随后切到一个没有远端跟踪关系的 local-branch;调用 git_diff_to_remote;结果里的 sha 应该等于 origin/feature 的提交编号。

调用关系:它测试 git_diff_to_remote 的兜底选择逻辑。这个场景防止本地新分支没有上游分支时功能直接失败。

调用图:调用 1 个内部函数(create_test_git_repo_with_remote);外部调用 5 个(from_utf8, new, assert_eq!, new, git_diff_to_remote)。

resolve_root_git_project_for_trust_returns_none_outside_repo481–488 ↗
async fn resolve_root_git_project_for_trust_returns_none_outside_repo()

作用:确认信任判断用的“项目根目录解析”在普通目录里不会返回假仓库根目录。

数据流:进去的是普通临时目录的绝对路径;函数 resolve_root_git_project_for_trust 检查它;出来应是 None,表示不属于可识别 Git 项目。

调用关系:它直接测试 resolve_root_git_project_for_trust 的非仓库场景。这里使用 LOCAL_FS,意思是通过真实本地文件系统读取目录。

调用图:外部调用 2 个(new, assert!)。

get_git_repo_root_with_fs_detects_gitdir_pointer491–502 ↗
async fn get_git_repo_root_with_fs_detects_gitdir_pointer()

作用:确认即使 .git 不是目录,而是一个写着 gitdir 路径的文件,也能把所在项目目录识别成仓库根。

数据流:测试先造出 proj/nested,并在 proj 下写一个 .git 文件,内容形如 gitdir: 某路径;然后从 nested 开始查找仓库根;结果应返回 proj 的绝对路径。

调用关系:它测试 get_git_repo_root_with_fs 对 Git 指针文件的支持。这种 .git 文件常见于 worktree 或子模块等特殊布局。

调用图:外部调用 4 个(new, assert_eq!, create_dir_all, write)。

resolve_root_git_project_for_trust_regular_repo_returns_repo_root505–519 ↗
async fn resolve_root_git_project_for_trust_regular_repo_returns_repo_root()

作用:确认普通 Git 仓库无论从根目录还是子目录开始解析,信任判断都能回到同一个仓库根。

数据流:先创建一个真实仓库并取绝对路径;从仓库根调用 resolve_root_git_project_for_trust,应返回根路径;再创建 sub/dir,从子目录调用,也应返回同一个根路径。

调用关系:它用 create_test_git_repo 准备标准仓库,验证 resolve_root_git_project_for_trust 的最常见行为。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 3 个(new, assert_eq!, create_dir_all)。

resolve_root_git_project_for_trust_detects_worktree_and_returns_main_root522–561 ↗
async fn resolve_root_git_project_for_trust_detects_worktree_and_returns_main_root()

作用:确认遇到 Git worktree 时,信任判断返回主仓库根目录,而不是临时工作树目录。

数据流:先创建主仓库;再用 git worktree add 建一个关联工作树;从工作树根和它的子目录分别解析;结果经过路径规范化后,都应等于主仓库路径。

调用关系:它调用真实 git 命令制造 worktree,然后检查 resolve_root_git_project_for_trust 是否把工作树归并到主项目。normalize_for_path_comparison 用来消除不同系统路径写法差异。

调用图:调用 1 个内部函数(create_test_git_repo);外部调用 6 个(new, assert_eq!, new, resolve_root_git_project_for_trust, normalize_for_path_comparison, create_dir_all)。

resolve_root_git_project_for_trust_detects_worktree_pointer_without_git_command564–590 ↗
async fn resolve_root_git_project_for_trust_detects_worktree_pointer_without_git_command()

作用:确认只靠文件结构,不执行 git 命令,也能识别 worktree 指针并找到主仓库根。

数据流:测试手工创建 repo/.git/worktrees/feature-x 和 wt/.git 指针文件;再从 wt 和 wt/nested 解析;结果都应该返回 repo 的绝对路径。

调用关系:它专门覆盖 resolve_root_git_project_for_trust 的纯文件系统判断路径。这样即使不能或不想运行 git 命令,也能识别常见 worktree 结构。

调用图:外部调用 5 个(new, assert_eq!, format!, create_dir_all, write)。

resolve_root_git_project_for_trust_non_worktrees_gitdir_returns_none593–620 ↗
async fn resolve_root_git_project_for_trust_non_worktrees_gitdir_returns_none()

作用:确认 .git 指针文件如果不是指向 Git worktrees 结构,就不会被当成可信的主仓库。

数据流:测试创建一个 proj,并写入 .git 文件,但 gitdir 指向某个无关位置;从 proj 和 nested 子目录解析;结果都应是 None。

调用关系:它是 worktree 指针识别的反例测试。和前一个测试配合,确保 resolve_root_git_project_for_trust 不是看到 .git 文件就盲目信任。

调用图:外部调用 5 个(new, assert!, format!, create_dir_all, write)。

test_get_git_working_tree_state_unpushed_commit623–657 ↗
async fn test_get_git_working_tree_state_unpushed_commit()

作用:确认本地有已经提交但还没推送的提交时,git_diff_to_remote 能把它和远端之间的差别算出来。

数据流:先创建带远端的仓库并记录远端 sha;然后修改 test.txt、提交一个本地新提交但不 push;调用 git_diff_to_remote;结果 sha 仍指向远端,diff 中应包含本地提交带来的 updated 内容。

调用关系:它测试 git_diff_to_remote 对“本地领先远端”的处理。前面的工作区改动测试看未提交变化,这个测试看已提交但未推送变化。

调用图:调用 1 个内部函数(create_test_git_repo_with_remote);外部调用 8 个(from_utf8, new, assert!, assert_eq!, new, git_diff_to_remote, format!, write)。

test_git_info_serialization660–676 ↗
fn test_git_info_serialization()

作用:确认 GitInfo 转成 JSON 时,提交编号、分支名和仓库地址会用预期的字段名和值保存下来。

数据流:测试先手工构造一个 GitInfo,里面三个字段都有值;用 serde_json 转成字符串,再解析回普通 JSON 值;最后逐项检查字段内容。

调用关系:它不跑 git 命令,而是测试 GitInfo 这个数据结构的序列化格式。这个格式可能会被日志、接口或持久化内容使用,所以不能随便变。

调用图:调用 1 个内部函数(new);外部调用 3 个(assert_eq!, from_str, to_string)。

test_git_info_serialization_with_nones679–693 ↗
fn test_git_info_serialization_with_nones()

作用:确认 GitInfo 里没有值的字段转成 JSON 时会被省略,而不是输出成 null。

数据流:测试构造一个所有字段都是 None 的 GitInfo;转成 JSON 后再解析;最后检查对象里不包含 commit_hash、branch、repository_url 这些键。

调用关系:它补充测试 GitInfo 的空值序列化规则。这样外部读取 JSON 时不会看到一堆没有意义的空字段。

调用图:外部调用 3 个(assert!, from_str, to_string)。

core/src/shell_tests.rs源码 ↗
testtest run

这个文件像一套“开机前检查清单”,专门检查 shell 相关功能是否靠谱。shell 可以理解成系统里负责执行文字命令的工具,比如你输入 echo hello,真正帮你跑起来的就是它。测试会确认程序能找到常见 shell,能把一条命令拼成正确的启动参数,还会真的启动一次 shell,看它能不能输出 “Works”。它也考虑了不同系统的差异:macOS 上检查 zsh,Windows 上检查 PowerShell,其他系统上重点检查 bash 和 sh。还有一些兜底行为,比如用户 shell 是 fish 时回退到 zsh,防止程序遇到暂不支持的 shell 就失灵。整体来说,这个文件不提供正式功能,而是守住 shell 执行这条基础通道,避免跨平台运行时踩坑。

函数细节10
detects_zsh7–13 ↗
fn detects_zsh()

作用:这个测试确认在 macOS 上请求 zsh 时,程序能找到系统默认的 zsh 路径。zsh 是 macOS 常见的命令行外壳,找不到它会影响命令执行。

数据流:进去的是一个指定 shell 类型的请求:要找 Zsh,并且不手动给路径。测试调用查找 shell 的能力,拿到结果里的路径。出来的是一次断言:路径必须等于 /bin/zsh,否则测试失败。

调用关系:它由 Rust 测试框架在 macOS 环境下运行。它主要验证上层的 shell 查找逻辑,最后用 assert_eq! 这个断言工具判断结果是不是预期值。

调用图:外部调用 1 个(assert_eq!)。

fish_fallback_to_zsh17–23 ↗
fn fish_fallback_to_zsh()

作用:这个测试确认当用户当前 shell 是 fish 时,程序会安全地回退到 zsh。fish 是另一种 shell,但这里的程序显然不把它当作首选执行环境,所以需要一个可靠替代品。

数据流:进去的是一个模拟出来的用户 shell 路径 /bin/fish。测试把这个路径交给默认 shell 判断逻辑,逻辑应当选出 zsh。出来的是一次断言:最终 shell 路径必须是 /bin/zsh。

调用关系:它只在 macOS 上运行,由测试框架触发。它用 PathBuf::from 构造测试路径,再用 assert_eq! 检查回退结果,目的是保护默认 shell 选择规则不被改坏。

调用图:外部调用 2 个(from, assert_eq!)。

detects_bash26–34 ↗
fn detects_bash()

作用:这个测试确认程序能找到 bash。bash 是非常常见的命令行外壳,很多脚本都默认可以在它里面运行。

数据流:进去的是一个请求:查找 Bash,并且不指定固定路径。测试拿到 shell 路径后,只检查文件名是不是 bash,而不强行要求完整路径一样。出来的是成功或失败的断言结果。

调用关系:它由测试框架运行,用来覆盖 bash 查找能力。它最后调用 assert! 做判断;如果找到的路径结尾不是 bash,会把实际路径打印出来帮助排查。

调用图:外部调用 1 个(assert!)。

detects_sh37–44 ↗
fn detects_sh()

作用:这个测试确认程序能找到 sh。sh 是最基础、最通用的 Unix 风格命令行外壳,常作为最后的兼容选择。

数据流:进去的是一个请求:查找 Sh,不指定路径。测试读取返回结果中的 shell 路径,并检查这个路径的文件名是不是 sh。出来的是一个断言结果,表示查找是否符合预期。

调用关系:它由测试框架运行,验证 shell 查找逻辑里的 sh 分支。它使用 assert! 检查结果,失败时会显示实际路径,方便看出是系统环境问题还是代码问题。

调用图:外部调用 1 个(assert!)。

can_run_on_shell_test47–87 ↗
fn can_run_on_shell_test()

作用:这个测试不只是检查“找到了 shell”,还检查“找到的 shell 真的能跑命令”。这比只看路径更可靠,因为路径存在不代表执行参数一定正确。

数据流:进去的是一条简单命令,目标是输出 Works。测试根据当前是不是 Windows 分两条路:Windows 上测试 PowerShell、cmd 和兜底 shell;非 Windows 上测试兜底 shell、zsh、bash 和 sh。每个 shell 都交给 shell_works 去实际执行,出来的是多次断言:能用的 shell 必须成功输出 Works。

调用关系:它由测试框架运行,是这个文件里较完整的端到端检查。它用 cfg! 判断当前操作系统,用 assert! 要求结果为真,并把具体执行工作交给 shell_works。

调用图:外部调用 2 个(assert!, cfg!)。

shell_works89–102 ↗
fn shell_works(shell: Option<Shell>, command: &str, required: bool) -> bool

作用:这是一个测试用的小帮手,用来实际启动某个 shell,跑一条命令,并确认输出里有 Works。它把重复的“启动 shell、检查结果”步骤集中起来,避免每个测试都写一遍。

数据流:进去的是一个可能存在的 Shell、一条要执行的命令,以及这个 shell 是否必须存在的标记。函数先看有没有 shell;如果有,就让 shell 生成启动参数,用 Command::new 真正启动进程,检查退出状态成功,并检查标准输出包含 Works,然后返回 true。如果没有 shell,就根据 required 决定返回 false 还是 true:必需的 shell 缺失就是失败,非必需的 shell 缺失可以接受。

调用关系:它主要被 can_run_on_shell_test 使用,承担实际执行命令的部分。它会调用 Command::new 创建外部进程,并用 assert! 检查进程是否成功和输出是否正确。

调用图:外部调用 2 个(assert!, new)。

derive_exec_args105–144 ↗
fn derive_exec_args()

作用:这个测试确认不同 shell 在执行同一条命令时,会生成正确的启动参数。因为 bash、zsh、PowerShell 的参数习惯不一样,拼错一个参数就可能导致命令完全不执行。

数据流:进去的是几个手工构造的 Shell:bash、zsh 和 PowerShell,以及同一条命令 echo hello。测试分别调用 derive_exec_args,看它生成的参数列表是否符合预期。出来的是多次 assert_eq!:比如 bash 普通执行用 -c,登录 shell 用 -lc;PowerShell 普通执行会带 -NoProfile。

调用关系:它由测试框架运行,直接保护 Shell::derive_exec_args 这个参数生成规则。它用 PathBuf::from 准备测试路径,并用 assert_eq! 对比完整参数列表。

调用图:外部调用 2 个(from, assert_eq!)。

test_current_shell_detects_zsh147–164 ↗
async fn test_current_shell_detects_zsh()

作用:这个异步测试检查:如果当前系统环境变量 SHELL 显示用户正在用 zsh,那么程序的默认 shell 判断也应该认出 zsh。异步测试表示它运行在 tokio 测试运行时里,tokio 是 Rust 里常用的异步任务工具。

数据流:进去的是一次外部命令调用:用 sh -c echo $SHELL 读取当前用户 shell。函数把输出从字节转成文字并去掉空白。如果这个路径以 /zsh 结尾,就调用默认 shell 判断函数,并断言它返回的类型是 Zsh、路径也和环境变量一致。出来的是一次条件性的测试结果:只有当前环境确实是 zsh 时才做严格检查。

调用关系:它由 tokio::test 测试运行时触发。它使用 Command::new 启动 sh 读取环境变量,用 String::from_utf8_lossy 把输出转成人能读的字符串,最后用 assert_eq! 对比默认 shell 检测结果。

调用图:外部调用 3 个(from_utf8_lossy, assert_eq!, new)。

detects_powershell_as_default167–176 ↗
async fn detects_powershell_as_default()

作用:这个测试确认在 Windows 上,默认 shell 会被识别为 PowerShell。PowerShell 是 Windows 上常见的现代命令行外壳。

数据流:进去的是当前运行平台信息。函数先用 cfg! 判断是不是 Windows;不是就直接返回,不做测试。是 Windows 时,它读取默认 shell 的路径,并检查路径结尾是不是 pwsh.exe 或 powershell.exe。出来的是一个断言结果。

调用关系:它由测试框架运行,但只在 Windows 上真正检查。它用 cfg! 做平台分流,用 assert! 确认默认 shell 路径符合 PowerShell 的常见可执行文件名。

调用图:外部调用 2 个(assert!, cfg!)。

finds_powershell179–188 ↗
fn finds_powershell()

作用:这个测试确认程序能主动找到 PowerShell,而不只是把它当作默认 shell。这样其他代码明确要求 PowerShell 时,也能拿到可用路径。

数据流:进去的是当前平台信息和一个请求:查找 PowerShell。非 Windows 系统会直接跳过。Windows 上,测试调用 shell 查找功能,取出返回路径,并检查它是不是以 pwsh.exe 或 powershell.exe 结尾。出来的是一个断言结果。

调用关系:它由测试框架运行,是 Windows 专用的查找能力检查。它用 cfg! 避免在非 Windows 平台误测,用 assert! 验证 get_shell 对 PowerShell 的定位结果。

调用图:外部调用 2 个(assert!, cfg!)。

core/src/shell_snapshot_tests.rs源码 ↗
testtest

这个文件不负责给用户提供功能,而是像质检员一样验证 shell 快照这套功能。shell 快照可以理解成“把当前命令行环境拍一张照片”,里面有 PATH、别名、导出的环境变量等信息,之后新任务可以按这张照片恢复环境。测试覆盖了几个容易出错的地方:快照文件开头的杂音要能去掉;文件名要能认出对应会话;非法环境变量不能写进去,多行变量也不能写坏;创建快照后文件要存在,快照对象销毁后文件要删除;生成新快照不能覆盖旧快照;运行 shell 时不能继承会卡住的标准输入;超时的 shell 进程必须被杀掉;清理逻辑要删掉孤儿快照和过期快照,但不能删当前活跃会话。文件里还用一些 Unix 系统调用模拟特殊情况,比如临时替换标准输入、修改文件时间。

函数细节22
BlockingStdinPipe::install23–57 ↗
fn install() -> Result<Self>

作用:这个函数在 Unix 测试里临时把当前进程的标准输入换成一根不会立刻结束的管道。它用来模拟一种危险情况:如果被测试的 shell 继承了这个输入,可能会一直等用户输入而卡住。

数据流:进去时不需要业务参数,只读取操作系统的标准输入编号 → 它创建管道,备份原来的标准输入,再把标准输入指向管道读端 → 出来一个 BlockingStdinPipe 对象,里面记着原标准输入和管道写端;如果任何系统调用失败,就返回带上下文的错误。

调用关系:snapshot_shell_does_not_inherit_stdin 会先调用它布置一个“会卡住的输入环境”,然后再运行快照 shell,借此验证快照 shell 没有错误继承测试进程的标准输入。它底层把活交给 pipe、dup、dup2、close 这些操作系统接口。

调用图:被 1 处调用(snapshot_shell_does_not_inherit_stdin);外部调用 5 个(last_os_error, close, dup, dup2, pipe)。

BlockingStdinPipe::drop62–68 ↗
fn drop(&mut self)

作用:这个函数是 BlockingStdinPipe 被销毁时自动执行的清理动作。它把测试进程的标准输入恢复原样,并关闭临时打开的文件描述符,避免影响后面的测试。

数据流:进去的是对象里保存的原标准输入和管道写端 → 它把原标准输入复制回标准输入位置,然后关闭备份和管道 → 出来没有返回值,但进程的标准输入状态从“被测试替换过”恢复为“原来的样子”。

调用关系:它不是手动调用的普通函数,而是 Rust 的 Drop 清理机制自动调用。BlockingStdinPipe::install 创建的保护对象离开作用域时,它会收尾,保证 snapshot_shell_does_not_inherit_stdin 之后的测试不被污染。

调用图:外部调用 2 个(close, dup2)。

assert_posix_snapshot_sections72–81 ↗
fn assert_posix_snapshot_sections(snapshot: &str)

作用:这个辅助函数检查 Unix 类 shell 的快照里有没有几个关键段落。它关心的是快照像不像一份完整的环境记录,而不是具体每一行内容。

数据流:进去一整段快照文本 → 它检查里面是否包含快照标记、别名段、环境变量段、PATH 变量和 shell 选项段 → 如果都在,测试继续;少了任何一项就直接让测试失败。

调用关系:macos_zsh_snapshot_includes_sections、linux_bash_snapshot_includes_sections 和 linux_sh_snapshot_includes_sections 都复用它。这样不同 Unix shell 的测试不用重复写同一套基础检查。

调用图:被 3 处调用(linux_bash_snapshot_includes_sections, linux_sh_snapshot_includes_sections, macos_zsh_snapshot_includes_sections);外部调用 1 个(assert!)。

get_snapshot83–89 ↗
async fn get_snapshot(shell_type: ShellType) -> Result<String>

作用:这个异步辅助函数真的生成一份 shell 快照并把文件内容读回来。它让多个测试可以简单地说“给我某种 shell 的快照文本”。

数据流:进去一个 ShellType,也就是要测试的 shell 种类 → 它创建临时目录,调用写快照的核心函数把快照写到 snapshot.sh,再从磁盘读回这个文件 → 出来是快照文本字符串,失败时返回错误。

调用关系:Linux、macOS 和 Windows 的快照内容测试都会调用它。它把临时目录准备、调用 write_shell_snapshot、读取文件这些杂活集中起来,让具体测试只关心断言快照内容。

调用图:被 4 处调用(linux_bash_snapshot_includes_sections, linux_sh_snapshot_includes_sections, macos_zsh_snapshot_includes_sections, windows_powershell_snapshot_includes_sections);外部调用 2 个(read_to_string, tempdir)。

strip_snapshot_preamble_removes_leading_output92–96 ↗
fn strip_snapshot_preamble_removes_leading_output()

作用:这个测试确认快照前面如果混进了无关输出,清理函数能从真正的快照标记开始截取。这样用户启动脚本里乱打印的内容不会破坏快照。

数据流:进去一段包含“noise”和“# Snapshot file”的假快照文本 → 它调用 strip_snapshot_preamble 清掉标记前的内容 → 出来的结果应该只剩从“# Snapshot file”开始的有效快照;如果不一致,测试失败。

调用关系:它直接验证 strip_snapshot_preamble 的正常路径。这个能力对实际生成快照很重要,因为很多用户的 shell 启动文件会打印欢迎语或提示信息。

调用图:外部调用 1 个(assert_eq!)。

strip_snapshot_preamble_requires_marker99–102 ↗
fn strip_snapshot_preamble_requires_marker()

作用:这个测试确认如果文本里根本没有快照标记,清理函数不能假装成功。没有标记就说明这不是一份可信快照。

数据流:进去一段没有“# Snapshot file”的字符串 → 它调用 strip_snapshot_preamble → 出来应该是错误结果,而不是一段被误认为快照的文本。

调用关系:它验证 strip_snapshot_preamble 的失败路径,和 strip_snapshot_preamble_removes_leading_output 一起保证快照清理既能容忍杂音,也不会误收垃圾内容。

调用图:外部调用 1 个(assert!)。

snapshot_file_name_parser_supports_legacy_and_suffixed_names105–124 ↗
fn snapshot_file_name_parser_supports_legacy_and_suffixed_names()

作用:这个测试检查快照文件名解析器能认出老格式和带后缀的新格式。这样升级前后留下的快照文件都能被清理逻辑正确理解。

数据流:进去几种文件名字符串,包括“会话ID.sh”“会话ID.123.sh”“会话ID.tmp-123”和一个无关文件名 → 它调用 snapshot_session_id_from_file_name 解析 → 出来应当是正确的会话 ID,或者对无关文件返回 None。

调用关系:它保护的是清理快照时用到的文件名识别规则。后面的 cleanup_stale_snapshots 测试依赖这种识别能力,但这个测试单独把解析规则拎出来检查。

调用图:外部调用 1 个(assert_eq!)。

bash_snapshot_filters_invalid_exports128–148 ↗
fn bash_snapshot_filters_invalid_exports() -> Result<()>

作用:这个 Unix 测试确认 Bash 快照脚本不会把不该保存的环境变量写进快照。比如名字非法的变量、过时的 PWD,或测试框架临时变量,都应该被过滤掉。

数据流:进去的是一组人为设置的环境变量和 bash_snapshot_script 生成的脚本文本 → 它启动 /bin/bash 执行脚本,读取标准输出 → 出来要看到合法变量 VALID_NAME,同时不能看到 PWD、NEXTEST_BIN_EXE_codex-write-config-schema 和 BAD-NAME。

调用关系:它直接运行 bash_snapshot_script 产出的脚本,检查脚本本身的输出质量。这个测试不经过完整 ShellSnapshot 创建流程,目的是更精确地盯住 Bash 导出变量过滤规则。

调用图:外部调用 3 个(from_utf8_lossy, assert!, new)。

bash_snapshot_preserves_multiline_exports152–188 ↗
fn bash_snapshot_preserves_multiline_exports() -> Result<()>

作用:这个 Unix 测试确认多行环境变量不会被快照写坏。证书、私钥这类内容常常跨多行,如果保存方式不对,重新加载时 shell 会报错。

数据流:进去一个带换行的 MULTILINE_CERT 环境变量 → 它运行 Bash 快照脚本,确认输出里有这个变量名,再把输出写成临时快照文件,并让 Bash 重新 source 这个文件 → 出来要求重新加载成功,否则说明快照格式不安全。

调用关系:它先检查 bash_snapshot_script 的输出,再用真实 Bash 验证这份输出能不能被重新执行。它和 bash_snapshot_filters_invalid_exports 都在保护 Bash 快照脚本的可用性。

调用图:外部调用 5 个(from_utf8_lossy, assert!, new, write, tempdir)。

try_create_creates_and_deletes_snapshot_file192–216 ↗
async fn try_create_creates_and_deletes_snapshot_file() -> Result<()>

作用:这个 Unix 异步测试确认创建 ShellSnapshot 时确实会在磁盘上生成快照文件,并且对象销毁时会自动删掉文件。它验证“临时文件不乱留”的行为。

数据流:进去一个临时目录、一个新会话 ID 和 Bash shell 配置 → 它调用 ShellSnapshot::try_create 生成快照,记录生成的路径并检查文件存在 → drop 掉快照对象后,路径上的文件应该消失。

调用关系:它直接测试 ShellSnapshot::try_create 和 ShellSnapshot 的清理行为。这个测试说明快照文件的生命周期跟快照对象绑定,而不是永久散落在磁盘上。

调用图:调用 2 个内部函数(try_create, new);外部调用 3 个(from, assert!, tempdir)。

try_create_uses_distinct_generation_paths220–262 ↗
async fn try_create_uses_distinct_generation_paths() -> Result<()>

作用:这个 Unix 异步测试确认同一个会话连续生成两份快照时,会得到不同文件路径。这样刷新快照不会踩坏旧快照,也能安全地分别清理。

数据流:进去同一个临时目录、同一个会话 ID 和 Bash shell 配置 → 它调用两次 ShellSnapshot::try_create → 出来两条不同路径;删除第一份快照对象时只删第一份文件,第二份仍在,最后删除第二份对象时第二份文件也消失。

调用关系:它继续验证 ShellSnapshot::try_create 的文件命名和生命周期。和 try_create_creates_and_deletes_snapshot_file 相比,它重点检查“多代快照”不会互相干扰。

调用图:调用 2 个内部函数(try_create, new);外部调用 4 个(from, assert_eq!, assert_ne!, tempdir)。

snapshot_shell_does_not_inherit_stdin266–312 ↗
async fn snapshot_shell_does_not_inherit_stdin() -> Result<()>

作用:这个 Unix 异步测试确认生成快照时启动的 shell 不会继承测试进程的标准输入。否则如果标准输入一直不结束,快照进程可能卡住,用户就会觉得程序假死。

数据流:进去一个被 BlockingStdinPipe::install 替换过的标准输入、临时 HOME、写入的 .bashrc 和 Bash shell 配置 → 它让 .bashrc 尝试读取标准输入并记录结果,再运行 run_script_with_timeout 执行快照脚本 → 出来应当看到读取结果是 EOF,并且输出里包含快照标记。

调用关系:它先调用 BlockingStdinPipe::install 布置陷阱,再通过 run_script_with_timeout 启动快照 shell。这个测试保护的是快照执行器的进程启动方式,确保它给子 shell 的输入是安全的。

调用图:调用 1 个内部函数(install);外部调用 8 个(from_secs, from, assert!, assert_eq!, format!, read_to_string, write, tempdir)。

timed_out_snapshot_shell_is_terminated316–369 ↗
async fn timed_out_snapshot_shell_is_terminated() -> Result<()>

作用:这个 Linux 异步测试确认快照 shell 如果超时,不只是函数返回错误,还会真的把子进程结束掉。否则后台会留下睡眠进程,像垃圾一样越积越多。

数据流:进去一个会先写 pid 再 sleep 30 秒的脚本和 1 秒超时时间 → 它调用 run_script_with_timeout,期待得到超时错误,然后读取 pid,用 kill -0 反复检查进程是否还活着 → 出来要求进程在宽限时间内消失。

调用关系:它围绕 run_script_with_timeout 做故障场景测试。它不只看返回值,还向操作系统确认子进程确实被清掉,因此能发现“报错了但进程没杀”的隐藏问题。

调用图:外部调用 12 个(from_secs, now, from, new, null, from_millis, from_secs, assert!, format!, read_to_string (+2 more))。

macos_zsh_snapshot_includes_sections373–377 ↗
async fn macos_zsh_snapshot_includes_sections() -> Result<()>

作用:这个 macOS 异步测试确认 Zsh 快照包含基础段落。macOS 默认常用 Zsh,所以这能保证主流本机环境能被正确记录。

数据流:进去没有额外参数,只指定 ShellType::Zsh → 它通过 get_snapshot 生成并读取快照文本,再交给 assert_posix_snapshot_sections 检查关键段落 → 出来如果段落齐全就通过,否则失败。

调用关系:它是平台专用的外层测试,主要把“macOS + Zsh”这个组合接到通用辅助函数 get_snapshot 和 assert_posix_snapshot_sections 上。

调用图:调用 2 个内部函数(assert_posix_snapshot_sections, get_snapshot)。

linux_bash_snapshot_includes_sections381–385 ↗
async fn linux_bash_snapshot_includes_sections() -> Result<()>

作用:这个 Linux 异步测试确认 Bash 快照包含基础段落。Bash 是 Linux 上很常见的 shell,这个测试保证快照内容至少有完整骨架。

数据流:进去没有额外参数,只指定 ShellType::Bash → 它调用 get_snapshot 生成快照,再调用 assert_posix_snapshot_sections 检查标记、别名、环境变量、PATH 和选项 → 出来是测试通过或失败。

调用关系:它负责覆盖“Linux + Bash”组合。具体生成工作交给 get_snapshot,具体内容检查交给 assert_posix_snapshot_sections。

调用图:调用 2 个内部函数(assert_posix_snapshot_sections, get_snapshot)。

linux_sh_snapshot_includes_sections389–393 ↗
async fn linux_sh_snapshot_includes_sections() -> Result<()>

作用:这个 Linux 异步测试确认普通 sh 的快照也包含基础段落。这样即使用户使用更简洁的 /bin/sh,也能得到可用的环境记录。

数据流:进去没有额外参数,只指定 ShellType::Sh → 它通过 get_snapshot 得到快照文本,再用 assert_posix_snapshot_sections 检查标准 Unix 快照段落 → 出来如果内容齐全就通过。

调用关系:它覆盖“Linux + sh”组合,复用同一套快照生成和断言辅助,避免每个 shell 都写重复检查。

调用图:调用 2 个内部函数(assert_posix_snapshot_sections, get_snapshot)。

windows_powershell_snapshot_includes_sections398–404 ↗
async fn windows_powershell_snapshot_includes_sections() -> Result<()>

作用:这个 Windows 异步测试用于检查 PowerShell 快照是否包含基础段落。不过它当前被标记为忽略,说明平时测试不会自动跑它。

数据流:进去没有额外参数,只指定 ShellType::PowerShell → 它调用 get_snapshot 读取 PowerShell 快照,然后检查里面有快照标记、别名段和环境变量段 → 出来是通过或失败;但因为 ignore,默认测试流程会跳过。

调用关系:它是 Windows 平台的对应检查,结构上类似 Linux 和 macOS 的快照段落测试,只是断言内容更少,并且目前需要手动启用。

调用图:调用 1 个内部函数(get_snapshot);外部调用 1 个(assert!)。

write_rollout_stub406–416 ↗
async fn write_rollout_stub(codex_home: &Path, session_id: ThreadId) -> Result<PathBuf>

作用:这个辅助函数在测试目录里写一个假的 rollout 会话记录文件。清理快照时需要知道哪些会话还存在,这个假文件就是给测试用的“会话存在证明”。

数据流:进去 codex_home 根目录和一个 session_id → 它创建 sessions/2025/01/01 目录,并写入一个名字包含会话 ID 的空 jsonl 文件 → 出来是这个假 rollout 文件的路径。

调用关系:cleanup_stale_snapshots_removes_orphans_and_keeps_live、cleanup_stale_snapshots_removes_stale_rollouts 和 cleanup_stale_snapshots_skips_active_session 都调用它。它帮这些测试搭好清理逻辑需要扫描的会话记录。

调用图:被 3 处调用(cleanup_stale_snapshots_removes_orphans_and_keeps_live, cleanup_stale_snapshots_removes_stale_rollouts, cleanup_stale_snapshots_skips_active_session);外部调用 4 个(join, format!, create_dir_all, write)。

cleanup_stale_snapshots_removes_orphans_and_keeps_live419–442 ↗
async fn cleanup_stale_snapshots_removes_orphans_and_keeps_live() -> Result<()>

作用:这个异步测试确认清理快照时,会保留有会话记录的快照,删除没有会话记录的孤儿快照,也删除名字不合法的垃圾文件。

数据流:进去一个临时 codex_home,里面人为放入 live 快照、orphan 快照和无效文件名 → 它给 live 会话写 rollout 证明,然后调用 cleanup_stale_snapshots → 出来 live 快照还在,orphan 快照和无效文件都没了。

调用关系:它调用 write_rollout_stub 搭建“活会话”,再测试 cleanup_stale_snapshots 的基本判断能力。这个测试保护的是清理逻辑不会误删还可追踪的会话快照,同时会清掉明显无主的文件。

调用图:调用 2 个内部函数(write_rollout_stub, new);外部调用 5 个(assert_eq!, format!, create_dir_all, write, tempdir)。

cleanup_stale_snapshots_removes_stale_rollouts446–463 ↗
async fn cleanup_stale_snapshots_removes_stale_rollouts() -> Result<()>

作用:这个 Unix 异步测试确认即使快照有对应会话记录,只要记录已经太旧,也会被清理掉。它防止很久以前的会话快照永久占磁盘。

数据流:进去一个临时 codex_home、一个 stale 会话和对应快照 → 它写假 rollout 文件,再用 set_file_mtime 把这个 rollout 的修改时间调到保留期限之外,然后调用 cleanup_stale_snapshots → 出来旧快照应该被删除。

调用关系:它把 write_rollout_stub 和 set_file_mtime 组合起来,制造“有记录但过期”的场景,然后交给 cleanup_stale_snapshots 判断。它补上了仅测试孤儿文件还不够覆盖的过期规则。

调用图:调用 3 个内部函数(set_file_mtime, write_rollout_stub, new);外部调用 6 个(from_secs, assert_eq!, format!, create_dir_all, write, tempdir)。

cleanup_stale_snapshots_skips_active_session467–484 ↗
async fn cleanup_stale_snapshots_skips_active_session() -> Result<()>

作用:这个 Unix 异步测试确认当前正在使用的会话即使看起来很旧,也不会被清理掉。这样清理任务不会把自己脚下的快照删了。

数据流:进去一个临时 codex_home、一个 active 会话和对应快照 → 它写假 rollout 文件,把文件时间调旧,然后调用 cleanup_stale_snapshots,并把这个会话 ID 作为当前活跃会话传入 → 出来 active 快照必须还存在。

调用关系:它也使用 write_rollout_stub 和 set_file_mtime 制造旧文件,但重点是传入 active_session 给 cleanup_stale_snapshots。它和 cleanup_stale_snapshots_removes_stale_rollouts 形成对照:同样旧,活跃的不能删,非活跃的可以删。

调用图:调用 3 个内部函数(set_file_mtime, write_rollout_stub, new);外部调用 6 个(from_secs, assert_eq!, format!, create_dir_all, write, tempdir)。

set_file_mtime487–503 ↗
fn set_file_mtime(path: &Path, age: Duration) -> Result<()>

作用:这个 Unix 辅助函数把某个文件的修改时间改成“看起来已经过去了指定时长”。测试清理过期文件时,需要用它伪造旧文件。

数据流:进去一个文件路径和一个年龄 Duration → 它用当前时间减去年龄算出目标时间,转成 Unix 系统调用需要的 timespec,再调用 utimensat 修改文件时间 → 出来没有业务数据;成功时文件时间被改旧,失败时返回操作系统错误。

调用关系:cleanup_stale_snapshots_removes_stale_rollouts 和 cleanup_stale_snapshots_skips_active_session 调用它来搭建过期场景。它把底层 libc 时间修改细节藏起来,让测试主体只表达“这个文件已经很旧了”。

调用图:被 2 处调用(cleanup_stale_snapshots_removes_stale_rollouts, cleanup_stale_snapshots_skips_active_session);外部调用 6 个(as_secs, as_os_str, now, last_os_error, utimensat, new)。

core/src/realtime_context_tests.rs源码 ↗
testtest

这份文件不是真正给用户运行的功能,而是给开发者用的“安全网”。它测试的是实时会话启动时生成的一段上下文:里面会包含当前对话的最近几轮、最近做过的工作、当前文件夹的大致结构等。模型启动时靠这些信息接上上下文,就像新同事接班前先看一张交接单。测试会检查几件关键事:最近对话要按最新优先排列;太长的内容要裁短,但要保留开头和结尾;每个区块都有自己的长度预算,不能最后再把整包内容粗暴截断;空文件夹不要硬凑目录说明;有文件时要列出目录树;最近会话要按所在目录或 Git 仓库分组。文件里还准备了一些小帮手,用来造假的聊天消息、假的历史会话和很长的文本,方便测试各种边界情况。

函数细节14
stored_thread30–69 ↗
fn stored_thread(cwd: &str, title: &str, first_user_message: &str) -> StoredThread

作用:造一个假的历史会话记录,用来测试“最近做过的工作”这一块内容。它让测试不用真的跑一场完整聊天,也能得到一条看起来完整的会话数据。

数据流:进去的是工作目录、标题和第一条用户消息 → 它把这些填进一个 StoredThread 结构里,同时补上固定的时间、模型名、Git 分支、权限等测试用默认值 → 出来的是一条可被后续上下文生成函数读取的假会话记录。

调用关系:它是测试数据工厂。recent_work_section_groups_threads_by_cwd 这类测试会用它准备多条历史会话,然后把这些会话交给 build_recent_work_section 去验证分组和展示是否正确。它内部会创建 ThreadId、GitSha、路径和只读权限配置。

调用图:调用 3 个内部函数(read_only, new, new);外部调用 1 个(from)。

message71–79 ↗
fn message(role: &str, content: ContentItem) -> ResponseItem

作用:把一段内容包装成一条通用聊天消息。它是 user_message 和 assistant_message 的底层小工具,避免每个测试都手写完整消息结构。

数据流:进去的是角色名,比如 user 或 assistant,以及一块消息内容 → 它把内容放进列表里,并填入 ResponseItem::Message 需要的字段 → 出来的是一条统一格式的聊天记录。

调用关系:它位于测试消息构造的底层。user_message 和 assistant_message 会调用它,分别生成用户消息和助手消息,然后这些消息再被送进 build_current_thread_section 做当前对话上下文测试。

调用图:被 2 处调用(assistant_message, user_message);外部调用 1 个(vec!)。

user_message81–83 ↗
fn user_message(text: impl Into<String>) -> ResponseItem

作用:快速造一条“用户说的话”。测试当前对话历史时,经常需要一串用户和助手轮流说话的记录,这个函数就是为了少写重复代码。

数据流:进去的是一段可以转成字符串的文字 → 它先把文字转成字符串,再包成 InputText,也就是用户输入文本 → 出来的是角色为 user 的 ResponseItem。

调用关系:它把具体工作交给 message。current_thread_section_keeps_latest_turns_when_history_exceeds_budget 会用它生成多轮很长的用户发言,用来检查超出长度预算时是否保留最新几轮。

调用图:调用 1 个内部函数(message);被 1 处调用(current_thread_section_keeps_latest_turns_when_history_exceeds_budget);外部调用 1 个(into)。

assistant_message85–87 ↗
fn assistant_message(text: impl Into<String>) -> ResponseItem

作用:快速造一条“助手回复的话”。它让测试可以轻松拼出用户问、助手答的对话轮次。

数据流:进去的是一段可以转成字符串的文字 → 它把文字变成 OutputText,也就是助手输出文本,再交给 message 包装 → 出来的是角色为 assistant 的 ResponseItem。

调用关系:它和 user_message 搭配使用。current_thread_section_keeps_latest_turns_when_history_exceeds_budget 会用它生成助手回复,然后一起交给 build_current_thread_section 检查对话摘要是否按规则保留。

调用图:调用 1 个内部函数(message);被 1 处调用(current_thread_section_keeps_latest_turns_when_history_exceeds_budget);外部调用 1 个(into)。

long_turn_text89–95 ↗
fn long_turn_text(index: usize) -> String

作用:生成一段故意很长的测试文本,用来逼出“内容太长需要截断”的情况。它会在文本开头、中间、结尾放上明显标记,方便测试判断哪些部分被留下了。

数据流:进去的是一个编号 → 它拼出包含 start、middle、end 三个标记的大段文字,中间塞入大量 filler 占位词 → 出来的是一条很长的字符串。

调用关系:它服务于长度预算相关测试。current_thread_section_keeps_latest_turns_when_history_exceeds_budget 会调用它制造多轮长消息,再交给 build_current_thread_section,确认旧内容会被丢掉而最新内容会保留。

调用图:被 1 处调用(current_thread_section_keeps_latest_turns_when_history_exceeds_budget);外部调用 1 个(format!)。

current_thread_section_includes_short_turns_newest_first_until_budget98–145 ↗
fn current_thread_section_includes_short_turns_newest_first_until_budget()

作用:检查短对话历史会不会被整理成“最新一轮在最前面”的格式。这样模型先看到最近发生的事,更容易接上当前话题。

数据流:进去的是测试里手工写好的四轮用户/助手短消息 → 测试调用当前线程区块生成逻辑,并把结果和一整段预期文本逐字比较 → 如果顺序、标题或内容有一点不对,测试就失败。

调用关系:它直接验证 build_current_thread_section 的核心展示规则。这里没有复杂准备工作,重点是用 assert_eq! 把生成结果和标准答案对齐,防止格式被无意改坏。

调用图:外部调用 2 个(assert_eq!, vec!)。

current_thread_turn_truncation_preserves_start_and_end148–161 ↗
fn current_thread_turn_truncation_preserves_start_and_end()

作用:检查单条消息太长时,裁剪不是随便砍掉一边,而是保留开头和结尾。这样模型还能看到用户怎么开头、最后落到什么问题上。

数据流:进去的是一条由 long_turn_text 生成风格的超长用户消息 → 它调用 build_current_thread_section 生成当前对话区块 → 出来后测试检查结果包含 start 和 end,不包含 middle,并且明确写了 tokens truncated,也就是“有内容被截掉了”。

调用关系:它把长消息交给 build_current_thread_section,专门盯住截断策略。assert_eq! 用四个布尔结果一次性说明:该留的留下,该删的删掉,还要提示读者发生过裁剪。

调用图:外部调用 3 个(assert_eq!, build_current_thread_section, vec!)。

current_thread_section_keeps_latest_turns_when_history_exceeds_budget164–183 ↗
fn current_thread_section_keeps_latest_turns_when_history_exceeds_budget()

作用:检查对话历史太多时,系统优先保留最近几轮,而不是平均保留或从最早开始保留。对正在继续聊天的模型来说,最近内容通常最重要。

数据流:进去的是 8 轮很长的用户消息加简短助手回复 → 它把这些消息交给 build_current_thread_section → 出来的区块应包含第 8 轮的开头和结尾,也应显示还有前几轮,但不应再包含第 1 轮的内容。

调用关系:这个测试会调用 user_message、assistant_message 和 long_turn_text 来批量造数据,然后把结果交给 build_current_thread_section。它验证的是“预算不够时保新丢旧”的整体行为。

调用图:调用 3 个内部函数(assistant_message, long_turn_text, user_message);外部调用 4 个(new, assert_eq!, format!, build_current_thread_section)。

startup_context_blob_is_wrapped_in_tags_without_final_truncation186–194 ↗
fn startup_context_blob_is_wrapped_in_tags_without_final_truncation()

作用:检查启动上下文最后会被包在一对明确标签里。标签就像信封,告诉后续读取者:这一整段都是启动上下文。

数据流:进去的是一段已经拼好的启动上下文正文 → 它调用 format_startup_context_blob 包上 <startup_context> 和 </startup_context> → 出来后测试逐字确认包装格式正确,而且没有额外裁剪正文。

调用关系:它直接测试 format_startup_context_blob。这个函数处在最终封装阶段,前面的各个区块已经准备好,它负责把整段内容放进统一边界里。

调用图:外部调用 2 个(assert_eq!, format_startup_context_blob)。

fixed_section_budgets_apply_per_section_without_total_blob_truncation197–236 ↗
fn fixed_section_budgets_apply_per_section_without_total_blob_truncation()

作用:检查每个区块按自己的长度预算裁剪,而不是等所有内容拼完后再一刀切。这样可以保证“当前对话”“最近工作”“工作区地图”“备注”这些栏目都还有机会出现。

数据流:进去的是四个很长或较长的区块内容,以及各自的 token 预算;token 可以理解成模型读文本时的计量单位 → 它分别调用 format_section 做单区块裁剪,再调用 format_startup_context_blob 包成最终正文 → 出来后测试确认有裁剪提示,也确认四个标题都还在。

调用关系:它连接了 format_section 和 format_startup_context_blob 两层逻辑:先按栏目处理,再整体包装。它防止未来有人把策略改成“最后统一截断”,导致后面的栏目整个消失。

调用图:外部调用 3 个(assert!, format_section, format_startup_context_blob)。

workspace_section_requires_meaningful_structure239–245 ↗
async fn workspace_section_requires_meaningful_structure()

作用:检查空目录不会生成没意义的工作区说明。没有文件可讲时,硬塞一个空的目录地图只会浪费模型可读的长度。

数据流:进去的是一个新建的临时空目录,并且没有额外用户根目录 → 它调用 build_workspace_section_with_user_root → 出来的结果应是 None,表示不用生成这个区块。

调用关系:它测试 build_workspace_section_with_user_root 的“别废话”规则。临时目录由测试现场创建,用完自动清理。

调用图:外部调用 2 个(new, assert_eq!)。

workspace_section_includes_tree_when_entries_exist248–260 ↗
async fn workspace_section_includes_tree_when_entries_exist()

作用:检查目录里真的有东西时,工作区说明会列出简单目录树。这样模型可以快速知道当前文件夹下有哪些重要入口。

数据流:进去的是一个临时目录,测试先在里面创建 docs 文件夹和 README.md 文件 → 它调用 build_workspace_section_with_user_root → 出来的文本应包含“Working directory tree:”以及 docs/ 和 README.md。

调用关系:它通过真实写文件来模拟一个小工作区,然后把路径交给 build_workspace_section_with_user_root。assert! 负责确认生成的目录树确实把这些可见条目写出来了。

调用图:外部调用 5 个(new, assert!, create_dir, write, build_workspace_section_with_user_root)。

workspace_section_includes_user_root_tree_when_distinct263–282 ↗
async fn workspace_section_includes_user_root_tree_when_distinct()

作用:检查当用户指定的根目录和当前工作目录不一样时,上下文也会给出用户根目录的简要树状图。这样模型不只知道当前小文件夹,也知道用户认为更大的工作范围在哪里。

数据流:进去的是三个临时位置:当前工作目录、Git 根目录风格的目录、用户根目录 → 测试创建一些文件和文件夹后调用 build_workspace_section_with_user_root → 出来的文本应包含 User root tree 和 code/,但不应包含 .zshrc 这种隐藏配置文件。

调用关系:它测试 build_workspace_section_with_user_root 对多个根位置的处理。重点是:用户根目录不同才展示;展示时也会过滤掉不适合放进上下文的隐藏文件。

调用图:外部调用 5 个(new, assert!, create_dir_all, write, build_workspace_section_with_user_root)。

recent_work_section_groups_threads_by_cwd285–332 ↗
async fn recent_work_section_groups_threads_by_cwd()

作用:检查最近会话会按所在 Git 仓库或目录分组展示。这样模型看到的不只是零散历史,而是知道哪些历史属于同一个项目。

数据流:进去的是一个临时 Git 仓库、两个仓库内工作目录、一个仓库外目录,以及三条假的历史会话 → 它调用 build_recent_work_section → 出来的文本应把仓库内两条归到同一个 Git repo 下,并把仓库外那条单独按 Directory 展示。

调用关系:它先用文件系统和 git init 搭出真实环境,再用 stored_thread 造历史会话,最后交给 build_recent_work_section。这个测试验证最近工作区块能把“同项目的历史”聚到一起,方便启动时给模型交代背景。

调用图:外部调用 7 个(new, assert!, new, create_dir, create_dir_all, build_recent_work_section, vec!)。

core/src/realtime_conversation_tests.rs源码 ↗
testtest run

实时对话里,系统有时需要把当前聊天内容“交接”给另一个处理流程。这个文件就像一张验收清单:如果用户有明确输入,就优先用这段输入;如果没有,就从当前聊天记录里拼出文字;如果两边都空,就不要凭空造内容。它还检查交接内容会被包进一种类似 XML 的标签文本里,并且会把 <、>、& 这类特殊符号转义,避免内容被误当成标签。除此之外,它验证实时会话状态里的“当前交接编号”可以被清掉,以及不同实时 WebSocket 版本该不该带 openai-alpha 请求头。这里的 WebSocket 可以理解成一条持续连接的电话线,请求头就是通话前递过去的小纸条。这个文件不做真正业务,只负责防止这些规则以后被改坏。

函数细节11
prefers_handoff_input_transcript_over_active_transcript14–34 ↗
fn prefers_handoff_input_transcript_over_active_transcript()

作用:这个测试确认:交接请求里如果已经有明确的输入文字,就应该优先用它,而不是去用旁边的实时聊天记录。这样可以避免系统拿错用户真正想交给后续流程的内容。

数据流:进去的是一个假的交接请求,里面同时放了 input_transcript 和 active_transcript。测试把它交给 realtime_text_from_handoff_request,然后检查出来的结果必须是 input_transcript 里的“ignored”。它不改动外部状态,只判断取文字的优先级是否正确。

调用关系:它直接验证上层实时交接逻辑里的取文本函数。流程很简单:测试准备数据,再用 assert_eq! 对比结果;vec! 只是用来构造聊天记录列表。

调用图:外部调用 2 个(assert_eq!, vec!)。

extracts_text_from_handoff_request_active_transcript_if_input_missing37–51 ↗
fn extracts_text_from_handoff_request_active_transcript_if_input_missing()

作用:这个测试确认:如果交接请求里没有单独的输入文字,系统会退一步,从当前聊天记录里整理出可用文本。这样用户没填 input_transcript 时,交接也不会丢掉上下文。

数据流:进去的是一个 input_transcript 为空、active_transcript 里有一条用户消息的交接请求。测试调用 realtime_text_from_handoff_request,期望它把消息整理成“user: hello”。结果只是返回文本,不会修改状态。

调用关系:它覆盖的是“没有明确输入时怎么办”的分支。new 用来创建空字符串,vec! 用来放聊天条目,最后 assert_eq! 检查真实结果和期望结果是否一致。

调用图:外部调用 3 个(new, assert_eq!, vec!)。

wraps_handoff_with_transcript_delta54–77 ↗
fn wraps_handoff_with_transcript_delta()

作用:这个测试确认:从交接请求生成给后续流程看的内容时,不只会放入用户输入,还会附上这次实时聊天的新增对话片段。这样接手的一方能同时看到任务和必要上下文。

数据流:进去的是一个带 input_transcript 和两条聊天记录的交接请求。测试调用 realtime_delegation_from_handoff,期望出来的是一段带 <realtime_delegation>、<input> 和 <transcript_delta> 标签的文本。它不保存东西,只验证包装格式正确。

调用关系:它检查的是实时交接从原始请求变成“委托文本”的过程。测试自己构造请求和聊天记录,然后用 assert_eq! 确认 realtime_delegation_from_handoff 没漏掉 transcript_delta。

调用图:外部调用 2 个(assert_eq!, vec!)。

extracts_text_from_handoff_request_input_transcript_if_messages_missing80–91 ↗
fn extracts_text_from_handoff_request_input_transcript_if_messages_missing()

作用:这个测试确认:即使当前聊天记录为空,只要交接请求里有输入文字,系统仍然能取到这段文字。这样不会因为没有聊天记录就错误地认为没有内容。

数据流:进去的是一个有 input_transcript、但 active_transcript 是空列表的交接请求。测试调用 realtime_text_from_handoff_request,期望得到“ignored”。整个过程只读取请求内容并返回判断结果。

调用关系:它补齐了另一种常见情况:没有聊天记录但有明确输入。vec! 构造空列表,assert_eq! 用来确认取文本函数仍然按预期工作。

调用图:外部调用 2 个(assert_eq!, vec!)。

ignores_empty_handoff_request_input_transcript94–102 ↗
fn ignores_empty_handoff_request_input_transcript()

作用:这个测试确认:如果交接请求里的输入文字是空的,聊天记录也没有,系统应该返回“没有内容”,而不是返回空字符串假装有内容。这样后续流程能清楚知道这里没东西可处理。

数据流:进去的是一个 input_transcript 为空、active_transcript 也为空的交接请求。测试调用 realtime_text_from_handoff_request,期望结果是 None,也就是 Rust 里表示“没有值”的结果。它不改变任何状态。

调用关系:它测试的是兜底分支:所有可用文本都不存在时应该怎么做。new 创建空字符串,vec! 创建空聊天记录,assert_eq! 确认函数返回 None。

调用图:外部调用 3 个(new, assert_eq!, vec!)。

wraps_realtime_delegation_input105–110 ↗
fn wraps_realtime_delegation_input()

作用:这个测试确认:一段普通输入可以被包成实时交接使用的固定文本格式。这个格式像一个小信封,后续流程打开后知道哪部分是用户输入。

数据流:进去的是字符串“hello”和没有聊天增量的标记。测试调用 wrap_realtime_delegation_input,期望出来的是只包含 <input> 的 <realtime_delegation> 包装文本。它不读写外部状态。

调用关系:它直接盯住包装函数的最基本用法。测试只用 assert_eq! 比较包装后的文本,确保没有额外内容、换行或标签错误。

调用图:外部调用 1 个(assert_eq!)。

wraps_realtime_delegation_input_with_xml_escaping113–118 ↗
fn wraps_realtime_delegation_input_with_xml_escaping()

作用:这个测试确认:包装实时交接内容时,输入和聊天增量里的特殊符号会被安全转义。这样用户写的 < 或 & 不会被误解成格式标签,避免后续解析出错。

数据流:进去的是一段包含 <、>、&& 的输入,以及一段包含 <that> 的聊天增量。测试调用 wrap_realtime_delegation_input,期望这些符号变成 &lt;、&gt;、&amp; 这样的安全写法,并且同时保留 input 和 transcript_delta 两块内容。

调用关系:它验证包装函数里最容易被忽略的安全细节。assert_eq! 把完整字符串逐字对比,确保转义规则同时作用在输入和聊天增量上。

调用图:外部调用 1 个(assert_eq!)。

wraps_realtime_delegation_input_with_xml_escaping_without_transcript121–126 ↗
fn wraps_realtime_delegation_input_with_xml_escaping_without_transcript()

作用:这个测试确认:即使没有聊天增量,单独的用户输入也照样会做特殊符号转义。这样安全规则不会只在附带聊天记录时才生效。

数据流:进去的是包含 <、>、&& 的输入,以及没有 transcript_delta 的标记。测试调用 wrap_realtime_delegation_input,期望输出里只有 input 标签,并且里面的特殊符号已经被转义。它只返回字符串,不改状态。

调用关系:它补充检查包装函数的另一个分支:没有 transcript_delta 时也不能跳过转义。assert_eq! 用完整文本对比来防止格式或安全行为退化。

调用图:外部调用 1 个(assert_eq!)。

clears_active_handoff_explicitly129–146 ↗
async fn clears_active_handoff_explicitly()

作用:这个异步测试确认:实时交接状态里记录的“当前正在处理的交接编号”可以被明确清空。这样一次交接结束后,系统不会误以为旧交接还在继续。

数据流:进去的是一个新建的 RealtimeHandoffState,它内部有一个 active_handoff 字段。测试先把这个字段设成“handoff_1”,确认能读出来;然后再设成 None,确认已经清空。这里用了互斥锁,也就是一把锁,防止异步任务同时改同一份状态。

调用关系:它验证 RealtimeHandoffState 的状态字段能按预期被设置和清掉。bounded 创建一个测试用的小通道,RealtimeHandoffState::new 建状态,assert_eq! 分别检查写入前后结果。

调用图:调用 1 个内部函数(new);外部调用 2 个(assert_eq!, bounded)。

uses_quicksilver_alpha_header_for_realtime_v1149–161 ↗
fn uses_quicksilver_alpha_header_for_realtime_v1()

作用:这个测试确认:当使用实时 WebSocket V1 版本时,请求头里必须带上 openai-alpha: quicksilver=v1。请求头可以理解成发请求时附带的说明纸条,服务端会用它决定走哪种实验或版本行为。

数据流:进去的是会话编号、测试 API 密钥,以及 RealtimeWsVersion::V1。测试调用 realtime_request_headers 生成请求头,再从中读取 openai-alpha,期望它的值正好是“quicksilver=v1”。它只检查生成结果,不真正发网络请求。

调用关系:它盯住的是构造实时连接请求时的版本兼容规则。realtime_request_headers 负责产出请求头,assert_eq! 确保 V1 场景没有漏掉 quicksilver 标记。

调用图:外部调用 2 个(assert_eq!, realtime_request_headers)。

omits_quicksilver_alpha_header_for_realtime_v2164–171 ↗
fn omits_quicksilver_alpha_header_for_realtime_v2()

作用:这个测试确认:当使用实时 WebSocket V2 版本时,请求头里不应该再带 V1 专用的 openai-alpha 标记。这样新版本不会被错误地当成旧实验版本处理。

数据流:进去的是会话编号、测试 API 密钥,以及 RealtimeWsVersion::V2。测试调用 realtime_request_headers 生成请求头,然后检查里面没有 openai-alpha 这一项。它不发请求,只验证本地生成的头部内容。

调用关系:它和 V1 请求头测试成对出现,防止版本判断写反或漏改。realtime_request_headers 生成头部,assert! 确认 V2 结果中确实不存在 quicksilver alpha 头。

调用图:外部调用 2 个(assert!, realtime_request_headers)。