Skip to content

Fix tool-call loop leaks, raise step cap, add message queueing - #6

Merged
MathiTz merged 1 commit into
mainfrom
fix/tool-loop-tag-leaks-and-message-queue
Aug 23, 2026
Merged

Fix tool-call loop leaks, raise step cap, add message queueing#6
MathiTz merged 1 commit into
mainfrom
fix/tool-loop-tag-leaks-and-message-queue

Conversation

@MathiTz

@MathiTz MathiTz commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes a recurring bug where malformed/unrecognized tool-call tags leaked raw JSON into the chat instead of executing, raises the agent loop's tool-call safety cap, and adds message queueing + live step visibility so long-running builds don't get silently cut off.

Changes

  • Tag-leak fixes (core/workspace_tools.py): tolerate stray whitespace in <motion_tool> tags, recognize the <| DSML | tool:NAME> channel leak observed from deepseek-v4-flash, and add a general fallback guard so any unrecognized envelope wrapping tool-call-shaped JSON is treated as malformed (triggering a retry) instead of being shown to the user as the final answer.
  • Tool-call loop (main.py): raised MAX_TOOL_STEPS from a tight limit to a generous safety ceiling (150), intended only to catch a truly stuck model rather than cap legitimate multi-file builds. If it's ever hit, completed work is reported instead of discarded. Every tool op (not just writes) now streams progress.
  • UI (ui/tui.py):
    • New conversations start in read-only "plan" mode (discuss first); an explicit build-trigger phrase or Tab switches to "build" mode.
    • Plan-mode instructions no longer demand file writes; the model is nudged to produce a concrete plan instead of punting back to the user.
    • Added StepsMessage: an always-visible live tool-activity feed in chat, separate from the opt-in "thinking" view.
    • Messages submitted while the agent is busy are now queued instead of cancelling the in-flight worker; the same worker drains the queue once its current turn finishes.
  • Memory system (memory/db.py, memory/retriever.py, core/learning.py): fixed inverted cosine-distance ranking in the sqlite-vec path, skip zero-norm embeddings instead of crashing, added a minimum relevance threshold, unconditional recall de-duplication, and SkillSynthesizer now computes a real (or hash-fallback) embedding instead of a hardcoded zero vector.
  • Workspace resolution (core/config.py, core/learning.py, core/orchestrator.py, install.sh): anchor the harness's own persistent state (config, memory DB, skills) to its install directory instead of CWD, so motion can be invoked from any workspace directory without losing track of its own state.
  • Docs: added docs/cli.md, updated docs/architecture.md / docs/roadmap.md.

Testing

Full test suite passes locally: PYTHONPATH=. .venv/bin/pytest tests/ -q → 66 passed.

Co-Authored-By: Warp agent@warp.dev

- core/workspace_tools.py: tolerate stray whitespace in <motion_tool> tags,
  recognize the <| DSML | tool:NAME> channel leak from deepseek-v4-flash, and
  add a general fallback guard so any unrecognized envelope wrapping
  tool-call-shaped JSON is treated as malformed (and retried) instead of
  leaking raw JSON to the user as a final answer.
- main.py: raise the per-turn tool-call cap (MAX_TOOL_STEPS) from a tight
  limit to a generous safety ceiling (150) intended only to catch a truly
  stuck model; report whatever progress was made instead of discarding it
  when the cap is hit; stream progress for every tool op (not just writes)
  so the UI can show live step-by-step activity for the whole loop.
- ui/tui.py:
  - New asks start in read-only "plan" mode (discuss first); an explicit
    build-trigger phrase or Tab switches to "build" mode.
  - Plan-mode instructions no longer demand writes; the model is nudged to
    produce a concrete plan instead of punting back to the user.
  - Add StepsMessage: always-visible live tool-activity feed in chat (no
    toggle required), separate from the opt-in "thinking" view.
  - Messages submitted while the agent is busy are now queued instead of
    cancelling the in-flight worker (@work(exclusive=True) would otherwise
    kill it); the same worker drains the queue once its current turn ends.
- memory/db.py, memory/retriever.py: fix inverted cosine-distance ranking in
  the sqlite-vec path, skip zero-norm embeddings instead of crashing, add a
  minimum relevance threshold, and unconditional recall de-duplication.
- core/learning.py: SkillSynthesizer now computes a real (or hash-fallback)
  embedding instead of a hardcoded zero vector.
- core/config.py, core/learning.py, core/orchestrator.py, install.sh: anchor
  the harness's own persistent state (config, memory DB, skills) to the
  install directory (REPO_DIR) instead of CWD, so `motion` can be invoked
  from any workspace directory without losing track of its own state.
- docs/cli.md, docs/architecture.md, docs/roadmap.md: document the CLI/auth
  flow and note which orchestration features aren't yet wired into the TUI.

Co-Authored-By: Warp <agent@warp.dev>
@MathiTz MathiTz self-assigned this Aug 23, 2026
@MathiTz
MathiTz merged commit cda14c3 into main Aug 23, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant