工具回执进 message 前先按各自预算做有界序列化

- tool/error.rs 新增 bounded_report_text:把 JSON 载荷按给定预算先截断再拼进文案
- browser_playtest / cocos_execute / environment_check / editor_execute 的 report 变体改用该 helper,预算取变体自己的 redact_limit
- 最终可见的头部内容不变,只是不再把整份大载荷搬进多趟脱敏;超长报告被截掉的尾部本来也不会出现在最终文案里
This commit is contained in:
2026-10-01 17:56:16 +08:00
parent 7eb62b09e2
commit 004889f273
5 changed files with 38 additions and 8 deletions
@@ -2,7 +2,7 @@
//!
//! 这里只放错误本身;参数解析与工具执行留在 `direct_tool_bridge` 与 `direct_validation`。
use crate::agent::tool::error::ToolFailure;
use crate::agent::tool::error::{bounded_report_text, ToolFailure};
use serde_json::Value;
/// `agc_browser_playtest` 的每一种失败各占一个变体;文案写在这里,捕获处只调 `to_user_msg`。
@@ -25,7 +25,12 @@ impl ToolFailure for BrowserPlaytestError {
fn to_user_msg(&self) -> String {
match self {
Self::PlaytestFailed { cause } => cause.to_string(),
Self::PlaytestNotPassed { report, .. } => format!("浏览器试玩未通过:{report}"),
Self::PlaytestNotPassed { report, .. } => {
format!(
"浏览器试玩未通过:{}",
bounded_report_text(report, self.redact_limit())
)
}
}
}
@@ -2,7 +2,9 @@
//!
//! 这里只放错误本身;参数解析与工具执行留在 `direct_tool_bridge`。
use crate::agent::tool::error::{ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure};
use crate::agent::tool::error::{
bounded_report_text, ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure,
};
use serde_json::Value;
/// Cocos 执行工具的每一种失败各占一个变体;文案写在这里,捕获处只调 `to_user_msg`。
@@ -77,7 +79,10 @@ impl ToolFailure for CocosExecuteError {
.to_string()
}
Self::ExecutionNotCompleted { report, .. } => {
format!("Cocos 执行未完成:{report}")
format!(
"Cocos 执行未完成:{}",
bounded_report_text(report, self.redact_limit())
)
}
}
}
@@ -2,7 +2,9 @@
//!
//! 这里只放错误本身;参数解析与工具执行留在 `direct_tool_bridge`。
use crate::agent::tool::error::{ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure};
use crate::agent::tool::error::{
bounded_report_text, ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure,
};
use serde_json::Value;
/// `code` 的长度上限(字节):编辑器适配器按 UTF-8 字节数收代码。
@@ -106,7 +108,11 @@ impl ToolFailure for EditorExecuteError {
} => format!("code 有 {got_bytes} 字节,超过上限 {max_bytes} 字节。"),
Self::EditorRejected { cause } => cause.to_string(),
Self::ExecutionNotCompleted { editor, report } => {
format!("{} 执行未完成:{report}", editor.label())
format!(
"{} 执行未完成:{}",
editor.label(),
bounded_report_text(report, self.redact_limit())
)
}
Self::ExecutionUnconfirmed { editor } => format!(
"{} 执行任务异常,回执不可用;执行已发出,结果待核对,不要自动重放:\
@@ -2,7 +2,9 @@
//!
//! 这里只放错误本身;参数解析与工具执行留在 `direct_tool_bridge`。
use crate::agent::tool::error::{ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure};
use crate::agent::tool::error::{
bounded_report_text, ProjectPermissionRejection, ToolArgumentsRejection, ToolFailure,
};
use serde_json::Value;
/// `agc_environment_check` 不接受任何参数,所以它自己的失败只有权限门禁与环境未就绪两类。
@@ -33,7 +35,10 @@ impl ToolFailure for EnvironmentCheckError {
match self {
Self::Arguments(rejection) => rejection.to_user_msg(),
Self::PermissionDenied(rejection) => rejection.to_user_msg(),
Self::EnvironmentNotReady { report } => format!("本地环境未就绪:{report}"),
Self::EnvironmentNotReady { report } => format!(
"本地环境未就绪:{}",
bounded_report_text(report, self.redact_limit())
),
}
}
@@ -17,6 +17,15 @@ pub(crate) fn bounded_echo(text: &str) -> String {
crate::agent::runtime_state::truncate_agent_runtime_text(text, BOUNDED_ECHO_MAX_CHARS)
}
/// 工具回执一类的 JSON 载荷落进 message 前的有界序列化。
///
/// [`ToolFailure::to_user_msg`] 的结果之后还要过整条脱敏流水线,最后才按
/// [`ToolFailure::redact_limit`] 截断;先按同一预算截一次,避免整份大载荷在多趟脱敏里
/// 被反复搬运。
pub(crate) fn bounded_report_text(value: &Value, max_chars: usize) -> String {
crate::agent::runtime_state::truncate_agent_runtime_text(&value.to_string(), max_chars)
}
/// `sourceLocalAssetId` 不在当前项目 manifest 时的完整指引:模型要知道下一步做什么,
/// 只报「不属于已登记资源」会让它原地重试。
///