These workplans exist only in the retired local hub. Their random pre-ADR-007 identifiers are refused by C-06 as stale references, so they cannot be registered. Deriving from the canonical record id takes no identity from anything: central does not hold them and the old ids die with the cache. Records central already holds were deliberately left untouched. Refs CUST-WP-0068-T06 Assistant: claude-code Assistant-Model: opus Assistant-Process: 2583210@bnt-lap001 Assistant-Session: f2bff2d5-e9b2-4338-92ca-10282a927006
12 KiB
| id | type | title | domain | repo | status | owner | topic_slug | planning_priority | planning_order | created | updated | depends_on_workplans | related_workplans | state_hub_workstream_id | ||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| LLM-WP-0007 | workplan | Kimi K3 default via OpenRouter + EUR spend reporting | agents | llm-connect | finished | codex | kimi-k3-default-spend-reporting | high | 7 | 2026-08-03 | 2026-08-03 |
|
|
7878d7d1-b56f-5ac7-9203-e2ce44ac7c2e |
LLM-WP-0007 — Kimi K3 default via OpenRouter + EUR spend reporting
status: finished owner: codex
Purpose
- Make MoonshotAI Kimi K3 (
moonshotai/kimi-k3on 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). - Ensure every path that uses llm-connect from the command line reports token usage and cost in euros for the work it handled.
- 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:- Explicit arg / config
- Env
LLM_CONNECT_EUR_PER_USD(float: euros per one USD) - Bundled snapshot rate with
captured_at(operator can refresh)
- Extend
CostEstimatewith optionalcost_eur,prompt_cost_eur,completion_cost_eur,fx_source— missing FX yieldscost_eur=Nonewith 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).
@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:
--ledger/ explicit pathLLM_CONNECT_USAGE_LEDGERenv~/.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
# 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
id: LLM-WP-0007-T01
status: done
priority: high
state_hub_task_id: "ca5aabf6-6444-5710-8437-241c99177152"
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.
id: LLM-WP-0007-T02
status: done
priority: high
state_hub_task_id: "cb0a4fb2-d008-51f8-b222-ee16dfdf16fe"
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.
id: LLM-WP-0007-T03
status: done
priority: high
state_hub_task_id: "6fa5a4d7-e694-5a7b-b16b-4652062dd78d"
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.
id: LLM-WP-0007-T04
status: done
priority: high
state_hub_task_id: "0ac06271-5dea-5f4f-8ce6-b5db549a21df"
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.
id: LLM-WP-0007-T05
status: done
priority: high
state_hub_task_id: "33443864-fdce-5b24-8a7f-00c0697a69a1"
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.
id: LLM-WP-0007-T06
status: done
priority: high
state_hub_task_id: "23223ec1-5575-589d-a8b0-50df8d38bd3c"
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.
id: LLM-WP-0007-T07
status: done
priority: medium
state_hub_task_id: "79dd15d9-b2ad-547b-a4e8-d80b26d342e4"
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.
id: LLM-WP-0007-T08
status: done
priority: medium
state_hub_task_id: "4b835a23-048b-51ee-837d-48abd108f182"
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-k3is 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 weekandspend week --lastshow 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
unknownmarker
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.
Implementation notes (2026-08-03)
- Live OpenRouter smoke:
moonshotai/kimi-k3returned content "ok" with usage tokens (Together provider). Note: shortmax_tokenscan yield emptycontentwhile spending tokens on reasoning. - Default OpenRouter / LLMConfig model flipped to
moonshotai/kimi-k3. - Added
fx.py, EUR fields onCostEstimate,usage.pyledger, CLIrun/cost estimate/spend week. - Opt-in library/server recording via
LLM_CONNECT_USAGE_LEDGER; CLI suppresses double-record. - Full unit suite: 224 passed offline.