Add LLM client interface with LiteLLM adapter (A5/A11) #8

Merged
dongar merged 1 commits from llm-client into main 2026-09-06 22:31:36 +00:00
Collaborator

PR 2 of the approved steps-3/4 plan.

  • llm.py — LLMClient protocol: complete(events, tools, model) -> canonical events, present from the first real LLM call as A5 requires. LiteLLMClient renders the request body via the A10 renderer, posts to the proxy's OpenAI-compatible chat/completions route with the bearer token, and maps provider tool-call IDs to locally-minted canonical IDs at the boundary — a provider ID never enters the log, since every future request is rendered wholly from the canonical record.
  • RoleMap (A11) — executor/planner/delegate/consultant resolved from NISSE_ROLE_* env vars; pinned() returns the resolved mapping for recording at task start (wired into the orchestrator at build step 5).
  • Config strictly from env — NISSE_LLM_BASE_URL + NISSE_LLM_TOKEN; envfile.py is a ~15-line .env loader where the real environment always wins. .env is now gitignored, with a committed .env.example documenting every variable (Matrix ones included, ready for the transport PR).
  • Live smoke test — integration-marked, skips unless the LLM env vars are present. Per operator decision CI stays credential-free; the test runs from the operator's machine once .env exists, and wiring CI secrets later is a five-line change.
  • httpx added as nisse-dev's HTTP dependency.

13 new unit tests over a mocked HTTP layer: request shape/auth, producing-model attribution, canonical ID minting (provider IDs dropped), HTTP/connection/malformed-response errors, role-map resolution and pinning, env-file semantics. 67 unit + 5 integration green locally, 1 skip (the live test, by design until credentials exist).

🤖 Generated with Claude Code

PR 2 of the approved steps-3/4 plan. - **`llm.py`** — `LLMClient` protocol: `complete(events, tools, model) -> canonical events`, present from the first real LLM call as A5 requires. `LiteLLMClient` renders the request body via the A10 renderer, posts to the proxy's OpenAI-compatible `chat/completions` route with the bearer token, and maps provider tool-call IDs to **locally-minted canonical IDs at the boundary** — a provider ID never enters the log, since every future request is rendered wholly from the canonical record. - **`RoleMap` (A11)** — `executor`/`planner`/`delegate`/`consultant` resolved from `NISSE_ROLE_*` env vars; `pinned()` returns the resolved mapping for recording at task start (wired into the orchestrator at build step 5). - **Config strictly from env** — `NISSE_LLM_BASE_URL` + `NISSE_LLM_TOKEN`; `envfile.py` is a ~15-line `.env` loader where the real environment always wins. `.env` is now gitignored, with a committed `.env.example` documenting every variable (Matrix ones included, ready for the transport PR). - **Live smoke test** — integration-marked, skips unless the LLM env vars are present. Per operator decision CI stays credential-free; the test runs from the operator's machine once `.env` exists, and wiring CI secrets later is a five-line change. - `httpx` added as nisse-dev's HTTP dependency. 13 new unit tests over a mocked HTTP layer: request shape/auth, producing-model attribution, canonical ID minting (provider IDs dropped), HTTP/connection/malformed-response errors, role-map resolution and pinning, env-file semantics. 67 unit + 5 integration green locally, 1 skip (the live test, by design until credentials exist). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
dev-agent added 1 commit 2026-09-06 20:58:13 +00:00
Add LLM client interface with LiteLLM adapter (A5/A11)
CI / checks (push) Successful in 9s
CI / checks (pull_request) Successful in 10s
0c2021fced
PR 2 of the steps-3/4 plan.

- llm.py: LLMClient protocol — complete(events, tools, model) ->
  canonical events — present from the first real LLM call.
  LiteLLMClient renders requests via the A10 renderer, targets the
  proxy's OpenAI-compatible route, and maps provider tool-call IDs
  to locally-minted canonical IDs at the boundary
- RoleMap (A11): executor/planner/delegate/consultant resolved from
  env; pinned() returns the mapping to record at task start
- Config strictly from env: NISSE_LLM_BASE_URL, NISSE_LLM_TOKEN;
  envfile.py is a minimal .env loader where real env wins; .env now
  gitignored with a committed .env.example documenting all variables
  (Matrix ones included for the upcoming transport PR)
- Live smoke test against the proxy is integration-marked and skips
  without credentials — CI stays credential-free per operator
  decision; the test runs locally once .env exists
- httpx added as nisse-dev's HTTP client

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
dongar approved these changes 2026-09-06 22:31:32 +00:00
dongar merged commit 5dad5cf90f into main 2026-09-06 22:31:36 +00:00
dongar deleted branch llm-client 2026-09-06 22:31:36 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: dev/nisse#8