@workweave/router 0.2.1 → 0.2.3

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.
package/bin.js CHANGED
@@ -17,7 +17,7 @@ const script = path.join(__dirname, scriptName);
17
17
 
18
18
  if (!existsSync(script)) {
19
19
  console.error(
20
- `weave-router: ${scriptName} missing from package — please report at https://github.com/workweave/router/issues`,
20
+ `Weave Router: ${scriptName} missing from package — report it at https://github.com/workweave/router/issues`,
21
21
  );
22
22
  process.exit(1);
23
23
  }
@@ -25,7 +25,7 @@ if (!existsSync(script)) {
25
25
  const bash = pickBash();
26
26
  if (!bash) {
27
27
  console.error(
28
- "weave-router: bash is required. On Windows install Git Bash or run inside WSL.",
28
+ "Weave Router: bash is required. On Windows install Git Bash or run inside WSL.",
29
29
  );
30
30
  process.exit(1);
31
31
  }
@@ -36,7 +36,7 @@ const result = spawnSync(bash, [script, ...args], {
36
36
  });
37
37
 
38
38
  if (result.error) {
39
- console.error("weave-router:", result.error.message);
39
+ console.error("Weave Router:", result.error.message);
40
40
  process.exit(1);
41
41
  }
42
42
  process.exit(result.status ?? 1);
package/cc-statusline.sh CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env bash
2
2
  #
3
- # Claude Code statusline for the Weave router. CC pipes a JSON blob on stdin
3
+ # Claude Code statusline for the Weave Router. CC pipes a JSON blob on stdin
4
4
  # whose `transcript_path` points at the JSONL log of the current session and
5
5
  # whose `model.display_name` is the user's CC-side model selection. The
6
6
  # router rewrites each request's `model` field before forwarding, so
@@ -129,6 +129,7 @@ normalize_model() {
129
129
  # BEGIN_GENERATED_PRICES
130
130
  prices='{
131
131
  "input": {
132
+ "claude-fable-5": 0.01,
132
133
  "claude-haiku-4-5": 0.0008,
133
134
  "claude-opus-4-6": 0.005,
134
135
  "claude-opus-4-7": 0.005,
@@ -165,9 +166,11 @@ prices='{
165
166
  "gpt-5.5-nano": 0.00015,
166
167
  "gpt-5.5-pro": 0.03,
167
168
  "minimax/minimax-m2.7": 0.0003,
169
+ "minimax/minimax-m3": 0.0003,
168
170
  "mistralai/mistral-small-2603": 0.0002,
169
171
  "moonshotai/kimi-k2.5": 0.0006,
170
172
  "moonshotai/kimi-k2.6": 0.00095,
173
+ "moonshotai/kimi-k2.7": 0.00095,
171
174
  "qwen/qwen3-235b-a22b-2507": 0.0002266,
172
175
  "qwen/qwen3-30b-a3b-instruct-2507": 0.00015,
173
176
  "qwen/qwen3-coder": 0.0009,
@@ -175,11 +178,13 @@ prices='{
175
178
  "qwen/qwen3-next-80b-a3b-instruct": 0.00015,
176
179
  "qwen/qwen3.5-flash-02-23": 0.00005,
177
180
  "qwen/qwen3.6-35b-a3b": 0.00015,
181
+ "qwen/qwen3.7-plus": 0.0004,
178
182
  "xiaomi/mimo-v2.5-pro": 0.001,
179
183
  "z-ai/glm-5": 0.0006,
180
184
  "z-ai/glm-5.1": 0.00105
181
185
  },
182
186
  "output": {
187
+ "claude-fable-5": 0.05,
183
188
  "claude-haiku-4-5": 0.004,
184
189
  "claude-opus-4-6": 0.025,
185
190
  "claude-opus-4-7": 0.025,
@@ -216,9 +221,11 @@ prices='{
216
221
  "gpt-5.5-nano": 0.0006,
217
222
  "gpt-5.5-pro": 0.12,
218
223
  "minimax/minimax-m2.7": 0.0012,
224
+ "minimax/minimax-m3": 0.0012,
219
225
  "mistralai/mistral-small-2603": 0.0006,
220
226
  "moonshotai/kimi-k2.5": 0.003,
221
227
  "moonshotai/kimi-k2.6": 0.004,
228
+ "moonshotai/kimi-k2.7": 0.004,
222
229
  "qwen/qwen3-235b-a22b-2507": 0.0009064,
223
230
  "qwen/qwen3-30b-a3b-instruct-2507": 0.0006,
224
231
  "qwen/qwen3-coder": 0.0027,
@@ -226,6 +233,7 @@ prices='{
226
233
  "qwen/qwen3-next-80b-a3b-instruct": 0.0012,
227
234
  "qwen/qwen3.5-flash-02-23": 0.00015,
228
235
  "qwen/qwen3.6-35b-a3b": 0.00095,
236
+ "qwen/qwen3.7-plus": 0.0016,
229
237
  "xiaomi/mimo-v2.5-pro": 0.003,
230
238
  "z-ai/glm-5": 0.00208,
231
239
  "z-ai/glm-5.1": 0.0035
@@ -234,6 +242,8 @@ prices='{
234
242
  # END_GENERATED_PRICES
235
243
 
236
244
  routed=""
245
+ forced="false"
246
+ forced_model=""
237
247
  session_savings=""
238
248
  tot_in=0
239
249
  tot_out=0
@@ -271,6 +281,36 @@ if [[ -n "$transcript_path" && -f "$transcript_path" ]]; then
271
281
  routed="$(normalize_model "$routed")"
272
282
  fi
273
283
 
284
+ # Detect an active /force-model pin from the router's synthetic ack turns —
285
+ # the only turns stamped message.model == "weave-router". The router emits
286
+ # one whenever a pin changes state:
287
+ # * /force-model → "force-model applied: <model> (<provider>) …"
288
+ # * /unforce-model → "force-model cleared …"
289
+ # * loop / no-progress break → "… clearing the session pin …" (expires the
290
+ # pin, including a user-forced one)
291
+ # * unrecognized model → "… isn't a recognized model · keeping
292
+ # automatic routing" — a NO-OP: the prior
293
+ # pin, if any, is left untouched
294
+ # These persist on disk (the ingress stripper only scrubs them from upstream
295
+ # requests). Classify each weave-router turn newest-first, skip the no-op
296
+ # "rejected" acks, and let the latest real state change decide: an "applied"
297
+ # marker means the session is pinned (and names the model); anything else
298
+ # (cleared / loop-break / no-progress) means automatic routing has resumed.
299
+ # Restricting to weave-router turns keeps a normal reply that merely quotes
300
+ # these phrases from flipping the tag. (A silent server-side TTL expiry emits
301
+ # no turn and so can't be reflected here — the pin TTL outlives a session.)
302
+ force_state="$("${reverse[@]}" "$transcript_path" 2>/dev/null \
303
+ | jq -r 'select(.type=="assistant" and .message.model=="weave-router")
304
+ | ([.message.content[]? | select(.type? == "text") | .text] | join(" ") | gsub("[\n\r]"; " ")) as $t
305
+ | if ($t | test("force-model applied:")) then "APPLIED " + ($t | capture("force-model applied: (?<m>[^ ]+)").m)
306
+ elif ($t | test("isn.t a recognized model")) then "REJECTED"
307
+ else "CLEARED" end' 2>/dev/null \
308
+ | grep -m1 -v '^REJECTED$' || true)"
309
+ if [[ "$force_state" == APPLIED\ * ]]; then
310
+ forced="true"
311
+ forced_model="${force_state#APPLIED }"
312
+ fi
313
+
274
314
  # Compute a session running total: savings across every assistant turn
275
315
  # whose marker reports a requested ≠ routed swap, plus cumulative token
276
316
  # counts across every assistant turn (rerouted or not — total work the
@@ -373,7 +413,14 @@ if [[ "$tot_in" -gt 0 || "$tot_out" -gt 0 || "$tot_cache_read" -gt 0 || "$tot_ca
373
413
  fi
374
414
  fi
375
415
 
376
- if [[ "$routed" == "failure" ]]; then
416
+ if [[ "$forced" == "true" ]]; then
417
+ # Session is pinned via /force-model. The "← selection · saved $X" clause
418
+ # describes automatic routing and would be misleading on a manual pin, so
419
+ # show the pinned model with a [forced] tag instead. forced_model comes from
420
+ # the marker; fall back to the routed/selected id if parsing came up empty.
421
+ forced_display="${forced_model:-${routed:-$selected_display}}"
422
+ printf '%s — %s [forced]%s' "$brand" "$forced_display" "$tokens_clause"
423
+ elif [[ "$routed" == "failure" ]]; then
377
424
  # Latest turn was a CC-synthesized error stub — don't claim a routing
378
425
  # swap or compute savings against a non-model.
379
426
  printf '%s — %s%s' "$brand" "$routed" "$tokens_clause"
package/commands/fm.md ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ description: Alias for /force-model — pin this session to a specific model via the Weave Router.
3
+ argument-hint: <model-id>
4
+ ---
5
+
6
+ /force-model $ARGUMENTS
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Pin this session to a specific model via the Weave Router
2
+ description: Pin this session to a specific model via the Weave Router.
3
3
  argument-hint: <model-id>
4
4
  ---
5
5
 
package/commands/rf.md ADDED
@@ -0,0 +1,6 @@
1
+ ---
2
+ description: Alias for /router-feedback — submit feedback about router decision or model performance.
3
+ argument-hint: <feedback-text>
4
+ ---
5
+
6
+ /router-feedback $ARGUMENTS
@@ -0,0 +1,6 @@
1
+ ---
2
+ description: Submit feedback about router decision or model performance.
3
+ argument-hint: <feedback-text>
4
+ ---
5
+
6
+ /router-feedback $ARGUMENTS
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Route Claude Code directly to Anthropic again (turn the Weave Router off)
2
+ description: Route Claude Code directly to Anthropic again (turn the Weave Router off).
3
3
  allowed-tools: Bash(npx:*)
4
4
  ---
5
5
 
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Route Claude Code through the Weave Router again (turn it back on)
2
+ description: Route Claude Code through the Weave Router again (turn it back on).
3
3
  allowed-tools: Bash(npx:*)
4
4
  ---
5
5
 
@@ -1,9 +1,9 @@
1
1
  ---
2
- description: Show whether Claude Code is routing through the Weave Router or directly to Anthropic
2
+ description: Show whether Claude Code is routing through the Weave Router or directly to Anthropic.
3
3
  allowed-tools: Bash(npx:*)
4
4
  ---
5
5
 
6
- Report whether Claude Code is currently using the Weave Router by running:
6
+ Report whether Claude Code is using the Weave Router by running:
7
7
 
8
8
  `npx @workweave/router status --claude{{SCOPE}}`
9
9
 
@@ -0,0 +1,5 @@
1
+ ---
2
+ description: Alias for /unforce-model — clear an active /force-model pin and resume automatic routing.
3
+ ---
4
+
5
+ /unforce-model
@@ -1,5 +1,5 @@
1
1
  ---
2
- description: Clear an active /force-model pin and resume automatic routing
2
+ description: Clear an active /force-model pin and resume automatic routing.
3
3
  ---
4
4
 
5
5
  /unforce-model