Fix direct-provider command monitoring
This commit is contained in:
+25
-15
@@ -80,7 +80,18 @@ pub(crate) async fn prepare_provider_run(
|
||||
let skill_path_origin = params.session_context.skill_path_origin();
|
||||
let max_context_tokens = params.context_window_limit;
|
||||
let mut cli_params = params.clone();
|
||||
cli_params.model = params.cli_agent_model.clone();
|
||||
let cli_provider_config = match cli_provider_config {
|
||||
crate::ai::provider::ProviderConfig::None => {
|
||||
// The CLI model can be absent from a model-specific provider routing table even when
|
||||
// the base model is usable. Keep monitoring available through the base provider/model.
|
||||
cli_params.model = params.model.clone();
|
||||
base_provider_config.clone()
|
||||
}
|
||||
provider_config => {
|
||||
cli_params.model = params.cli_agent_model.clone();
|
||||
provider_config
|
||||
}
|
||||
};
|
||||
|
||||
let (base_runtime, prepared) = prepare_provider_profile(
|
||||
base_provider_config,
|
||||
@@ -90,20 +101,15 @@ pub(crate) async fn prepare_provider_run(
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
let cli_monitor_profile = match cli_provider_config {
|
||||
crate::ai::provider::ProviderConfig::None => None,
|
||||
provider_config => {
|
||||
let (runtime, prepared) = prepare_provider_profile(
|
||||
provider_config,
|
||||
cli_params,
|
||||
supported_tools,
|
||||
supported_cli_agent_tools,
|
||||
Some(RigRequestMode::Cli),
|
||||
)
|
||||
.await?;
|
||||
Some(ProviderRunProfile::new(runtime, prepared.request))
|
||||
}
|
||||
};
|
||||
let (cli_runtime, cli_prepared) = prepare_provider_profile(
|
||||
cli_provider_config,
|
||||
cli_params,
|
||||
supported_tools,
|
||||
supported_cli_agent_tools,
|
||||
Some(RigRequestMode::Cli),
|
||||
)
|
||||
.await?;
|
||||
let cli_monitor_profile = Some(ProviderRunProfile::new(cli_runtime, cli_prepared.request));
|
||||
|
||||
let PreparedRigTurn {
|
||||
task_id,
|
||||
@@ -250,3 +256,7 @@ pub(crate) async fn provider_runtime_for_request(
|
||||
};
|
||||
Ok(runtime)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "rig_tests.rs"]
|
||||
mod tests;
|
||||
|
||||
@@ -816,7 +816,7 @@ fn build_system_prompt(
|
||||
"## Orchestration Mode\nDelegate only independent, bounded work where parallelism materially helps, then synthesize the results.\n\n",
|
||||
),
|
||||
RigRequestMode::Cli => prompt.push_str(
|
||||
"## Running Command Monitor\nThis turn concerns a running or just-finished shell command. Act as its dedicated monitor while still following the user's steering messages. Use the command ID from the tool result for every read/write operation. If the result says the command finished, report its outcome and stop polling. If it says the command is still running, the next assistant output MUST be a tool call: use `read_shell_command_output` with a short delay, or use `interrupt_shell_command` immediately when the user's explicit stop condition is met. Do not end a still-running monitor turn with prose, a status message, or a request for the user to say continue. Never choose a poll interval that crosses a user-specified deadline or stop condition. After an interrupt, poll briefly to verify the outcome. Never start a duplicate command merely to check its state, and never report completion while a result says it is still running.\n\n",
|
||||
"## Running Command Monitor\nThis turn concerns a running or just-finished shell command. Act as its dedicated monitor while still following the user's steering messages. Use the command ID from the tool result for every read/write operation. If the result says the command finished, report its outcome and stop polling. If it says the command is still running, the next assistant output MUST be a tool call. Use `read_shell_command_output` with a short delay for normal progress. If the snapshot clearly shows an interactive pager or editor, do not keep polling: an alternate screen containing `(END)` is `less`, so call `write_to_long_running_shell_command` with input `q` and mode `raw`; for a clearly identified Vim screen, send input `:q` with mode `line`. Poll briefly after sending quit input to verify the outcome. Use `interrupt_shell_command` immediately when the user's explicit stop condition is met. Do not end a still-running monitor turn with prose, a status message, or a request for the user to say continue. Never choose a poll interval that crosses a user-specified deadline or stop condition. After an interrupt, poll briefly to verify the outcome. Never start a duplicate command merely to check its state, and never report completion while a result says it is still running.\n\n",
|
||||
),
|
||||
RigRequestMode::CompletedCommandAssessment => prompt.push_str(
|
||||
"## Completed Command Assessment\nThe monitored command has finished. Use its command, command ID, final terminal output, and the assessment instruction in the latest hidden input to provide the final user-facing outcome. Do not continue polling, request more terminal output, or call tools.\n\n",
|
||||
|
||||
@@ -429,6 +429,8 @@ fn lrc_snapshot_follow_up_uses_the_cli_monitor_prompt_and_tools() {
|
||||
assert!(prompt.contains("## Running Command Monitor"));
|
||||
assert!(prompt.contains("`read_shell_command_output` with a short delay"));
|
||||
assert!(prompt.contains("next assistant output MUST be a tool call"));
|
||||
assert!(prompt.contains("alternate screen containing `(END)` is `less`"));
|
||||
assert!(prompt.contains("`write_to_long_running_shell_command` with input `q` and mode `raw`"));
|
||||
assert!(prompt.contains("Do not end a still-running monitor turn with prose"));
|
||||
assert!(prepared
|
||||
.request
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
use super::prepare_provider_run;
|
||||
use crate::ai::agent::api::RequestParams;
|
||||
use crate::ai::llms::LLMId;
|
||||
use crate::ai::openai::client::OpenAIClientConfig;
|
||||
use crate::ai::provider::ProviderConfig;
|
||||
use crate::settings::OpenAIProviderKind;
|
||||
|
||||
fn openai_config(model: &str) -> OpenAIClientConfig {
|
||||
OpenAIClientConfig {
|
||||
kind: OpenAIProviderKind::LiteLLM,
|
||||
base_url: "http://localhost:4000/v1".to_string(),
|
||||
api_key: None,
|
||||
project_id: None,
|
||||
location: None,
|
||||
model: Some(model.to_string()),
|
||||
reasoning_effort: None,
|
||||
max_input_tokens: Some(128_000),
|
||||
max_output_tokens: Some(8_192),
|
||||
use_rig: true,
|
||||
supports_system_messages: true,
|
||||
}
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn missing_cli_provider_route_falls_back_to_base_provider_profile() {
|
||||
let mut params = RequestParams::new_for_test();
|
||||
params.model = LLMId::from("base-selection");
|
||||
params.cli_agent_model = LLMId::from("unroutable-cli-selection");
|
||||
|
||||
let prepared = prepare_provider_run(
|
||||
ProviderConfig::OpenAI(openai_config("base-provider-model")),
|
||||
ProviderConfig::None,
|
||||
params,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let cli_profile = prepared
|
||||
.cli_monitor_profile
|
||||
.expect("base provider should supply the CLI monitor fallback");
|
||||
|
||||
assert_eq!(cli_profile.request.model.as_str(), "base-provider-model");
|
||||
assert!(cli_profile
|
||||
.request
|
||||
.system_prompt
|
||||
.as_deref()
|
||||
.is_some_and(|prompt| prompt.contains("## Running Command Monitor")));
|
||||
assert!(cli_profile
|
||||
.request
|
||||
.tools
|
||||
.iter()
|
||||
.any(|tool| tool.name == "write_to_long_running_shell_command"));
|
||||
assert!(cli_profile
|
||||
.request
|
||||
.tools
|
||||
.iter()
|
||||
.any(|tool| tool.name == "read_shell_command_output"));
|
||||
}
|
||||
Reference in New Issue
Block a user