fix(runtime): deep audit fixes — clarification loop termination + callback alignment
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
Some checks failed
CI / Lint & TypeCheck (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Build Frontend (push) Has been cancelled
CI / Rust Check (push) Has been cancelled
CI / Security Scan (push) Has been cancelled
CI / E2E Tests (push) Has been cancelled
CRITICAL: - ask_clarification now terminates Agent Loop in both run() and run_streaming() paths, preventing the LLM from continuing after requesting user clarification HIGH: - SaaS relay now forwards plan_mode and subagent_enabled to backend - GatewayClient.chatStream now supports onThinkingDelta, onSubtaskStatus, and token-bearing onComplete — aligned with kernel-types StreamCallbacks - ZclawStreamEvent type extended with thinking_delta, subtask_status variants and input_tokens/output_tokens fields for token tracking via Gateway path
This commit is contained in:
@@ -402,6 +402,7 @@ impl AgentLoop {
|
||||
let tool_context = self.create_tool_context(session_id.clone());
|
||||
let mut circuit_breaker_triggered = false;
|
||||
let mut abort_result: Option<AgentLoopResult> = None;
|
||||
let mut clarification_result: Option<AgentLoopResult> = None;
|
||||
for (id, name, input) in tool_calls {
|
||||
// Check if loop was already aborted
|
||||
if abort_result.is_some() {
|
||||
@@ -475,6 +476,32 @@ impl AgentLoop {
|
||||
Err(e) => serde_json::json!({ "error": e.to_string() }),
|
||||
};
|
||||
|
||||
// Check if this is a clarification response — terminate loop immediately
|
||||
// so the LLM waits for user input instead of continuing to generate.
|
||||
if name == "ask_clarification"
|
||||
&& tool_result.get("status").and_then(|v| v.as_str()) == Some("clarification_needed")
|
||||
{
|
||||
tracing::info!("[AgentLoop] Clarification requested, terminating loop");
|
||||
let question = tool_result.get("question")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("需要更多信息")
|
||||
.to_string();
|
||||
messages.push(Message::tool_result(
|
||||
id,
|
||||
zclaw_types::ToolId::new(&name),
|
||||
tool_result,
|
||||
false,
|
||||
));
|
||||
self.memory.append_message(&session_id, &Message::assistant(&question)).await?;
|
||||
clarification_result = Some(AgentLoopResult {
|
||||
response: question,
|
||||
input_tokens: total_input_tokens,
|
||||
output_tokens: total_output_tokens,
|
||||
iterations,
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
// Add tool result to messages
|
||||
messages.push(Message::tool_result(
|
||||
id,
|
||||
@@ -491,6 +518,11 @@ impl AgentLoop {
|
||||
break result;
|
||||
}
|
||||
|
||||
// If clarification was requested, return immediately
|
||||
if let Some(result) = clarification_result {
|
||||
break result;
|
||||
}
|
||||
|
||||
// If circuit breaker was triggered, terminate immediately
|
||||
if circuit_breaker_triggered {
|
||||
let msg = "检测到工具调用循环,已自动终止";
|
||||
@@ -972,6 +1004,35 @@ impl AgentLoop {
|
||||
(error_output, true)
|
||||
};
|
||||
|
||||
// Check if this is a clarification response — break outer loop
|
||||
if name == "ask_clarification"
|
||||
&& result.get("status").and_then(|v| v.as_str()) == Some("clarification_needed")
|
||||
{
|
||||
tracing::info!("[AgentLoop] Streaming: Clarification requested, terminating loop");
|
||||
let question = result.get("question")
|
||||
.and_then(|v| v.as_str())
|
||||
.unwrap_or("需要更多信息")
|
||||
.to_string();
|
||||
messages.push(Message::tool_result(
|
||||
id,
|
||||
zclaw_types::ToolId::new(&name),
|
||||
result,
|
||||
is_error,
|
||||
));
|
||||
// Send the question as final delta so the user sees it
|
||||
let _ = tx.send(LoopEvent::Delta(question.clone())).await;
|
||||
let _ = tx.send(LoopEvent::Complete(AgentLoopResult {
|
||||
response: question.clone(),
|
||||
input_tokens: total_input_tokens,
|
||||
output_tokens: total_output_tokens,
|
||||
iterations: iteration,
|
||||
})).await;
|
||||
if let Err(e) = memory.append_message(&session_id_clone, &Message::assistant(&question)).await {
|
||||
tracing::warn!("[AgentLoop] Failed to save clarification message: {}", e);
|
||||
}
|
||||
break 'outer;
|
||||
}
|
||||
|
||||
// Add tool result to message history
|
||||
tracing::debug!("[AgentLoop] Adding tool_result to history: id={}, name={}, is_error={}", id, name, is_error);
|
||||
messages.push(Message::tool_result(
|
||||
|
||||
Reference in New Issue
Block a user