Skip to content

fix(agents): skip empty allowlist guard for modelRun#73031

Closed
aa-on-ai wants to merge 1 commit into
openclaw:mainfrom
aa-on-ai:fix/infer-model-run-allowlist-guard
Closed

fix(agents): skip empty allowlist guard for modelRun#73031
aa-on-ai wants to merge 1 commit into
openclaw:mainfrom
aa-on-ai:fix/infer-model-run-allowlist-guard

Conversation

@aa-on-ai

Copy link
Copy Markdown

Summary

openclaw infer model run aborts before any provider request when ~/.openclaw/openclaw.json has a non-empty tools.alsoAllow, because the empty explicit-allowlist guard still evaluates the global tool policy even though modelRun:true intentionally zeroes toolsRaw.

The fix adds a modelRun?: boolean parameter to buildEmptyExplicitToolAllowlistError and short-circuits to null when it is true. The embedded attempt path (attempt.ts) now passes modelRun: params.modelRun into the guard so model-only call shapes can run text-only without failing on a global tools.alsoAllow.

This keeps the existing fail-closed behavior for runtime disableTools conflicts and for ordinary agent runs whose explicit allowlist resolves to no callable tools (the original intent of #71292).

Repro

  1. Set in ~/.openclaw/openclaw.json:

    "tools": { "profile": "coding", "alsoAllow": ["lobster", "llm-task"] }
  2. Run:

    openclaw infer model run --local --model openai-codex/gpt-5.5 --prompt 'reply exactly: ok' --json

    Before this PR, fails with No callable tools remain after resolving explicit tool allowlist (...). After this PR, the model is reached.

Test added

src/agents/tool-allowlist-guard.test.ts — new case skips the empty-allowlist guard for modelRun call shapes. Asserts buildEmptyExplicitToolAllowlistError returns null when modelRun: true even with non-empty sources and zero callable tools. The existing disableTools: true fail-closed test is unchanged.

Validation

  • pnpm test src/agents/tool-allowlist-guard.test.ts — 7/7 passing
  • pnpm check:changed --staged — green (typecheck core/test, lint, import cycles, conflict markers, changelog attributions, etc.)
  • pnpm test:changed — 2521 passing; one unrelated pre-existing failure on src/agents/tools/cron-tool.schema.test.ts (job.delivery keys assertion is missing the new threadId introduced by upstream b6be422306 fix(cron): accept threaded delivery in gateway schema). Reproduces on bare upstream/main with my changes stashed, so it is not blocking.

Closes

Fixes #73024

AI assistance

This PR was prepared with Claude Code (Opus 4.7). Lightly tested locally — the unit test covers the guard contract; the end-to-end infer model run repro was not exercised live since it requires a live model account.

The infer model run flow sets modelRun=true and disableTools=true so toolsRaw
is intentionally empty. The empty-allowlist guard still ran with the global
tools.alsoAllow expanded as an explicit allowlist, so the run failed before
any provider request was made. Skip the guard when modelRun is true so
text-only model smokes succeed even when tools.alsoAllow is configured.

Fixes openclaw#73024.
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: XS labels Apr 27, 2026
@greptile-apps

greptile-apps Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a false-positive error in buildEmptyExplicitToolAllowlistError where a globally-configured tools.alsoAllow would trigger the empty-allowlist guard for modelRun call shapes — which intentionally carry zero tools. The fix adds an early modelRun short-circuit before any guard logic and threads params.modelRun through the one production call site in attempt.ts. The change is minimal, targeted, and covered by a new unit test.

Confidence Score: 5/5

Safe to merge — targeted one-line guard bypass, single call site updated, well-tested.

The change is minimal and correct: a single early-exit added before the guard logic, only one production call site, and the new parameter is optional so no other callers are affected. The test suite covers both the new bypass and the existing fail-closed paths.

No files require special attention.

Reviews (1): Last reviewed commit: "fix(agents): skip empty allowlist guard ..." | Re-trigger Greptile

@clawsweeper

clawsweeper Bot commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Summary
The branch adds a modelRun bypass to the empty explicit tool allowlist guard, passes that flag from the embedded attempt runner, adds a focused guard test, and adds an Unreleased changelog fix entry.

Reproducibility: yes. The current-main source path is high-confidence without a live model account: gateway model run sets modelRun/promptMode: "none", the embedded runner intentionally empties tools, inherited explicit allowlist sources are still collected, and the guard can return the pre-provider error.

Next step before merge
Maintainers should choose whether to land this narrow PR separately or reconcile it with #74139; there is no discrete patch defect that needs an automated repair branch.

Security
Cleared: No concrete security or supply-chain concern was found; the diff only changes an in-process tool-policy guard, one internal call site, a unit test, and a changelog entry.

Review details

Best possible solution:

Land this narrow modelRun guard bypass with its regression test if maintainers want the infer model run fix separately, while deciding the broader disabled-tools policy in the #74139/#74019 track.

Do we have a high-confidence way to reproduce the issue?

Yes. The current-main source path is high-confidence without a live model account: gateway model run sets modelRun/promptMode: "none", the embedded runner intentionally empties tools, inherited explicit allowlist sources are still collected, and the guard can return the pre-provider error.

Is this the best way to solve the issue?

Yes for the central modelRun bug. Passing modelRun into the guard is narrower than skipping all disableTools cases and preserves the existing fail-closed runtime toolsAllow conflict behavior for ordinary disabled-tools runs.

Acceptance criteria:

  • pnpm test src/agents/tool-allowlist-guard.test.ts
  • Focused infer model run --gateway regression with inherited tools.alsoAllow and no callable tools
  • pnpm check:changed in Testbox after rebase or material updates

What I checked:

  • Current guard has no modelRun bypass: buildEmptyExplicitToolAllowlistError still accepts disableTools but not modelRun, and returns an error whenever explicit allowlist sources exist and no callable tool names remain. (src/agents/tool-allowlist-guard.ts:17, 929df0f5567f)
  • Current test preserves runtime fail-closed behavior: The existing guard test expects runtime toolsAllow with disableTools: true and no callable tools to produce the disabled-tools error, which this PR leaves intact for non-modelRun calls. (src/agents/tool-allowlist-guard.test.ts:20, 929df0f5567f)
  • Raw model runs intentionally have no tools: The embedded attempt runner treats params.modelRun === true || params.promptMode === "none" as a raw model run and sets toolsRaw to an empty array in that mode. (src/agents/pi-embedded-runner/run/attempt.ts:821, 929df0f5567f)
  • Inherited allowlists still reach the guard: The embedded runner collects global, provider, agent, group, sandbox, subagent, and runtime allowlist sources before calling the empty allowlist guard with the effective tool names. (src/agents/pi-embedded-runner/run/attempt.ts:1121, 929df0f5567f)
  • Gateway model probe sets modelRun: The infer model run --gateway path sends modelRun: true and promptMode: "none", matching the PR's proposed guard input. (src/cli/capability-cli.ts:743, 929df0f5567f)
  • Docs describe gateway model run as no-tools: The CLI docs say model run --gateway is a raw model probe without prior transcript, agent context, tools, or bundled MCP servers. Public docs: docs/cli/infer.md. (docs/cli/infer.md:137, 929df0f5567f)

Likely related people:

  • steipete: Peter Steinberger introduced the empty explicit allowlist guard in 61ee67ae, worked on model-run stabilization in 54f4c45e, and is the most recent maintainer touching the embedded attempt runner at current main. (role: introduced behavior and recent maintainer; confidence: high; commits: 61ee67aecc3f, 54f4c45e5d7e, 929df0f5567f; files: src/agents/tool-allowlist-guard.ts, src/agents/tool-allowlist-guard.test.ts, src/agents/pi-embedded-runner/run/attempt.ts)
  • Tak Hoffman: Tak Hoffman introduced the first-class infer CLI surface that owns the affected infer model run entry point. (role: infer CLI surface introducer; confidence: medium; commits: 97c031a8db48; files: src/cli/capability-cli.ts, src/cli/capability-cli.test.ts)
  • jalehman: Josh Lehman's adjacent work touched effective tool policy and embedded-runner allowlist-related surfaces near the fail-closed contract this PR preserves. (role: adjacent owner; confidence: medium; commits: 12c52963ea80; files: src/agents/pi-embedded-runner/run/attempt.ts, src/agents/pi-embedded-runner/effective-tool-policy.ts, src/agents/tool-policy.ts)

Remaining risk / open question:

Codex review notes: model gpt-5.5, reasoning high; reviewed against 929df0f5567f.

@steipete

steipete commented May 3, 2026

Copy link
Copy Markdown
Contributor

Closing as superseded by the landed generic fix in #76686: 3491060. It fixes the disabled-tools plus inherited allowlist guard path without adding a modelRun-only bypass.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling size: XS

Projects

None yet

Development

Successfully merging this pull request may close these issues.

infer model run fails before model call when tools.alsoAllow is set and modelRun disables tools

2 participants