Skip to content

Session设置约束

解释 rust-v0.150.0 中 Session 设置如何经过约束、预览、应用和快照传播,并区分失败时的状态边界。

基于rust-v0.150.0
CodexRustSessionConfig

Session设置约束 ​

rust-v0.150.0 已移除旧版 config lock 文件的加载、导出和 replay。当前 Session 的配置一致性由 requirements、PermissionProfileState、SessionConfiguration 和设置更新流程共同维护。本文回答一个 实际问题:调用方提交设置时,Codex 如何判断候选值、何时改变运行时、哪些值只影响后续 Turn。

阅读本文前,建议先读 Session依赖装配 了解 Session 如何构造 SessionConfiguration 与 SessionServices,再读 CodexThread公共API 了解 preview、apply 和 Turn input 调用面。本文不展开模型采样和平台沙箱实现。

1. 约束对象 ​

设置输入、内部更新和对外快照是三种不同对象:协议层的 ThreadSettingsOverrides 描述候选修改; Core 的 SessionSettingsUpdate 负责合并字段;SessionConfiguration 通过约束后才成为 Session 的 有效状态;ThreadSettingsSnapshot 只是只读投影。

源码位置:codex-rs/core/src/session/session.rs :: SessionSettingsUpdate, SessionConfiguration::thread_settings_snapshot

rust
#[derive(Default, Clone)]
pub(crate) struct SessionSettingsUpdate {
    pub(crate) environments: Option<TurnEnvironmentSelections>,
    pub(crate) approval_policy: Option<AskForApproval>,
    pub(crate) approvals_reviewer: Option<ApprovalsReviewer>,
    pub(crate) permission_profile: Option<PermissionProfile>,
    pub(crate) active_permission_profile: Option<ActivePermissionProfile>,
    pub(crate) collaboration_mode: Option<CollaborationMode>,
    pub(crate) reasoning_summary: Option<ReasoningSummaryConfig>,
    pub(crate) service_tier: Option<Option<String>>,
    pub(crate) personality: Option<Personality>,
}

真实协议类型位于 codex-rs/protocol/src/protocol.rs :: ThreadSettingsSnapshot。快照不是可以原样提交的 锁文件:requirements、当前 environment 和 active permission profile 仍会在 Core 中重新约束。

2. 预览与应用 ​

preview_settings() 只复制并验证候选配置,不改变 Session;update_settings() 才提交新的 SessionConfiguration。应用后,Core 根据差异更新环境选择、标记 MCP runtime dirty、通知 extension config contributors,并在 permission profile 变化时刷新 managed network proxy。

源码位置:codex-rs/core/src/session/mod.rs :: Session::preview_settings, Session::update_settings

rust
pub(crate) async fn preview_settings(
    &self,
    updates: &SessionSettingsUpdate,
) -> ConstraintResult<ThreadConfigSnapshot> {
    let state = self.state.lock().await;
    let configuration = self.apply_session_settings(
        &state.session_configuration,
        updates,
    )?;
    let environments = updates.environments.as_ref().map_or_else(
        || self.services.turn_environments.selections(),
        |value| value.environments.clone(),
    );
    Ok(configuration.thread_config_snapshot(environments))
}

pub(crate) async fn update_settings(
    &self,
    updates: SessionSettingsUpdate,
) -> ConstraintResult<()> {
    let mut state = self.state.lock().await;
    let updated = self.apply_session_settings(
        &state.session_configuration,
        &updates,
    )?;
    state.session_configuration = updated;
    Ok(())
}

真实实现还会在释放状态锁后通知 contributors、刷新环境和 managed proxy。关键边界是:预览不写状态; 应用通过同一 apply_session_settings 约束候选值后才提交。

3. 约束合并 ​

SessionConfiguration::apply 复制旧配置后逐项合并。审批字段调用 Constrained::set;permission profile 重建文件与网络策略并保留已有 deny-read;环境变化经过环境校验;requirements 要求时,切换到不兼容模型 还会强制 AutoReview。

源码位置:codex-rs/core/src/session/session.rs :: SessionConfiguration::apply

rust
if let Some(approval_policy) = updates.approval_policy {
    next_configuration.approval_policy.set(approval_policy)?;
}
if let Some(approvals_reviewer) = updates.approvals_reviewer {
    next_configuration
        .original_config_do_not_use
        .config_layer_stack
        .requirements()
        .approvals_reviewer
        .can_set(&approvals_reviewer)?;
    next_configuration.approvals_reviewer = approvals_reviewer;
}
if let Some(permission_profile) = updates.permission_profile.clone() {
    next_configuration.set_permission_profile_projection(
        permission_profile,
        updates.active_permission_profile.clone(),
        updates.profile_workspace_roots.clone().unwrap_or_default(),
        Some(&current_file_system_sandbox_policy),
    )?;
}
next_configuration.validate(next_environments)?;
Ok(next_configuration)

这不是单一 allowlist:requirements 可以限制 reviewer 或 model,validate_environment_selections 检查 环境,permission profile projection 还维护文件和网络策略不变量。任一校验失败都保留旧配置。

4. 生效边界 ​

standalone ThreadSettings 和 Turn input 携带的 settings 都经过同一套约束。成功后由 thread_settings.rs 生成完整 ThreadSettingsAppliedEvent;事件内容是更新后的 snapshot,而不是请求 patch 的回声。

源码位置:codex-rs/core/src/session/thread_settings.rs :: update, apply_update, emit_applied

rust
pub(super) async fn apply_update(
    session: &Session,
    submission_id: String,
    updates: SessionSettingsUpdate,
) -> ConstraintResult<()> {
    session.update_settings(updates).await?;
    emit_applied(session, submission_id).await;
    Ok(())
}

pub(super) async fn emit_applied(session: &Session, submission_id: String) {
    let msg = applied_event(session).await;
    session
        .send_event_raw_without_materializing_rollout(Event {
            id: submission_id,
            msg,
        })
        .await;
}

如果本地 rollout 尚未物化,设置事件不会仅因为设置成功而创建空文件;已有持久化线程仍按正常策略记录。 运行中的 active Turn 保持自己的 TurnContext,新设置主要影响后续 Turn。

5. 失败处理 ​

候选值违反 requirements、permission profile 无法转换或 environment 不合法时,失败发生在状态替换之前; MCP prewarm 和 managed proxy 刷新则只在更新成功后触发。

失败位置典型原因原配置是否替换调用方看到什么
Constrained::setapproval policy 不允许否BadRequest Error Event
requirements reviewerreviewer 不在允许集合否BadRequest Error Event
permission profile projectionprofile/network 约束无效否ConstraintError
environment validationcwd、root 或 environment 选择无效否ConstraintError
MCP 输入变化server 配置需重建是runtime dirty + prewarm
permission profile 已应用managed proxy 需换绑是proxy refresh

ThreadSettings 的错误由 session/thread_settings.rs :: update 转成 EventMsg::Error;TurnInput 的错误 由 TurnInputSubmission::NotSubmitted 或上层 JSON-RPC 错误返回。两者共享约束实现,但完成信号不同。

6. 测试边界 ​

当前版本不再有 config-lock schema/version/replay 测试;测试集中在设置合并、Turn input 路由和权限投影。

源码位置:codex-rs/core/src/session/turn_input_tests.rs :: start_only_rejects_active_turn_without_injecting

rust
let submission = submit_start_only(
    &session,
    SubmittedTurnInput::ResponseItem(user_message("synthetic idle input")),
)
.await;
assert_eq!(
    submission,
    TurnInputSubmission::NotSubmitted {
        reason: NotSubmittedReason::NotIdle,
    }
);
assert_eq!(
    session.input_queue.get_pending_input(&session.active_turn).await,
    (Vec::<TurnInput>::new(), None, None),
);

该测试证明 idle-only 输入在 active Turn 存在时不会注入或排队;它不覆盖所有 requirements 组合。通用约束 容器的失败保持旧值由 codex-rs/config/src/constraint.rs :: Constrained::set 的单元测试覆盖。

7. 继续阅读 ​

要追踪设置从 App Server 进入 Core,可回看 Session依赖装配 与 CodexThread公共API。要理解 permission profile 如何影响文件和网络 强制,转到 Codex信任边界。

bash
rg -n "apply_session_settings|preview_settings|update_settings|ThreadSettingsSnapshot|ConstraintError" \
  codex-rs/core/src codex-rs/config/src codex-rs/protocol/src