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
|
node_modules
|
||||||
logs
|
logs
|
||||||
dist
|
dist
|
||||||
|
.qoder
|
||||||
|
|||||||
@ -1097,15 +1097,20 @@ impl AgentLoop {
|
|||||||
.zip(tool_results.iter())
|
.zip(tool_results.iter())
|
||||||
.find(|(_, result)| result.state == ToolExecutionState::PendingUserAction)
|
.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!(
|
let assistant_message = ChatMessage::assistant(format!(
|
||||||
"{}\n\n当前等待中的工具: {}",
|
"{}\n\n当前等待中的工具: {}",
|
||||||
pending_result
|
content_line, tool_call.name,
|
||||||
.output
|
|
||||||
.lines()
|
|
||||||
.next()
|
|
||||||
.filter(|line| !line.trim().is_empty())
|
|
||||||
.unwrap_or(DEFAULT_PENDING_ASSISTANT_MESSAGE),
|
|
||||||
tool_call.name,
|
|
||||||
));
|
));
|
||||||
emitted_messages.push(assistant_message.clone());
|
emitted_messages.push(assistant_message.clone());
|
||||||
self.emit_live_tool_call_message(assistant_message.clone()).await;
|
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_TIMEOUT_SECS: u64 = 600;
|
||||||
const MAX_OUTPUT_CHARS: usize = 50_000;
|
const MAX_OUTPUT_CHARS: usize = 50_000;
|
||||||
const PENDING_USER_ACTION_MARKER: &str = "__PICOBOT_PENDING_USER_ACTION__";
|
const PENDING_USER_ACTION_MARKER: &str = "__PICOBOT_PENDING_USER_ACTION__";
|
||||||
|
/// 检测到 stdin 等待后,给 read_stream 任务将最后的提示内容传入 channel 的时间
|
||||||
|
const STDIN_FLUSH_MS: u64 = 500;
|
||||||
const INTERACTIVE_HINT: &str =
|
const INTERACTIVE_HINT: &str =
|
||||||
"进程正在等待输入。请使用 session_id 和 stdin_input 参数回复交互内容。";
|
"进程正在等待输入。请使用 session_id 和 stdin_input 参数回复交互内容。";
|
||||||
const NON_INTERACTIVE_HINT: &str =
|
const NON_INTERACTIVE_HINT: &str =
|
||||||
@ -182,12 +184,17 @@ impl BashTool {
|
|||||||
let session_line = session_id
|
let session_line = session_id
|
||||||
.map(|id| format!("[session_id: {}]\n", id))
|
.map(|id| format!("[session_id: {}]\n", id))
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
|
let output_section = if output.trim().is_empty() {
|
||||||
|
"(进程尚未输出内容。进程正在等待输入,请使用 session_id 和 stdin_input 参数发送输入内容。)"
|
||||||
|
} else {
|
||||||
|
&self.truncate_output(output.trim())
|
||||||
|
};
|
||||||
format!(
|
format!(
|
||||||
"{}\n{}{}\n\n{}",
|
"{}\n{}{}\n\n{}",
|
||||||
PENDING_USER_ACTION_MARKER,
|
PENDING_USER_ACTION_MARKER,
|
||||||
session_line,
|
session_line,
|
||||||
hint,
|
hint,
|
||||||
self.truncate_output(output.trim())
|
output_section
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -472,25 +479,26 @@ impl BashTool {
|
|||||||
// Periodic safety net: check OS-level process state
|
// Periodic safety net: check OS-level process state
|
||||||
if let Some(pid) = child.id() {
|
if let Some(pid) = child.id() {
|
||||||
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true) {
|
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() {
|
if let Some(rx_ref) = rx.as_mut() {
|
||||||
drain_available_chunks(rx_ref, &stdout_buf, &stderr_buf).await;
|
drain_available_chunks(rx_ref, &stdout_buf, &stderr_buf).await;
|
||||||
}
|
}
|
||||||
let combined = format_command_output(&stdout_buf.lock().await, &stderr_buf.lock().await, None);
|
let combined = format_command_output(&stdout_buf.lock().await, &stderr_buf.lock().await, None);
|
||||||
if !combined.trim().is_empty() {
|
// 始终创建 session,即使输出为空(进程可能还没写出提示)
|
||||||
if let Some(stdin) = child_stdin {
|
if let Some(stdin) = child_stdin {
|
||||||
if let Some(rx_val) = rx.take() {
|
if let Some(rx_val) = rx.take() {
|
||||||
let session_id = self.session_manager.save_session(
|
let session_id = self.session_manager.save_session(
|
||||||
child, stdin, rx_val,
|
child, stdin, rx_val,
|
||||||
stdout_buf.lock().await.clone(),
|
stdout_buf.lock().await.clone(),
|
||||||
stderr_buf.lock().await.clone(),
|
stderr_buf.lock().await.clone(),
|
||||||
).await;
|
).await;
|
||||||
return Ok(self.pending_output(&combined, Some(&session_id)));
|
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
|
// OS-level check: if blocked on stdin, save as session
|
||||||
if let Some(pid) = child.id() {
|
if let Some(pid) = child.id() {
|
||||||
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true)
|
if crate::platform::is_process_waiting_on_stdin(pid) == Some(true) {
|
||||||
&& !combined.trim().is_empty()
|
// 给 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(stdin) = child_stdin {
|
||||||
if let Some(rx_val) = rx.take() {
|
if let Some(rx_val) = rx.take() {
|
||||||
let session_id = self.session_manager.save_session(
|
let session_id = self.session_manager.save_session(
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user