fix: ACP session/prompt now drives the full tool-execution loop
run_prompt_turn previously performed a single completion and returned,
leaving tool calls unexecuted. It now mirrors start_directive's loop:
call -> execute tools -> merge results -> continue until no tool results,
then check the pending-agents guardrail before returning.
The pending-agents guardrail injects a reminder prompt when sub-agents
are pending, matching the same loop termination semantics as --headless.
The session is NOT exited between turns (unlike start_directive) so
multi-turn ACP conversations retain history across session/prompt calls.
Manual gate (tool-probe agent, fs_write + fs_read tools):
id 3 result: {"output":"DONE:probe.txt","stopReason":"end_turn"}
probe.txt exists: YES, content: hello
This commit is contained in:
+23
-5
@@ -1,6 +1,7 @@
|
||||
use super::types::{METHOD_NOT_FOUND, PARSE_ERROR, Request, Response};
|
||||
use crate::client::call_chat_completions_streaming;
|
||||
use crate::config::{Input, RenderMode, RequestContext};
|
||||
use crate::function::supervisor::{GuardrailAction, check_pending_agents_guardrail};
|
||||
use crate::utils;
|
||||
use crate::utils::AbortSignal;
|
||||
use anyhow::Result;
|
||||
@@ -198,16 +199,33 @@ async fn run_prompt_turn(
|
||||
abort: AbortSignal,
|
||||
) -> Result<String> {
|
||||
ctx.render_mode = RenderMode::Silent;
|
||||
let input = Input::from_str(ctx, text, None)?;
|
||||
let mut input = Input::from_str(ctx, text, None)?;
|
||||
loop {
|
||||
ctx.before_chat_completion(&input)?;
|
||||
let client = input.create_client()?;
|
||||
let (output, tool_results) =
|
||||
call_chat_completions_streaming(&input, client.as_ref(), ctx, abort).await?;
|
||||
call_chat_completions_streaming(&input, client.as_ref(), ctx, abort.clone()).await?;
|
||||
let app = Arc::clone(&ctx.app.config);
|
||||
|
||||
ctx.after_chat_completion(app.as_ref(), &input, &output, &tool_results)?;
|
||||
|
||||
Ok(output)
|
||||
if !tool_results.is_empty() {
|
||||
input = input.merge_tool_results(output, tool_results);
|
||||
continue;
|
||||
}
|
||||
match check_pending_agents_guardrail(ctx) {
|
||||
GuardrailAction::Inject(prompt) => {
|
||||
input = Input::from_str(ctx, &prompt, None)?;
|
||||
}
|
||||
GuardrailAction::ForceTerminate(ids) => {
|
||||
warn!(
|
||||
"Pending-agent guardrail force-cancelled {} agent(s): {:?}",
|
||||
ids.len(),
|
||||
ids
|
||||
);
|
||||
return Ok(output);
|
||||
}
|
||||
GuardrailAction::NoAction => return Ok(output),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_session_cancel(state: &mut AcpServerState) {
|
||||
|
||||
Reference in New Issue
Block a user