Skip to content

fix(loop): use string_length instead of first_char to detect valid response#138

Open
hlgreenblatt wants to merge 1 commit into
asi-alliance:mainfrom
hlgreenblatt:fix/loop-first-char-safety-net
Open

fix(loop): use string_length instead of first_char to detect valid response#138
hlgreenblatt wants to merge 1 commit into
asi-alliance:mainfrom
hlgreenblatt:fix/loop-first-char-safety-net

Conversation

@hlgreenblatt

Copy link
Copy Markdown

Summary

Loosen the safety-net check at src/loop.metta:65 from (== "(" (first_char $resp)) to (> (string_length $resp) 1). The original first_char == "(" check fails reliably for valid Python-string returns from py-call even when the returned string obviously starts with (, because of a String-vs-atom type mismatch in the SWI-Prolog↔MeTTa binding for first_char/2.

When this check fails, the loop substitutes (REMEMBER:OUTPUT_NOTHING_ELSE_THAN: ((skill arg) ...)) for $response and the agent's actual output gets discarded — the agent sees only the reminder string in the next iteration. The bug surfaces any time a skill body calls a Python helper that returns a string, including any new skill that wraps py-call and returns an s-expression.

The length-based replacement is permissive enough to let well-formed Python-string returns through and still gates against the empty-string failure mode that the original check was guarding.

Provenance

This bug is documented in a downstream fork's implementation notes from 2026-04-25 (gotcha #3 in a dual-format-LLM-adapter work item). The same one-line fix is in production use in that fork. Submitting upstream as a standalone single-concern PR.

Test plan

  • Existing agent loop continues to function normally — empty-string responses still trigger the reminder branch.
  • Skills that return strings via py-call (any new Python-bridged skill) now have their output reach $response cleanly instead of being dropped.
  • A simple regression: define (= (echo $s) (py-call (helper.normalize_string $s))), ask the agent to call (echo "(send hi)"), observe that the next iteration's RESULTS contains (send hi) instead of REMEMBER:OUTPUT_NOTHING_ELSE_THAN:.

Scope

One line, one file. No new dependencies. No behavioral change for valid (...)-prefixed responses (the new check is strictly more permissive on those). The only behavioral difference is that single-character outputs are now treated as valid and routed to sread, where they will fail parsing cleanly via the existing HandleError MULTI_COMMAND_FAILURE_... path rather than being substituted for the reminder string.

…sponse

The safety-net check at src/loop.metta:65 was `(== "(" (first_char $resp))`,
which fails reliably for Python-string returns from py-call even when the
string obviously starts with `(`, due to a String-vs-atom type mismatch in
the SWI-Prolog↔MeTTa binding for first_char/2. When this triggers, the
agent's actual output is discarded and substituted for the reminder
string.

Replace with a length-based check that gates against the empty-string
failure mode (the original intent) without false negatives on valid
py-call returns. No new dependencies; single line; no behavior change
for any valid (...)-prefixed response.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants