generated from coulomb/repo-seed
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>
This commit is contained in:
80
contracts/config/toml-chain.md
Normal file
80
contracts/config/toml-chain.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# 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` |
|
||||
Reference in New Issue
Block a user