Files
ironclaw/crates
firat.sertgoz 11f006987d fix(engine): FINAL-await support + runaway loop protection (#2531)
* fix(engine): make FINAL/FINAL_VAR awaitable in CodeAct scripts

LLMs frequently emit `await FINAL(answer)` by analogy with async tool
calls. The handler returned `MontyObject::None` synchronously, so the
subsequent `await` raised `TypeError: 'NoneType' object can't be
awaited` and the answer was dropped on the floor.

Route FINAL and FINAL_VAR through the existing `pending_futures`
mechanism with a trivially-resolving task. `final_answer` is set the
moment the call arrives, so both `FINAL(x)` (coroutine discarded) and
`await FINAL(x)` (resolves to None) succeed. Two regression tests in
`scripting::tests` pin both forms.

* fix(engine): normalize typographic punctuation before skill activation

iOS, macOS, and most rich-text inputs autocorrect `I'm` (ASCII U+0027)
to `I'm` (curly U+2019). Skill activation patterns like
`(?i)I'm a (CEO|...)` are authored with ASCII punctuation, so the
curly form silently failed to match — `ceo-setup` and any other skill
with apostrophes in its regex never activated for autocorrected input.

Add `normalize_punctuation()` in `default.py` that folds 8 typographic
quote variants and the en/em dashes to ASCII before scoring runs.
Implemented with chained `.replace()` because Monty does not expose
`str.maketrans`/`.translate()`. Runs once per turn on the goal text;
user content is untouched everywhere else.

Two regression tests under `executor::orchestrator::tests` drive
`normalize_punctuation` and `select_skills` end-to-end with the exact
ceo-setup pattern and a curly-apostrophe goal.

* docs(codeact): note closure capture quirk and Rust regex limits

Two recurring CodeAct failures got their own paragraphs in the
preamble:

- Function closures defined in one ```repl``` block do not reliably
  capture names (modules, top-level vars) defined in earlier blocks,
  producing spurious `NameError`. Authors must keep the helper, its
  imports, and its call sites in the same block.

- The embedded `re` is the Rust `regex` crate, not CPython: positional-
  only flag args, no lookaround, no backreferences. Lead with string
  methods (`in`, `startswith`, `splitlines`) and only reach for `re`
  when truly needed.

Pure docs change.

* fix(engine): adapt FINAL-await tests to staging CodeExecutionResult API

Replace `had_error` field references with `failure.is_none()` to match
the staging struct where `had_error: bool` was replaced by
`failure: Option<CodeExecutionFailure>`.

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

* fix(engine): address gemini-code-assist review — normalize before extraction, seed explicit skills (#2531)

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

* fix(skills): remove useless .into_iter() to satisfy clippy (#2531)

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

* fix(clippy): collapse nested if blocks into match guards (#2531)

Fixes collapsible_match lints in ironclaw_tui::render and
ironclaw_engine::runtime::mission triggered by Rust 1.95.

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

* fix(clippy): resolve collapsible_match and unnecessary_sort_by lints (#2531)

Fix 5 collapsible_match lints (responses_api, cli/tool, rig_adapter,
setup/prompts) and 2 unnecessary_sort_by lints (glob_tool, grep_tool)
triggered by Rust 1.95 clippy. Also fix rustfmt formatting for match
guards in render.rs.

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

* fix(clippy): group wasm startup channel registration context

---------

Co-authored-by: Illia Polosukhin <ilblackdragon@gmail.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-18 23:07:32 +03:00
..