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>
2.4 KiB
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_namedefaults 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:
explicitargument- Environment variable
env_var - First readable file in
key_file_pathswith 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 |