Skip to content

fix(agent): suppress tool protocol when no tools are available#6546

Merged
Audacity88 merged 1 commit into
zeroclaw-labs:masterfrom
EyrieCommander:codex/fix-5287-no-tools-prompt
May 10, 2026
Merged

fix(agent): suppress tool protocol when no tools are available#6546
Audacity88 merged 1 commit into
zeroclaw-labs:masterfrom
EyrieCommander:codex/fix-5287-no-tools-prompt

Conversation

@Audacity88
Copy link
Copy Markdown
Collaborator

@Audacity88 Audacity88 commented May 9, 2026

Summary

  • Base branch: master (all contributions)
  • What changed and why:
    • Suppresses no-tools prompt scaffolding when the effective tool set is empty, so small/local models are not told about unavailable tools or XML tool syntax.
    • Stops direct Agent turns and runtime tool-loop turns from parsing/executing native or XML tool calls when no tool specs are effective.
    • Keeps channel/runtime prompt tool descriptions aligned with the effective registered tool set after allowlist or non-CLI exclusion filtering.
    • Preserves <think>...</think> stripping in no-tools responses so reasoning scratchpad text does not leak just because tool parsing is disabled.
    • Adds focused regressions for no-effective-tools native request shape, XML text preservation, reasoning-tag stripping, prompt sections, and protocol-block behavior.
  • Scope boundary: This is the first narrow slice of [Feature]: Local-First Mode for Small Models — Compact No-Tools Prompting, Strict Parser Option, and No Prompt-Leakage #5287. It does not add a runtime_profile = "ollama_local" config surface, a strict-parser config knob, provider-specific local-model profiles, or a full local-first mode. Those remain follow-up design/work items.
  • Blast radius: High-risk agent/runtime prompt and tool-call behavior. The touched paths affect direct Agent turns, the CLI/runtime tool loop, XML dispatcher prompt instructions, reusable prompt sections, and the channel orchestrator's non-native prompt assembly.
  • Linked issue(s): Related [Feature]: Local-First Mode for Small Models — Compact No-Tools Prompting, Strict Parser Option, and No Prompt-Leakage #5287
  • Labels: Current labels: enhancement, risk: high, size: M, agent:agent, agent:dispatcher, agent:loop, agent:prompt, agent: tests, channel:core.

Validation Evidence (required)

  • Commands run and tail output:
cargo fmt --all
Result: passed.

git diff --check
Result: passed.

cargo test -p zeroclaw-runtime turn_with_no_effective_tools --lib
Result: passed.
Tests: 3 passed; 0 failed; 1637 filtered out.

cargo test -p zeroclaw-channels prompt_includes_single_tool_protocol_block_after_append --lib
Result: passed.
Tests: 1 passed; 0 failed; 951 filtered out.

cargo test -p zeroclaw-runtime no_tools --lib
Result: passed.
Tests: 3 passed; 0 failed; 1637 filtered out.

Post-#6544 rebase cargo fmt --all -- --check
Result: passed.

Post-#6544 rebase git diff --check
Result: passed.

Post-#6544 rebase cargo test -p zeroclaw-runtime no_tools --lib
Result: passed.
Tests: 3 passed; 0 failed; 1642 filtered out.

Post-#6544 rebase cargo test -p zeroclaw-runtime turn_with_no_effective_tools --lib
Result: passed.
Tests: 3 passed; 0 failed; 1642 filtered out.

Post-#6544 rebase cargo test -p zeroclaw-channels prompt_includes_single_tool_protocol_block_after_append --lib
Result: passed.
Tests: 1 passed; 0 failed; 959 filtered out.

Post-#6544 rebase cargo clippy -p zeroclaw-channels --all-targets -- -D warnings
Result: passed.

GitHub Actions on current head
Result: passed.
Checks: Lint, Test, Security, Build, Check, Benchmarks Compile, and CI Required Gate passed on head 275ddcb489a97c85f54abb7f1a014dbefe5b603e.
  • Beyond CI — what did you manually verify? I checked the direct Agent path, runtime loop path, XML dispatcher prompt path, reusable prompt-builder path, and channel orchestrator path so prompt text, provider tool specs, parser behavior, and executable tool availability agree when the effective tool set is empty or filtered. During the post-fix(runtime): omit native tool prompt catalog #6544 rebase, I also verified the conflict resolution preserves both the native-tool prompt-catalog suppression from fix(runtime): omit native tool prompt catalog #6544 and this PR's no-effective-tools filtering.
  • If any command was intentionally skipped, why: CodeRabbit was skipped by reviewer instruction. Full cargo test, workspace cargo clippy --all-targets -- -D warnings, and ./dev/ci.sh all were not run locally because this is a focused high-risk slice with targeted runtime/channel tests plus CI coverage. After the CI lint failures, I moved the test-only import into the test module and verified the affected lint class locally with cargo clippy -p zeroclaw-channels --all-targets -- -D warnings.

Security & Privacy Impact (required)

Yes/No for each. Answer any Yes with a 1–2 sentence explanation.

  • New permissions, capabilities, or file system access scope? (No)
  • New external network calls? (No)
  • Secrets / tokens / credentials handling changed? (No)
  • PII, real identities, or personal data in diff, tests, fixtures, or docs? (No)
  • If any Yes, describe the risk and mitigation: No new permissions, network calls, credential handling, or PII are introduced. The security impact is intended to be defensive: when no tools are effective, the model is no longer prompted to emit tool calls and no longer has tool-like output parsed as executable action.

Compatibility (required)

  • Backward compatible? (Yes)
  • Config / env / CLI surface changed? (No)
  • If No or Yes to either: No user action is required. Existing configured tools still work; this only changes behavior when the effective tool list for a turn is empty or when prompt descriptions previously drifted from filtered tool availability.

Rollback (required for risk: medium and risk: high)

  • Fast rollback command/path: Revert this PR's squash commit with git revert <squash-commit-sha>.
  • Feature flags or config toggles: None.
  • Observable failure symptoms: Local/no-tools agents might stop receiving expected prompt guidance, tool-capable channels might show missing tool instructions, or logs/tests around no-effective-tools turns may show unexpected tool-call parsing. Check agent responses for missing tool affordances and runtime/channel logs around prompt assembly and tool-call parsing.

Supersede Attribution (required only when Supersedes # is used)

  • Superseded PRs + authors (#<pr> by @<author>, one per line): N/A
  • Scope materially carried forward: N/A
  • Co-authored-by trailers added in commit messages for incorporated contributors? (No)
  • If No, why (inspiration-only, no direct code/design carry-over): No superseded PR is incorporated.

@Audacity88 Audacity88 added enhancement New feature or request risk: high Auto risk: security/runtime/gateway/tools/workflows. size: M Auto size: 251-500 non-doc changed lines. agent Auto scope: src/agent/** changed. runtime Auto scope: src/runtime/** changed. channel Auto scope: src/channels/** changed. agent:agent Auto module: agent/agent changed. agent:dispatcher Auto module: agent/dispatcher changed. agent:loop Auto module: agent/loop changed. agent:prompt Auto module: agent/prompt changed. agent: tests Auto module: agent/tests changed. channel:core Auto module: channel core files changed. labels May 9, 2026
@Audacity88 Audacity88 force-pushed the codex/fix-5287-no-tools-prompt branch from 449ab0e to b09e830 Compare May 9, 2026 06:51
@github-actions github-actions Bot removed agent Auto scope: src/agent/** changed. channel Auto scope: src/channels/** changed. runtime Auto scope: src/runtime/** changed. labels May 9, 2026
@Audacity88 Audacity88 force-pushed the codex/fix-5287-no-tools-prompt branch from b09e830 to 4def38f Compare May 9, 2026 07:28
@Audacity88 Audacity88 marked this pull request as ready for review May 9, 2026 08:00
Copy link
Copy Markdown
Collaborator

@WareWolf-MoonWall WareWolf-MoonWall left a comment

Choose a reason for hiding this comment

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

I've read the full diff across all five touched files: agent.rs, dispatcher.rs, loop_.rs, delegate.rs, and orchestrator/mod.rs.

🟢 What looks good — Defense-in-depth across all code paths

The no-tools guard fires consistently at four independent checkpoints: Agent::should_send_tool_specs() (no specs sent to the provider), Agent::parse_response_for_effective_tools() (no calls parsed from the response), run_tool_call_loop (no native collection, no fallback XML parser, no parse-issue detection, think-tag stripping applied), and XmlToolDispatcher::prompt_instructions() (empty protocol block). Each layer would be independently correct; together they eliminate the category of bugs where one code path emits tool scaffolding while another path is silently skipped. This is the right depth of defense for a change touching agent/runtime prompt behavior.

🟢 What looks good — Prompt/description alignment via effective_tool_names

The effective_tool_namestool_descs.retainbuild_tool_instructions_for_names chain in both process_message and start_channels ensures the prose tool catalog in the system prompt reflects exactly what the runtime will actually execute. The retain_registered_tool_descriptions helper enforces the same invariant in the CLI run path. This removes the drift between described tools and executable tools that was the root of the original issue.

🟡 Warning — Sequencing risk with #6544 and #6541

orchestrator/mod.rs, agent.rs, loop_.rs, and delegate.rs are all modified by #6544 and #6541 as well. These will produce merge conflicts. The recommended sequence: merge #6541 first (session key scoping), then #6544 (adds sends_native_tool_specs to PromptContext), then this PR rebased against both. Before posting the rebase, confirm that build_tool_instructions_for_names (added here) is consistent with whatever final import line state results from the prior two merges.

🔵 Suggestion — Unit test for the partial-exclusion path

The effective_tool_names filtering (AutonomyLevel < Full, some tools excluded) is covered by CI but lacks a focused unit test for the "some excluded, some retained" case on build_tool_instructions_for_names. Adding one would make future regressions in the filter logic immediately visible without a full integration run.

Approved.

Copy link
Copy Markdown
Collaborator

@tidux tidux left a comment

Choose a reason for hiding this comment

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

I read the full diff across the runtime agent paths and the channel orchestrator path, including the no-tools response parsing, native tool-spec gating, prompt-section omission, and effective tool-name filtering.

🟢 What looks good — Empty effective tool sets are handled as a first-class state

The change treats "no effective tools" as its own runtime state instead of as a degenerate tool-enabled turn. Agent::should_send_tool_specs() avoids sending an empty native tools array, Agent::parse_response_for_effective_tools() prevents tool-like text from being parsed when there is nothing executable, and run_tool_call_loop applies the same rule to both native calls and text fallback parsing. That is the right security posture for the #5287 slice because tool-looking model output cannot become executable action unless the runtime actually has an effective tool set for the turn.

🟢 What looks good — Prompt text now matches executable availability

The prompt-side filtering is consistent with the runtime behavior: tool_descs is retained against the effective registered names, non-native XML instructions are built only for those names, and the system prompt sections omit tool honesty/protocol scaffolding when no tools remain. This closes the confusing local-model path where the assistant was told how to call tools that the runtime would not actually expose.

🟢 What looks good — Regression coverage hits the risky paths

The new tests cover the important failure modes directly: no native specs sent for an empty effective set, XML-looking output preserved as text, <think> stripping retained, prompt sections omitted, and the channel prompt still emitting exactly one protocol block when a tool is present. I also reran the focused local checks:

cargo test -p zeroclaw-runtime no_tools --lib
cargo test -p zeroclaw-runtime turn_with_no_effective_tools --lib
cargo test -p zeroclaw-channels prompt_includes_single_tool_protocol_block_after_append --lib

All passed.

Approved.

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior.
@Audacity88 Audacity88 force-pushed the codex/fix-5287-no-tools-prompt branch from 4def38f to 275ddcb Compare May 10, 2026 02:58
@Audacity88 Audacity88 merged commit 6a1c6ff into zeroclaw-labs:master May 10, 2026
12 checks passed
github-actions Bot pushed a commit that referenced this pull request May 10, 2026
#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to luridarmawan/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to Xuano47/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to nagyist/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to aliasliao/zeroclaw-contribute that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to thanhtantran/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to ConYel/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to drowning-in-codes/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to k-axiom/zeroclaw that referenced this pull request May 10, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to tidux/zeroclaw that referenced this pull request May 11, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to FTDGRT/zeroclaw that referenced this pull request May 11, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
github-actions Bot pushed a commit to vmisunv/my_zeroclaw that referenced this pull request May 11, 2026
zeroclaw-labs#6546)

Treat empty effective tool sets as a no-tools turn across prompt assembly, provider request shape, and parser execution.

Preserve reasoning-tag stripping while avoiding execution of tool-like output when no tools are available.

Add focused regressions for native request shape, XML text preservation, prompt scaffolding, and channel protocol prompt behavior. 6a1c6ff
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agent:agent Auto module: agent/agent changed. agent:dispatcher Auto module: agent/dispatcher changed. agent:loop Auto module: agent/loop changed. agent:prompt Auto module: agent/prompt changed. agent: tests Auto module: agent/tests changed. channel:core Auto module: channel core files changed. enhancement New feature or request risk: high Auto risk: security/runtime/gateway/tools/workflows. size: M Auto size: 251-500 non-doc changed lines.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants