Skip to content

feat(cli): persistent default_model via gaia config (#98)#1863

Open
kovtcharov wants to merge 5 commits into
mainfrom
feat/cli-config-default-model
Open

feat(cli): persistent default_model via gaia config (#98)#1863
kovtcharov wants to merge 5 commits into
mainfrom
feat/cli-config-default-model

Conversation

@kovtcharov

@kovtcharov kovtcharov commented Jun 25, 2026

Copy link
Copy Markdown
Collaborator

Why this matters

Before, you had to type --model <id> on every gaia chat / gaia llm / gaia prompt to use anything other than the built-in default — tedious and easy to forget. After, you set it once and forget it:

gaia config set default_model Qwen3.5-35B-A3B-GGUF
gaia llm "hello"      # now uses your configured model, no --model needed
gaia prompt "hi" --model Gemma-4-E4B-it-GGUF   # flag still overrides for one run

Model resolution is documented and highest-wins: explicit --model flag > default_model from the config file > each command's built-in default. A missing config file correctly falls back to defaults; a corrupt one fails loudly (with the file path + how to recover) instead of silently reverting — per the repo's no-silent-fallbacks rule. gaia init preserves a user-set default_model across re-runs (and repairs a corrupt file).

gaia config set/get/show are generic over the GaiaConfig dataclass fields, so future config keys need no new plumbing.

Using a custom config file

Point GAIA at a config file anywhere on disk (per-project configs, separate work/personal defaults) — via the --config flag or the GAIA_CONFIG_FILE env var. Both are honored by gaia config, gaia chat, gaia llm, and gaia prompt:

gaia config set default_model Qwen3.5-35B-A3B-GGUF --config ./project.gaia.json
gaia llm "hello" --config ./project.gaia.json          # reads that file's default_model
# or: GAIA_CONFIG_FILE=./project.gaia.json gaia llm "hello"

Precedence: --config > GAIA_CONFIG_FILE > default ~/.gaia/config.json.

Closes #98

Test plan

  • python -m pytest tests/unit/test_cli_config.py tests/unit/test_npu_device_support.py -q — passing (round-trip, missing→defaults, corrupt/non-object/unreadable→loud error, precedence incl. empty-string, CLI show/get/set + unknown-key + no-subcommand, model injection for prompt/chat/llm, chat --device skip, --config flag, and GAIA_CONFIG_FILE/GAIA_CONFIG_DIR overrides)
  • gaia config set default_model X then gaia config get default_model / gaia config show → value + resolved file path
  • gaia config set bogus x / gaia config get bogus → exit non-zero, actionable "Unknown config key"
  • gaia llm "hi" with default_model set uses it; --model X overrides it
  • gaia config set default_model M --config ./p.json writes to that file (not ~/.gaia); gaia llm "hi" --config ./p.json reads it; --config overrides GAIA_CONFIG_FILE
  • python util/lint.py --black --isort --flake8 clean on the changed files

@github-actions github-actions Bot added documentation Documentation changes dependencies Dependency updates devops DevOps/infrastructure changes cli CLI changes tests Test changes agents labels Jun 25, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Verdict: Approve

This PR does two well-scoped things: it adds a persistent default_model (gaia config set/get/show, with documented --model > config > built-in precedence) so users stop retyping --model on every command, and it finishes moving the DocQA and Routing agents out of core into standalone hub wheels. Both halves are thorough — the migration updates every reference (src, docs, workflows, lint, conventions checker) and the config feature ships ~17 focused tests including the corrupt-config-fails-loudly path that the no-silent-fallbacks rule requires.

Nothing blocking. Two minor things worth a glance before merge, both non-blocking: gaia init now quietly logs-and-skips when it hits a corrupt config (so init can no longer repair one), and gaia config set accepts any field value without validation, so a typo'd device/profile only surfaces later. Neither needs to hold the merge.

🔍 Technical details

🟢 Minor

gaia init swallows a corrupt-config error instead of repairing it (src/gaia/installer/init_command.py:594-601). The switch to load-then-update is right for preserving a user-set default_model, but GaiaConfig.load() can now raise GaiaConfigError, and the surrounding except Exception as e: log.warning(...) catches it — so on a corrupt config, init warns and skips the save entirely. Previously init overwrote (repaired) the file. init is the natural recovery path, so consider catching GaiaConfigError explicitly and resetting to a fresh GaiaConfig() before applying profile/device, rather than leaving the bad file in place. Edge case, non-blocking.

gaia config set does no value validation (src/gaia/config.py:1328-1335). set() validates the key but stores any value verbatim, so gaia config set default_device foo or a bogus default_model succeeds silently and only fails downstream at inference time. A default_model typo failing loudly at use is acceptable per fail-loud, but default_device has a known small enum (cpu/gpu/npu) that's cheap to validate at set-time. Optional.

Notes (no action needed)

  • default_device/profile are not preserved across gaia init (init re-derives them from --profile); only default_model survives. That matches the comment's intent, just worth being explicit that the "survives re-run" guarantee is model-only.
  • The injection block (src/gaia/cli.py:2961-2981) only loads config when --model is absent, so a corrupt config won't abort a command that passed --model explicitly. That's correct (you don't need config then), just slightly narrower than the PR description's blanket "a corrupt one now fails loudly."

Strengths

  • Complete migration, no stragglers. Grepping gaia.agents.routing / agents/docqa across src/, docs/, .github/, util/, and setup.py turns up zero stale references — registry, error FRAMEWORK_PATHS, lint import checks, conventions checker, and the API class_name are all updated together.
  • Fail-loud done correctly. GaiaConfig.load() cleanly separates missing (→ defaults) from corrupt/non-object/unreadable (→ GaiaConfigError naming the file + recovery steps), and test_npu_device_support.py / test_cli_config.py flip the old "falls back to defaults" assertion to assert the raise — exactly the contract change the rule wants.
  • The gaia-code ImportError now carries an install hint (src/gaia/api/agent_registry.py:157-171) instead of a bare "not available", and the routing-not-on-PyPI ordering is handled in CI by installing the local hub package first — good attention to the real failure mode.
  • config get/set/show are generic over the dataclass fields, so future config keys need no new CLI plumbing.

Users had to pass --model on every `gaia chat` / `gaia llm` / `gaia prompt`
to override the built-in default. Now they can set it once in
~/.gaia/config.json and skip the flag entirely.

Extends the existing GaiaConfig with a default_model field and a new
`gaia config show|get|set` subcommand. Model resolution is highest-wins:
explicit --model flag > config default_model > each command's built-in
default. `gaia chat --device` still selects a device-specific model and
keeps precedence over the config default.

Per the no-silent-fallbacks rule, a missing config file falls back to
built-in defaults (correct), but a corrupt/unreadable file now fails
loudly with the file path and recovery steps instead of silently
reverting. `gaia init` load-then-updates so a user-set default_model
survives re-running setup. Config file location is overridable via
GAIA_CONFIG_DIR / GAIA_CONFIG_FILE.
@kovtcharov kovtcharov force-pushed the feat/cli-config-default-model branch from ed94640 to 67e401d Compare June 25, 2026 21:07
itomek
itomek previously approved these changes Jun 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents cli CLI changes dependencies Dependency updates devops DevOps/infrastructure changes documentation Documentation changes tests Test changes

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Config file for GAIA CLI (set default model)

2 participants