Skip to content

fix(config): unbrick first-run setup — default google/anthropic models, enter setup on fixable config errors#385

Merged
kevincodex1 merged 2 commits into
mainfrom
fix/google-model-default
Jul 2, 2026
Merged

fix(config): unbrick first-run setup — default google/anthropic models, enter setup on fixable config errors#385
kevincodex1 merged 2 commits into
mainfrom
fix/google-model-default

Conversation

@gnanam1990

@gnanam1990 gnanam1990 commented Jul 2, 2026

Copy link
Copy Markdown
Collaborator

Fixes #384.

Problem

A provider entry with an API key but no model bricked Zero — reported twice in the wild against a fresh npm install -g (#384):

% zero
[zero] provider google requires model (apiKey=[REDACTED])
% zero setup
[zero] provider google requires model (apiKey=[REDACTED])
% zero config
[zero] provider google requires model (apiKey=[REDACTED])
% zero login
unknown command "login"

Chicken-and-egg: zero config and bare zero setup resolve the full config up front, so the exact commands that could fix the config died with the same error. The trigger doesn't even need a config file — applyEnv synthesizes a google provider from a GEMINI_API_KEY/GOOGLE_API_KEY exported in the user's shell, with no model unless GEMINI_MODEL is also set, which is how a completely fresh install hits this. Anthropic had the identical gap.

Fix (commit 1): default missing google/anthropic models from the catalog

The resolver has always defaulted a missing model for the openai kind, and catalogID-carrying profiles get defaults via applyCatalogDescriptor — but catalog-less provider_kind: google/anthropic profiles (hand-written or env-synthesized) had no fallback. They now fall back to their provider-catalog default models (gemini-2.5-pro / claude-sonnet-4.5), same shape and same gate as openai (option renamed defaultOpenAIModeldefaultModels). An explicit model always wins; provider-command configs (ZERO_PROVIDER_COMMAND) still get no invented models (pinned by a test).

Fix (commit 2): enter setup on the remaining fixable shape + zero login hint

  • Custom openai-/anthropic-compatible endpoints have no catalog default (Zero can't guess a gateway's model), so that shape still failed resolve — and still bricked bare zero/zero setup. The failure is now tagged ErrProviderRequiresModel via a message-preserving wrapper (multi-target Unwrap), and the interactive TUI's fixable-error fallback (previously ErrNoActiveProvider only, from fix(config): create the right config file on first setup (macOS ~/.config) (#371) #372) also drops into the setup wizard for it. Headless commands (zero config, zero exec) still fail with the actionable message, now with a hint: provider gw requires model — add "model" to its entry in config.json, or re-run: zero setup <catalog-id> --model <model>. Every other resolve error (malformed JSON, directory conflicts) stays fatal.
  • zero login/zero logout don't exist (it's zero auth login); first-run users try them (Bug: First-run setup is blocked by "provider google requires model" before setup/auth can run #384). The unknown-command error now answers did you mean "zero auth login"? — unrelated unknown commands get no suggestion.

Testing

  • Catalog defaulting: google/anthropic red-green (reverting the google fallback reproduces the exact reported error), explicit-model-wins, provider-command gate still errors.
  • Setup fallback: the sentinel comes from a real Resolve over a real config file (not a hand-built error); red-green — reverting the condition reproduces the exact brick. Existing no-active-provider fallback and other-errors-stay-fatal tests unchanged and passing.
  • Validation treats official-kind model-less profiles as clean while still flagging customs (with the hint asserted).
  • Manually verified with the built binary: the exact Bug: First-run setup is blocked by "provider google requires model" before setup/auth can run #384 repro (zero, zero setup, zero config with only GEMINI_API_KEY exported) now works; the custom-endpoint shape enters the wizard interactively and errors actionably headless; zero login prints the suggestion.
  • Full suite: go test ./... — 73/73 packages pass.

Summary by CodeRabbit

  • Bug Fixes
    • Official provider setup now auto-fills the provider catalog default model when no model is configured (while preserving explicitly configured models).
    • “Model required” issues now show a clearer, actionable remediation hint for faster config fixes.
    • Interactive setup can recover when the active provider is missing a required model.
    • Unknown command handling now suggests the correct auth login/auth logout commands for common typos.
  • Tests
    • Added/expanded coverage for default model resolution, error messaging, and the improved CLI behaviors.

A hand-written provider entry like {name: "google", provider_kind:
"google", apiKey: ...} with no model bricked Zero: config resolution
failed with "provider google requires model", and since zero config and
bare zero setup both resolve up front, the only commands that could have
fixed the config died with the same error (reported in the wild — the
one working escape, zero setup google --model <m>, is undiscoverable
from that message).

The openai kind has always defaulted a missing model
(modelregistry.DefaultModelID); google and anthropic were missed. Fall
back to their provider-catalog default models (gemini-2.5-pro /
claude-sonnet-4.5) the same way, behind the same gate: provider-command
configs (normalizeProvidersWithoutModelDefaults) still surface exactly
what the external command returned. An explicitly configured model
always wins, and profiles with a catalogID already got this via
applyCatalogDescriptor — this covers the catalog-less hand-written case.

The residual requires-model error (openai-compatible customs, which
have no catalog default) now carries an actionable hint: add "model" in
config.json or re-run zero setup with --model.

Tests: google/anthropic defaulting (red-green: reverting the google
fallback reproduces the exact reported error), explicit model wins,
provider-command gate still errors with the hint, and validation treats
official-kind model-less profiles as clean while still flagging customs.
@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Zero automated PR review

Verdict: No blockers found

Blockers

  • None found.

Validation

  • [pass] Diff hygiene: git diff --check
  • [pass] Tests: go test ./...
  • [pass] Build: go run ./cmd/zero-release build
  • [pass] Smoke build: go run ./cmd/zero-release smoke

Scope

Head: 03455ad9155c
Changed files (5): internal/cli/app.go, internal/cli/app_test.go, internal/config/resolver.go, internal/config/resolver_test.go, internal/config/validate_test.go

This deterministic review checks validation status and basic diff hygiene. A human reviewer still owns product judgment and design quality.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown

Review Change Stack

Walkthrough

Provider model resolution now uses catalog defaults for official providers, returns a setup-fixable missing-model error, and the CLI adds login/logout suggestions while treating missing-model startup failures as interactive-setup recoverable.

Changes

Provider model defaults and CLI recovery

Layer / File(s) Summary
Catalog defaults and setup-fixable model errors
internal/config/resolver.go
Adds catalog-backed default model lookup, generalizes official-provider defaulting, and changes missing-model failures to return a setup-fixable sentinel error with remediation text.
Resolver and validation coverage
internal/config/resolver_test.go, internal/config/validate_test.go
Adds coverage for Google and Anthropic catalog defaults, explicit model preservation, the without-defaults path, missing-model hints, and setup-fixable error matching.
CLI setup recovery and command hints
internal/cli/app.go, internal/cli/app_test.go
Adds login/logout suggestions for unknown commands and makes interactive startup fall back to setup when config resolution fails with a missing-model error.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant runWithDeps
  participant runInteractiveTUIWithSetup
  participant configResolve
  participant SetupWizard

  runWithDeps->>runWithDeps: handle unknown login/logout suggestion
  runInteractiveTUIWithSetup->>configResolve: resolve active provider config
  configResolve-->>runInteractiveTUIWithSetup: ErrProviderRequiresModel
  runInteractiveTUIWithSetup->>SetupWizard: launch interactive setup
Loading

Possibly related PRs

  • Gitlawb/zero#141: Both PRs modify internal/config/resolver.go to use provider catalog metadata for default model behavior in official-provider normalization, with overlapping logic and tests.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main config defaulting and setup-recovery changes in the pull request.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/google-model-default

Comment @coderabbitai help to get the list of available commands.

…ogin

Two residual first-run gaps after the catalog model-defaulting fix:

- An active provider whose model has NO catalog default to fall back on
  (custom openai-/anthropic-compatible endpoints) still bricked bare
  `zero` and `zero setup` — the exact commands that could have repaired
  the config. Tag that resolve failure with ErrProviderRequiresModel and
  extend the interactive TUI's fixable-error fallback (previously only
  ErrNoActiveProvider) to drop into the setup wizard for it. The sentinel
  is attached via a message-preserving wrapper (multi-target Unwrap), so
  headless commands (zero config / zero exec) print the exact actionable
  text unchanged and every other resolve error stays fatal.

- `zero login` / `zero logout` don't exist (it's `zero auth login`);
  first-run users try them and got only "unknown command" (reported in
  the wild). The unknown-command error now answers: did you mean
  "zero auth login"? Unrelated unknown commands get no suggestion.

Tests: the sentinel comes from a REAL Resolve over a real config file
(message-prefix asserted, no key leak); the TUI fallback is red-green
(reverting the condition reproduces the exact brick with the old error);
the existing no-active-provider fallback and other-errors-stay-fatal
tests still pass; login/logout hint with a no-false-positive check.
@gnanam1990 gnanam1990 changed the title fix(config): default missing google/anthropic models from the catalog fix(config): unbrick first-run setup — default google/anthropic models, enter setup on fixable config errors Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/cli/app.go (1)

541-556: 🩺 Stability & Availability | 🔵 Trivial

Full resolve failure loses saved-provider fallback (pre-existing, now reachable via a second path).

When Resolve fails for the active provider, resolver.go's normalizeProvidersWithOptions drops the entire provider list, not just the broken active entry. So even if the user has another valid saved provider, firstUsableProvider fallback (line 582) never gets a chance to run here since forceSetup is already true. This limitation pre-dates this PR (already true for ErrNoActiveProvider) but is now also triggered by ErrProviderRequiresModel.

Not blocking this PR, but consider whether Resolve could preserve the other valid providers even when the active one fails, so users with multiple saved providers aren't forced into full re-onboarding.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/cli/app.go` around lines 541 - 556, Resolve currently drops the
whole provider list when the active provider fails, which prevents
saved-provider fallback from being used in the CLI flow. Review `Resolve` and
`normalizeProvidersWithOptions` so a bad active provider only removes or marks
that entry while preserving other valid saved providers, allowing
`firstUsableProvider` to still pick one before `forceSetup` is set. Keep the
existing fatal handling for unrecoverable errors, but make the provider
normalization path in `config.ResolvedConfig` resilient to a broken active
provider.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/cli/app.go`:
- Around line 541-556: Resolve currently drops the whole provider list when the
active provider fails, which prevents saved-provider fallback from being used in
the CLI flow. Review `Resolve` and `normalizeProvidersWithOptions` so a bad
active provider only removes or marks that entry while preserving other valid
saved providers, allowing `firstUsableProvider` to still pick one before
`forceSetup` is set. Keep the existing fatal handling for unrecoverable errors,
but make the provider normalization path in `config.ResolvedConfig` resilient to
a broken active provider.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 0b21dd91-cc2e-4a58-9904-6caa99049ac6

📥 Commits

Reviewing files that changed from the base of the PR and between 0e7a1fc and 03455ad.

📒 Files selected for processing (4)
  • internal/cli/app.go
  • internal/cli/app_test.go
  • internal/config/resolver.go
  • internal/config/resolver_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • internal/config/resolver.go

@anandh8x anandh8x left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Clean, well-tested fix. Two things done right:

  • Catalog defaults for google/anthropic — mirrors the existing openai pattern. Explicit model wins, provider-command path untouched.
  • setupFixableError — multi-target Unwrap() is the right pattern for tagging without polluting the user-facing message. The TUI fallback and headless hint cover both paths cleanly.

Tests cover defaulting, explicit-model-wins, provider-command gate, sentinel wrapping, key-leak guard, validation, TUI fallback, login hint, and false-positive. No gaps.

LGTM.

@kevincodex1 kevincodex1 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.

lgtm

@kevincodex1 kevincodex1 merged commit 72eed06 into main Jul 2, 2026
9 checks passed
eli-l pushed a commit to eli-l/zero that referenced this pull request Jul 2, 2026
…s, enter setup on fixable config errors (Gitlawb#385)

* fix(config): default missing google/anthropic models from the catalog

A hand-written provider entry like {name: "google", provider_kind:
"google", apiKey: ...} with no model bricked Zero: config resolution
failed with "provider google requires model", and since zero config and
bare zero setup both resolve up front, the only commands that could have
fixed the config died with the same error (reported in the wild — the
one working escape, zero setup google --model <m>, is undiscoverable
from that message).

The openai kind has always defaulted a missing model
(modelregistry.DefaultModelID); google and anthropic were missed. Fall
back to their provider-catalog default models (gemini-2.5-pro /
claude-sonnet-4.5) the same way, behind the same gate: provider-command
configs (normalizeProvidersWithoutModelDefaults) still surface exactly
what the external command returned. An explicitly configured model
always wins, and profiles with a catalogID already got this via
applyCatalogDescriptor — this covers the catalog-less hand-written case.

The residual requires-model error (openai-compatible customs, which
have no catalog default) now carries an actionable hint: add "model" in
config.json or re-run zero setup with --model.

Tests: google/anthropic defaulting (red-green: reverting the google
fallback reproduces the exact reported error), explicit model wins,
provider-command gate still errors with the hint, and validation treats
official-kind model-less profiles as clean while still flagging customs.

* fix(cli): enter setup on a requires-model config and hint zero auth login

Two residual first-run gaps after the catalog model-defaulting fix:

- An active provider whose model has NO catalog default to fall back on
  (custom openai-/anthropic-compatible endpoints) still bricked bare
  `zero` and `zero setup` — the exact commands that could have repaired
  the config. Tag that resolve failure with ErrProviderRequiresModel and
  extend the interactive TUI's fixable-error fallback (previously only
  ErrNoActiveProvider) to drop into the setup wizard for it. The sentinel
  is attached via a message-preserving wrapper (multi-target Unwrap), so
  headless commands (zero config / zero exec) print the exact actionable
  text unchanged and every other resolve error stays fatal.

- `zero login` / `zero logout` don't exist (it's `zero auth login`);
  first-run users try them and got only "unknown command" (reported in
  the wild). The unknown-command error now answers: did you mean
  "zero auth login"? Unrelated unknown commands get no suggestion.

Tests: the sentinel comes from a REAL Resolve over a real config file
(message-prefix asserted, no key leak); the TUI fallback is red-green
(reverting the condition reproduces the exact brick with the old error);
the existing no-active-provider fallback and other-errors-stay-fatal
tests still pass; login/logout hint with a no-false-positive check.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: First-run setup is blocked by "provider google requires model" before setup/auth can run

3 participants