Routes Agent tool calls: simple chores to Haiku, heavy work stays on Sonnet/Opus.

Routes Agent tool calls: simple chores to Haiku, heavy work stays on Sonnet/Opus.
claude plugin marketplace add kenhuangus/claude-code-mods-pack
claude plugin install model-router@kenhuang-modshooks/model-router.mjs 35 lines1const STATS = { plugin: "model-router", key: "stats" };
2const SIMPLE = /\b(unit test|docstring|comment|rename|typo|format|lint|changelog|readme)\b/i;
3export function pickModel(prompt, current) {
4 if (SIMPLE.test(String(prompt ?? ""))) return { model: "haiku", tier: "haiku" };
5 return { model: current || "sonnet", tier: "premium" };
6}
7export function register(on) {
8 on("session.start", async ($, e, next) => {
9 const r = await next(e);
10 await $.state.set(STATS, { routedHaiku: 0, routedPremium: 0 });
11 return r;
12 });
13 on("tool.call", { tool: "Agent" }, async ($, e, next) => {
14 const prompt = e.prompt ?? e.description ?? e.input ?? "";
15 const choice = pickModel(prompt, e.model);
16 const { value: stats } = await $.state.get(STATS);
17 if (choice.tier === "haiku") {
18 await $.state.set(STATS, { routedHaiku: (stats?.routedHaiku ?? 0) + 1, routedPremium: stats?.routedPremium ?? 0, last: "haiku" });
19 return next({ ...e, model: "haiku" });
20 }
21 await $.state.set(STATS, { routedHaiku: stats?.routedHaiku ?? 0, routedPremium: (stats?.routedPremium ?? 0) + 1, last: "premium" });
22 return next(e);
23 });
24 on("ui.render", { component: "AbovePrompt" }, async ($, e, next) => {
25 if (e.props?.hasSurvey) return next(e);
26 const { value: stats } = await $.state.get(STATS);
27 if (!stats) return next(e);
28 const { Box, Text } = $.ui.resolve(e);
29 return Box({
30 paddingX: 1,
31 children: [Text({ dimColor: true, children: `ROUTER haiku:${stats.routedHaiku} premium:${stats.routedPremium}` })],
32 });
33 });
34}
35types/index.d.ts 8 lines1declare module "claude-code" {
2 interface PluginState {
3 "model-router": {
4 stats: { routedHaiku: number; routedPremium: number; last?: string };
5 };
6 }
7}
8