Bug type
Behavior bug (incorrect output/state without crash) — performance.
Beta release blocker
No
Summary
The image-generate, video-generate, and music-generate agent tools eagerly list runtime capability providers during tool registration, even when the agent has an explicit and complete modelConfig and the provider list goes unused. On hosted gateways with plugins.entries non-empty, each provider listing triggers a full plugin-registry reload (~5–6s per call), adding ~15–18s of wall-clock latency to every agent turn for capabilities the agent isn't using.
Steps to reproduce
- Run any gateway with
openclaw.json containing at least one plugin in plugins.entries. Confirmed against 2026.4.26-f53b52ad6d21.
- Connect any agent that registers the built-in
image-generate / video-generate / music-generate tools (i.e. all agents, since these are core agent tools).
- Send a single inbound message.
- Observe register() being invoked 3 additional times during the turn (4 total counting the initial load), with stack
runPluginRegisterSync ← loadOpenClawPlugins ← resolveRuntimePluginRegistry ← resolvePluginCapabilityProviders ← resolvePluginImageGenerationProviders ← buildProviderMaps ← listImageGenerationProviders (and likewise for video / music).
Observed log (top of stack on the 3 in-turn reloads):
register #3 caller: ... resolvePluginCapabilityProviders ← resolvePluginImageGenerationProviders ← buildProviderMaps ← listImageGenerationProviders
register #4 caller: ... resolvePluginCapabilityProviders ← resolvePluginVideoGenerationProviders ← buildProviderMaps ← listVideoGenerationProviders
register #5 caller: ... resolvePluginCapabilityProviders ← resolvePluginMusicGenerationProviders ← buildProviderMaps ← listMusicGenerationProviders
Expected behavior
When an agent has an explicit complete modelConfig for image / video / music generation, resolveCapabilityModelConfigForTool short-circuits at the hasToolModelConfig(explicit) check and returns without using the provider list. In that path, listing providers is pure waste — and on hosted gateways it's a 5–6s cache miss per call.
Actual behavior
resolveCapabilityModelConfigForTool (in src/agents/tools/media-tool-shared.ts:246) takes providers: CapabilityProvider[] as a required eagerly-evaluated parameter. The 3 callers (image-generate-tool.ts:202, video-generate-tool.ts:232, music-generate-tool.ts:138) call listRuntime{Image,Video,Music}GenerationProviders({ config: cfg }) to compute it before calling resolveCapabilityModelConfigForTool, so providers are listed even when hasToolModelConfig(explicit) would short-circuit.
listRuntime{...}GenerationProviders flows through resolvePluginCapabilityProviders (src/plugins/capability-provider-runtime.ts:316) which calls resolveRuntimePluginRegistry({config: compatConfig, activate: false}). That's a cache key not held by the active registry, so it falls through to loadOpenClawPlugins, re-imports every plugin, and re-runs each plugin's register() (~5–6s each in production).
This is independent of #73793 — it's about avoiding the lookup entirely when not needed.
Environment
- OpenClaw
2026.4.26-f53b52ad6d21 (production gateway)
- Node
v24.14.0
- Linux x64 (Elestio-hosted Docker container)
- Active plugins:
memory-core, plus a third-party channel plugin
Logs / evidence
Per-turn timing from instrumented third-party plugin (paths trimmed):
register #3 caller: runPluginRegisterSync ← loadOpenClawPlugins ← resolveRuntimePluginRegistry ← resolvePluginCapabilityProviders ← resolvePluginImageGenerationProviders ← buildProviderMaps ← listImageGenerationProviders
register #4 caller: ... ← resolvePluginVideoGenerationProviders ← buildProviderMaps ← listVideoGenerationProviders
register #5 caller: ... ← resolvePluginMusicGenerationProviders ← buildProviderMaps ← listMusicGenerationProviders
Proposed fix
Change the providers parameter on resolveCapabilityModelConfigForTool from CapabilityProvider[] to () => CapabilityProvider[] so the listing is deferred until the function actually needs it (i.e. when modelConfig is incomplete and candidate resolution must run). Update the 3 internal callers to pass thunks. PR with fix + regression tests filed alongside.
Bug type
Behavior bug (incorrect output/state without crash) — performance.
Beta release blocker
No
Summary
The
image-generate,video-generate, andmusic-generateagent tools eagerly list runtime capability providers during tool registration, even when the agent has an explicit and completemodelConfigand the provider list goes unused. On hosted gateways withplugins.entriesnon-empty, each provider listing triggers a full plugin-registry reload (~5–6s per call), adding ~15–18s of wall-clock latency to every agent turn for capabilities the agent isn't using.Steps to reproduce
openclaw.jsoncontaining at least one plugin inplugins.entries. Confirmed against2026.4.26-f53b52ad6d21.image-generate/video-generate/music-generatetools (i.e. all agents, since these are core agent tools).runPluginRegisterSync ← loadOpenClawPlugins ← resolveRuntimePluginRegistry ← resolvePluginCapabilityProviders ← resolvePluginImageGenerationProviders ← buildProviderMaps ← listImageGenerationProviders(and likewise for video / music).Observed log (top of stack on the 3 in-turn reloads):
Expected behavior
When an agent has an explicit complete
modelConfigfor image / video / music generation,resolveCapabilityModelConfigForToolshort-circuits at thehasToolModelConfig(explicit)check and returns without using the provider list. In that path, listing providers is pure waste — and on hosted gateways it's a 5–6s cache miss per call.Actual behavior
resolveCapabilityModelConfigForTool(insrc/agents/tools/media-tool-shared.ts:246) takesproviders: CapabilityProvider[]as a required eagerly-evaluated parameter. The 3 callers (image-generate-tool.ts:202,video-generate-tool.ts:232,music-generate-tool.ts:138) calllistRuntime{Image,Video,Music}GenerationProviders({ config: cfg })to compute it before callingresolveCapabilityModelConfigForTool, so providers are listed even whenhasToolModelConfig(explicit)would short-circuit.listRuntime{...}GenerationProvidersflows throughresolvePluginCapabilityProviders(src/plugins/capability-provider-runtime.ts:316) which callsresolveRuntimePluginRegistry({config: compatConfig, activate: false}). That's a cache key not held by the active registry, so it falls through toloadOpenClawPlugins, re-imports every plugin, and re-runs each plugin'sregister()(~5–6s each in production).This is independent of #73793 — it's about avoiding the lookup entirely when not needed.
Environment
2026.4.26-f53b52ad6d21(production gateway)v24.14.0memory-core, plus a third-party channel pluginLogs / evidence
Per-turn timing from instrumented third-party plugin (paths trimmed):
Proposed fix
Change the
providersparameter onresolveCapabilityModelConfigForToolfromCapabilityProvider[]to() => CapabilityProvider[]so the listing is deferred until the function actually needs it (i.e. whenmodelConfigis incomplete and candidate resolution must run). Update the 3 internal callers to pass thunks. PR with fix + regression tests filed alongside.