给模型的工具结果不再脱敏或截断,脱敏只留在诊断侧
- bridge_tool_failure 原样回传 typed 错误的 message,去掉 redact_agent_runtime_error - compose_direct_tool_outcome 只在写诊断时按 ToolFailure::redact_limit 脱敏截断,模型面用原文 - 编辑器执行与 Cocos 执行的成功回执去掉脱敏/路径替换,report 原样进工具结果 - 账号素材导入的 failures、生成/抠图/美术准备的 warnings 不再脱敏 - 删除随之失效的 bridge_safe_warning_messages 及其断言脱敏的测试
This commit is contained in:
@@ -544,7 +544,7 @@ fn bridge_append_tool_images(result: &mut Value, images: Vec<String>) {
|
||||
/// 工具失败在 dispatch 边界上的唯一载体:具体类型泛型进、具体字段出,不枚举、不 Box。
|
||||
///
|
||||
/// `message` / `redact_limit` 来自具体 [`ToolFailure`],`error` 是它的原样序列化。
|
||||
/// 结构化事实与给模型的那句话都靠它带出 dispatch,composer 一处写结果与诊断。
|
||||
/// `message` 原样进给模型的工具结果;`redact_limit` 只用于写诊断的那一份。
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct ToolCallError {
|
||||
pub message: String,
|
||||
@@ -566,11 +566,11 @@ impl<T: ToolFailure + ?Sized> From<&T> for ToolCallError {
|
||||
}
|
||||
|
||||
/// 失败结果:`isError` 只在 composer 的分支上出现一次,工具与桥都不再手传这个布尔。
|
||||
fn bridge_tool_failure(root: &Path, error: &ToolCallError) -> Value {
|
||||
let mut result = bridge_tool_result(
|
||||
redact_agent_runtime_error(root, &error.message, error.redact_limit),
|
||||
Vec::new(),
|
||||
);
|
||||
///
|
||||
/// 文案原样给模型(是 typed 错误自己写的那一句),桥不脱敏、不截断;脱敏与预算只发生在
|
||||
/// 诊断侧(见 [`compose_direct_tool_outcome`])。
|
||||
fn bridge_tool_failure(error: &ToolCallError) -> Value {
|
||||
let mut result = bridge_tool_result(error.message.clone(), Vec::new());
|
||||
result["isError"] = Value::Bool(true);
|
||||
result
|
||||
}
|
||||
@@ -593,18 +593,22 @@ fn compose_direct_tool_outcome(
|
||||
value
|
||||
}
|
||||
Err(error) => {
|
||||
// 给模型的失败结果不脱敏、不截断:模型看到的就是 typed 错误写的原文。
|
||||
// 写诊断的那一份才脱敏,并按工具自己声明的 `redact_limit` 截断。
|
||||
let diagnostic_message =
|
||||
redact_agent_runtime_error(&state.root, &error.message, error.redact_limit);
|
||||
// 诊断事件按回合归属:并发排障要能从错误记录认出是哪一轮调的工具。
|
||||
// 桥没被回合授权(外部客户端工具桥)或授权状态不可用时如实记为无回合。
|
||||
let client_turn_id = state.active_client_turn_id().ok().flatten();
|
||||
// `code` 只放稳定的工具名,供并发排障定位"是哪个工具、哪一轮";文案是 typed 错误
|
||||
// 写好的那一句,原始 typed 错误整体进 `error`,入参与上下文进 metadata。
|
||||
// `code` 只放稳定的工具名,供并发排障定位"是哪个工具、哪一轮";原始 typed 错误
|
||||
// 整体进 `error`,入参与上下文进 metadata。
|
||||
let _ = persist_agent_runtime_error(
|
||||
&state.root,
|
||||
client_turn_id.as_deref(),
|
||||
"agc-tools",
|
||||
"tool-execution",
|
||||
tool,
|
||||
&error.message,
|
||||
&diagnostic_message,
|
||||
error.error.clone(),
|
||||
None,
|
||||
json!({
|
||||
@@ -614,7 +618,7 @@ fn compose_direct_tool_outcome(
|
||||
"dispatchDenied": dispatch_denied,
|
||||
}),
|
||||
);
|
||||
let mut value = bridge_tool_failure(&state.root, &error);
|
||||
let mut value = bridge_tool_failure(&error);
|
||||
bridge_append_tool_images(&mut value, error.images);
|
||||
value
|
||||
}
|
||||
@@ -2118,7 +2122,7 @@ async fn bridge_import_account_assets(
|
||||
"source": source,
|
||||
})
|
||||
})),
|
||||
Err(error) => failures.push(redact_agent_runtime_error(&state.root, &error, 360)),
|
||||
Err(error) => failures.push(error),
|
||||
}
|
||||
}
|
||||
if !local_paths.is_empty() {
|
||||
@@ -2135,7 +2139,7 @@ async fn bridge_import_account_assets(
|
||||
"source": "local",
|
||||
})
|
||||
})),
|
||||
Err(error) => failures.push(redact_agent_runtime_error(&state.root, &error, 360)),
|
||||
Err(error) => failures.push(error),
|
||||
}
|
||||
}
|
||||
// Direct tools run outside the normal Runtime action loop. Keep the
|
||||
@@ -2191,8 +2195,8 @@ fn bridge_completed_resource_result(
|
||||
"sourceResourceId": result.source_resource_id,
|
||||
"committedProjectRevision": result.committed_project_revision,
|
||||
"resource": bridge_registered_resource(asset, true),
|
||||
"warnings": bridge_safe_warning_messages(root, warnings),
|
||||
"sliceWarnings": bridge_safe_warning_messages(root, slice_warnings),
|
||||
"warnings": warnings,
|
||||
"sliceWarnings": slice_warnings,
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -2618,25 +2622,16 @@ fn bridge_art_resources(
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn bridge_safe_warning_messages(root: &Path, warnings: Vec<String>) -> Vec<String> {
|
||||
warnings
|
||||
.into_iter()
|
||||
.map(|warning| redact_agent_runtime_error(root, &warning, 480))
|
||||
.collect()
|
||||
}
|
||||
|
||||
async fn bridge_prepare_game_art_validated(
|
||||
root: &Path,
|
||||
brief: String,
|
||||
mode: DirectTaonierArtPreparationMode,
|
||||
) -> Result<Value, PrepareGameArtError> {
|
||||
let mut package = with_direct_editor_api_credentials(ensure_direct_taonier_art_package_at(
|
||||
let package = with_direct_editor_api_credentials(ensure_direct_taonier_art_package_at(
|
||||
root, &brief, mode,
|
||||
))
|
||||
.await
|
||||
.map_err(|cause| PrepareGameArtError::PackageGenerationFailed { cause })?;
|
||||
package.warnings = bridge_safe_warning_messages(root, package.warnings);
|
||||
package.slice_warnings = bridge_safe_warning_messages(root, package.slice_warnings);
|
||||
let resources = bridge_art_resources(root, &package.asset_paths, &package.slice_paths)
|
||||
.map_err(|cause| PrepareGameArtError::ArtResourcesUnreadable { cause })?;
|
||||
let images = package
|
||||
@@ -3171,8 +3166,8 @@ async fn bridge_generate_image(
|
||||
"taskId": generated.task_id,
|
||||
},
|
||||
"resources": resources,
|
||||
"warnings": generated.warning.map(|warning| bridge_safe_warning_messages(&state.root, vec![warning])).unwrap_or_default(),
|
||||
"sliceWarnings": generated.slice_warning.map(|warning| bridge_safe_warning_messages(&state.root, vec![warning])).unwrap_or_default(),
|
||||
"warnings": generated.warning.map(|warning| vec![warning]).unwrap_or_default(),
|
||||
"sliceWarnings": generated.slice_warning.map(|warning| vec![warning]).unwrap_or_default(),
|
||||
"sliceMode": generated.slice_mode,
|
||||
"gridX": generated.grid_x,
|
||||
"gridY": generated.grid_y,
|
||||
@@ -3638,10 +3633,7 @@ async fn bridge_editor_execute(
|
||||
report: response,
|
||||
});
|
||||
}
|
||||
Ok(bridge_tool_result(
|
||||
redact_agent_runtime_error(&state.root, &response.to_string(), 32_000),
|
||||
Vec::new(),
|
||||
))
|
||||
Ok(bridge_tool_result(response.to_string(), Vec::new()))
|
||||
}
|
||||
Ok(Err(error)) => Err(error),
|
||||
Err(_) => Err(EditorExecuteError::ExecutionUnconfirmed { editor }),
|
||||
@@ -3850,18 +3842,7 @@ async fn bridge_cocos_call(
|
||||
screenshots: images,
|
||||
});
|
||||
}
|
||||
Ok(bridge_tool_result(
|
||||
redact_agent_runtime_project_paths(
|
||||
&state.root,
|
||||
&report.to_string(),
|
||||
if operation.is_some() {
|
||||
2 * 1024 * 1024
|
||||
} else {
|
||||
32_000
|
||||
},
|
||||
),
|
||||
images,
|
||||
))
|
||||
Ok(bridge_tool_result(report.to_string(), images))
|
||||
}
|
||||
failed => {
|
||||
let (is_uncertain, error) = match failed {
|
||||
@@ -6359,42 +6340,4 @@ mod tests {
|
||||
assert_eq!(projection["kind"], "ui-design");
|
||||
assert_eq!(projection["category"], "ui-interaction");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bridge_success_warnings_are_redacted_before_serialization() {
|
||||
let root = tempfile::tempdir().expect("warning redaction root");
|
||||
let private_path = root.path().join("assets/private.png");
|
||||
let warnings = bridge_safe_warning_messages(
|
||||
root.path(),
|
||||
vec![
|
||||
format!(
|
||||
"写入失败:{};api_key=private-warning-key",
|
||||
private_path.display()
|
||||
),
|
||||
"Authorization=Basic private-authorization".to_string(),
|
||||
"Cookie=session_id=private-cookie".to_string(),
|
||||
"token: private-token".to_string(),
|
||||
r#"{"Authorization":"Basic private-json","token" = "private-json-token"}"#
|
||||
.to_string(),
|
||||
],
|
||||
);
|
||||
let serialized = serde_json::to_string(&warnings).expect("serialize safe warnings");
|
||||
assert!(!serialized.contains(&root.path().to_string_lossy().to_string()));
|
||||
for private in [
|
||||
"private-warning-key",
|
||||
"private-authorization",
|
||||
"private-cookie",
|
||||
"private-token",
|
||||
"private-json",
|
||||
"private-json-token",
|
||||
"api_key",
|
||||
"Authorization",
|
||||
"Cookie",
|
||||
] {
|
||||
assert!(
|
||||
!serialized.contains(private),
|
||||
"leaked {private}: {serialized}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user