# llm-connect Integration (CYA-WP-0008) ## Mapping: cya ↔ llm-connect | cya (`AssistanceRequest`) | llm-connect | |---------------------------|-------------| | `user_request` | User message body (after context framing) | | `context` (envelope + memory + `session_turns`) | Serialized into the prompt via `cya.llm.prompt.build_assistance_prompt` | | `hints` (`model`, `temperature`, `max_tokens`) | `RunConfig` fields for `execute_prompt` | | `AssistanceResponse.suggestion` | `LLMResponse.content` | | `AssistanceResponse.metadata` | `LLMResponse.model`, `usage`, `finish_reason` | llm-connect owns provider clients (`create_adapter`), API key resolution, retries, and token usage. `cya` never imports vendor SDKs directly. ## Configuration User config: `~/.config/cya/config.toml` ```toml [llm] adapter = "connect" # "connect" | "fake" (default: fake when absent) backend = "openrouter" # openrouter | openai | gemini | claude-code | mock model = "anthropic/claude-sonnet-4" temperature = 0.3 max_tokens = 2000 api_key_env = "OPENROUTER_API_KEY" # optional override # system_prompt = "..." # optional; uses cya default when omitted ``` Optional project override: `.cya.toml` (same `[llm]` section; merged over user config). Environment overrides: | Variable | Purpose | |----------|---------| | `CYA_LLM_ADAPTER` | `connect` or `fake` | | `CYA_LLM_BACKEND` / `CYA_LLM_PROVIDER` | Provider name | | `CYA_LLM_MODEL` | Model id | CLI: `cya --offline "..."` forces `FakeLLMAdapter`. ## Session context budget (multi-turn / `cya shell`) Recent turns are passed in `AssistanceRequest.context["session_turns"]` as `{"user": "...", "assistant": "..."}` records. Bounds (see `cya.config`): - **Max turns:** 10 - **Max characters:** 4000 (total across included turns) Older or oversized history is dropped from the prompt automatically. ## Credential routing Do **not** commit API keys. Before requesting secrets, route custody: ```bash warden route find "OpenRouter API key" --json warden route show --json ``` Typical ownership: | Need | Owner | ops-warden executes? | |------|-------|----------------------| | `OPENROUTER_API_KEY` | OpenBao (`railiance-platform`) | No — route only | | `OPENAI_API_KEY` | OpenBao | No — route only | | `GEMINI_API_KEY` | OpenBao | No — route only | llm-connect resolves keys via `resolve_api_key()` (explicit arg → env var → project key file). ## Adapter selection `cya.llm.factory.get_adapter()` is the single factory for one-shot and shell paths: 1. `--offline` or `CYA_LLM_ADAPTER=fake` → `FakeLLMAdapter` 2. `adapter = "connect"` in config/env → `LLMConnectAdapter` (graceful degrade on failure) 3. Otherwise → `FakeLLMAdapter` (current default) ## Installation ```bash make dev-install pip install -e ~/llm-connect # sibling checkout ``` Optional extra group (placeholder for packaging): `pip install -e ".[llm]"`. ## Tests - Default CI: `make test` — mocks llm-connect; no network. - Manual live check: `pytest -m llm_live` (requires configured API key). ## Known gaps - Structured JSON output schema not enforced yet (free-form model text). - `claude-code` backend does not require an API key; other backends do. - Per-directory `.cya.toml` overrides user config but does not yet mirror llm-connect's full 7-layer resolution.