Skip to content

[AI-assisted] Fix cached plugin tool wrapper bug - iterate through candidates to match by actual runtime tool name#78716

Merged
obviyus merged 10 commits into
openclaw:mainfrom
zanni098:fix/cached-plugin-tool-wrapper-declarednames
May 8, 2026
Merged

[AI-assisted] Fix cached plugin tool wrapper bug - iterate through candidates to match by actual runtime tool name#78716
obviyus merged 10 commits into
openclaw:mainfrom
zanni098:fix/cached-plugin-tool-wrapper-declarednames

Conversation

@zanni098

@zanni098 zanni098 commented May 7, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #78671

The bug was in createCachedDescriptorPluginTool.execute: cached descriptor execution could treat plugin-level declaredNames as per-factory identity for unnamed factories. In a plugin that declares multiple contracts.tools and registers each tool through unnamed factories, the first factory could effectively claim sibling manifest tools and cause plugin tool runtime missing.

This PR dispatches cached descriptor-backed tools by resolving the actual runtime tool name. It tries matching named factories first, then unnamed factories, and keeps tool execution outside factory/materialization error handling so real execution errors are preserved.

Real behavior proof

Behavior or issue addressed: Cached descriptor-backed plugin tool execution now reaches the runtime factory whose returned tool name matches the requested manifest tool. This fixes multi-tool plugins where shared manifest contracts.tools expose sibling tools but unnamed factories previously caused plugin tool runtime missing.

Real environment tested: Windows local OpenClaw checkout at C:\Users\eishm\CascadeProjects\openclaw, PR branch fix/cached-plugin-tool-wrapper-declarednames, patched source build, temporary OPENCLAW_HOME, and a disposable local OpenClaw plugin with one unrelated named factory plus two unnamed factories under shared contracts.tools.

Exact steps or command run after this patch: Ran pnpm test src/plugins/tools.optional.test.ts, pnpm exec oxfmt --check --threads=1 src/plugins/tools.ts src/plugins/tools.optional.test.ts CHANGELOG.md, pnpm build, pnpm check:changed, and node --import tsx .proof/cached-plugin-dispatch-proof.mjs.

After-fix evidence:

> pnpm test src/plugins/tools.optional.test.ts
Test Files  1 passed (1)
Tests  60 passed (60)

> pnpm exec oxfmt --check --threads=1 src/plugins/tools.ts src/plugins/tools.optional.test.ts CHANGELOG.md
All matched files use the correct format.

> pnpm build
[build-all] runtime-postbuild
runtime-postbuild: plugin SDK root alias completed in 1ms
runtime-postbuild: bundled plugin metadata completed in 538ms
runtime-postbuild: official channel catalog completed in 18ms
runtime-postbuild: bundled plugin runtime overlay completed in 1062ms
runtime-postbuild: stable root runtime imports completed in 491ms
runtime-postbuild: stable root runtime aliases completed in 145ms
runtime-postbuild: legacy root runtime compat aliases completed in 51ms
OK: All 4 required plugin-sdk exports verified.

> pnpm check:changed
[email protected] check:changed C:\Users\eishm\CascadeProjects\openclaw
node scripts/check-changed.mjs

> node --import tsx .proof/cached-plugin-dispatch-proof.mjs
OpenClaw cached descriptor dispatch real behavior proof
repo: C:\Users\eishm\CascadeProjects\openclaw
temporary OPENCLAW_HOME: C:\Users\eishm\AppData\Local\Temp\openclaw-proof-MlpcU7\home
temporary plugin root: C:\Users\eishm\AppData\Local\Temp\openclaw-proof-MlpcU7\proof-cached-dispatch
manifest contracts.tools: ["proof_alpha","proof_beta","proof_named_unrelated"]
plugin registration shape: one unrelated named factory, two unnamed factories
first resolve exposed tools: proof_named_unrelated, proof_alpha, proof_beta
cached resolve exposed tools: proof_named_unrelated, proof_alpha, proof_beta
factory log before cached execution: factory:proof_named_unrelated | factory:proof_alpha | factory:proof_beta
cached execution command: execute proof_beta
cached execution result: {"content":[{"type":"text","text":"proof-beta-ok"}]}
factory log during cached execution: factory:proof_alpha | factory:proof_beta | execute:proof_beta
runtime observation: proof_beta reached the second unnamed runtime factory and returned proof-beta-ok
runtime non-regression: unrelated named factory was not invoked during cached proof_beta execution

Observed result after fix: The cached descriptor for proof_beta executed the second unnamed runtime factory and returned proof-beta-ok. The prior failure mode, plugin tool runtime missing, did not occur. The unrelated named factory was not invoked during cached proof_beta execution.

What was not tested: Production/private plugin data, secrets, and user conversations were not used. The runtime proof used a disposable local plugin with the same manifest and unnamed-factory shape described in #78671.

@openclaw-barnacle openclaw-barnacle Bot added size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 7, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ff3ab330e6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/tools.ts Outdated
@clawsweeper

clawsweeper Bot commented May 7, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Summary
The PR changes cached plugin descriptor execution to resolve descriptor-backed tools by actual runtime tool name, with tests and a changelog entry for the multi-tool unnamed-factory bug.

Reproducibility: yes. Source inspection shows current main can select the first unnamed factory through shared plugin-level declaredNames, and the linked lossless-claw report describes that exact multi-tool shape failing with plugin tool runtime missing.

Real behavior proof
Sufficient (terminal): The PR body contains after-fix terminal output from a real Windows checkout and disposable local plugin showing the fixed cached dispatch path.

Next step before merge
No ClawSweeper repair lane is needed because the latest PR has no concrete review finding and already includes real behavior proof plus exact-head CI.

Security
Cleared: The diff only changes plugin dispatch logic, tests, and changelog text; it does not add dependencies, workflows, permissions, downloads, package resolution, publishing, or secret handling.

Review details

Best possible solution:

Land this runtime-name dispatch fix or an equivalent focused patch after maintainer approval, keeping contracts.tools as discovery metadata rather than per-factory runtime identity.

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

Yes. Source inspection shows current main can select the first unnamed factory through shared plugin-level declaredNames, and the linked lossless-claw report describes that exact multi-tool shape failing with plugin tool runtime missing.

Is this the best way to solve the issue?

Yes. Matching explicit named registrations first and then unnamed factories by returned runtime tool name is the narrow maintainable fix; changing manifest contracts or requiring new plugin author behavior would be broader.

What I checked:

  • Current-main root cause: The cached descriptor wrapper on main selects a single registry entry using explicit names or fallback declaredNames before checking the returned runtime tool name, which lets the first unnamed factory match sibling manifest tools. (src/plugins/tools.ts:556, a1ac559ed7e6)
  • Shared declaredNames source: registerTool computes declaredNames from the plugin contracts and stores them on each registration; unnamed factories keep names empty, so multiple unnamed factories can share the same plugin-level contract list. (src/plugins/registry.ts:530, a1ac559ed7e6)
  • Manifest contract intent: The plugin docs say runtime-registered tools must be listed in contracts.tools so OpenClaw can discover the owning plugin without loading every plugin runtime, supporting use as discovery metadata rather than per-factory identity. Public docs: docs/plugins/building-plugins.md. (docs/plugins/building-plugins.md:98, a1ac559ed7e6)
  • Latest PR implementation: The final patch filters candidates to the plugin, tries matching named registrations first, then unnamed registrations, and executes the matched runtime tool outside the factory/materialization catch block. (src/plugins/tools.ts:553, 8040057e9813)
  • Regression coverage: The PR adds tests for shared unnamed factories resolving the second tool and for avoiding unrelated named factory invocation before cached unnamed fallback execution. (src/plugins/tools.optional.test.ts:1724, 8040057e9813)
  • Real behavior proof: The PR body includes terminal output from a Windows checkout and disposable local plugin showing cached proof_beta execution returned proof-beta-ok and did not invoke the unrelated named factory. (8040057e9813)

Likely related people:

  • steipete: Authored the plugin tool descriptor cache refactor and adjacent tool factory execution isolation that created the cached descriptor execution path under review. (role: introduced descriptor-cache surface; confidence: high; commits: 1466878c36ff, a254fdaf4212; files: src/plugins/tools.ts, src/plugins/tool-descriptor-cache.ts, src/plugins/tools.optional.test.ts)
  • shakkernerd: Authored plugin tool manifest contract enforcement and is credited as co-author on the descriptor-cache feature commit; the PR timeline also shows this handle was mentioned on the thread. (role: manifest contract and adjacent contributor; confidence: high; commits: 7641783d6b0e, 1466878c36ff; files: src/plugins/registry.ts, src/plugins/tools.ts, docs/plugins/building-plugins.md)
  • vincentkoc: Recent main history for src/plugins/tools.ts includes several plugin tool availability, optional metadata, denylist, and conflict fixes near the affected dispatch surface. (role: recent plugin tool maintainer; confidence: medium; commits: 09e7eb6687a1, e3cba91ef059, 571d75aab351; files: src/plugins/tools.ts)

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

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c9defb48c2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/tools.ts Outdated
@zanni098
zanni098 marked this pull request as draft May 7, 2026 02:35
@zanni098
zanni098 marked this pull request as ready for review May 7, 2026 02:39

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 556ba77d6c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/tools.ts Outdated
Comment thread src/plugins/tools.ts Outdated
@zanni098
zanni098 marked this pull request as draft May 7, 2026 02:43
@zanni098
zanni098 marked this pull request as ready for review May 7, 2026 02:48

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7563085dfc

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/plugins/tools.ts Outdated
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 7, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

1 similar comment
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@zanni098
zanni098 force-pushed the fix/cached-plugin-tool-wrapper-declarednames branch from b83680a to 5835285 Compare May 7, 2026 08:40
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 7, 2026
@zanni098
zanni098 force-pushed the fix/cached-plugin-tool-wrapper-declarednames branch from c91a3b7 to 8040057 Compare May 8, 2026 00:21
@chatgpt-codex-connector

Copy link
Copy Markdown
Contributor

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 8, 2026
zanni098 and others added 10 commits May 8, 2026 12:38
… with names and catching factory failures

- First try to narrow candidates using names when available to preserve original behavior for named factories
- Add try-catch around factory invocation to continue on failures, matching uncached path behavior
- This prevents regression for plugins with multiple named factories while fixing the bug for unnamed factories
- P1: Restore catch (error) for cold-load failures (line 986)
- P2: Preserve synchronous tool execution errors by moving return outside try blocks
- P2: Try named candidates first, then fall back to all candidates (including unnamed)
- P2: Keep error handling for factory/materialization failures
- Only try unnamed candidates in the fallback to avoid double invocation
- This prevents performance issues and side effects from calling named factories twice
@obviyus
obviyus force-pushed the fix/cached-plugin-tool-wrapper-declarednames branch from 2615dc2 to e40ce4f Compare May 8, 2026 07:09
@obviyus
obviyus merged commit 3adbbe7 into openclaw:main May 8, 2026
110 checks passed
@obviyus

obviyus commented May 8, 2026

Copy link
Copy Markdown
Contributor

Landed via squash onto main.

  • Scoped tests: bunx pnpm exec oxfmt --check --threads=1 src/plugins/tools.ts src/plugins/tools.optional.test.ts CHANGELOG.md; bunx pnpm test src/plugins/tools.optional.test.ts
  • Changelog: updated
  • Land commit: e40ce4f
  • Merge commit: 3adbbe7

Thanks @zanni098!

github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 9, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

Thanks @zanni098!
rogerdigital pushed a commit to rogerdigital/openclaw that referenced this pull request May 9, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

Thanks @zanni098!
@robg-cyber

Copy link
Copy Markdown

Confirming real-world reproduction of #78671 from a production OpenClaw setup, in case it helps unblock the "needs-real-behavior-proof" gate.

Environment:

  • OpenClaw 2026.5.4 (Docker, Debian, Node 24.15.0)
  • @martian-engineering/[email protected]
  • Headless server deployment, Tailscale-fronted

Symptom (exactly as in #78671):

[tools] lcm_describe failed: plugin tool runtime missing (lossless-claw): lcm_describe
[tools] lcm_expand failed: plugin tool runtime missing (lossless-claw): lcm_expand

lcm_grep works. lcm_describe, lcm_expand, and lcm_expand_query all fail with the runtime-missing error.

What we've verified does NOT fix it:

The "plugin tool runtime missing" wording (rather than e.g. "subagent override denied") suggests the registration-time path described in #78671 — handlers are visible in palette but the wrong factory is selected at execution time.

Happy to test a build with the patch applied against my live setup if that would help validate the fix.

lykeion-dev pushed a commit to lykeion-dev/openclaw--rev that referenced this pull request May 14, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

Thanks @zanni098!
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

Thanks @zanni098!
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

Thanks @zanni098!
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Fix cached descriptor-backed plugin tool dispatch for unnamed factories sharing manifest contracts.

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

Labels

proof: supplied External PR includes structured after-fix real behavior proof. size: S

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: cached plugin tool wrapper uses plugin-level declaredNames as per-factory runtime identity

3 participants