fix(core): restrict modal questions to supported hosts

This commit is contained in:
Felipe Coury
2026-05-26 14:36:32 -03:00
parent 816e48ccca
commit a906903e13
4 changed files with 41 additions and 7 deletions
@@ -8,4 +8,4 @@ Your active mode changes only when new developer instructions with a different `
Use the `request_user_input` tool only when it is listed in the available tools for this turn.
In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message.
In Default mode, strongly prefer making reasonable assumptions and executing the user's request rather than stopping to ask questions. If you absolutely must ask a question because the answer cannot be discovered from local context and a reasonable assumption would be risky, use `request_user_input` when it is available. If the tool is unavailable, ask the user directly with a concise plain-text question. Never write a multiple choice question as a textual assistant message.
+7 -3
View File
@@ -568,9 +568,13 @@ fn add_core_utility_tools(context: &CoreToolPlanContext<'_>, planned_tools: &mut
planned_tools.add(UpdateGoalHandler);
}
planned_tools.add(RequestUserInputHandler {
available_modes: request_user_input_available_modes(),
});
if !turn_context.session_source.is_non_root_agent()
&& !matches!(&turn_context.session_source, SessionSource::Exec)
{
planned_tools.add(RequestUserInputHandler {
available_modes: request_user_input_available_modes(),
});
}
if features.enabled(Feature::RequestPermissionsTool) {
planned_tools.add(RequestPermissionsHandler);
@@ -442,6 +442,33 @@ async fn host_context_gates_goal_and_agent_job_tools() {
worker_agent_job.assert_visible_contains(&["spawn_agents_on_csv", "report_agent_job_result"]);
}
#[tokio::test]
async fn request_user_input_is_hidden_from_unsupported_session_sources() {
let interactive_root = probe(|turn| {
turn.session_source = SessionSource::VSCode;
})
.await;
interactive_root.assert_visible_contains(&["request_user_input"]);
let exec = probe(|turn| {
turn.session_source = SessionSource::Exec;
})
.await;
exec.assert_visible_lacks(&["request_user_input"]);
let sub_agent = probe(|turn| {
turn.session_source = SessionSource::SubAgent(SubAgentSource::ThreadSpawn {
parent_thread_id: Default::default(),
depth: 1,
agent_path: None,
agent_nickname: None,
agent_role: None,
});
})
.await;
sub_agent.assert_visible_lacks(&["request_user_input"]);
}
#[tokio::test]
async fn mcp_and_tool_search_follow_direct_and_deferred_tool_exposure() {
let direct_mcp = probe_with(
@@ -700,6 +727,7 @@ async fn code_mode_only_exposes_code_executor_and_hides_nested_tools() {
#[tokio::test]
async fn code_mode_only_keeps_request_user_input_as_a_direct_modal_tool() {
let plan = probe(|turn| {
turn.session_source = SessionSource::VSCode;
set_features(turn, &[Feature::CodeMode, Feature::CodeModeOnly]);
})
.await;
@@ -897,6 +925,7 @@ async fn multi_agent_v2_namespace_is_ignored_without_provider_namespace_support(
#[tokio::test]
async fn code_mode_only_can_expose_namespaced_multi_agent_v2_as_normal_tools() {
let plan = probe(|turn| {
turn.session_source = SessionSource::VSCode;
set_features(
turn,
&[
@@ -30,7 +30,8 @@ fn default_mode_instructions_replace_mode_names_placeholder() {
assert!(default_instructions.contains(
"Use the `request_user_input` tool only when it is listed in the available tools"
));
assert!(
default_instructions.contains("ask the user directly with a concise plain-text question")
);
assert!(default_instructions.contains("use `request_user_input` when it is available"));
assert!(default_instructions.contains(
"If the tool is unavailable, ask the user directly with a concise plain-text question"
));
}