Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 20 additions & 8 deletions rustcode/engine/src/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,25 @@ pub(crate) const CHATGPT_TURN_STATE_HEADER: &str = "x-codex-turn-state";
/// synchronous MCP/filesystem work. Cache metadata is snapshotted before the
/// computation and sticky names are committed only if that snapshot is still
/// current when the computation finishes.
/// The root agent's tool policy for a request. The system prompt and the
/// provider request both build it here, so a tool the prompt describes
/// (`localhost_preview`) is always in the request's `tools` too.
pub(crate) fn root_schema_policy(
s: &AppState,
compact_tool_prompt: bool,
) -> crate::tools::ToolSchemaPolicy {
let policy = crate::tools::ToolSchemaPolicy::root_for_mode_with_compact_prompt(
s.delegation_active,
s.agent_mode,
compact_tool_prompt,
);
if s.preview_client.is_some() && !compact_tool_prompt {
policy.with_preview_tool()
} else {
policy
}
}

pub(crate) async fn prepare_native_tool_schemas(
state: &Arc<Mutex<AppState>>,
policy: crate::tools::ToolSchemaPolicy,
Expand Down Expand Up @@ -1558,17 +1577,10 @@ pub(crate) async fn prepare_turn_request_with_checkpoint_and_prefix_cache(
&& !matches!(protocol, crate::config::ToolProtocol::ApiNative);
let session_title_tool_available =
s.session_title_tool_available && agent_mode != crate::config::AgentMode::Plan;
let mut schema_policy = crate::tools::ToolSchemaPolicy::root_for_mode_with_compact_prompt(
delegation_active,
agent_mode,
compact_tool_prompt,
);
let mut schema_policy = root_schema_policy(&s, compact_tool_prompt);
if session_title_tool_available {
schema_policy = schema_policy.with_session_title_tool();
}
if s.preview_client.is_some() && !compact_tool_prompt {
schema_policy = schema_policy.with_preview_tool();
}
// The session-title tool only changes the native `tools` field; its
// guidance goes in the context tail so the system prompt (and the
// cached prefix) stays identical between the first and later turns.
Expand Down
6 changes: 1 addition & 5 deletions rustcode/engine/src/network/turn/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -586,11 +586,7 @@ pub(super) async fn collect_round(
(
s.api_base_url.clone(),
s.model_name.clone(),
crate::tools::ToolSchemaPolicy::root_for_mode_with_compact_prompt(
s.delegation_active,
s.agent_mode,
compact_tool_prompt,
),
crate::network::root_schema_policy(&s, compact_tool_prompt),
s.active_session_id.clone(),
)
};
Expand Down
22 changes: 22 additions & 0 deletions rustcode/engine/src/preview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -754,6 +754,28 @@ mod tests {
})
}

/// The prompt's hint and the provider request's `tools` come from one
/// policy: a session with a preview offers the tool it is told about.
#[test]
fn request_policy_offers_preview_with_a_client() {
let mut state = crate::app::AppState::new();
assert!(!crate::network::root_schema_policy(&state, false).include_preview_tool);
state.preview_client = Some(answering(Value::Null) as Arc<dyn PreviewClient>);
let policy = crate::network::root_schema_policy(&state, false);
assert!(policy.include_preview_tool);
let mut prompt = String::new();
crate::tools::schema::append_preview_hint(&mut prompt, policy);
assert!(prompt.contains(PREVIEW_TOOL_NAME));
let tools = crate::tools::native_tools_schema_for_context(policy, &[]).0;
assert!(
tools
.iter()
.any(|tool| tool.to_string().contains(PREVIEW_TOOL_NAME))
);
// A compact prompt describes no preview, so offers none.
assert!(!crate::network::root_schema_policy(&state, true).include_preview_tool);
}

fn no_save(_: &[u8], _: &str) -> std::io::Result<PathBuf> {
panic!("nothing should be saved")
}
Expand Down
Loading