fix(agents): skip implicit provider discovery when models.mode is 'replace' [AI-assisted]#82638
Conversation
|
Codex review: needs maintainer review before merge. Reviewed July 1, 2026, 12:47 AM ET / 04:47 UTC. Summary PR surface: Source +6, Tests +121. Total +127 across 2 files. Reproducibility: yes. at source level. Current main still awaits implicit provider discovery in resolveProvidersForModelsJsonWithDeps before any replace-mode handling; this review did not rerun the reporter's wall-clock startup benchmark. Review metrics: 1 noteworthy metric.
Root-cause cluster Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Rank-up moves:
Risk before merge
Maintainer options:
Next step before merge
Security Review detailsBest possible solution: Land the early replace-mode guard after maintainer compatibility acceptance, preserving merge/default discovery behavior and the focused regression coverage. Do we have a high-confidence way to reproduce the issue? Yes, at source level. Current main still awaits implicit provider discovery in resolveProvidersForModelsJsonWithDeps before any replace-mode handling; this review did not rerun the reporter's wall-clock startup benchmark. Is this the best way to solve the issue? Yes, technically. The early guard is the narrowest maintainable fix because branching later in planOpenClawModelsJsonWithDeps is too late to avoid discovery; the remaining question is maintainer acceptance of the compatibility impact. AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning high; reviewed against d68ba5edc598. Label changesLabel justifications:
Evidence reviewedPR surface: Source +6, Tests +121. Total +127 across 2 files. View PR surface stats
What I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Real-behavior proof — upgraded (production code path, no DI stubs)Addressing the review note that the prior evidence used Redacted runtime output: What this demonstrates with the real resolver (not a mock):
Honest scope: the ~48 s figure is this clean checkout's discovery cost and will vary with the reporter's configured providers/plugins. The behavioral contract the patch guarantees — replace mode performs zero implicit discovery — is what this run verifies against the production resolver. The colocated unit test also remains green (2 files / 6 tests passed). (AI-assisted contribution; verified against current |
|
@clawsweeper re-review |
|
🦞🧹 I asked ClawSweeper to review this item again. Re-review progress:
|
…place' [AI-assisted] resolveProvidersForModelsJsonWithDeps unconditionally awaited the implicit provider resolver before honoring models.mode. With mode: 'replace' the user opts out of discovery, so add a 3-line early-return guard that returns only the explicit providers — eliminating the (slow) discovery pass for replace-mode. Closes openclaw#66957. AI-assisted contribution.
c2ab17f to
4472561
Compare
|
Rebased onto current |
|
Thanks for the clawsweeper re-review on June 14 — appreciated the detailed platinum-hermit verdict. On the P1 risk clawsweeper flagged: existing replace-mode users who unintentionally relied on runtime-discovered provider/plugin catalog entries will stop receiving those entries after this patch — this is intentional and matches the documented replace-mode contract (explicit-only), but I want to surface it clearly for your decision. If you want to confirm the behavior change is acceptable before merging, I am happy to provide a before/after |
…cancelled gates; no code change)
|
Thanks for the merge, @vincentkoc! 🙏 Glad the replace-mode skip-implicit-discovery fix is in. |
Summary
src/agents/models-config.plan.ts:60-61unconditionallyawaitsresolveImplicitProvidersImpl(...)(the provider-discovery scan) before readingcfg.models?.mode. When the user has setmodels.mode: "replace"to opt out of discovery, this still runs the full implicit-resolver — wasted work and (in some setups) 70+s of startup latency.src/config/schema.help.ts:924is thatmodels.mode = "replace"uses only the configured providers. Honoring it eliminates the discovery cost for replace-mode users and fixes the timing regression they were filing the issue about.resolveProvidersForModelsJsonWithDepsthat short-circuits tomergeProviders({ implicit: {}, explicit: explicitProviders })whencfg.models?.mode === "replace". The injecteddeps.resolveImplicitProvidersseam used by tests is preserved for merge-mode callers.merge/undefinedpaths are untouched.planOpenClawModelsJsonWithDeps(which also readscfg.models?.modeat L156) is unchanged — its existing logic short-circuits cleanly on the emptyimplicitresult. No public type changes. No new exports.Mirrors the sibling short-circuit at
src/flows/model-picker.ts:116-118(loadPickerModelCatalogdoes the sameif (cfg.models?.mode === "replace") return ...before its catalog load).Change Type (select all)
Scope (select all touched areas)
(Closest match: agents config plumbing; no checkbox fits cleanly.)
Linked Issue/PR
Real behavior proof (required for external PRs)
resolveProvidersForModelsJsonWithDepsran the implicit provider resolver even whenmodels.mode === "replace", violating the documented contract and adding 70+s of startup latency in replace-mode setups.models-config.replace-mode-skip-implicit-discovery.test.tshas 3 scenarios:skips implicit discovery when models.mode === 'replace'— DI spy assertionnot.toHaveBeenCalled, result contains only explicit providers.still resolves implicit when models.mode === 'merge'— spy called once, result merges both.still resolves implicit when models.mode is undefined (defaults to merge)— spy called once.Regression: all 46 existing tests across
models-config.applies-config-env-vars.test.ts,models-config.providers.implicit.discovery-scope.test.ts, andmodels-config.merge.test.tscontinue to pass — they usemode: undefinedormerge, so they enter the same code path as before.mode: "replace"and an injected spy,resolveImplicitProvidersis never called.pnpm tsxcold-load time). The new test proves the implicit-resolver call is genuinely skipped; converting that skip into measured-on-host latency win would require a configured agent with provider-discovery providers loaded.not.toHaveBeenCalledis violated becauseresolveImplicitProvidersImplis awaited unconditionally before the mode is read.Root Cause (if applicable)
explicitProvidersfirst, then unconditionally awaits the implicit resolver, then merges. There is no mode check untilplanOpenClawModelsJsonWithDeps:156— too late to skip the discovery work.src/config/schema.help.ts:924("replaceuses only your configured providers") was not enforced anywhere inresolveProvidersForModelsJsonWithDeps. The new test locks the contract via spy assertion.src/flows/model-picker.ts:116-118, which is the canonical in-repo idiom for replace-mode short-circuits.Regression Test Plan (if applicable)
src/agents/models-config.replace-mode-skip-implicit-discovery.test.ts(new).cfg.models.mode === "replace", the injectedresolveImplicitProvidersspy must never be called and the result must contain only the explicit-provider entries.deps.resolveImplicitProviders) the codebase already uses for testing the merge path. No new mocking infrastructure required.models-config.applies-config-env-vars.test.tsandmodels-config.providers.implicit.discovery-scope.test.tsexercise the merge/undefined paths only.User-visible / Behavior Changes
For users with
models.mode: "replace":pnpm tsxcold-load behavior).models.jsoncontents are identical to what the merge-mode emitter would produce given zero implicit providers — i.e. theprovidersmap is exactly the user'scfg.models.providers.No change for
merge/undefinedmode users.Diagram (if applicable)
N/A
AI Disclosure
This PR was authored with AI assistance (Claude Code, Opus 4.7). The fix shape was selected after a 5-lens design debate (MVD, defensive, pattern-match, performance, DX) — all five lenses converged on the same 3-line early-return mirroring
src/flows/model-picker.ts:116-118. The chosen variant is the smallest viable diff that honors the documented contract.