generated from coulomb/repo-seed
WP-0001 — Foundation & GAAF Baseline - SCOPE.md, ARCHITECTURE-LAYERS.md, contracts/ tree - .claude/rules/ stubs filled (architecture, stack, boundary) - 57 tests (pytest), pyproject.toml with ruff+mypy, CI workflow WP-0002 — Core Extensions (FR-4 + FR-3) - FR-4: BudgetTracker (thread-safe) + LLMBudgetExceededError + optional RunConfig.budget_tracker + enforcement in all adapters - FR-3: async_execute_prompt on LLMAdapter ABC (asyncio.to_thread fallback) + native asyncio.create_subprocess_exec in ClaudeCodeAdapter 81 tests passing. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
81 lines
2.4 KiB
Markdown
81 lines
2.4 KiB
Markdown
# Contract: Configuration — TOML Config Chain
|
|
|
|
**Layer:** Configuration
|
|
**Version:** 0.1.0
|
|
**Last updated:** 2026-04-01
|
|
|
|
---
|
|
|
|
## resolve_llm()
|
|
|
|
`llm_connect.toml_config.resolve_llm(cli_provider, cli_model, app_name)`
|
|
|
|
Walks a 7-level priority chain to resolve provider and model independently.
|
|
Returns `ResolvedLLM(provider, model, provider_source, model_source)`.
|
|
|
|
### Priority chain (highest → lowest)
|
|
|
|
| Level | Source |
|
|
|-------|--------|
|
|
| 1 | CLI flags (`cli_provider`, `cli_model`) |
|
|
| 2 | Env var `{APP_NAME}_HELPER_MODEL` (model only) |
|
|
| 3 | User preference — `~/.config/{app_name}/config.toml` `[llm.preference]` |
|
|
| 4 | Directory preference — `.{app_name}.toml` `[llm.preference]` |
|
|
| 5 | Directory default — `.{app_name}.toml` `[llm.default]` |
|
|
| 6 | User default — `~/.config/{app_name}/config.toml` `[llm.default]` |
|
|
| 7 | Hardcoded fallback — `gemini / gemini-2.5-flash` |
|
|
|
|
### Invariants
|
|
|
|
- Always returns a fully-resolved `ResolvedLLM` (never raises, never returns None).
|
|
- Provider and model are resolved independently — a preference for model does
|
|
not imply a preference for provider.
|
|
- TOML parse errors are silently ignored (returns empty layer).
|
|
- `app_name` defaults to `"markitect"` for backward compatibility; consumers
|
|
should pass their own app name.
|
|
|
|
### Known issue
|
|
|
|
`toml_config.py` has `markitect`-specific defaults (`MARKITECT_HELPER_MODEL`,
|
|
`USER_CONFIG_DIR`). These are kept for backward compatibility but callers
|
|
outside markitect should always pass an explicit `app_name`.
|
|
|
|
---
|
|
|
|
## resolve_api_key()
|
|
|
|
`llm_connect.config.resolve_api_key(explicit, env_var, key_file_paths)`
|
|
|
|
Resolution order:
|
|
1. `explicit` argument
|
|
2. Environment variable `env_var`
|
|
3. First readable file in `key_file_paths` with non-empty content
|
|
|
|
Returns `None` if nothing is found. Never raises.
|
|
|
|
---
|
|
|
|
## find_project_root()
|
|
|
|
Walks up from CWD looking for `pyproject.toml`. Returns the containing directory
|
|
or `None`. Used by adapters to locate key files.
|
|
|
|
---
|
|
|
|
## LLMConfig
|
|
|
|
`llm_connect.config.LLMConfig`
|
|
|
|
Dataclass holding per-adapter configuration. Used directly by `OpenRouterAdapter`
|
|
and `ClaudeCodeAdapter`. Not required by the Core `LLMAdapter` ABC.
|
|
|
|
| Field | Default |
|
|
|-------|---------|
|
|
| `provider` | `"openrouter"` |
|
|
| `model` | `"anthropic/claude-sonnet-4"` |
|
|
| `api_key` | `None` |
|
|
| `api_base` | `"https://openrouter.ai/api/v1"` |
|
|
| `claude_cli_path` | `"claude"` |
|
|
| `timeout_seconds` | `300` |
|
|
| `max_retries` | `3` |
|