fix(agent): 优化工具待处理输出和交互会话行为
- 从工具输出中过滤元数据和内部标记,仅显示有意义内容 - 增加等待stdin输入时的短暂延迟,确保提示内容传入通道 - 始终创建交互式会话,即使当前输出为空,避免丢失会话信息 - 优化交互会话保存逻辑,确保正确处理stdin等待状态 - 修改.gitignore,添加.qoder目录忽略规则
This commit is contained in:
parent
a7883dbed9
commit
c5f4209d33
1
.gitignore
vendored
1
.gitignore
vendored
@ -33,3 +33,4 @@ uv.lock
|
||||
node_modules
|
||||
logs
|
||||
dist
|
||||
.qoder
|
||||
|
||||
@ -1097,15 +1097,20 @@ impl AgentLoop {
|
||||
.zip(tool_results.iter())
|
||||
.find(|(_, result)| result.state == ToolExecutionState::PendingUserAction)
|
||||
{
|
||||
// 从工具输出中提取有意义的内容,跳过内部标记和元数据行
|
||||
let content_line = pending_result
|
||||
.output
|
||||
.lines()
|
||||
.map(|l| l.trim())
|
||||
.find(|line| {
|
||||
!line.is_empty()
|
||||
&& !line.starts_with("__PICOBOT_")
|
||||
&& !line.starts_with("[session_id:")
|
||||
})
|
||||
.unwrap_or(DEFAULT_PENDING_ASSISTANT_MESSAGE);
|
||||
let assistant_message = ChatMessage::assistant(format!(
|
||||
"{}\n\n当前等待中的工具: {}",
|
||||
pending_result
|
||||
.output
|
||||
.lines()
|
||||
.next()
|
||||
.filter(|line| !line.trim().is_empty())
|
||||
.unwrap_or(DEFAULT_PENDING_ASSISTANT_MESSAGE),
|
||||
tool_call.name,
|
||||
content_line, tool_call.name,
|
||||
));
|
||||
emitted_messages.push(assistant_message.clone());
|
||||
self.emit_live_tool_call_message(assistant_message.clone()).await;
|
||||
|
||||
@ -18,6 +18,8 @@ use crate::tools::{extract_u64, extract_bool, check_null_args};
|
||||
const MAX_TIMEOUT_SECS: u64 = 600;
|
||||
const MAX_OUTPUT_CHARS: usize = 50_000;
|
||||
const PENDING_USER_ACTION_MARKER: &str = "__PICOBOT_PENDING_USER_ACTION__";
|
||||
/// 检测到 stdin 等待后,给 read_stream 任务将最后的提示内容传入 channel 的时间
|
||||
const STDIN_FLUSH_MS: u64 = 500;
|
||||
const INTERACTIVE_HINT: &str =
|
||||
"进程正在等待输入。请使用 session_id 和 stdin_input 参数回复交互内容。";
|
||||
const NON_INTERACTIVE_HINT: &str =
|
||||
@ -182,12 +184,17 @@ impl BashTool {
|
||||
let session_line = session_id
|
||||
.map(|id| format!("[session_id: {}]\n", id))
|
||||
.unwrap_or_default();
|
||||
let output_section = if output.trim().is_empty() {
|
||||
"(进程尚未输出内容。进程正在等待输入,请使用 session_id 和 stdin_input 参数发送输入内容。)"
|
||||
} else {
|
||||
&self.truncate_output(output.trim())
|
||||
};
|
||||
format!(
|
||||
"{}\n{}{}\n\n{}",
|
||||
PENDING_USER_ACTION_MARKER,
|
||||
session_line,
|
||||
hint,
|
||||
self.truncate_output(output.trim())
|
||||
output_section
|
||||
)
|
||||
}
|
||||
|
||||
@ -472,25 +479,26 @@ impl BashTool {
|
||||
// Periodic safety net: check OS-level process state
|
||||
if let Some(pid) = child.id() {
|
||||
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true) {
|
||||
// 给 read_stream 任务时间将最后的提示内容传入 channel
|
||||
tokio::time::sleep(Duration::from_millis(STDIN_FLUSH_MS)).await;
|
||||
if let Some(rx_ref) = rx.as_mut() {
|
||||
drain_available_chunks(rx_ref, &stdout_buf, &stderr_buf).await;
|
||||
}
|
||||
let combined = format_command_output(&stdout_buf.lock().await, &stderr_buf.lock().await, None);
|
||||
if !combined.trim().is_empty() {
|
||||
if let Some(stdin) = child_stdin {
|
||||
if let Some(rx_val) = rx.take() {
|
||||
let session_id = self.session_manager.save_session(
|
||||
child, stdin, rx_val,
|
||||
stdout_buf.lock().await.clone(),
|
||||
stderr_buf.lock().await.clone(),
|
||||
).await;
|
||||
return Ok(self.pending_output(&combined, Some(&session_id)));
|
||||
}
|
||||
// 始终创建 session,即使输出为空(进程可能还没写出提示)
|
||||
if let Some(stdin) = child_stdin {
|
||||
if let Some(rx_val) = rx.take() {
|
||||
let session_id = self.session_manager.save_session(
|
||||
child, stdin, rx_val,
|
||||
stdout_buf.lock().await.clone(),
|
||||
stderr_buf.lock().await.clone(),
|
||||
).await;
|
||||
return Ok(self.pending_output(&combined, Some(&session_id)));
|
||||
}
|
||||
let _ = child.start_kill();
|
||||
let _ = child.wait().await;
|
||||
return Ok(self.pending_output(&combined, None));
|
||||
}
|
||||
let _ = child.start_kill();
|
||||
let _ = child.wait().await;
|
||||
return Ok(self.pending_output(&combined, None));
|
||||
}
|
||||
}
|
||||
|
||||
@ -523,9 +531,13 @@ impl BashTool {
|
||||
|
||||
// OS-level check: if blocked on stdin, save as session
|
||||
if let Some(pid) = child.id() {
|
||||
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true)
|
||||
&& !combined.trim().is_empty()
|
||||
{
|
||||
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true) {
|
||||
// 给 read_stream 任务时间将最后的提示内容传入 channel
|
||||
tokio::time::sleep(Duration::from_millis(STDIN_FLUSH_MS)).await;
|
||||
if let Some(rx_ref) = rx.as_mut() {
|
||||
drain_available_chunks(rx_ref, &stdout_buf, &stderr_buf).await;
|
||||
}
|
||||
let combined = format_command_output(&stdout_buf.lock().await, &stderr_buf.lock().await, None);
|
||||
if let Some(stdin) = child_stdin {
|
||||
if let Some(rx_val) = rx.take() {
|
||||
let session_id = self.session_manager.save_session(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user