Add LLM-WP-0007: Kimi K3 default and EUR spend reporting
Propose workplan for moonshotai/kimi-k3 as OpenRouter basemodel/default, CLI token+EUR cost reporting, and Mon-based weekly spend views.
This commit is contained in:
parent
ef2231b2cc
commit
7d4a8a51c2
1 changed files with 291 additions and 0 deletions
291
workplans/LLM-WP-0007-kimi-k3-default-and-spend-reporting.md
Normal file
291
workplans/LLM-WP-0007-kimi-k3-default-and-spend-reporting.md
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
---
|
||||
id: LLM-WP-0007
|
||||
type: workplan
|
||||
title: "Kimi K3 default via OpenRouter + EUR spend reporting"
|
||||
domain: agents
|
||||
repo: llm-connect
|
||||
status: ready
|
||||
owner: codex
|
||||
topic_slug: kimi-k3-default-spend-reporting
|
||||
planning_priority: high
|
||||
planning_order: 7
|
||||
created: "2026-08-03"
|
||||
updated: "2026-08-03"
|
||||
depends_on_workplans:
|
||||
- LLM-WP-0005
|
||||
related_workplans:
|
||||
- LLM-WP-0006
|
||||
---
|
||||
|
||||
# LLM-WP-0007 — Kimi K3 default via OpenRouter + EUR spend reporting
|
||||
|
||||
**status:** ready
|
||||
**owner:** codex
|
||||
|
||||
## Purpose
|
||||
|
||||
1. Make **MoonshotAI Kimi K3** (`moonshotai/kimi-k3` on OpenRouter) a first-class
|
||||
basemodel option, and **promote it to the library default** once a live smoke
|
||||
call succeeds (rate table, adapter default, config default, docs).
|
||||
2. Ensure every path that uses **llm-connect from the command line** reports
|
||||
**token usage and cost in euros** for the work it handled.
|
||||
3. Make weekly spend easy to inspect:
|
||||
- **Last week** Monday 00:00 → Sunday 24:00 (local operator timezone, default
|
||||
Europe/Berlin)
|
||||
- **Current week** Monday 00:00 → now
|
||||
|
||||
This workplan does **not** change activity-core runtime profiles or K8s deploy
|
||||
defaults unless those profiles currently inherit the global OpenRouter default
|
||||
without an explicit model — those stay explicit where they already are.
|
||||
|
||||
## Demand signal
|
||||
|
||||
Operator request (2026-08-03): no open workplans; next priority is evaluating
|
||||
Kimi K3 as basemodel/default via OpenRouter, plus CLI cost transparency in
|
||||
tokens and €, plus mon–sun / mon–now weekly spend views.
|
||||
|
||||
## Current repo state (as of 2026-08-03)
|
||||
|
||||
| Area | State |
|
||||
|---|---|
|
||||
| Active workplans | **None** — WP-0001…0006 + ADHOC-2026-06-02 all finished/completed |
|
||||
| OpenRouter default model | `anthropic/claude-sonnet-4` (`openrouter.py`, `config.LLMConfig`) |
|
||||
| Rate table | USD-only seed of nine models; **no** `moonshotai/kimi-k3` entry |
|
||||
| Cost model | `estimate_cost` → `CostEstimate` with `cost_usd` only (`costs.py`) |
|
||||
| CLI (`llm-connect`) | Registry tools only: `rates show`, `classes show`, `classes fit` — **no** prompt execute, **no** spend report |
|
||||
| Usage persistence | Server optional audit JSON under `LLM_CONNECT_AUDIT_DIR`; quality ledger is for adaptive routing, not operator spend |
|
||||
| BudgetTracker | Token-cap only; no EUR accounting |
|
||||
|
||||
OpenRouter live listing (checked 2026-08-03):
|
||||
|
||||
- Model id: `moonshotai/kimi-k3`
|
||||
- Context: 1_048_576
|
||||
- List price (USD per token → per 1k): **prompt $0.003 / 1k**, **completion $0.015 / 1k**
|
||||
|
||||
## Architecture sketch
|
||||
|
||||
```
|
||||
llm_connect/
|
||||
rates.py # + moonshotai/kimi-k3 rate; currency remains list-price USD
|
||||
costs.py # CostEstimate gains EUR fields via FxRate
|
||||
fx.py # NEW: USD→EUR conversion (config/env/snapshot; never invent FX)
|
||||
usage.py # NEW: UsageEvent + UsageLedger (append-only JSONL)
|
||||
openrouter.py # default model → moonshotai/kimi-k3 after T01 smoke
|
||||
config.py # LLMConfig.model default aligned
|
||||
cli.py # run | cost report | spend week
|
||||
```
|
||||
|
||||
### Defaults (after smoke gate)
|
||||
|
||||
| Surface | New default |
|
||||
|---|---|
|
||||
| `OpenRouterAdapter` `_DEFAULT_MODEL` | `moonshotai/kimi-k3` |
|
||||
| `LLMConfig.model` | `moonshotai/kimi-k3` |
|
||||
| `create_adapter("openrouter")` with no model | inherits adapter default |
|
||||
| Explicit profiles / activity-core triage model | **unchanged** (already pin a model) |
|
||||
|
||||
If T01 smoke **fails** (auth, model unavailable, empty content), keep Claude Sonnet
|
||||
as default, ship Kimi as an **opt-in** model id in rates + docs, and mark T02
|
||||
`wait` with a short note — do not force a broken default.
|
||||
|
||||
### Cost + EUR
|
||||
|
||||
- Keep rate table denominated in **USD** (OpenRouter list prices).
|
||||
- Add `FxRate(usd_per_eur or eur_per_usd, source, captured_at)` with resolution:
|
||||
1. Explicit arg / config
|
||||
2. Env `LLM_CONNECT_EUR_PER_USD` (float: euros per one USD)
|
||||
3. Bundled snapshot rate with `captured_at` (operator can refresh)
|
||||
- Extend `CostEstimate` with optional `cost_eur`, `prompt_cost_eur`,
|
||||
`completion_cost_eur`, `fx_source` — missing FX yields `cost_eur=None` with
|
||||
explicit source (same philosophy as unknown models).
|
||||
- Never treat missing rates or missing FX as zero cost.
|
||||
|
||||
### Usage ledger (spend history)
|
||||
|
||||
Append-only JSONL, separate from `QualityLedger` (quality is adaptive-routing
|
||||
signal; spend is operator accounting).
|
||||
|
||||
```python
|
||||
@dataclass(frozen=True)
|
||||
class UsageEvent:
|
||||
recorded_at: datetime # timezone-aware UTC
|
||||
provider: str
|
||||
model_id: str
|
||||
prompt_tokens: int
|
||||
completion_tokens: int
|
||||
total_tokens: int
|
||||
cost_usd: float | None
|
||||
cost_eur: float | None
|
||||
cost_source: str
|
||||
fx_source: str | None
|
||||
source: str # "cli" | "server" | "library"
|
||||
tags: dict[str, Any] # optional request id, profile, etc.
|
||||
```
|
||||
|
||||
Default ledger path resolution:
|
||||
|
||||
1. `--ledger` / explicit path
|
||||
2. `LLM_CONNECT_USAGE_LEDGER` env
|
||||
3. `~/.local/share/llm-connect/usage.jsonl` (XDG-style fallback)
|
||||
|
||||
Week windows use **Monday 00:00 local** → exclusive end. Local timezone default
|
||||
`Europe/Berlin` (override: `--tz` / `LLM_CONNECT_TZ`).
|
||||
|
||||
### CLI surface
|
||||
|
||||
```bash
|
||||
# One-shot prompt (records usage when ledger available)
|
||||
llm-connect run "Summarise X" [--provider openrouter] [--model moonshotai/kimi-k3]
|
||||
# stderr or footer: tokens in/out/total · € cost (and USD if useful)
|
||||
|
||||
# Weekly spend
|
||||
llm-connect spend week # current week Mon → now
|
||||
llm-connect spend week --last # previous Mon → Sun
|
||||
llm-connect spend week --json
|
||||
|
||||
# Optional: show cost for a hypothetical token count
|
||||
llm-connect cost estimate --model moonshotai/kimi-k3 --prompt-tokens N --completion-tokens M
|
||||
```
|
||||
|
||||
Per-call reporting for `run`: always print tokens; print € when FX + rate known;
|
||||
print clear `unknown` when not.
|
||||
|
||||
## Scope guardrails
|
||||
|
||||
**In scope**
|
||||
|
||||
- Kimi K3 rate entry + default flip after smoke
|
||||
- EUR conversion on top of existing USD rate table
|
||||
- Usage ledger + CLI run/spend/cost commands
|
||||
- Unit tests with fixed FX and fake clock; no live network in default CI
|
||||
- Contract doc updates under `contracts/functional/`
|
||||
|
||||
**Out of scope**
|
||||
|
||||
- Multi-currency rate tables beyond USD list + EUR display
|
||||
- Billing reconciliation against OpenRouter invoices (estimate-based only)
|
||||
- Changing activity-core K8s model pins or triage profile model ids
|
||||
- Full TUI / web dashboard
|
||||
- Automatic live FX fetch in CI (optional later; snapshot + env is enough)
|
||||
|
||||
## Tasks
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T01
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Validate Kimi K3 via OpenRouter.** Confirm `moonshotai/kimi-k3` is callable
|
||||
with a real key when available (manual/operator smoke; CI uses mock). Add rate
|
||||
table entry: prompt `$0.003` / completion `$0.015` per 1k USD (captured from
|
||||
OpenRouter 2026-08-03). Document model id and pricing source in rates contract
|
||||
or README providers table. Gate for T02.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T02
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Promote Kimi K3 to OpenRouter basemodel default** after T01 smoke passes.
|
||||
Update `openrouter._DEFAULT_MODEL`, `LLMConfig.model`, any factory/docs that
|
||||
advertise the default, and tests that hard-code `anthropic/claude-sonnet-4` as
|
||||
the implicit default. Leave explicit profile models untouched. If smoke failed,
|
||||
leave default unchanged and record the blocker in the task notes.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T03
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**USD→EUR cost conversion.** Add `fx` helper + extend `CostEstimate` with EUR
|
||||
fields and `fx_source`. Resolution order: explicit → env → bundled snapshot.
|
||||
Update `contracts/functional/costs.md`. Tests: known FX, missing FX, unknown
|
||||
model still yields `cost_usd=None` / `cost_eur=None`.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T04
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**Usage ledger.** Implement `UsageEvent` + append-only JSONL `UsageLedger`
|
||||
(path locks patterned after `QualityLedger`). Helpers: `record(...)`,
|
||||
`iter_events()`, `sum_range(start, end)` aggregating tokens + cost_usd/eur.
|
||||
Default path via env / XDG. Tests for append, concurrent-safe append (best
|
||||
effort flock), and range aggregation.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T05
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**CLI `run` with per-call cost footer.** Extend `llm-connect` with a `run`
|
||||
subcommand that creates an adapter, executes a prompt, prints content, and
|
||||
reports tokens + € (and USD). Record a `UsageEvent` to the ledger. Wire cost
|
||||
estimation from response usage + rate table + FX. Tests with mock adapter.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T06
|
||||
status: todo
|
||||
priority: high
|
||||
```
|
||||
|
||||
**CLI weekly spend views.** `llm-connect spend week` and `spend week --last`
|
||||
using Mon–Sun / Mon–now windows in `Europe/Berlin` (overridable). Human table +
|
||||
`--json`. Empty ledger → zero totals, exit 0. Tests with synthetic events and
|
||||
fixed timezone.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T07
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
**Optional library/server recording.** When `LLM_CONNECT_USAGE_LEDGER` is set,
|
||||
record usage from adapter post-call path and/or server `/execute` (source
|
||||
`library` / `server`) so non-CLI traffic contributes to weekly spend. Keep
|
||||
opt-in so library consumers are not surprised by home-dir writes.
|
||||
|
||||
```task
|
||||
id: LLM-WP-0007-T08
|
||||
status: todo
|
||||
priority: medium
|
||||
```
|
||||
|
||||
**Docs + acceptance polish.** README: new default model, CLI examples for
|
||||
`run` / `spend week`, env vars (`LLM_CONNECT_USAGE_LEDGER`,
|
||||
`LLM_CONNECT_EUR_PER_USD`, `LLM_CONNECT_TZ`). Update `contracts/functional/`
|
||||
as needed. Smoke script or Makefile target for optional live Kimi check.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- [ ] `moonshotai/kimi-k3` is in the default rate registry with documented USD rates
|
||||
- [ ] After successful smoke, OpenRouter/library default model is `moonshotai/kimi-k3`
|
||||
- [ ] `llm-connect run "..."` prints token counts and € cost (or explicit unknown)
|
||||
- [ ] Successful CLI runs append to the usage ledger
|
||||
- [ ] `llm-connect spend week` and `spend week --last` show tokens + € for the
|
||||
correct Mon-based windows
|
||||
- [ ] Default CI tests pass offline (mock adapter, fixed FX, no live OpenRouter)
|
||||
- [ ] Missing rate or FX never reported as €0.00 without an `unknown` marker
|
||||
|
||||
## Risks / notes
|
||||
|
||||
- **Model id spelling:** operator said "kimi-k3"; OpenRouter id is
|
||||
`moonshotai/kimi-k3` (not K2 variants). Stick to that id unless operator
|
||||
renames the requirement.
|
||||
- **FX staleness:** bundled EUR rate will drift; env override is the operator
|
||||
escape hatch. Do not scrape FX APIs in the hot path for v1.
|
||||
- **Default flip blast radius:** any consumer relying on implicit Sonnet will
|
||||
change behaviour — document in README and release notes; profiles that pin
|
||||
models are safe.
|
||||
- **Estimate vs invoice:** ledger costs are list-price estimates, not OpenRouter
|
||||
billed totals (discounts, cache reads, provider routing may differ).
|
||||
|
||||
## Implementation order
|
||||
|
||||
T01 → T02 (gated) in parallel with T03 → T04 → T05 → T06 → T07 → T08.
|
||||
T03/T04 can start before T01; T02 must wait for T01 smoke outcome.
|
||||
Loading…
Add table
Add a link
Reference in a new issue