@workweave/router 0.2.10 → 0.2.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +40 -14
  2. package/cc-statusline.sh +274 -23
  3. package/codex-skills/fm/SKILL.md +15 -0
  4. package/codex-skills/fm/scripts/emit.sh +8 -0
  5. package/codex-skills/force-model/SKILL.md +15 -0
  6. package/codex-skills/force-model/scripts/emit.sh +9 -0
  7. package/codex-skills/rf/SKILL.md +15 -0
  8. package/codex-skills/rf/scripts/emit.sh +7 -0
  9. package/codex-skills/router-feedback/SKILL.md +15 -0
  10. package/codex-skills/router-feedback/scripts/emit.sh +9 -0
  11. package/codex-skills/router-models/SKILL.md +51 -0
  12. package/codex-skills/router-off/SKILL.md +22 -0
  13. package/codex-skills/router-on/SKILL.md +22 -0
  14. package/codex-skills/router-status/SKILL.md +19 -0
  15. package/codex-skills/ufm/SKILL.md +14 -0
  16. package/codex-skills/ufm/scripts/emit.sh +3 -0
  17. package/codex-skills/unforce-model/SKILL.md +14 -0
  18. package/codex-skills/unforce-model/scripts/emit.sh +4 -0
  19. package/codex-status.sh +312 -0
  20. package/commands/beta.md +5 -0
  21. package/commands/models.md +46 -0
  22. package/commands/router-models.md +46 -0
  23. package/directives.tsv +13 -0
  24. package/install.sh +1849 -263
  25. package/package.json +7 -1
  26. package/pi-router/README.md +39 -7
  27. package/pi-router/skills/install-lsps/SKILL.md +75 -0
  28. package/pi-router/skills/lsp-guide/SKILL.md +63 -0
  29. package/pi-router/src/beta.ts +21 -0
  30. package/pi-router/src/compaction.ts +46 -8
  31. package/pi-router/src/config.ts +34 -5
  32. package/pi-router/src/context-window.ts +12 -0
  33. package/pi-router/src/dispatch.ts +35 -2
  34. package/pi-router/src/index.ts +12 -1
  35. package/pi-router/src/lsp-broker.ts +255 -0
  36. package/pi-router/src/lsp-client.ts +435 -0
  37. package/pi-router/src/lsp-format.ts +230 -0
  38. package/pi-router/src/lsp-install.ts +215 -0
  39. package/pi-router/src/lsp-protocol.ts +128 -0
  40. package/pi-router/src/lsp-servers.ts +361 -0
  41. package/pi-router/src/lsp.ts +529 -0
  42. package/pi-router/src/pricing.generated.ts +77 -70
  43. package/pi-router/src/provider.ts +15 -2
  44. package/pi-router/src/routed-model.ts +17 -0
  45. package/pi-router/src/savings.ts +1 -1
  46. package/registry.sh +102 -0
  47. package/uninstall.sh +210 -31
@@ -4,78 +4,85 @@
4
4
  export interface ModelPricing {
5
5
  inputUsdPerMillion: number;
6
6
  outputUsdPerMillion: number;
7
+ cacheReadMultiplier: number;
7
8
  }
8
9
 
9
- export const PRICING_VERSION = "catalog-sha256:f2841a252235d113";
10
+ export const PRICING_VERSION = "catalog-sha256:f2403470b0f8838c";
10
11
 
11
12
  export const MODEL_PRICING: Readonly<Record<string, ModelPricing>> = Object.freeze({
12
- "claude-fable-5": { inputUsdPerMillion: 10, outputUsdPerMillion: 50 },
13
- "claude-haiku-4-5": { inputUsdPerMillion: 1, outputUsdPerMillion: 5 },
14
- "claude-opus-4-0": { inputUsdPerMillion: 15, outputUsdPerMillion: 75 },
15
- "claude-opus-4-1": { inputUsdPerMillion: 15, outputUsdPerMillion: 75 },
16
- "claude-opus-4-5": { inputUsdPerMillion: 5, outputUsdPerMillion: 25 },
17
- "claude-opus-4-6": { inputUsdPerMillion: 5, outputUsdPerMillion: 25 },
18
- "claude-opus-4-7": { inputUsdPerMillion: 5, outputUsdPerMillion: 25 },
19
- "claude-opus-4-8": { inputUsdPerMillion: 5, outputUsdPerMillion: 25 },
20
- "claude-opus-5": { inputUsdPerMillion: 5, outputUsdPerMillion: 25 },
21
- "claude-sonnet-4-5": { inputUsdPerMillion: 3, outputUsdPerMillion: 15 },
22
- "claude-sonnet-4-6": { inputUsdPerMillion: 3, outputUsdPerMillion: 15 },
23
- "claude-sonnet-5": { inputUsdPerMillion: 3, outputUsdPerMillion: 15 },
24
- "deepseek/deepseek-v4-flash": { inputUsdPerMillion: 0.1134, outputUsdPerMillion: 0.2791 },
25
- "deepseek/deepseek-v4-pro": { inputUsdPerMillion: 1.74, outputUsdPerMillion: 3.48 },
26
- "gemini-2.0-flash": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4 },
27
- "gemini-2.0-flash-lite": { inputUsdPerMillion: 0.075, outputUsdPerMillion: 0.3 },
28
- "gemini-2.5-flash": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2 },
29
- "gemini-2.5-flash-lite": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4 },
30
- "gemini-2.5-pro": { inputUsdPerMillion: 1.25, outputUsdPerMillion: 5 },
31
- "gemini-3-flash-preview": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2 },
32
- "gemini-3-pro-preview": { inputUsdPerMillion: 2, outputUsdPerMillion: 8 },
33
- "gemini-3.1-flash-lite-preview": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4 },
34
- "gemini-3.1-pro-preview": { inputUsdPerMillion: 2, outputUsdPerMillion: 8 },
35
- "gemini-3.5-flash": { inputUsdPerMillion: 1.5, outputUsdPerMillion: 9 },
36
- "gemini-3.5-flash-lite": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 2.5 },
37
- "gemini-3.6-flash": { inputUsdPerMillion: 1.5, outputUsdPerMillion: 7.5 },
38
- "google/gemma-4-26b-a4b-it": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6 },
39
- "gpt-4.1": { inputUsdPerMillion: 2, outputUsdPerMillion: 8 },
40
- "gpt-4.1-mini": { inputUsdPerMillion: 0.4, outputUsdPerMillion: 1.6 },
41
- "gpt-4.1-nano": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4 },
42
- "gpt-4o": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10 },
43
- "gpt-4o-mini": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6 },
44
- "gpt-5": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10 },
45
- "gpt-5-chat": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10 },
46
- "gpt-5-mini": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2 },
47
- "gpt-5-nano": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4 },
48
- "gpt-5.4": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 15 },
49
- "gpt-5.4-mini": { inputUsdPerMillion: 0.75, outputUsdPerMillion: 4.5 },
50
- "gpt-5.4-nano": { inputUsdPerMillion: 0.2, outputUsdPerMillion: 1.25 },
51
- "gpt-5.4-pro": { inputUsdPerMillion: 30, outputUsdPerMillion: 180 },
52
- "gpt-5.5": { inputUsdPerMillion: 5, outputUsdPerMillion: 30 },
53
- "gpt-5.5-mini": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2.5 },
54
- "gpt-5.5-nano": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6 },
55
- "gpt-5.5-pro": { inputUsdPerMillion: 30, outputUsdPerMillion: 180 },
56
- "gpt-5.6-luna": { inputUsdPerMillion: 1, outputUsdPerMillion: 6 },
57
- "gpt-5.6-sol": { inputUsdPerMillion: 5, outputUsdPerMillion: 30 },
58
- "gpt-5.6-terra": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 15 },
59
- "grok-4.5": { inputUsdPerMillion: 2, outputUsdPerMillion: 6 },
60
- "grok-4.6": { inputUsdPerMillion: 2, outputUsdPerMillion: 6 },
61
- "minimax/minimax-m2.7": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2 },
62
- "minimax/minimax-m3": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2 },
63
- "mistralai/mistral-small-2603": { inputUsdPerMillion: 0.2, outputUsdPerMillion: 0.6 },
64
- "moonshotai/kimi-k2.5": { inputUsdPerMillion: 0.6, outputUsdPerMillion: 3 },
65
- "moonshotai/kimi-k2.6": { inputUsdPerMillion: 0.95, outputUsdPerMillion: 4 },
66
- "moonshotai/kimi-k2.7": { inputUsdPerMillion: 0.95, outputUsdPerMillion: 4 },
67
- "moonshotai/kimi-k3": { inputUsdPerMillion: 3, outputUsdPerMillion: 15 },
68
- "qwen/qwen3-235b-a22b-2507": { inputUsdPerMillion: 0.2266, outputUsdPerMillion: 0.9064 },
69
- "qwen/qwen3-30b-a3b-instruct-2507": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6 },
70
- "qwen/qwen3-coder": { inputUsdPerMillion: 0.9, outputUsdPerMillion: 2.7 },
71
- "qwen/qwen3-coder-next": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 1.2 },
72
- "qwen/qwen3-next-80b-a3b-instruct": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 1.2 },
73
- "qwen/qwen3.5-flash-02-23": { inputUsdPerMillion: 0.05, outputUsdPerMillion: 0.15 },
74
- "qwen/qwen3.6-35b-a3b": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 1 },
75
- "qwen/qwen3.7-plus": { inputUsdPerMillion: 0.4, outputUsdPerMillion: 1.6 },
76
- "qwen/qwen3.8-max": { inputUsdPerMillion: 2, outputUsdPerMillion: 6 },
77
- "xiaomi/mimo-v2.5-pro": { inputUsdPerMillion: 1, outputUsdPerMillion: 3 },
78
- "z-ai/glm-5": { inputUsdPerMillion: 1, outputUsdPerMillion: 3.2 },
79
- "z-ai/glm-5.1": { inputUsdPerMillion: 1.4, outputUsdPerMillion: 4.4 },
80
- "z-ai/glm-5.2": { inputUsdPerMillion: 1.4, outputUsdPerMillion: 4.4 },
13
+ "claude-fable-5": { inputUsdPerMillion: 10, outputUsdPerMillion: 50, cacheReadMultiplier: 0.1 },
14
+ "claude-haiku-4-5": { inputUsdPerMillion: 1, outputUsdPerMillion: 5, cacheReadMultiplier: 0.1 },
15
+ "claude-opus-4-0": { inputUsdPerMillion: 15, outputUsdPerMillion: 75, cacheReadMultiplier: 0.1 },
16
+ "claude-opus-4-1": { inputUsdPerMillion: 15, outputUsdPerMillion: 75, cacheReadMultiplier: 0.1 },
17
+ "claude-opus-4-5": { inputUsdPerMillion: 5, outputUsdPerMillion: 25, cacheReadMultiplier: 0.1 },
18
+ "claude-opus-4-6": { inputUsdPerMillion: 5, outputUsdPerMillion: 25, cacheReadMultiplier: 0.1 },
19
+ "claude-opus-4-7": { inputUsdPerMillion: 5, outputUsdPerMillion: 25, cacheReadMultiplier: 0.1 },
20
+ "claude-opus-4-8": { inputUsdPerMillion: 5, outputUsdPerMillion: 25, cacheReadMultiplier: 0.1 },
21
+ "claude-opus-5": { inputUsdPerMillion: 5, outputUsdPerMillion: 25, cacheReadMultiplier: 0.1 },
22
+ "claude-sonnet-4-5": { inputUsdPerMillion: 3, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
23
+ "claude-sonnet-4-6": { inputUsdPerMillion: 3, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
24
+ "claude-sonnet-5": { inputUsdPerMillion: 3, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
25
+ "deepseek/deepseek-v4-flash": { inputUsdPerMillion: 0.1134, outputUsdPerMillion: 0.2791, cacheReadMultiplier: 0.2 },
26
+ "deepseek/deepseek-v4-pro": { inputUsdPerMillion: 1.74, outputUsdPerMillion: 3.48, cacheReadMultiplier: 0.11494252873563218 },
27
+ "deepseek/deepseek-v4-pro-0813": { inputUsdPerMillion: 1.74, outputUsdPerMillion: 3.48, cacheReadMultiplier: 0.11494252873563218 },
28
+ "gemini-2.0-flash": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4, cacheReadMultiplier: 0.25 },
29
+ "gemini-2.0-flash-lite": { inputUsdPerMillion: 0.075, outputUsdPerMillion: 0.3, cacheReadMultiplier: 0.25 },
30
+ "gemini-2.5-flash": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2, cacheReadMultiplier: 0.1 },
31
+ "gemini-2.5-flash-lite": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4, cacheReadMultiplier: 0.1 },
32
+ "gemini-2.5-pro": { inputUsdPerMillion: 1.25, outputUsdPerMillion: 5, cacheReadMultiplier: 0.1 },
33
+ "gemini-3-flash-preview": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2, cacheReadMultiplier: 0.1 },
34
+ "gemini-3-pro-preview": { inputUsdPerMillion: 2, outputUsdPerMillion: 8, cacheReadMultiplier: 0.1 },
35
+ "gemini-3.1-flash-lite-preview": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4, cacheReadMultiplier: 0.1 },
36
+ "gemini-3.1-pro-preview": { inputUsdPerMillion: 2, outputUsdPerMillion: 8, cacheReadMultiplier: 0.1 },
37
+ "gemini-3.5-flash": { inputUsdPerMillion: 1.5, outputUsdPerMillion: 9, cacheReadMultiplier: 0.1 },
38
+ "gemini-3.5-flash-lite": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 2.5, cacheReadMultiplier: 0.1 },
39
+ "gemini-3.6-flash": { inputUsdPerMillion: 1.5, outputUsdPerMillion: 7.5, cacheReadMultiplier: 0.1 },
40
+ "gemini-3.7-flash": { inputUsdPerMillion: 1.5, outputUsdPerMillion: 7.5, cacheReadMultiplier: 0.1 },
41
+ "google/gemma-4-26b-a4b-it": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6, cacheReadMultiplier: 0.1 },
42
+ "gpt-4.1": { inputUsdPerMillion: 2, outputUsdPerMillion: 8, cacheReadMultiplier: 0.25 },
43
+ "gpt-4.1-mini": { inputUsdPerMillion: 0.4, outputUsdPerMillion: 1.6, cacheReadMultiplier: 0.25 },
44
+ "gpt-4.1-nano": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4, cacheReadMultiplier: 0.25 },
45
+ "gpt-4o": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10, cacheReadMultiplier: 0.5 },
46
+ "gpt-4o-mini": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6, cacheReadMultiplier: 0.5 },
47
+ "gpt-5": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10, cacheReadMultiplier: 0.1 },
48
+ "gpt-5-chat": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 10, cacheReadMultiplier: 0.1 },
49
+ "gpt-5-mini": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2, cacheReadMultiplier: 0.1 },
50
+ "gpt-5-nano": { inputUsdPerMillion: 0.1, outputUsdPerMillion: 0.4, cacheReadMultiplier: 0.1 },
51
+ "gpt-5.4": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
52
+ "gpt-5.4-mini": { inputUsdPerMillion: 0.75, outputUsdPerMillion: 4.5, cacheReadMultiplier: 0.1 },
53
+ "gpt-5.4-nano": { inputUsdPerMillion: 0.2, outputUsdPerMillion: 1.25, cacheReadMultiplier: 0.1 },
54
+ "gpt-5.4-pro": { inputUsdPerMillion: 30, outputUsdPerMillion: 180, cacheReadMultiplier: 1 },
55
+ "gpt-5.5": { inputUsdPerMillion: 5, outputUsdPerMillion: 30, cacheReadMultiplier: 0.1 },
56
+ "gpt-5.5-mini": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 2.5, cacheReadMultiplier: 0.1 },
57
+ "gpt-5.5-nano": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6, cacheReadMultiplier: 0.1 },
58
+ "gpt-5.5-pro": { inputUsdPerMillion: 30, outputUsdPerMillion: 180, cacheReadMultiplier: 1 },
59
+ "gpt-5.6-luna": { inputUsdPerMillion: 1, outputUsdPerMillion: 6, cacheReadMultiplier: 0.1 },
60
+ "gpt-5.6-luna-pro": { inputUsdPerMillion: 1, outputUsdPerMillion: 6, cacheReadMultiplier: 0.1 },
61
+ "gpt-5.6-sol": { inputUsdPerMillion: 5, outputUsdPerMillion: 30, cacheReadMultiplier: 0.1 },
62
+ "gpt-5.6-sol-pro": { inputUsdPerMillion: 5, outputUsdPerMillion: 30, cacheReadMultiplier: 0.1 },
63
+ "gpt-5.6-terra": { inputUsdPerMillion: 2.5, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
64
+ "grok-4.5": { inputUsdPerMillion: 2, outputUsdPerMillion: 6, cacheReadMultiplier: 0.25 },
65
+ "grok-4.6": { inputUsdPerMillion: 2, outputUsdPerMillion: 6, cacheReadMultiplier: 0.25 },
66
+ "minimax/minimax-m2.7": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2, cacheReadMultiplier: 0.2 },
67
+ "minimax/minimax-m3": { inputUsdPerMillion: 0.3, outputUsdPerMillion: 1.2, cacheReadMultiplier: 0.2 },
68
+ "mistralai/mistral-small-2603": { inputUsdPerMillion: 0.2, outputUsdPerMillion: 0.6, cacheReadMultiplier: 0.1 },
69
+ "moonshotai/kimi-k2.5": { inputUsdPerMillion: 0.6, outputUsdPerMillion: 3, cacheReadMultiplier: 0.5 },
70
+ "moonshotai/kimi-k2.6": { inputUsdPerMillion: 0.95, outputUsdPerMillion: 4, cacheReadMultiplier: 0.1684 },
71
+ "moonshotai/kimi-k2.7": { inputUsdPerMillion: 0.95, outputUsdPerMillion: 4, cacheReadMultiplier: 0.2 },
72
+ "moonshotai/kimi-k3": { inputUsdPerMillion: 3, outputUsdPerMillion: 15, cacheReadMultiplier: 0.1 },
73
+ "qwen/qwen3-235b-a22b-2507": { inputUsdPerMillion: 0.2266, outputUsdPerMillion: 0.9064, cacheReadMultiplier: 0.5 },
74
+ "qwen/qwen3-30b-a3b-instruct-2507": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.6, cacheReadMultiplier: 0.1684 },
75
+ "qwen/qwen3-coder": { inputUsdPerMillion: 0.9, outputUsdPerMillion: 2.7, cacheReadMultiplier: 0.1684 },
76
+ "qwen/qwen3-coder-next": { inputUsdPerMillion: 0.5, outputUsdPerMillion: 1.2, cacheReadMultiplier: 0.5 },
77
+ "qwen/qwen3-next-80b-a3b-instruct": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 1.2, cacheReadMultiplier: 0.5 },
78
+ "qwen/qwen3.5-flash-02-23": { inputUsdPerMillion: 0.05, outputUsdPerMillion: 0.15, cacheReadMultiplier: 0.1 },
79
+ "qwen/qwen3.6-35b-a3b": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 1, cacheReadMultiplier: 0.1 },
80
+ "qwen/qwen3.7-plus": { inputUsdPerMillion: 0.4, outputUsdPerMillion: 1.6, cacheReadMultiplier: 0.2 },
81
+ "qwen/qwen3.8-max": { inputUsdPerMillion: 2, outputUsdPerMillion: 6, cacheReadMultiplier: 0.125 },
82
+ "xiaomi/mimo-v2.5-pro": { inputUsdPerMillion: 1, outputUsdPerMillion: 3, cacheReadMultiplier: 0.1 },
83
+ "z-ai/glm-5": { inputUsdPerMillion: 1, outputUsdPerMillion: 3.2, cacheReadMultiplier: 0.2 },
84
+ "z-ai/glm-5.1": { inputUsdPerMillion: 1.4, outputUsdPerMillion: 4.4, cacheReadMultiplier: 0.18571428571428572 },
85
+ "z-ai/glm-5.2": { inputUsdPerMillion: 1.4, outputUsdPerMillion: 4.4, cacheReadMultiplier: 0.18571428571428572 },
86
+ "z-ai/glm-5.3": { inputUsdPerMillion: 1.4, outputUsdPerMillion: 4.4, cacheReadMultiplier: 0.18571428571428572 },
87
+ "z-ai/glm-5.3-flash": { inputUsdPerMillion: 0.15, outputUsdPerMillion: 0.5, cacheReadMultiplier: 0.2 },
81
88
  });
@@ -18,7 +18,20 @@ import {
18
18
  WEAVE_MODELS,
19
19
  } from "./config.js";
20
20
 
21
- export function registerWeave(pi: ExtensionAPI): void {
21
+ export interface ContextWindowOverride {
22
+ modelId: string;
23
+ contextWindow: number;
24
+ }
25
+
26
+ function modelsForContextWindow(override?: ContextWindowOverride): typeof WEAVE_MODELS {
27
+ if (!override) return WEAVE_MODELS;
28
+ return WEAVE_MODELS.map((model) =>
29
+ model.id === override.modelId ? { ...model, contextWindow: override.contextWindow } : model,
30
+ );
31
+ }
32
+
33
+ /** Register the Weave provider, optionally using the router-confirmed active context window. */
34
+ export function registerWeave(pi: ExtensionAPI, contextWindowOverride?: ContextWindowOverride): void {
22
35
  const key = resolveRouterKey();
23
36
  const role = getRole();
24
37
 
@@ -46,6 +59,6 @@ export function registerWeave(pi: ExtensionAPI): void {
46
59
  api: "anthropic-messages",
47
60
  authHeader: false,
48
61
  headers: providerHeaders(role, key),
49
- models: WEAVE_MODELS,
62
+ models: modelsForContextWindow(contextWindowOverride),
50
63
  });
51
64
  }
@@ -13,10 +13,14 @@ import {
13
13
  isSubagent,
14
14
  ROUTED_MODEL_HEADER,
15
15
  ROUTED_MODEL_STDERR_PREFIX,
16
+ ROUTED_CONTEXT_WINDOW_HEADER,
16
17
  ROUTED_PROVIDER_HEADER,
17
18
  ROUTER_DECISION_HEADER,
19
+ PROVIDER_NAME,
18
20
  } from "./config.js";
21
+ import { parseRoutedContextWindow } from "./context-window.js";
19
22
  import { forcedModelFromBranch } from "./force-model.js";
23
+ import { registerWeave } from "./provider.js";
20
24
  import {
21
25
  aggregateSavings,
22
26
  createSavingsEntry,
@@ -90,6 +94,9 @@ export function registerRoutedModel(pi: ExtensionAPI): void {
90
94
  });
91
95
 
92
96
  pi.on("model_select", (event, ctx: ExtensionContext) => {
97
+ // A new requested model has not yet received a router-confirmed window.
98
+ // Restore the conservative virtual-model default until its first response.
99
+ registerWeave(pi);
93
100
  if (isSubagent()) return;
94
101
  requestedModel = event.model.id;
95
102
  routedModel = undefined;
@@ -100,6 +107,10 @@ export function registerRoutedModel(pi: ExtensionAPI): void {
100
107
  if (event.status < 200 || event.status >= 300) return;
101
108
  const model = event.headers?.[ROUTED_MODEL_HEADER];
102
109
  if (!model) return;
110
+ const contextWindow = parseRoutedContextWindow(event.headers?.[ROUTED_CONTEXT_WINDOW_HEADER]);
111
+ if (contextWindow && ctx.model?.provider === PROVIDER_NAME) {
112
+ registerWeave(pi, { modelId: ctx.model.id, contextWindow });
113
+ }
103
114
  const route: PendingRoute = {
104
115
  ...(ctx.model?.id ? { requestedModel: ctx.model.id } : {}),
105
116
  routedModel: normalizeModelId(model),
@@ -130,6 +141,9 @@ export function registerRoutedModel(pi: ExtensionAPI): void {
130
141
  const restoredForcedModel = forcedModelFromBranch(ctx.sessionManager.getBranch());
131
142
  if (restoredForcedModel !== forcedModel) {
132
143
  forcedModel = restoredForcedModel;
144
+ // Force-model directives take effect between responses, before the next
145
+ // served-window header can arrive. Fall back to the conservative value.
146
+ registerWeave(pi);
133
147
  refresh(ctx);
134
148
  }
135
149
  const pending = pendingRoutes.shift();
@@ -153,6 +167,9 @@ export function registerRoutedModel(pi: ExtensionAPI): void {
153
167
  });
154
168
 
155
169
  pi.on("session_tree", (_event, ctx: ExtensionContext) => {
170
+ // A branch can have been served by another pinned model. Do not carry that
171
+ // window into the first request on the newly selected branch.
172
+ registerWeave(pi);
156
173
  if (isSubagent()) return;
157
174
  restore(ctx);
158
175
  refresh(ctx);
@@ -60,7 +60,7 @@ function normalizedUsage(usage: TokenUsage): TokenUsage | undefined {
60
60
  function modelCostUsd(model: string, usage: TokenUsage): number | undefined {
61
61
  const price = MODEL_PRICING[normalizeModelId(model)];
62
62
  if (!price) return undefined;
63
- const inputTokens = usage.input + 1.25 * usage.cacheWrite + 0.1 * usage.cacheRead;
63
+ const inputTokens = usage.input + 1.25 * usage.cacheWrite + price.cacheReadMultiplier * usage.cacheRead;
64
64
  return (inputTokens * price.inputUsdPerMillion + usage.output * price.outputUsdPerMillion) / 1_000_000;
65
65
  }
66
66
 
package/registry.sh ADDED
@@ -0,0 +1,102 @@
1
+ #!/usr/bin/env bash
2
+ #
3
+ # Shared, shell-portable directive registry helpers. Columns are documented in
4
+ # directives.tsv, which is the canonical declaration.
5
+ #
6
+ # install.sh is served standalone (WorkWeave serves it for `curl | sh`, and it
7
+ # has no sibling files there), so it carries an embedded copy of both this
8
+ # helper block and the registry data. The region between the markers below is
9
+ # copied verbatim into install.sh; install/tests/registry_test.sh asserts the
10
+ # two never drift. Callers that DO have the files alongside them (uninstall.sh,
11
+ # the packaged installer) source this file instead.
12
+ #
13
+ # Rows come from $WEAVE_REGISTRY_DATA when set (install.sh's embedded copy),
14
+ # otherwise from directives.tsv next to this script.
15
+
16
+ # >>> weave-router registry lib >>>
17
+ weave_registry_rows() {
18
+ if [ -n "${WEAVE_REGISTRY_DATA:-}" ]; then
19
+ printf '%s\n' "$WEAVE_REGISTRY_DATA" | awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }'
20
+ return 0
21
+ fi
22
+ local registry="${WEAVE_REGISTRY_FILE:-}"
23
+ if [ -z "$registry" ]; then
24
+ local dir
25
+ dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" 2>/dev/null && pwd -P)" || return 1
26
+ registry="$dir/directives.tsv"
27
+ fi
28
+ [ -f "$registry" ] || return 1
29
+ awk -F '|' '!/^([[:space:]]*#|[[:space:]]*$)/ { print }' "$registry"
30
+ }
31
+
32
+ # weave_registry_names lists every canonical name and alias a client installs.
33
+ weave_registry_names() {
34
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
35
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
36
+ case "$target" in
37
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
38
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
39
+ cursor) [ "$cursor" = yes ] || continue ;;
40
+ esac
41
+ printf '%s\n' "$canonical"
42
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
43
+ done <<EOF
44
+ $(weave_registry_rows)
45
+ EOF
46
+ }
47
+
48
+ # weave_registry_skill_names lists the prompt directives a client exposes as a
49
+ # native skill. Local-config toggles are excluded: they mutate config this
50
+ # installer owns and are handled per target, not as a generic prompt.
51
+ weave_registry_skill_names() {
52
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
53
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
54
+ [ "$capability" = prompt ] || continue
55
+ case "$target" in
56
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
57
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
58
+ cursor) [ "$cursor" = yes ] || continue ;;
59
+ esac
60
+ printf '%s\n' "$canonical"
61
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
62
+ done <<EOF
63
+ $(weave_registry_rows)
64
+ EOF
65
+ }
66
+
67
+ # weave_registry_skill_assets lists every directive a client ships as a skill
68
+ # file, including local-config toggles such as Codex's disable-routing. Install
69
+ # and uninstall use this for file management; weave_registry_skill_names is the
70
+ # narrower prompt-only set used when generating prompt adapters.
71
+ weave_registry_skill_assets() {
72
+ local target="$1" canonical aliases capability claude codex opencode pi cursor adapter
73
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
74
+ case ",$adapter," in *,skill,*) ;; *) continue ;; esac
75
+ case "$target" in
76
+ claude) [ "$claude" = yes ] || continue ;; codex) [ "$codex" = yes ] || continue ;;
77
+ opencode) [ "$opencode" = yes ] || continue ;; pi) [ "$pi" = yes ] || continue ;;
78
+ cursor) [ "$cursor" = yes ] || continue ;;
79
+ esac
80
+ printf '%s\n' "$canonical"
81
+ [ -n "$aliases" ] && printf '%s\n' "$aliases" | tr ',' '\n'
82
+ done <<EOF
83
+ $(weave_registry_rows)
84
+ EOF
85
+ }
86
+
87
+ # weave_registry_canonical_for resolves a name or alias to its canonical
88
+ # directive, and fails when the name is not in the registry at all.
89
+ weave_registry_canonical_for() {
90
+ local wanted="$1" canonical aliases capability claude codex opencode pi cursor adapter alias
91
+ while IFS='|' read -r canonical aliases capability claude codex opencode pi cursor adapter; do
92
+ [ "$wanted" = "$canonical" ] && { printf '%s' "$canonical"; return 0; }
93
+ IFS=',' read -ra _aliases <<< "$aliases"
94
+ for alias in ${_aliases[@]+"${_aliases[@]}"}; do
95
+ [ "$wanted" = "$alias" ] && { printf '%s' "$canonical"; return 0; }
96
+ done
97
+ done <<EOF
98
+ $(weave_registry_rows)
99
+ EOF
100
+ return 1
101
+ }
102
+ # <<< weave-router registry lib <<<