mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-09-01 00:59:33 +00:00
feat(web): show error details for failed tool calls (#490)
* feat(web): show error details and input params for failed tool calls Failed tool calls in the gateway UI previously showed only a red X icon with an empty expandable body. This change: - Adds optional `error` and `parameters` fields to `ToolCompleted` SSE events so the browser receives failure details in real-time - Auto-expands failed tool cards to make errors immediately visible - Adds `StatusUpdate::tool_completed()` constructor that centralizes the 5 duplicated construction sites and applies `redact_params()` to prevent sensitive values (e.g. secret_save's "value" param) from leaking through SSE broadcasts - Adds `sensitive_params()` trait method to `Tool` for declaring which parameters must be redacted before logging, hooks, and UI display - Adds `redact_params()` utility and wires it through hooks, approvals, ActionRecord storage, and debug logs in dispatcher/worker - Adds `SecretListTool` and `SecretDeleteTool` for LLM-driven secret management (values never returned, only names/metadata) - Fixes auth flow: setup-only extensions show configure modal instead of OAuth card; auth_completed SSE dismisses both UI paths - CI: release workflow creates PR instead of pushing directly to main - Registry: MissingChecksum error enables source fallback for bootstrapping when checksums haven't been populated yet Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * style: apply cargo fmt Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: keep original params in PendingApproval for execution, redact only for display Address two PR review comments: 1. execute_chat_tool_standalone now redacts sensitive params before logging, matching the pattern already used in worker.rs. 2. PendingApproval previously stored redacted parameters, which meant approved tool calls received "[REDACTED]" instead of the actual values. Add a display_parameters field for UI/logs and keep parameters as the original values used for execution. Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]> * fix: address PR review comments - worker.rs: redact sensitive params before BeforeToolCall hook, matching dispatcher.rs — hooks in the autonomous job path now receive redacted params instead of raw values - registry.rs: fix docstring for register_secrets_tools (list, delete, not save/list/delete — no SecretSaveTool is registered) - app.js: fix double toast/loadExtensions in submitConfigureModal — for non-OAuth success the auth_completed SSE already handles both, so skip them in the HTTP response handler to avoid duplicates [skip-regression-check] Co-Authored-By: Claude Sonnet 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
13697976db
commit
902492bcdb
@@ -47,6 +47,9 @@ pub enum RegistryError {
|
||||
actual_sha256: String,
|
||||
},
|
||||
|
||||
#[error("Missing SHA256 checksum for '{name}' artifact. Use --build to build from source.")]
|
||||
MissingChecksum { name: String },
|
||||
|
||||
#[error(
|
||||
"Source fallback unavailable for '{name}' after artifact install failed. Retry artifact download or run from a repository checkout."
|
||||
)]
|
||||
|
||||
@@ -20,6 +20,10 @@ const ALLOWED_ARTIFACT_HOSTS: &[&str] = &[
|
||||
];
|
||||
|
||||
fn should_attempt_source_fallback(err: &RegistryError) -> bool {
|
||||
// MissingChecksum is intentionally allowed here — it's a bootstrapping issue
|
||||
// (no release has populated checksums yet), not a security concern. Source
|
||||
// builds use local trusted code. ChecksumMismatch (tampered artifact) and
|
||||
// InvalidManifest (structural problem) remain blocked.
|
||||
!matches!(
|
||||
err,
|
||||
RegistryError::AlreadyInstalled { .. }
|
||||
@@ -367,15 +371,15 @@ impl RegistryInstaller {
|
||||
|
||||
// Require SHA256 — refuse to install unverified binaries. Check before
|
||||
// downloading to avoid wasting bandwidth on manifests that are missing
|
||||
// checksums.
|
||||
// checksums. Uses MissingChecksum (not InvalidManifest) so that
|
||||
// install_with_source_fallback can fall back to building from source
|
||||
// when checksums haven't been populated yet (bootstrapping).
|
||||
let expected_sha =
|
||||
artifact
|
||||
.sha256
|
||||
.as_ref()
|
||||
.ok_or_else(|| RegistryError::InvalidManifest {
|
||||
.ok_or_else(|| RegistryError::MissingChecksum {
|
||||
name: manifest.name.clone(),
|
||||
field: "artifacts.wasm32-wasip2.sha256",
|
||||
reason: "sha256 is required for artifact downloads".to_string(),
|
||||
})?;
|
||||
|
||||
let target_dir = match manifest.kind {
|
||||
@@ -500,7 +504,7 @@ impl RegistryInstaller {
|
||||
if prefer_build || !has_artifact {
|
||||
self.install_from_source(manifest, force).await
|
||||
} else {
|
||||
self.install_from_artifact(manifest, force).await
|
||||
self.install_with_source_fallback(manifest, force).await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -905,9 +909,8 @@ mod tests {
|
||||
|
||||
let result = installer.install_from_artifact(&manifest, false).await;
|
||||
match result {
|
||||
Err(RegistryError::InvalidManifest { field, reason, .. }) => {
|
||||
assert_eq!(field, "artifacts.wasm32-wasip2.sha256");
|
||||
assert!(reason.contains("required"), "reason: {}", reason);
|
||||
Err(RegistryError::MissingChecksum { name }) => {
|
||||
assert_eq!(name, "demo");
|
||||
}
|
||||
other => panic!("unexpected result: {:?}", other),
|
||||
}
|
||||
@@ -942,6 +945,12 @@ mod tests {
|
||||
reason: "host not allowed".to_string(),
|
||||
};
|
||||
assert!(!should_attempt_source_fallback(&invalid));
|
||||
|
||||
// MissingChecksum SHOULD allow source fallback (bootstrapping)
|
||||
let missing = RegistryError::MissingChecksum {
|
||||
name: "demo".to_string(),
|
||||
};
|
||||
assert!(should_attempt_source_fallback(&missing));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user