Skip to content

Fix gateway tool output visibility and timing - #2555

Merged
ilblackdragon merged 13 commits into
stagingfrom
tool-visibility
Apr 18, 2026
Merged

ilblackdragon merged 13 commits into
stagingfrom
tool-visibility

Conversation

@henrypark133

Copy link
Copy Markdown
Collaborator

Summary

  • fix gateway tool activity cards to correlate live tool events by call_id and show actual tool output when available
  • use the existing persisted result field for expanded history cards without adding new history storage, and bound active-thread history results to keep refreshes fast
  • thread call_id and live duration_ms through the web event surface, preserve engine_v2 action call IDs in the bridge, and replace misleading 0.0s with millisecond-friendly duration formatting

Testing

  • cargo fmt --all
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo test gateway_send_status_preserves_tool_event_fields --lib
  • cargo test test_build_turns_with_persisted_tool_result_for_display --lib
  • cargo test accumulator_tool_flow --lib
  • cargo test test_ws_multiple_events_in_sequence --test ws_gateway_integration
  • cargo test test_tool_result_for_display_truncates_long_content --lib
  • cargo test forward_event_to_channel_preserves_call_id_for_action_events --lib
  • cargo test thread_event_to_app_events_preserves_call_id_for_action_events --lib

Copilot AI review requested due to automatic review settings April 16, 2026 23:27
@github-actions github-actions Bot added scope: agent Agent core (agent loop, router, scheduler) scope: channel Channel infrastructure scope: channel/web Web gateway channel scope: channel/wasm WASM channel runtime size: XL 500+ changed lines risk: medium Business logic, config, or moderate-risk modules contributor: core 20+ merged PRs labels Apr 16, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves how the web gateway surfaces tool activity by correlating live tool events via call_id, exposing actual tool output (when persisted), and carrying real execution timings (duration_ms) end-to-end so the UI can render accurate tool cards and durations.

Changes:

  • Add call_id (and duration_ms for completions) to tool-related StatusUpdate/AppEvent variants and preserve these fields through the bridge and web channel layers.
  • Use persisted tool-call result to populate expanded history tool cards (with display truncation), avoiding new history storage.
  • Refactor frontend tool activity rendering to a controller that correlates events by call_id and formats durations in a millisecond-friendly way.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/ws_gateway_integration.rs Asserts WS payloads include call_id and duration_ms for tool events.
tests/support_unit_tests.rs Updates test fixtures for new duration_ms field on ToolCompleted.
src/channels/web/util.rs Adds tool_result_for_display and threads persisted result + call_id into ToolCallInfo.
src/channels/web/types.rs Extends ToolCallInfo DTO with call_id and result.
src/channels/web/tests/tool_event_passthrough.rs Regression test ensuring gateway preserves tool identity/timing fields to SSE.
src/channels/web/tests/mod.rs Registers new tool passthrough test module.
src/channels/web/server.rs Includes call_id and display-ready result for in-memory turn tool calls.
src/channels/web/responses_api.rs Correlates tool events by call_id when building response output items.
src/channels/web/mod.rs Ensures call_id/duration_ms are passed through as AppEvents.
src/channels/wasm/wrapper.rs Updates WASM channel tests for duration_ms.
src/channels/channel.rs Adds duration_ms to StatusUpdate::ToolCompleted and propagates it in constructor helpers/tests.
src/bridge/router.rs Preserves engine action call_id and forwards duration_ms via tool-status events.
src/agent/thread_ops.rs Measures tool execution durations and passes duration_ms into status updates.
src/agent/dispatcher.rs Measures tool execution durations and passes duration_ms into status updates.
crates/ironclaw_gateway/static/app.js Refactors tool activity cards to correlate by call_id, show persisted results, and format ms durations.
crates/ironclaw_common/src/event.rs Adds optional call_id and duration_ms fields to tool-related AppEvents.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/channels/web/util.rs
Comment thread crates/ironclaw_gateway/static/app.js Outdated

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces call_id and duration_ms fields across the system to improve the tracking and display of tool activity. Key changes include refactoring the frontend tool activity state into a reusable controller, adding execution timing in the agent dispatcher, and updating event propagation to preserve tool identity. A logic error was identified in the frontend's tool correlation function where name-based fallback could lead to incorrect state updates during parallel tool calls.

Comment thread crates/ironclaw_gateway/static/app.js

Copy link
Copy Markdown
Collaborator Author

Addressed the open review comments on tool-visibility:

  • tool_result_for_display() now returns None for JSON null and empty strings, so the UI no longer renders synthetic "null" output.
  • createToolActivitySummary() now builds the duration node with textContent instead of appending via innerHTML, so <1ms renders safely.
  • findRendered() now treats call_id as authoritative and no longer falls back to name-based matching when a call_id is present but does not satisfy the predicate.

Validation after the follow-up patch:

  • cargo fmt --all
  • node --check crates/ironclaw_gateway/static/app.js
  • cargo test test_tool_result_for_display_skips_null --lib

Follow-up commit pushed: 733f5b95.

@henrypark133

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 733f5b95ee

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread crates/ironclaw_gateway/static/app.js Outdated
henrypark133

This comment was marked as off-topic.

Comment thread src/channels/web/tests/tool_event_passthrough.rs
Copilot AI review requested due to automatic review settings April 17, 2026 04:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/channels/web/util.rs
Comment thread src/channels/web/responses_api.rs

@henrypark133 henrypark133 left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review: keep Responses API tool completions correlated per call

Most of the earlier tool-visibility feedback looks addressed, and the new call_id / duration_ms plumbing is much cleaner. One correctness issue still remains in the streaming Responses API path.

Critical: response.output_item.done still uses one global tool slot

File: src/channels/web/responses_api.rs:947
The streaming worker now threads call_id into the FunctionCall and FunctionCallOutput items, but it still tracks completion with a single current_tool_index. If tool A starts, tool B starts, and tool A completes first, the later start overwrites that slot and the code emits response.output_item.done for B instead of A. The final output list keeps the right call_id, but streamed clients can observe the wrong item transition to done and never get a done event for the actual completed call.

Suggested fix: track in-flight output indexes by call_id (or look them up by call_id on completion) instead of using a single mutable index.

Recommended verdict: Request changes.

Residual risk: I also kicked off a couple of targeted tests from the worktree, but they were still compiling when I posted this review.

Comment thread src/bridge/router.rs
Comment thread src/channels/web/util.rs Outdated
ilblackdragon and others added 2 commits April 18, 2026 06:56
Live in-memory turns have only the full tool result, not a separately
persisted short preview. Populate `ToolCallInfo.result` from the live
value and leave `result_preview` empty so both paths surface the same
field semantics to the UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 18, 2026 07:08

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 2777 to 2820
@@ -2761,15 +2790,12 @@ function addToolCard(name, callId) {

const icon = document.createElement('span');
icon.className = 'activity-tool-icon';
icon.innerHTML = '<div class="spinner"></div>';

const toolName = document.createElement('span');
toolName.className = 'activity-tool-name';
toolName.textContent = name;

const duration = document.createElement('span');
duration.className = 'activity-tool-duration';
duration.textContent = '';

const chevron = document.createElement('span');
chevron.className = 'activity-tool-chevron';
@@ -2787,175 +2813,332 @@ function addToolCard(name, callId) {
output.className = 'activity-tool-output';
body.appendChild(output);

const rendered = { entry, card, header, icon, toolName, duration, chevron, body, output, timer: null };
header.addEventListener('click', () => {
const isExpanded = body.classList.contains('expanded');
setActivityToolExpanded(header, body, chevron, !isExpanded);
const willExpand = !body.classList.contains('expanded');
setToolActivityCardExpanded(rendered, willExpand);
});

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

createToolActivityCard/applyToolActivityCardState always leaves the header as an enabled <button> with an active chevron, even when there is no body text (no result/error/preview). This creates a focusable control that expands/collapses an empty region, which is confusing UX and an accessibility regression vs the previous behavior that disabled the header and hid the chevron when there was nothing to expand. Consider disabling the header (and hiding the chevron) whenever rendered.output.textContent is empty, and only wiring expansion/aria affordances when there is expandable content.

Copilot uses AI. Check for mistakes.
ilblackdragon and others added 2 commits April 18, 2026 07:11
GitHub Actions dropped the Code Style workflow on the prior push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rust 1.95's stricter clippy::collapsible_match warning trips on the
inner `if` inside the ToolResult arm. Fold the preview check into the
arm's guard to match the same predicate-in-guard style as the arm
above. Fixes the Clippy (all-features) CI failure inherited from
staging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 18, 2026 07:17

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 23 out of 23 changed files in this pull request and generated 1 comment.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

container.scrollTop = container.scrollHeight;
function getToolActivityBodyText(entry) {
if (!entry) return '';
return entry.error || entry.result || entry.result_preview || '';

Copilot AI Apr 18, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

getToolActivityBodyText() returns entry.error || entry.result || entry.result_preview, which means historical tool cards with both error and result_preview will now hide the preview entirely (previously the history UI showed preview + error text together). Consider composing the body when error is present (e.g., include result/result_preview plus an Error: section) so failures don’t lose the tool output preview.

Suggested change
return entry.error || entry.result || entry.result_preview || '';
const output = entry.result || entry.result_preview || '';
if (!entry.error) return output;
return output ? (output + '\n\nError:\n' + entry.error) : ('Error:\n' + entry.error);

Copilot uses AI. Check for mistakes.
ilblackdragon added a commit that referenced this pull request Apr 18, 2026
…onclaw#2599 stage 1

First increment of the ironclaw#2599 gateway platform/feature split. Moves
the shared gateway state and the unauthenticated static-serving surface out
of the 8.5k-line `server.rs` monolith into a new `platform/` subtree:

- `platform/state.rs` — `GatewayState`, `RateLimiter`, `PerUserRateLimiter`,
  `WorkspacePool` (+ `WorkspaceResolver` impl), `FrontendHtmlCache`,
  `FrontendCacheKey`, `ActiveConfigSnapshot`, `PromptQueue`,
  `RoutineEngineSlot`, `rate_limit_key_from_headers`.
- `platform/static_files.rs` — CSP directive set + `BASE_CSP_HEADER`
  (single source of truth for both the global header layer and the
  per-response nonce variant), `build_frontend_html` + cache-key plumbing,
  unauthenticated static handlers (`/`, `/style.css`, `/app.js`,
  `/theme.css`, `/favicon.ico`, `/i18n/*`, `/admin*`, `/api/health`), and
  the authenticated `/projects/{id}/...` file-serving routes with the
  ownership check.

`server.rs` keeps `start_server()`, the route table, and the feature
handlers that have not yet moved (OAuth callbacks, chat, extensions,
pairing, logs, gateway status). It re-exports the relocated state types
under their old paths so the 30+ external call sites that reach for
`crate::channels::web::server::GatewayState` continue to resolve without
churn — follow-up PRs update them incrementally.

`CLAUDE.md` file map is updated to document `platform/` vs the
transitional `handlers/` folder and explains the layering rule:
features depend on platform, never the reverse.

No behavior change — route table, CSP policy, cache semantics, and
multi-tenant guard rails are byte-identical. `cargo clippy --all
--benches --tests --examples --all-features` is clean; the relocated
tests (`test_base_csp_header_matches_build_csp_none`,
`test_stamp_nonce_into_html_*`, `workspace_pool_resolve_seeds_new_user_workspace`,
`test_build_frontend_html_returns_none_in_multi_tenant_mode`, etc.) pass
against the re-exported surface.

Scope is intentionally narrow to avoid colliding with the open
XL PRs that touch `server.rs` (#2548 workspace entities, #2555 tool
output, #2532 engine v2 sidebar) — this PR does not modify anything
inside the feature-handler blocks those PRs edit.

Stats: server.rs 8534 → 7463 lines (−1071); new files 1210 lines.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ilblackdragon added a commit that referenced this pull request Apr 18, 2026
…onclaw#2599 stage 1 (#2628)

First increment of the ironclaw#2599 gateway platform/feature split. Moves
the shared gateway state and the unauthenticated static-serving surface out
of the 8.5k-line `server.rs` monolith into a new `platform/` subtree:

- `platform/state.rs` — `GatewayState`, `RateLimiter`, `PerUserRateLimiter`,
  `WorkspacePool` (+ `WorkspaceResolver` impl), `FrontendHtmlCache`,
  `FrontendCacheKey`, `ActiveConfigSnapshot`, `PromptQueue`,
  `RoutineEngineSlot`, `rate_limit_key_from_headers`.
- `platform/static_files.rs` — CSP directive set + `BASE_CSP_HEADER`
  (single source of truth for both the global header layer and the
  per-response nonce variant), `build_frontend_html` + cache-key plumbing,
  unauthenticated static handlers (`/`, `/style.css`, `/app.js`,
  `/theme.css`, `/favicon.ico`, `/i18n/*`, `/admin*`, `/api/health`), and
  the authenticated `/projects/{id}/...` file-serving routes with the
  ownership check.

`server.rs` keeps `start_server()`, the route table, and the feature
handlers that have not yet moved (OAuth callbacks, chat, extensions,
pairing, logs, gateway status). It re-exports the relocated state types
under their old paths so the 30+ external call sites that reach for
`crate::channels::web::server::GatewayState` continue to resolve without
churn — follow-up PRs update them incrementally.

`CLAUDE.md` file map is updated to document `platform/` vs the
transitional `handlers/` folder and explains the layering rule:
features depend on platform, never the reverse.

No behavior change — route table, CSP policy, cache semantics, and
multi-tenant guard rails are byte-identical. `cargo clippy --all
--benches --tests --examples --all-features` is clean; the relocated
tests (`test_base_csp_header_matches_build_csp_none`,
`test_stamp_nonce_into_html_*`, `workspace_pool_resolve_seeds_new_user_workspace`,
`test_build_frontend_html_returns_none_in_multi_tenant_mode`, etc.) pass
against the re-exported surface.

Scope is intentionally narrow to avoid colliding with the open
XL PRs that touch `server.rs` (#2548 workspace entities, #2555 tool
output, #2532 engine v2 sidebar) — this PR does not modify anything
inside the feature-handler blocks those PRs edit.

Stats: server.rs 8534 → 7463 lines (−1071); new files 1210 lines.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ilblackdragon

Copy link
Copy Markdown
Member

PR Re-Review (post-fix, head 28e93667)

Follow-up to my earlier review. The PR has been rebased on staging twice (pulling in the gateway platform refactor #2628 and CI-speedup #2566), and the one actionable review comment was addressed. CI is now fully green (Clippy, Formatting, cargo-deny, Gateway JS all passed).

What changed since first review

  • turn_info_from_in_memory_turn asymmetry — fixed in src/channels/web/server.rs:2033-2053. result is now populated from the full live value via tool_result_preview, result_preview is set to None, matching DB-path semantics where those fields carry distinct data. Accompanied by test_in_memory_turn_info_populates_result_without_preview covering both assertions. The code comment explains the invariant for future readers.
  • Everything else in the earlier review still stands unchanged.

Code quality

  • Backwards compat: #[serde(default)] on new duration_ms + regression test action_failed_defaults_missing_duration_ms_when_deserializing_legacy_payload verifies legacy ActionFailed payloads in storage still deserialize.
  • Timing defensiveness: every execute_action call site wraps with Instant::now() as a fallback when the effect adapter reports zero duration. Sensible.
  • Test coverage (Rust side): strong — boundary tests at deserialization, forward_event_to_channel, thread_event_to_app_events, SSE broadcast via gateway_send_status_preserves_tool_event_fields. Directly satisfies the "test through the caller" rule.
  • Style: no unwrap/expect in production code, no new info! noise, follows existing formatting conventions.

Remaining minor gaps (non-blocking)

  • duration_ms: 0 for preflight errors (orchestrator.rs:933, 967, 1035; structured.rs:94, 129): indistinguishable from a real 0ms execution. Option<u64> on the wire type would be cleaner. JS renders 0 as <1ms so user-visible impact is nil.
  • No JS test coverage for the 400-line createToolActivityController rewrite. The e2e Playwright harness in tests/e2e/ could cover the call_id correlation behavior in a follow-up.
  • UTF-8 truncation: JS truncates at 1000 chars, Rust at 1000 bytes via truncate_preview. Multi-byte UTF-8 content shows slightly less in the browser than stored. Negligible.

Security / correctness

  • .textContent used for tool output (not .innerHTML) — no XSS vectors introduced.
  • Wire-format change: parameters: Some(format!("{duration_ms}ms")) removed in favor of structured duration_ms. Any external SSE consumer parsing parameters for duration breaks, but parameters semantically means tool inputs — that misuse needed to end.
  • No new database reads/writes, no secrets handling, no sandbox-relevant changes.

Verdict

Approve. Full CI green, review feedback addressed with a dedicated regression test, merge with latest staging is conflict-free. The remaining minor gaps are out-of-scope follow-ups worth tracking separately if anyone cares.

@ilblackdragon
ilblackdragon merged commit 82a0b75 into staging Apr 18, 2026
16 checks passed
@ilblackdragon
ilblackdragon deleted the tool-visibility branch April 18, 2026 09:33
ilblackdragon added a commit that referenced this pull request Apr 19, 2026
Two independent staging CI regressions:

1. Docker Build was failing because `cargo install wasm-tools@1.246.1`
   re-resolved to the newest compatible `constant_time_eq@0.4.3`, which
   requires rustc >= 1.95, while the chef stage is pinned to rust:1.92.
   Add `--locked` so cargo uses the Cargo.lock shipped with each crate.

2. `test_builtin_echo_tool` started failing after PR #2555 intentionally
   aligned the in-memory history path with DB semantics: tool previews
   now surface in `result` with `result_preview` left empty. The test
   only inspected `result_preview`, so it timed out. Accept the preview
   from either field in `_wait_for_turn`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ilblackdragon added a commit that referenced this pull request Apr 19, 2026
Two independent staging CI regressions:

1. Docker Build was failing because `cargo install wasm-tools@1.246.1`
   re-resolved to the newest compatible `constant_time_eq@0.4.3`, which
   requires rustc >= 1.95, while the chef stage is pinned to rust:1.92.
   Add `--locked` so cargo uses the Cargo.lock shipped with each crate.

2. `test_builtin_echo_tool` started failing after PR #2555 intentionally
   aligned the in-memory history path with DB semantics: tool previews
   now surface in `result` with `result_preview` left empty. The test
   only inspected `result_preview`, so it timed out. Accept the preview
   from either field in `_wait_for_turn`.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@ironclaw-ci ironclaw-ci Bot mentioned this pull request Apr 21, 2026
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
…onclaw#2599 stage 1 (nearai#2628)

First increment of the ironclaw#2599 gateway platform/feature split. Moves
the shared gateway state and the unauthenticated static-serving surface out
of the 8.5k-line `server.rs` monolith into a new `platform/` subtree:

- `platform/state.rs` — `GatewayState`, `RateLimiter`, `PerUserRateLimiter`,
  `WorkspacePool` (+ `WorkspaceResolver` impl), `FrontendHtmlCache`,
  `FrontendCacheKey`, `ActiveConfigSnapshot`, `PromptQueue`,
  `RoutineEngineSlot`, `rate_limit_key_from_headers`.
- `platform/static_files.rs` — CSP directive set + `BASE_CSP_HEADER`
  (single source of truth for both the global header layer and the
  per-response nonce variant), `build_frontend_html` + cache-key plumbing,
  unauthenticated static handlers (`/`, `/style.css`, `/app.js`,
  `/theme.css`, `/favicon.ico`, `/i18n/*`, `/admin*`, `/api/health`), and
  the authenticated `/projects/{id}/...` file-serving routes with the
  ownership check.

`server.rs` keeps `start_server()`, the route table, and the feature
handlers that have not yet moved (OAuth callbacks, chat, extensions,
pairing, logs, gateway status). It re-exports the relocated state types
under their old paths so the 30+ external call sites that reach for
`crate::channels::web::server::GatewayState` continue to resolve without
churn — follow-up PRs update them incrementally.

`CLAUDE.md` file map is updated to document `platform/` vs the
transitional `handlers/` folder and explains the layering rule:
features depend on platform, never the reverse.

No behavior change — route table, CSP policy, cache semantics, and
multi-tenant guard rails are byte-identical. `cargo clippy --all
--benches --tests --examples --all-features` is clean; the relocated
tests (`test_base_csp_header_matches_build_csp_none`,
`test_stamp_nonce_into_html_*`, `workspace_pool_resolve_seeds_new_user_workspace`,
`test_build_frontend_html_returns_none_in_multi_tenant_mode`, etc.) pass
against the re-exported surface.

Scope is intentionally narrow to avoid colliding with the open
XL PRs that touch `server.rs` (nearai#2548 workspace entities, nearai#2555 tool
output, nearai#2532 engine v2 sidebar) — this PR does not modify anything
inside the feature-handler blocks those PRs edit.

Stats: server.rs 8534 → 7463 lines (−1071); new files 1210 lines.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
* Fix gateway tool output visibility

* Address PR review follow-ups

* fix(web): truncate live tool activity previews

* fix(engine): preserve failed tool durations in v2 gateway events

* fix(engine): default missing ActionFailed durations

* style: format scripting executor

* fix(web): keep history tool results aligned with preview

* fix(web): restore persisted tool result parsing

* fix(web): align in-memory turn result/preview with DB path

Live in-memory turns have only the full tool result, not a separately
persisted short preview. Populate `ToolCallInfo.result` from the live
value and leave `result_preview` empty so both paths surface the same
field semantics to the UI.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* chore: re-trigger CI

GitHub Actions dropped the Code Style workflow on the prior push.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix(tests): collapse nested match arm in live_harness

Rust 1.95's stricter clippy::collapsible_match warning trips on the
inner `if` inside the ToolResult arm. Fold the preview check into the
arm's guard to match the same predicate-in-guard style as the arm
above. Fixes the Clippy (all-features) CI failure inherited from
staging.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Illia Polosukhin <ilblackdragon@gmail.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
…2661)

Two independent staging CI regressions:

1. Docker Build was failing because `cargo install wasm-tools@1.246.1`
   re-resolved to the newest compatible `constant_time_eq@0.4.3`, which
   requires rustc >= 1.95, while the chef stage is pinned to rust:1.92.
   Add `--locked` so cargo uses the Cargo.lock shipped with each crate.

2. `test_builtin_echo_tool` started failing after PR nearai#2555 intentionally
   aligned the in-memory history path with DB semantics: tool previews
   now surface in `result` with `result_preview` left empty. The test
   only inspected `result_preview`, so it timed out. Accept the preview
   from either field in `_wait_for_turn`.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: agent Agent core (agent loop, router, scheduler) scope: channel/wasm WASM channel runtime scope: channel/web Web gateway channel scope: channel Channel infrastructure size: XL 500+ changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants