Skip to content
This repository was archived by the owner on May 26, 2026. It is now read-only.

feat(kora): KR-PLUGIN-COST-LADDER — first plugin extraction (cost-ladder)#185

Merged
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-PLUGIN-COST-LADDER
May 24, 2026
Merged

feat(kora): KR-PLUGIN-COST-LADDER — first plugin extraction (cost-ladder)#185
rafe-walker merged 1 commit into
feature/phase2-upgradesfrom
feat/kora-KR-PLUGIN-COST-LADDER

Conversation

@rafe-walker

Copy link
Copy Markdown
Owner

Summary

First plugin extraction per the KR-PLUGIN-COST-LADDER bucket spec. Sets the template for subsequent extractions (KR-PLUGIN-AUDIT, KR-PLUGIN-CACHING, KR-PLUGIN-CONSTITUTION, …).

  • Moves cost-router code from kora_cli/router/cost_router.py into the canonical Hermes plugin tree at kora_cli/reasoning/kora_hermes_plugin/cost_ladder/{constants,selector,plugin}.py
  • Adds an orchestrator plugin (kora_hermes_plugin/plugin.py) that delegates to sub-plugins and registers the 6 remaining hooks
  • Adds backward-compat shims at the old paths (kora_cli/router/cost_router.py + plugins/kora_hermes/__init__.py) so every existing import keeps working
  • Moves 50 behavioral tests 1:1 to mirror the canonical code location; converts the old test file to a 3-test shim-verification suite

Behavior: unchanged. KORA_REASONING_USE_GATEWAY stays default OFF. The bypass path and the route-through path both keep working through the same external API.

File-structure diagram

```
kora_cli/reasoning/kora_hermes_plugin/ ← NEW canonical location
├── init.py re-exports KoraHermesPlugin + register
├── plugin.py orchestrator (6 hooks); delegates to sub-plugins
└── cost_ladder/ ← first extracted sub-plugin
├── init.py re-exports cost-ladder public surface
├── constants.py DEFAULT_HAIKU_MODEL, regex defaults, rungs
├── selector.py RoutingDecision + select_model_pre_call + …
└── plugin.py pre_api_request_mutable hook + register()

kora_cli/router/cost_router.py ← shim (431 → 75 lines)
plugins/kora_hermes/init.py ← shim (527 → 70 lines)

tests/kora_cli/reasoning/kora_hermes_plugin/cost_ladder/test_selector.py
50 behavioral tests moved 1:1; imports now canonical.

tests/kora_cli/router/test_cost_router.py
Converted to 3-test shim-verification suite (identity-against-canonical).
```

Import-path-changes summary

Old import (still works via shim) New canonical import
`from kora_cli.router import select_model_pre_call` `from kora_cli.reasoning.kora_hermes_plugin.cost_ladder import select_model_pre_call`
`from kora_cli.router.cost_router import DEFAULT_HAIKU_MODEL` `from kora_cli.reasoning.kora_hermes_plugin.cost_ladder import DEFAULT_HAIKU_MODEL`
`from kora_cli.router import RoutingDecision, strip_opus_prefix, …` `from kora_cli.reasoning.kora_hermes_plugin.cost_ladder import RoutingDecision, strip_opus_prefix, …`
`from plugins.kora_hermes import register, KORA_ROUTES, _is_kora_call, …` `from kora_cli.reasoning.kora_hermes_plugin import register` (shim continues to re-export every symbol the discovery contract requires)

Both old and new paths are valid after this PR. Existing in-tree callers (`kora_cli/snapshot/state_snapshot.py`, `kora_cli/reasoning/anthropic_engine.py`, every `tests/plugins/test_kora_hermes_plugin*.py`) were left untouched and pass; the shim-verification tests in `tests/kora_cli/router/test_cost_router.py` assert the shim stays in sync via identity-against-canonical.

Recommendation for next plugin extraction

KR-PLUGIN-AUDIT — per the spec's closing note. Audit logic (`_emit_audit` + the `post_tool_call` write path inside `_execute_single_tool_block`) is similarly self-contained: pure functions + a single hook handler, no shared mutable state with the rest of the orchestrator. Same shape as cost-ladder — one constants file (audit event types / route literals), one writer module, one hook handler. Should fit the template this PR established with minimal new design work.

After audit: KR-PLUGIN-CACHING is a natural follow-on (lifts `_wrap_system_as_cacheable` + `_wrap_tools_as_cacheable` from `anthropic_engine.py` into `cost_ladder/`'s sibling sub-plugin — currently the hook handler in `cost_ladder/plugin.py` imports them from `anthropic_engine`, which is the next refactor seam).

Test plan

  • 50 cost-ladder behavioral tests pass at new location via canonical import
  • 3 shim-verification tests pass at old location
  • 67 `test_kora_hermes_plugin{,_st2,_st2b}.py` tests stay green (no consumer breakage)
  • 60 external-shim-consumer tests pass (`test_state_snapshot.py` + `test_anthropic_engine_router.py`)
  • Full xdist regression: 180/180 affected tests passing; remaining failures pre-exist on base branch and do not reference any module changed here
  • Manual smoke after merge: slack DM through a kora-runtime deployment with `KORA_FORCE_OPUS=true` to confirm both shim path and canonical path resolve to the same model decision

🤖 Generated with Claude Code

…der)

First plugin extraction per the bucket spec. Moves cost-router code
into the canonical Hermes plugin sub-directory shape; sets the
template for KR-PLUGIN-AUDIT / KR-PLUGIN-CACHING / etc. follow-ons.

Behavior: unchanged. KORA_REASONING_USE_GATEWAY stays default OFF;
the bypass path + the route-through path both keep working.

# Canonical location

  kora_cli/reasoning/kora_hermes_plugin/
    __init__.py        — re-exports KoraHermesPlugin + register
    plugin.py          — orchestrator (6 hooks); delegates to sub-plugins
    cost_ladder/
      __init__.py      — re-exports cost-ladder public surface
      constants.py     — DEFAULT_HAIKU_MODEL / regex defaults / rungs
      selector.py      — RoutingDecision + select_model_pre_call + …
      plugin.py        — pre_api_request_mutable hook handler + register

# Backward-compat shims (pure re-exports; old import paths keep working)

  kora_cli/router/cost_router.py    — 431 → 75 lines (shim only)
  plugins/kora_hermes/__init__.py   — 527 → 70 lines (discovery shim)

# Tests

  tests/kora_cli/reasoning/kora_hermes_plugin/cost_ladder/test_selector.py
    50 behavioral tests moved 1:1 from
    tests/kora_cli/router/test_cost_router.py; only the import path
    changed (now canonical).

  tests/kora_cli/router/test_cost_router.py — converted to a small
  3-test shim-verification suite (asserts every public symbol still
  re-exports, via identity-against-canonical).

# Scoped regression (xdist)

  tests/kora_cli/reasoning/kora_hermes_plugin/cost_ladder/   50 pass
  tests/kora_cli/router/                                       3 pass
  tests/plugins/test_kora_hermes_plugin*.py                   67 pass
  tests/kora_cli/snapshot/test_state_snapshot.py              … pass
  tests/kora_cli/reasoning/test_anthropic_engine_router.py    … pass
  Total directly-affected surface: 180/180 passing.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@rafe-walker rafe-walker merged commit d2f5911 into feature/phase2-upgrades May 24, 2026
@rafe-walker rafe-walker deleted the feat/kora-KR-PLUGIN-COST-LADDER branch May 24, 2026 05:21
rafe-walker added a commit that referenced this pull request May 24, 2026
…ircuit + state-holders (#188)

4 extractions following the #185 template. Audit (post_tool_call + post_llm_call writer), Caching (markers extracted from anthropic_engine.py; cost-ladder hook now imports from canonical), Short-Circuit (333 LOC matcher moved; dm_phrasebook.py shim), State-Holders (on_session_start registry). Each with backward-compat shim + identity-against-canonical drift guard.

Cross-dep cleanup confirmed: cost_ladder/plugin.py no longer imports from anthropic_engine.py. Asserted by test_cost_ladder_plugin_imports_markers_from_canonical_location via patched-canonical sentinel.

337/337 directly-affected tests pass under xdist. After this: 5 of 7 plugin extractions complete; KR-PLUGIN-IDENTITY deferred per Lock R3-2; KR-HAIKU-ROUTER-PLUGIN waits on KR-HERMES-LOCAL-EXT-REISSUE.
rafe-walker added a commit that referenced this pull request May 24, 2026
…ck R3-2 Phase C completion (#189)

Substantial paired bundle.

Deliverable 1 — New local Hermes hook post_llm_call_can_reissue at agent/conversation_loop.py. First-non-None override semantics matching #172/#181 family. Anti-loop safety: at most one reissue per iteration. Backward compat: post_api_request observer sees FINAL (post-reissue) response only.

Deliverable 2 — kora_hermes_plugin/haiku_router/ following #185 template. Plugin consumes should_escalate_post_call (from cost_ladder/selector.py since #185 but no caller until now). Implements parallel-Claude pattern from R3: low-confidence Haiku response → reissue to Opus with Haiku response in messages context. record_inference fires twice per iteration (Haiku + Opus reissue) with escalated_to_opus tagged correctly.

Sample trace: Haiku reply uncertain (i"m not sure...) → escalates → Opus response includes Haiku context → Opus confirms terser. Two consecutive record_inference calls, only second tagged escalated_to_opus=True.

What this completes: 6 of 7 plugin extractions (KR-PLUGIN-IDENTITY still deferred per Lock R3-2); all KR-HAIKU-ROUTER #165 escalation paths now functional end-to-end; Lock R3-2 Phase C closed.

Two non-blocking follow-ups flagged in PR body: escalation_reason as structured telemetry field (one-line CostStateHolder.record_inference bump); per-call api_call_count accounting (transparent-upgrade vs per-call — currently transparent).

125 directly-affected tests green; 56 broader-suite failures verified pre-existing on base (fastapi/blake3/HERMES_HOME environmental, not regressions).
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant