Skip to content

fix(agents): inherit default agent model catalog for secondary agents#90903

Open
thinhkhang97 wants to merge 1 commit into
openclaw:mainfrom
thinhkhang97:fix/secondary-agent-model-catalog-inheritance
Open

fix(agents): inherit default agent model catalog for secondary agents#90903
thinhkhang97 wants to merge 1 commit into
openclaw:mainfrom
thinhkhang97:fix/secondary-agent-model-catalog-inheritance

Conversation

@thinhkhang97

@thinhkhang97 thinhkhang97 commented Jun 6, 2026

Copy link
Copy Markdown

fix(agents): inherit default agent model catalog for secondary agents

Summary

Secondary (non-default) agents created with openclaw agents add fail at runtime
with FailoverError: Unknown model: google/gemini-2.5-flash when using a
Google/Gemini model authenticated via GEMINI_API_KEY. The default/main agent
works with the same model and key.

Root cause: model discovery only runs for the default agent at gateway
startup, so generated plugin model catalogs (plugins/<provider>/catalog.json)
are only populated under the default agent dir. A secondary agent gets an
apiKey-only google catalog with no models. ModelRegistry.loadCustomModels()
loads plugin catalogs only from the current agent dir, with no read-through to
the default agent — unlike auth profiles, which already inherit via
inheritedAuthDir.

The fix

Add read-through inheritance for generated plugin model catalogs, mirroring the
existing auth-profile read-through (inheritedAuthDir). Implementation is
local-first with a per-provider gap-fill gate:

  • ModelRegistry accepts an optional inheritedAgentDir. The agent's OWN
    catalogs (root models.json + local plugin catalogs) load first and establish
    its full local state (models + provider request config + per-model headers).
  • Inheritance is gated per provider: a provider the local agent already has
    any model for is excluded from the inherited load entirely — it contributes no
    provider request config, no per-model headers, and no models. So "local always
    wins" never depends on write order, and the inherited catalog can neither read
    nor overwrite the local agent's request config/headers (closes the
    cross-agent boundary concern). Provider request config (baseUrl/api/auth/
    headers) is per-provider with a single slot, so this also avoids pairing an
    inherited model with a local provider's credential.
  • Only providers the secondary agent does not configure at all are inherited
    (config + headers + models) — exactly the agent living on inheritance. apiKey
    values in catalogs are env refs (e.g. GEMINI_API_KEY) resolved per-agent, so
    no secret material crosses the agent boundary.
  • A broken/invalid inherited catalog is skipped, never breaking the local agent.
  • discoverModels threads inheritedAgentDir through to the registry.
  • discoverCachedAgentStores passes the resolved default agent dir, and the
    inherited catalog files are folded into the discovery-cache fingerprint so
    changes to the default agent's catalog invalidate the secondary agent's cached
    snapshot.

The default agent never inherits from itself (path-equality guard), so its
behavior is unchanged.

A heavier alternative — running model discovery for every agent at startup — is
the deeper root-cause fix but is costly (per-agent network discovery, needs to
be lazy) and much larger in scope; noting it as a possible follow-up.

Files

  • src/agents/sessions/model-registry.tsinheritedAgentDir option + read-through merge
  • src/agents/agent-model-discovery.ts — thread option through discoverModels
  • src/agents/embedded-agent-runner/model-discovery-cache.ts — pass default dir + fingerprint
  • src/agents/sessions/model-registry.test.ts — 6 new tests

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: A secondary agent created with openclaw agents add
    could not use google/gemini-2.5-flash (authed via GEMINI_API_KEY) and failed
    every turn with Unknown model: google/gemini-2.5-flash, while the default
    main agent worked with the same model and key.
  • Real environment tested: Local OpenClaw 2026.6.2 install on macOS (launchd
    gateway), Google Gemini via GEMINI_API_KEY, default model
    google/gemini-2.5-flash, with a real main agent plus a secondary agent
    (english-tutor).
  • Exact steps or command run after this patch: Applied the patch to my install,
    ran pnpm build, restarted the gateway, emptied the secondary agent's google
    plugin catalog to the apiKey-only state (the state agents add leaves behind),
    then ran a turn through the running gateway — the same lane a Telegram DM uses:
    openclaw agent --agent english-tutor -m "Hi Lexi, correct this: I has two cats yesterday." --json
  • Evidence after fix (copied live output from the running gateway):
    $ cat ~/.openclaw/agents/english-tutor/agent/plugins/google/catalog.json
    {"generatedBy":"openclaw-plugin-model-catalog-v1","providers":{"google":{"apiKey":"GEMINI_API_KEY"}}}   # no models
    
    $ openclaw agent --agent english-tutor -m "Hi Lexi, correct this: I has two cats yesterday." --json
    "status": "ok"
    "text": "...Câu đúng phải là: \"I **had** two cats yesterday.\" ... (real model reply)"
    
    And the patched discovery path exercised directly against the real on-disk agent
    dirs (discoverModels):
    secondary agent dir : ~/.openclaw/agents/english-tutor/agent   (catalog: apiKey-only, no models)
    BEFORE (no inheritance): Unknown model (undefined)
    AFTER  (inherit main)  : google/gemini-2.5-flash  api=google-generative-ai  baseUrl=https://generativelanguage.googleapis.com/v1beta
    
  • Observed result after fix: The secondary agent resolved
    google/gemini-2.5-flash via read-through inheritance, through the native
    google-generative-ai transport, and produced a real model reply — with no
    manual catalog seeding
    . Before the patch the identical gateway turn returned
    Unknown model: google/gemini-2.5-flash. Re-verified end-to-end on the final
    build with the per-provider gating: a secondary agent that configures no
    provider of its own inherits the default agent's google catalog and resolves
    the model (a provider the secondary configures itself would instead be
    local-owned and not inherited).
  • What was not tested: A second independent reproduction on a non-macOS host.
    Full pnpm test was run; 4 shards each reported 1 failing test, all unrelated
    to this change (macOS /private/var path-normalization / packaged-worker /
    fixture assertions; none of those files reference the changed modules).
  • Proof limitations or environment constraints: Verified on a single macOS
    workstation. The live gateway turn was invoked via the CLI agent command
    (which routes through the running gateway on the same agent lane as a Telegram
    DM) rather than by sending an actual Telegram message.
  • Before evidence (optional): openclaw agent --agent <secondary> -m "..."
    GatewayClientRequestError: FailoverError: Unknown model: google/gemini-2.5-flash
    (default main agent returned "status": "ok" for the same model).

Tests and validation

Supplemental (not a substitute for the real behavior proof above):

pnpm build        # exit 0
pnpm tsgo:all     # full prod + test typecheck, all projects — exit 0, 0 errors
npx oxlint <4 touched files>   # no warnings
npx vitest run src/agents/sessions/model-registry.test.ts src/agents/agent-model-discovery*.test.ts   # all pass

New tests cover: (1) a secondary agent inherits the default agent's catalog
models; (2) no inheritance without inheritedAgentDir; (3) the secondary agent's
own catalog wins over inherited models; (4)+(5) an inherited catalog never
overwrites a local provider's request config/headers and never leaks sibling
models into a provider the local agent owns — asserted at the request
resolution
level (getApiKeyAndHeaders returns the local headers), for both the
root models.json and local plugin catalog paths; (6) an inherited-only
provider resolves with the inherited baseUrl and headers.

CI status (rebased onto current origin/main e5a9c60851)

This branch is rebased onto origin/main HEAD (e5a9c60851). Most of the CI
failures present on the earlier base have since been fixed upstream. Current state:

Check CI result Local on this branch
check-lint ✅ pass pnpm lint:core exit 0
check-additional-runtime-topology-architecture ✅ pass pnpm check:architecture — 0 cycles
check-additional-extension-bundled ✅ pass pnpm lint:extensions:bundled exit 0
build-artifacts ✅ pass
check-test-types ❌ fail reproduces identically on clean origin/main

The single remaining check-test-types failure is pre-existing on main and
unrelated to this PR — it is two type errors in an extension test:

extensions/qa-lab/src/live-transports/whatsapp/cli.runtime.test.ts(48,5): error TS2322
extensions/qa-lab/src/live-transports/whatsapp/cli.runtime.test.ts(72,5): error TS2322

Verified by checking out clean origin/main (e5a9c60851) with none of this PR's
commits and running pnpm tsgo:extensions:test → the identical two errors, exit 2.
This PR changes only src/agents/** and does not touch extensions/qa-lab/**
(git diff --name-only origin/main HEAD lists four files, all under src/agents/),
so it cannot introduce this failure. The change's own surface is green: targeted
vitest for model-registry/agent-model-discovery passes and tsgo reports no
errors in the changed files.

AI assistance

Drafted with Claude Code (Opus); reviewed and validated by me. Session log
available on request.

@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels Jun 6, 2026
@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Codex review: found issues before merge. Reviewed June 30, 2026, 1:35 PM ET / 17:35 UTC.

Summary
The branch adds default-agent generated plugin catalog read-through for secondary-agent model discovery, threads inheritedAgentDir through discovery/cache code, fingerprints inherited catalogs, and adds ModelRegistry inheritance tests.

PR surface: Source +94, Tests +254. Total +348 across 4 files.

Reproducibility: yes. source-level. Current main prewarms generated plugin catalogs only for the default agent, ModelRegistry reads plugin catalogs from the current agent dir, and the PR body supplies live after-fix output for the secondary-agent Gemini case; I did not run a live repro in this read-only review.

Review metrics: 2 noteworthy metrics.

  • Cross-Agent Catalog Fallback: 1 added. The PR changes secondary-agent model resolution by reading default-agent generated plugin catalogs.
  • Local Catalog Error Isolation: 1 changed. The PR head changes how a local generated plugin catalog error affects otherwise valid root and sibling plugin models.

Stored data model
Persistent data-model change detected: serialized state: src/agents/sessions/model-registry.test.ts, serialized state: src/agents/sessions/model-registry.ts, unknown-data-model-change: src/agents/sessions/model-registry.test.ts, unknown-data-model-change: src/agents/sessions/model-registry.ts. Confirm migration or upgrade compatibility proof before merge.

Root-cause cluster
Relationship: canonical
Canonical: #90903
Summary: This PR is the candidate for the catalog-present-but-model-less secondary-agent case; the related missing root models.json work is adjacent but distinct.

Members:

Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything.

Merge readiness
Overall: 🧂 unranked krab
Proof: 🦞 diamond lobster
Patch quality: 🧂 unranked krab
Result: blocked by patch quality or review findings.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • Rebase against current main and preserve generated-catalog error isolation plus model params handling.
  • Get explicit maintainer acceptance for inherited-only provider request config and headers, or switch to the chosen per-agent discovery/bootstrap design.

Risk before merge

  • [P1] GitHub reports this branch as dirty/conflicting, so the final merge result cannot be trusted until the author rebases against current main.
  • [P1] The PR head can turn one bad local generated plugin catalog into unrelated Unknown model failures by discarding valid root and sibling plugin models.
  • [P1] Inherited-only providers intentionally carry default-agent generated baseUrl/api/headers into secondary-agent model resolution; maintainers need to accept that agent-directory trust boundary or choose another design.
  • [P1] The rebase must carry forward current main's model-registry invariants, including invalid catalog isolation and plugin catalog model params preservation.

Maintainer options:

  1. Rebase And Preserve Registry Invariants (recommended)
    Resolve the conflict against current main and keep the existing generated-catalog error isolation plus model params preservation while adding inheritance.
  2. Accept Inherited Provider Metadata
    Maintainers can explicitly accept that providers absent from a secondary agent inherit default-agent generated request config, headers, and model rows under per-provider gating.
  3. Pause For Per-Agent Discovery
    If cross-agent catalog read-through is not the desired boundary, pause this PR and pursue lazy per-agent discovery or a narrower bootstrap design instead.

Next step before merge

  • [P2] Human review is needed after contributor rebase because accepting default-agent provider headers/request config in secondary-agent discovery is a trust-boundary decision.

Security
Needs attention: No supply-chain change was found, but inherited provider catalog metadata is credential-adjacent and needs explicit boundary acceptance.

Review findings

  • [P1] Preserve valid models when a local catalog is invalid — src/agents/sessions/model-registry.ts:477
Review details

Best possible solution:

Land a rebased patch that preserves current main catalog error isolation and model params handling, then explicitly accept the inherited-only provider metadata boundary or replace it with per-agent discovery/bootstrap.

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

Yes, source-level. Current main prewarms generated plugin catalogs only for the default agent, ModelRegistry reads plugin catalogs from the current agent dir, and the PR body supplies live after-fix output for the secondary-agent Gemini case; I did not run a live repro in this read-only review.

Is this the best way to solve the issue?

No as submitted. Read-through inheritance is a plausible repair, but the branch must be rebased to preserve current main model-registry invariants and needs maintainer acceptance for inherited provider metadata crossing agent directories.

Full review comments:

  • [P1] Preserve valid models when a local catalog is invalid — src/agents/sessions/model-registry.ts:477
    Current main accumulates generated plugin catalog errors and still returns valid root and sibling plugin models. This return exits on the first local plugin catalog error, discarding already parsed models and making unrelated configured models resolve as Unknown model.
    Confidence: 0.92

Overall correctness: patch is incorrect
Overall confidence: 0.9

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 5c4e478df4ef.

Label changes

Label justifications:

  • P1: The underlying bug blocks secondary-agent turns with Unknown model, and the current patch still has a merge-blocking model-availability regression.
  • merge-risk: 🚨 compatibility: Existing agent registries with one bad generated plugin catalog can lose otherwise valid root or sibling plugin models under this PR head.
  • merge-risk: 🚨 auth-provider: Inherited-only providers carry default-agent generated provider request config into secondary-agent model resolution.
  • merge-risk: 🚨 security-boundary: The change crosses agent directories with credential-adjacent generated catalog metadata, including provider headers and request config.
  • rating: 🧂 unranked krab: Overall readiness is 🧂 unranked krab; proof is 🦞 diamond lobster and patch quality is 🧂 unranked krab.
  • status: ⏳ waiting on author: ClawSweeper has contributor-facing work open and is waiting for author action. Sufficient (live_output): The PR body supplies after-fix copied live output from a running macOS gateway CLI agent turn where a secondary agent resolves the inherited Google model and returns a real model reply.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies after-fix copied live output from a running macOS gateway CLI agent turn where a secondary agent resolves the inherited Google model and returns a real model reply.
Evidence reviewed

PR surface:

Source +94, Tests +254. Total +348 across 4 files.

View PR surface stats
Area Files Added Removed Net
Source 3 100 6 +94
Tests 1 254 0 +254
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 4 354 6 +348

Security concerns:

  • [medium] Confirm inherited provider headers stay within the agent trust model — src/agents/sessions/model-registry.ts:492
    For inherited-only providers, the PR loads default-agent generated baseUrl, api, headers, and model rows into secondary-agent model resolution. Catalog apiKey values are env refs rather than literal secrets, but headers and request config still cross an agent directory boundary.
    Confidence: 0.78

What I checked:

  • Repository policy read: Root AGENTS.md and scoped src/agents/AGENTS.md were read; provider routing, auth/session state, fallback behavior, and startup discovery are compatibility-sensitive review surfaces. (AGENTS.md:22, 5c4e478df4ef)
  • Scoped agents policy read: The scoped agents guide was read and applied for agent-runtime discovery/cache/test boundaries. (src/agents/AGENTS.md:1, 5c4e478df4ef)
  • Current main only prewarms the default agent catalog: Gateway startup resolves the default agent directory and calls ensureOpenClawModelsJson only for that default agent, matching the PR's root-cause claim that secondary agent generated plugin catalogs can remain unpopulated. (src/gateway/server-startup-post-attach.ts:607, 5c4e478df4ef)
  • Current main preserves valid models after local catalog errors: Current main accumulates generated plugin catalog errors and continues loading valid root and sibling plugin catalog models, returning salvaged models plus an error string. (src/agents/sessions/model-registry.ts:448, 5c4e478df4ef)
  • PR head aborts on the first local plugin catalog error: The PR head returns pluginResult on the first local generated plugin catalog error, discarding already parsed root models and later valid plugin catalog models. (src/agents/sessions/model-registry.ts:477, 5ddb7faae44a)
  • PR head inherits provider metadata across agent directories: For inherited-only providers, the PR loads default-agent generated catalog models plus provider request config/headers into the secondary agent's registry under per-provider gating. (src/agents/sessions/model-registry.ts:492, 5ddb7faae44a)

Likely related people:

  • tangtaizong666: Authored merged PR fix(agents): isolate invalid plugin model catalogs [AI-assisted] #92564, which added the current generated plugin catalog isolation behavior directly affected by this branch. (role: introduced current invariant; confidence: high; commits: 7f0d78b257aa, d2f6316c549a; files: src/agents/sessions/model-registry.ts, src/agents/sessions/model-registry.test.ts)
  • steipete: Merged the current invalid-catalog isolation PR, making this a useful routing signal for whether the new inheritance path preserves the intended provider/model behavior. (role: merger/reviewer; confidence: medium; commits: 7f0d78b257aa, d2f6316c549a; files: src/agents/sessions/model-registry.ts, src/agents/sessions/model-registry.test.ts)
  • RomneyDa: Live PR metadata and current shallow blame attribute the present main copies of the touched agent discovery/model-registry files to merged PR feat(qa): wire Crabline WhatsApp transport #95920. (role: recent area contributor; confidence: medium; commits: 5816e0194e59, c3390e60f5f9; files: src/agents/agent-model-discovery.ts, src/agents/embedded-agent-runner/model-discovery-cache.ts, src/agents/sessions/model-registry.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

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
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.
Review history (1 earlier review cycle)
  • reviewed 2026-06-21T18:57:00.108Z sha 5ddb7fa :: found issues before merge. :: [P1] Preserve valid models when a local catalog is invalid

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot added triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. 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. proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 6, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot added size: M and removed size: S proof: sufficient ClawSweeper judged the real behavior proof convincing. labels Jun 6, 2026
@thinhkhang97
thinhkhang97 force-pushed the fix/secondary-agent-model-catalog-inheritance branch from 8a68265 to addff0c Compare June 6, 2026 11:23
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. and removed proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. labels Jun 6, 2026
@clawsweeper clawsweeper Bot added rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels Jun 6, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@thinhkhang97

Copy link
Copy Markdown
Author

@clawsweeper re-review please.

Updated since the last (failed) review pass:

  • Reworked the inheritance to local-first with a per-provider gap-fill gate (excludeProviders). A provider the secondary agent already owns is excluded from the inherited load entirely — no request config, no per-model headers, no models — so the inherited catalog can never read or overwrite local request config/headers. This closes the cross-agent boundary concern; apiKey values are env refs resolved per-agent, so no secret crosses the boundary.
  • Squashed to a single commit (1de5362).
  • Added request-resolution regression tests (assert getApiKeyAndHeaders resolves local headers) for both local sources (root models.json and local plugin catalog), plus an inherited-only-provider test.
  • Re-ran the end-to-end proof on a patched gateway build (see PR body).

The two failing checks (check-additional-boundaries-bcd, build-artifacts) are pre-existing on mainextensions/google/google.live.test.ts and extensions/minimax/minimax.live.test.ts violating no-extension-test-core-imports / core-support-boundary. This PR touches no extensions/ files.

@clawsweeper

clawsweeper Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 6, 2026
@thinhkhang97
thinhkhang97 force-pushed the fix/secondary-agent-model-catalog-inheritance branch from 1de5362 to 7a65c7c Compare June 7, 2026 02:46
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@thinhkhang97

thinhkhang97 commented Jun 7, 2026

Copy link
Copy Markdown
Author

Correction to my note above (the "verified on main commits" line was the wrong way to check — those heavy checks are PR-gated, not run on main pushes). Here is the proper evidence.

I reproduced the failing checks on a clean checkout of origin/main (without this branch's commit) and they fail identically there:

  • pnpm check:test-typesextensions/memory-core/doctor-contract-api.test.ts (TS2345)
  • pnpm lint:core → the only error is src/cli/exec-approvals-cli.ts:66 (no-unnecessary-type-conversion)
  • pnpm check:architecture → a madge import cycle at src/agents/agent-auth-credentials.ts
  • check-additional-extension-bundled is an extensions/** oxlint shard; build-artifacts fails in the gateway-cpu startup-bench (gateway-watch) step

This PR changes only src/agents/sessions/model-registry.ts, src/agents/agent-model-discovery.ts, src/agents/embedded-agent-runner/model-discovery-cache.ts (+ model-registry.test.ts) and touches none of the files above, so it introduces no new failures. (The cycle root agent-auth-credentials.ts is not modified here and the cycle reproduces on clean main.) The earlier check-additional-boundaries-bcd failure is now green after the rebase.

The change's own surface is green: targeted vitest for model-registry/agent-model-discovery passes and tsgo reports no errors in the changed files. Security-boundary is closed via local-first per-provider gating, with request-level regression tests (getApiKeyAndHeaders).

I'm a fork contributor and can't re-run the inherited-from-main check failures. Would appreciate a review when there's bandwidth.

@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@thinhkhang97
thinhkhang97 force-pushed the fix/secondary-agent-model-catalog-inheritance branch from 7a65c7c to 8514259 Compare June 7, 2026 08:47
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 7, 2026
Model discovery only runs for the default/main agent at gateway startup, so
generated plugin model catalogs (e.g. plugins/google/catalog.json) are only
populated under the default agent dir. A secondary agent created with
`openclaw agents add` gets an apiKey-only google catalog with no models, so a
Google/Gemini model authenticated via GEMINI_API_KEY fails at runtime with
`FailoverError: Unknown model: google/gemini-2.5-flash`. The default agent works.

Add read-through inheritance for generated plugin model catalogs, mirroring the
existing auth-profile read-through (`inheritedAuthDir`).

Implementation is local-first with a per-provider gap-fill gate:

- The agent's OWN catalogs (root models.json + local plugin catalogs) load first
  and establish its full local state.
- Inheritance is gated per provider: a provider the local agent already has any
  model for is excluded from the inherited load entirely — it contributes no
  provider request config, no per-model headers, and no models for that provider.
  So "local always wins" never depends on write order, and an inherited catalog
  can neither read nor overwrite the local agent's request config/headers.
- Only providers the secondary agent does not configure at all are inherited
  (config + headers + models), which is exactly the agent that is living on
  inheritance. apiKey values in catalogs are env refs (e.g. GEMINI_API_KEY)
  resolved per-agent, so no secret material crosses the agent boundary.
- A broken/invalid inherited catalog is skipped, never breaking the local agent.

`discoverModels` threads `inheritedAgentDir` through to the registry;
`discoverCachedAgentStores` passes the resolved default agent dir and folds the
inherited catalog files into the discovery-cache fingerprint so changes to the
default agent's catalog invalidate the secondary agent's cached snapshot. The
default agent never inherits from itself (path-equality guard).
@thinhkhang97
thinhkhang97 force-pushed the fix/secondary-agent-model-catalog-inheritance branch from 8514259 to 5ddb7fa Compare June 8, 2026 04:46
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 8, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label Jun 8, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action. P1 High-priority user-facing bug, regression, or broken workflow. and removed rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P2 Normal backlog priority with limited blast radius. labels Jun 15, 2026
@openclaw-barnacle

Copy link
Copy Markdown

This pull request has been automatically marked as stale due to inactivity.
Please add updates or it will be closed.

@openclaw-barnacle openclaw-barnacle Bot added the stale Marked as stale due to inactivity label Jul 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling merge-risk: 🚨 auth-provider 🚨 May break OAuth, tokens, provider routing, model choice, or credentials. merge-risk: 🚨 compatibility 🚨 May break existing users, config, migrations, defaults, or upgrade paths. merge-risk: 🚨 security-boundary 🚨 May affect sandboxing, authorization, credentials, or sensitive data. P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. size: M stale Marked as stale due to inactivity status: ⏳ waiting on author ClawSweeper has contributor-facing work open and is waiting for author action.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant