Skip to content

fix(reborn): repair oversized provider tool arguments - #4805

Merged
think-in-universe merged 4 commits into
mainfrom
codex/fix-4751-provider-arg-overflow
Jun 14, 2026
Merged

think-in-universe merged 4 commits into
mainfrom
codex/fix-4751-provider-arg-overflow

Conversation

@hanakannzashi

@hanakannzashi hanakannzashi commented Jun 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • Repair provider tool-call batches when host validation rejects oversized arguments before capability registration.
  • Replay the rejected assistant tool calls with oversized arguments replaced by a safe marker, then ask the provider to retry with smaller arguments or answer directly.
  • Keep the repair fail-closed: if the retry still returns invalid tool output, the gateway returns the original validation path instead of executing tools.
  • Add regression coverage proving oversized provider arguments are repaired before any tool registration/execution.

Change Type

  • Bug fix
  • New feature
  • Refactor
  • Documentation
  • CI/Infrastructure
  • Security
  • Dependencies

Linked Issue

Closes #4751

Validation

  • cargo fmt --all -- --check
  • cargo clippy --all --benches --tests --examples --all-features -- -D warnings
  • cargo build
  • Relevant tests pass: cargo test -p ironclaw_reborn --features root-llm-provider --test llm_gateway gateway_repairs_oversized_provider_tool_arguments_before_registration
  • cargo test --features integration if database-backed or integration behavior changed
  • Manual testing: Not applicable; live LLM testing cannot reliably force oversized provider tool arguments without risking real tool calls.
  • If a coding agent was used and supports it, review-pr or pr-shepherd --fix was run before requesting review

Additional validation:

  • git diff --check

Security Impact

Yes. This touches the provider-tool boundary before capability registration/execution. Oversized provider tool arguments are not registered or executed; they are replaced with a safe marker in a single repair retry. The retry remains fail-closed if provider output is still invalid.

Database Impact

None.

Blast Radius

Limited to ironclaw_reborn model gateway handling of provider tool-call output and the llm_gateway regression test fixture. Normal assistant replies and valid tool calls should continue through the existing path.

Rollback Plan

Revert this PR to restore the previous behavior where oversized provider tool arguments fail immediately during host validation.

Review Follow-Through

Reviewer judgment requested on whether repair should remain scoped to the current host-validation safe summary only, or also cover provider-adapter LlmError::InvalidResponse shapes in a later follow-up.


Review track: C

Summary by CodeRabbit

  • Bug Fixes

    • Improved automatic repair-and-retry when provider tool arguments exceed size limits, recovering responses and preserving token accounting from the rejected attempt.
    • Repaired flows now return a repaired assistant reply when appropriate and retry provider calls with truncated/omitted argument payloads to avoid repeat failures.
  • Tests

    • Added end-to-end tests validating oversized-tool-argument detection, repaired retry behavior, and correct token usage accounting.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026 •

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: ed3a9c1d-8078-4ce2-a4a8-fd555b9b01af

📥 Commits

Reviewing files that changed from the base of the PR and between 1b9ced4 and 1e6814e.

📒 Files selected for processing (2)
  • crates/ironclaw_reborn/src/model_gateway.rs
  • crates/ironclaw_reborn/tests/llm_gateway.rs

📝 Walkthrough

Walkthrough

Gateway detects provider tool-call outputs rejected for "arguments too large", appends omission-marked repair messages, retries the provider with repaired tool-call arguments, merges token usage from the rejected attempt, and returns the repaired host-convertible response. Safety re-exports and tests added.

Changes

Provider Tool Argument Repair

Layer / File(s) Summary
Cargo + safety re-exports
crates/ironclaw_reborn/Cargo.toml, crates/ironclaw_safety/src/lib.rs, crates/ironclaw_safety/src/provider_validation.rs, crates/ironclaw_safety/src/provider_validation.rs::tests
Adds ironclaw_safety dependency; makes PROVIDER_ARGUMENTS_MAX_BYTES public; exports PROVIDER_ARGUMENTS_MAX_BYTES, is_provider_arguments_too_large_summary, and provider_arguments_exceed_max_bytes; adds unit test for oversize-summary.
Gateway imports and marker constant
crates/ironclaw_reborn/src/model_gateway.rs
Imports safety predicates and declares a static omission-marker used in repaired ToolCall JSON payloads.
Repair helper functions
crates/ironclaw_reborn/src/model_gateway.rs
Adds is_repairable_provider_tool_output_error, provider_tool_repair_messages, and provider_tool_call_for_repair to detect oversize-summary, synthesize assistant/tool-result repair msgs, and produce repaired ToolCall objects with omitted-arguments payloads.
Repair-retry cycle in complete_model_request
crates/ironclaw_reborn/src/model_gateway.rs
Wraps tool_response_to_host conversion with conditional repair/retry: on repairable InvalidOutput, append repair messages, re-call complete_with_tools, recover tool calls again, accumulate token usage from the rejected attempt, and retry tool_response_to_host; non-repairable errors unchanged.
Test harness: multi-response ToolAwareProvider
crates/ironclaw_reborn/tests/llm_gateway.rs
Refactors test provider to use tool_responses: Mutex<VecDeque<_>> and updates constructors/helpers and complete_with_tools to consume queued responses.
Repair behavior verification test
crates/ironclaw_reborn/tests/llm_gateway.rs
Adds gateway_repairs_oversized_provider_tool_arguments_before_registration asserting two tool-request rounds, omission-marker replacement of oversized arguments, repair-message contains the size-exceedance text and excludes the original blob, and no capability registrations occurred.

Sequence Diagram

No sequence diagram generated. (Change is primarily a focused retry within the gateway; the added interactions map to existing Client→Gateway→Provider requests without introducing three or more new distinct actors requiring a new sequential visualization.)

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Poem

A giant blob the provider spurned,
The gateway trimmed what servers learned,
It whispered "omitted" in the call,
Asked provider kindly for a small re-roll,
And stitched the tokens back — reply returned. 🛠️

Review Notes (terse, evidence-first)

  • Sandbox / egress: confirm repair messages and appended tool-result entries never contain full original oversized argument bytes in any final reply, logs, or appended provider messages; tests assert omission marker instead of original blob.
  • Trust boundary: appended assistant/tool-result messages are transmitted to provider; ensure they only instruct retry or direct answer and do not change capability/state. Tests assert no capability registration.
  • Secrets: repair path must not echo sensitive input; omission payload is constant marker — validate no accidental interpolation of original arguments.
  • Panic safety: test harness uses Mutex with lock().unwrap().pop_front(); under-provisioned queues will panic in tests — ensure tests enqueue exact sequence.
  • Retry gating: repair triggers only for HostManagedModelErrorKind::InvalidOutput with safe-summary matching is_provider_arguments_too_large_summary; string-matching must align with provider_validation helper.
  • Token accounting: accumulate_tool_response_usage saturating-adds fields (including cache token fields); verify this does not double-count tokens in telemetry/billing.
  • Repo invariant: No violations observed with CLAUDE.md / AGENTS.md / .claude/rules.
  • Public API: safety crate re-exports the new constants/functions; confirm downstream consumers expecting private constant are updated.
🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR title follows Conventional Commits style with fix(reborn) prefix and clearly summarizes the main change: repairing oversized provider tool arguments.
Description check ✅ Passed PR description covers all template sections: Summary, Change Type (Bug fix + Security), Linked Issue (#4751), Validation (fmt pass, targeted test pass), Security Impact, Database Impact, Blast Radius, Rollback Plan, and Review Follow-Through with C-track designation.
Linked Issues check ✅ Passed Code implements the core objective from #4751: detect and repair oversized provider tool arguments before capability registration/execution by replacing them with a safe marker and retrying. The repair path is fail-closed if retry still fails.
Out of Scope Changes check ✅ Passed All changes are scoped to the repair objective: model_gateway.rs implements repair-and-retry logic, tests add regression coverage, ironclaw_safety exports validation helpers. No unrelated refactoring or scope creep detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions Bot added size: M 50-199 changed lines risk: low Changes to docs, tests, or low-risk modules contributor: core 20+ merged PRs labels Jun 12, 2026

@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 a mechanism to automatically repair and retry LLM tool calls when the provider tool arguments exceed the host's size limit. It intercepts the oversized argument error, constructs a repair request that replaces the oversized arguments with an omission marker, and prompts the model to retry. Feedback suggests refining provider_tool_call_for_repair to selectively omit arguments only for the tool calls that actually exceed the limit, preserving valid ones, and to clear the reasoning field to prevent potential data leaks.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/ironclaw_reborn/src/model_gateway.rs

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_reborn/src/model_gateway.rs`:
- Around line 55-56: Replace the brittle byte-for-byte string match on
safe_summary (and the const PROVIDER_TOOL_ARGUMENTS_TOO_LARGE_SUMMARY) with a
shared, strongly-typed classifier from the safety crate: import the
authoritative constant, predicate function, or error enum (e.g., a new or
existing symbol in crates::ironclaw_safety such as arguments_too_large_constant,
is_provider_args_too_large(s: &str) or
ProviderValidationError::ArgumentsTooLarge) and use that to detect this retry
case in model_gateway.rs (instead of comparing safe_summary to the literal).
Update all occurrences (including the other match at lines referenced) to call
the shared predicate or match the exported enum/variant so the logic follows the
upstream limit changes automatically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f797358a-1fa7-460b-ac13-93993698e6e2

📥 Commits

Reviewing files that changed from the base of the PR and between 5d47973 and e4a1b85.

📒 Files selected for processing (2)
  • crates/ironclaw_reborn/src/model_gateway.rs
  • crates/ironclaw_reborn/tests/llm_gateway.rs

Comment thread crates/ironclaw_reborn/src/model_gateway.rs Outdated

@think-in-universe think-in-universe left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewed the PR and left one inline comment about accounting for the extra repair provider call.

Comment thread crates/ironclaw_reborn/src/model_gateway.rs
@github-actions github-actions Bot added the scope: dependencies Dependency updates label Jun 12, 2026

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/ironclaw_reborn/src/model_gateway.rs (1)

857-887: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Preserve the original invalid-output error if the repair retry also fails.

This branch drops error once it starts the retry. If the second tool_response_to_host(...) still returns HostManagedModelErrorKind::InvalidOutput, callers now get the retry's failure instead of the original oversize-validation path, so the fail-closed outcome depends on whatever the provider sent on the second round.

Suggested fix
-                Err(error) if is_repairable_provider_tool_output_error(&error) => {
+                Err(error) if is_repairable_provider_tool_output_error(&error) => {
                     debug!(
                         safe_summary = error.safe_summary.as_str(),
                         "reborn model gateway retrying after repairable provider tool output"
                     );
+                    let original_error = error;
                     let mut repair_request = tool_request;
                     repair_request
                         .messages
                         .extend(provider_tool_repair_messages(
                             &response,
-                            error.safe_summary.as_str(),
+                            original_error.safe_summary.as_str(),
                         ));
                     let rejected_response = response;
                     let response = provider
                         .complete_with_tools(repair_request)
                         .await
@@
-                    return tool_response_to_host(
+                    return match tool_response_to_host(
                         response,
                         capabilities,
                         provider_turn_scope
                             .as_deref()
                             .unwrap_or("model_call=unknown"),
                         &replay_identity,
                     )
-                    .await;
+                    .await
+                    {
+                        Err(retry_error)
+                            if retry_error.kind == HostManagedModelErrorKind::InvalidOutput =>
+                        {
+                            Err(original_error)
+                        }
+                        other => other,
+                    };
                 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/ironclaw_reborn/src/model_gateway.rs` around lines 857 - 887, The
branch that handles Err(error) from
is_repairable_provider_tool_output_error(&error) drops the original `error` when
retrying and may return a different failure from the retry; capture the original
error before doing the repair retry (e.g., store it in `original_error`) and
after the retry, if the eventual failure returned by
`tool_response_to_host(...)` maps to `HostManagedModelErrorKind::InvalidOutput`,
return or propagate the preserved `original_error` instead; ensure this logic is
applied around the `provider.complete_with_tools(...)`, `map_provider_error`,
and `tool_response_to_host` call sites so callers receive the original
oversize/invalid-output error when the repair attempt also fails.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/ironclaw_reborn/src/model_gateway.rs`:
- Around line 1261-1275: The helper provider_tool_call_for_repair currently sets
reasoning: None which drops the original per-tool reasoning; change it to
preserve the original reasoning by assigning reasoning:
tool_call.reasoning.clone() (or otherwise copying the existing
ToolCall.reasoning) so repaired replays retain the model-produced reasoning for
calls whose arguments were not omitted; update the struct construction in
provider_tool_call_for_repair to use tool_call.reasoning.clone() instead of
None.

---

Outside diff comments:
In `@crates/ironclaw_reborn/src/model_gateway.rs`:
- Around line 857-887: The branch that handles Err(error) from
is_repairable_provider_tool_output_error(&error) drops the original `error` when
retrying and may return a different failure from the retry; capture the original
error before doing the repair retry (e.g., store it in `original_error`) and
after the retry, if the eventual failure returned by
`tool_response_to_host(...)` maps to `HostManagedModelErrorKind::InvalidOutput`,
return or propagate the preserved `original_error` instead; ensure this logic is
applied around the `provider.complete_with_tools(...)`, `map_provider_error`,
and `tool_response_to_host` call sites so callers receive the original
oversize/invalid-output error when the repair attempt also fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 510f935d-ea50-498b-9df2-406c426fd843

📥 Commits

Reviewing files that changed from the base of the PR and between e4a1b85 and 1b9ced4.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock, !**/Cargo.lock
📒 Files selected for processing (5)
  • crates/ironclaw_reborn/Cargo.toml
  • crates/ironclaw_reborn/src/model_gateway.rs
  • crates/ironclaw_reborn/tests/llm_gateway.rs
  • crates/ironclaw_safety/src/lib.rs
  • crates/ironclaw_safety/src/provider_validation.rs

Comment thread crates/ironclaw_reborn/src/model_gateway.rs
@think-in-universe
think-in-universe added this pull request to the merge queue Jun 14, 2026
Merged via the queue into main with commit b4df62f Jun 14, 2026
87 of 95 checks passed
@think-in-universe
think-in-universe deleted the codex/fix-4751-provider-arg-overflow branch June 14, 2026 15:41
@ironclaw-ci ironclaw-ci Bot mentioned this pull request Jun 14, 2026
theredspoon pushed a commit to theredspoon/ironclaw that referenced this pull request Jun 21, 2026
* fix(reborn): repair oversized provider tool arguments

* fix(reborn): address provider tool repair review

* fix(reborn): preserve repaired tool reasoning

* ci: rerun checks

---------

Co-authored-by: Robert Yan <mstr.raphael@gmail.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: low Changes to docs, tests, or low-risk modules scope: dependencies Dependency updates size: M 50-199 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Reborn] Large response request fails with provider tool arguments exceed 16384 bytes

2 participants