Files
llm-connect/contracts/config/toml-chain.md
Bernd Worsch d71f4114d1 feat: WP-0001 foundation + WP-0002 core extensions
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>
2026-04-01 22:24:14 +00:00

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` |