@blockrun/clawrouter 0.9.26 → 0.9.28

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/dist/index.d.ts CHANGED
@@ -667,16 +667,16 @@ declare const blockrunProvider: ProviderPlugin;
667
667
 
668
668
  /**
669
669
  * Model aliases for convenient shorthand access.
670
- * Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4.6`.
670
+ * Users can type `/model claude` instead of `/model blockrun/anthropic/claude-sonnet-4-6`.
671
671
  */
672
672
  declare const MODEL_ALIASES: Record<string, string>;
673
673
  /**
674
674
  * Resolve a model alias to its full model ID.
675
675
  * Also strips "blockrun/" prefix for direct model paths.
676
676
  * Examples:
677
- * - "claude" -> "anthropic/claude-sonnet-4.6" (alias)
678
- * - "blockrun/claude" -> "anthropic/claude-sonnet-4.6" (alias with prefix)
679
- * - "blockrun/anthropic/claude-sonnet-4.6" -> "anthropic/claude-sonnet-4.6" (prefix stripped)
677
+ * - "claude" -> "anthropic/claude-sonnet-4-6" (alias)
678
+ * - "blockrun/claude" -> "anthropic/claude-sonnet-4-6" (alias with prefix)
679
+ * - "blockrun/anthropic/claude-sonnet-4-6" -> "anthropic/claude-sonnet-4-6" (prefix stripped)
680
680
  * - "openai/gpt-4o" -> "openai/gpt-4o" (unchanged)
681
681
  */
682
682
  declare function resolveModelAlias(model: string): string;
package/dist/index.js CHANGED
@@ -1,18 +1,22 @@
1
1
  // src/models.ts
2
2
  var MODEL_ALIASES = {
3
- // Claude - short names
4
- claude: "anthropic/claude-sonnet-4.6",
5
- sonnet: "anthropic/claude-sonnet-4.6",
6
- opus: "anthropic/claude-opus-4.6",
7
- // Updated to latest Opus 4.6
8
- "opus-46": "anthropic/claude-opus-4.6",
9
- "opus-45": "anthropic/claude-opus-4.5",
10
- haiku: "anthropic/claude-haiku-4.5",
3
+ // Claude - short names (use dashes in version, not dots - Anthropic API format)
4
+ claude: "anthropic/claude-sonnet-4-6",
5
+ sonnet: "anthropic/claude-sonnet-4-6",
6
+ opus: "anthropic/claude-opus-4-6",
7
+ "opus-46": "anthropic/claude-opus-4-6",
8
+ "opus-45": "anthropic/claude-opus-4-5",
9
+ haiku: "anthropic/claude-haiku-4-5",
11
10
  // Claude - provider/shortname patterns (common in agent frameworks)
12
- "anthropic/sonnet": "anthropic/claude-sonnet-4.6",
13
- "anthropic/opus": "anthropic/claude-opus-4.6",
14
- "anthropic/haiku": "anthropic/claude-haiku-4.5",
15
- "anthropic/claude": "anthropic/claude-sonnet-4.6",
11
+ "anthropic/sonnet": "anthropic/claude-sonnet-4-6",
12
+ "anthropic/opus": "anthropic/claude-opus-4-6",
13
+ "anthropic/haiku": "anthropic/claude-haiku-4-5",
14
+ "anthropic/claude": "anthropic/claude-sonnet-4-6",
15
+ // Backward compatibility - old dot notation still works
16
+ "anthropic/claude-sonnet-4.6": "anthropic/claude-sonnet-4-6",
17
+ "anthropic/claude-opus-4.6": "anthropic/claude-opus-4-6",
18
+ "anthropic/claude-opus-4.5": "anthropic/claude-opus-4-5",
19
+ "anthropic/claude-haiku-4.5": "anthropic/claude-haiku-4-5",
16
20
  // OpenAI
17
21
  gpt: "openai/gpt-4o",
18
22
  gpt4: "openai/gpt-4o",
@@ -201,7 +205,7 @@ var BLOCKRUN_MODELS = [
201
205
  },
202
206
  // Anthropic - all Claude models excel at agentic workflows
203
207
  {
204
- id: "anthropic/claude-haiku-4.5",
208
+ id: "anthropic/claude-haiku-4-5",
205
209
  name: "Claude Haiku 4.5",
206
210
  inputPrice: 1,
207
211
  outputPrice: 5,
@@ -210,7 +214,7 @@ var BLOCKRUN_MODELS = [
210
214
  agentic: true
211
215
  },
212
216
  {
213
- id: "anthropic/claude-sonnet-4.6",
217
+ id: "anthropic/claude-sonnet-4-6",
214
218
  name: "Claude Sonnet 4.6",
215
219
  inputPrice: 3,
216
220
  outputPrice: 15,
@@ -230,7 +234,7 @@ var BLOCKRUN_MODELS = [
230
234
  agentic: true
231
235
  },
232
236
  {
233
- id: "anthropic/claude-opus-4.5",
237
+ id: "anthropic/claude-opus-4-5",
234
238
  name: "Claude Opus 4.5",
235
239
  inputPrice: 5,
236
240
  outputPrice: 25,
@@ -240,7 +244,7 @@ var BLOCKRUN_MODELS = [
240
244
  agentic: true
241
245
  },
242
246
  {
243
- id: "anthropic/claude-opus-4.6",
247
+ id: "anthropic/claude-opus-4-6",
244
248
  name: "Claude Opus 4.6",
245
249
  inputPrice: 5,
246
250
  outputPrice: 25,
@@ -1000,6 +1004,7 @@ function calibrateConfidence(distance, steepness) {
1000
1004
  }
1001
1005
 
1002
1006
  // src/router/selector.ts
1007
+ var BASELINE_MODEL_ID = "anthropic/claude-opus-4-5";
1003
1008
  function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPricing, estimatedInputTokens, maxOutputTokens, routingProfile) {
1004
1009
  const tierConfig = tierConfigs[tier];
1005
1010
  const model = tierConfig.primary;
@@ -1009,7 +1014,7 @@ function selectModel(tier, confidence, method, reasoning, tierConfigs, modelPric
1009
1014
  const inputCost = estimatedInputTokens / 1e6 * inputPrice;
1010
1015
  const outputCost = maxOutputTokens / 1e6 * outputPrice;
1011
1016
  const costEstimate = inputCost + outputCost;
1012
- const opusPricing = modelPricing.get("anthropic/claude-opus-4.5");
1017
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
1013
1018
  const opusInputPrice = opusPricing?.inputPrice ?? 0;
1014
1019
  const opusOutputPrice = opusPricing?.outputPrice ?? 0;
1015
1020
  const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
@@ -1038,7 +1043,7 @@ function calculateModelCost(model, modelPricing, estimatedInputTokens, maxOutput
1038
1043
  const inputCost = estimatedInputTokens / 1e6 * inputPrice;
1039
1044
  const outputCost = maxOutputTokens / 1e6 * outputPrice;
1040
1045
  const costEstimate = inputCost + outputCost;
1041
- const opusPricing = modelPricing.get("anthropic/claude-opus-4.5");
1046
+ const opusPricing = modelPricing.get(BASELINE_MODEL_ID);
1042
1047
  const opusInputPrice = opusPricing?.inputPrice ?? 0;
1043
1048
  const opusOutputPrice = opusPricing?.outputPrice ?? 0;
1044
1049
  const baselineInput = estimatedInputTokens / 1e6 * opusInputPrice;
@@ -1726,7 +1731,7 @@ var DEFAULT_ROUTING_CONFIG = {
1726
1731
  "openai/gpt-5.2",
1727
1732
  // Newer and cheaper input than gpt-4o
1728
1733
  "openai/gpt-4o",
1729
- "anthropic/claude-sonnet-4.6"
1734
+ "anthropic/claude-sonnet-4-6"
1730
1735
  ]
1731
1736
  },
1732
1737
  REASONING: {
@@ -1789,7 +1794,7 @@ var DEFAULT_ROUTING_CONFIG = {
1789
1794
  SIMPLE: {
1790
1795
  primary: "moonshot/kimi-k2.5",
1791
1796
  // $0.50/$2.40 - good for simple coding
1792
- fallback: ["anthropic/claude-haiku-4.5", "google/gemini-2.5-flash", "xai/grok-code-fast-1"]
1797
+ fallback: ["anthropic/claude-haiku-4-5", "google/gemini-2.5-flash", "xai/grok-code-fast-1"]
1793
1798
  },
1794
1799
  MEDIUM: {
1795
1800
  primary: "openai/gpt-5.2-codex",
@@ -1798,26 +1803,26 @@ var DEFAULT_ROUTING_CONFIG = {
1798
1803
  "moonshot/kimi-k2.5",
1799
1804
  "google/gemini-2.5-pro",
1800
1805
  "xai/grok-4-0709",
1801
- "anthropic/claude-sonnet-4.6"
1806
+ "anthropic/claude-sonnet-4-6"
1802
1807
  ]
1803
1808
  },
1804
1809
  COMPLEX: {
1805
- primary: "anthropic/claude-opus-4.6",
1810
+ primary: "anthropic/claude-opus-4-6",
1806
1811
  // Best quality for complex tasks
1807
1812
  fallback: [
1808
1813
  "openai/gpt-5.2-codex",
1809
- "anthropic/claude-opus-4.5",
1810
- "anthropic/claude-sonnet-4.6",
1814
+ "anthropic/claude-opus-4-5",
1815
+ "anthropic/claude-sonnet-4-6",
1811
1816
  "google/gemini-3-pro-preview",
1812
1817
  "moonshot/kimi-k2.5"
1813
1818
  ]
1814
1819
  },
1815
1820
  REASONING: {
1816
- primary: "anthropic/claude-sonnet-4.6",
1821
+ primary: "anthropic/claude-sonnet-4-6",
1817
1822
  // $3/$15 - best for reasoning/instructions
1818
1823
  fallback: [
1819
- "anthropic/claude-opus-4.6",
1820
- "anthropic/claude-opus-4.5",
1824
+ "anthropic/claude-opus-4-6",
1825
+ "anthropic/claude-opus-4-5",
1821
1826
  "openai/o4-mini",
1822
1827
  // Newer and cheaper than o3 ($1.10 vs $2.00)
1823
1828
  "openai/o3",
@@ -1833,7 +1838,7 @@ var DEFAULT_ROUTING_CONFIG = {
1833
1838
  fallback: [
1834
1839
  "minimax/minimax-m2.5",
1835
1840
  // $0.30/$1.20 - agentic capable, cheaper than kimi
1836
- "anthropic/claude-haiku-4.5",
1841
+ "anthropic/claude-haiku-4-5",
1837
1842
  "xai/grok-4-1-fast-non-reasoning",
1838
1843
  "openai/gpt-4o-mini"
1839
1844
  ]
@@ -1845,14 +1850,14 @@ var DEFAULT_ROUTING_CONFIG = {
1845
1850
  "minimax/minimax-m2.5",
1846
1851
  // $0.30/$1.20 - agentic capable
1847
1852
  "moonshot/kimi-k2.5",
1848
- "anthropic/claude-haiku-4.5",
1849
- "anthropic/claude-sonnet-4.6"
1853
+ "anthropic/claude-haiku-4-5",
1854
+ "anthropic/claude-sonnet-4-6"
1850
1855
  ]
1851
1856
  },
1852
1857
  COMPLEX: {
1853
- primary: "anthropic/claude-sonnet-4.6",
1858
+ primary: "anthropic/claude-sonnet-4-6",
1854
1859
  fallback: [
1855
- "anthropic/claude-opus-4.6",
1860
+ "anthropic/claude-opus-4-6",
1856
1861
  // Latest Opus - best agentic
1857
1862
  "minimax/minimax-m2.5",
1858
1863
  // $0.30/$1.20 - cheap agentic fallback
@@ -1862,10 +1867,10 @@ var DEFAULT_ROUTING_CONFIG = {
1862
1867
  ]
1863
1868
  },
1864
1869
  REASONING: {
1865
- primary: "anthropic/claude-sonnet-4.6",
1870
+ primary: "anthropic/claude-sonnet-4-6",
1866
1871
  // Strong tool use + reasoning for agentic tasks
1867
1872
  fallback: [
1868
- "anthropic/claude-opus-4.6",
1873
+ "anthropic/claude-opus-4-6",
1869
1874
  "minimax/minimax-m2.5",
1870
1875
  // $0.30/$1.20 - reasoning + agentic
1871
1876
  "xai/grok-4-1-fast-reasoning",
@@ -3925,6 +3930,83 @@ var PROVIDER_ERROR_PATTERNS = [
3925
3930
  /request.*size.*exceeds/i,
3926
3931
  /payload too large/i
3927
3932
  ];
3933
+ var DEGRADED_RESPONSE_PATTERNS = [
3934
+ /the ai service is temporarily overloaded/i,
3935
+ /service is temporarily overloaded/i,
3936
+ /please try again in a moment/i
3937
+ ];
3938
+ var DEGRADED_LOOP_PATTERNS = [
3939
+ /the boxed is the response\./i,
3940
+ /the response is the text\./i,
3941
+ /the final answer is the boxed\./i
3942
+ ];
3943
+ function extractAssistantContent(payload) {
3944
+ if (!payload || typeof payload !== "object") return void 0;
3945
+ const record = payload;
3946
+ const choices = record.choices;
3947
+ if (!Array.isArray(choices) || choices.length === 0) return void 0;
3948
+ const firstChoice = choices[0];
3949
+ if (!firstChoice || typeof firstChoice !== "object") return void 0;
3950
+ const choice = firstChoice;
3951
+ const message = choice.message;
3952
+ if (!message || typeof message !== "object") return void 0;
3953
+ const content = message.content;
3954
+ return typeof content === "string" ? content : void 0;
3955
+ }
3956
+ function hasKnownLoopSignature(text) {
3957
+ const matchCount = DEGRADED_LOOP_PATTERNS.reduce(
3958
+ (count, pattern) => pattern.test(text) ? count + 1 : count,
3959
+ 0
3960
+ );
3961
+ if (matchCount >= 2) return true;
3962
+ const lines = text.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
3963
+ if (lines.length < 8) return false;
3964
+ const counts = /* @__PURE__ */ new Map();
3965
+ for (const line of lines) {
3966
+ counts.set(line, (counts.get(line) ?? 0) + 1);
3967
+ }
3968
+ const maxRepeat = Math.max(...counts.values());
3969
+ const uniqueRatio = counts.size / lines.length;
3970
+ return maxRepeat >= 3 && uniqueRatio <= 0.45;
3971
+ }
3972
+ function detectDegradedSuccessResponse(body) {
3973
+ const trimmed = body.trim();
3974
+ if (!trimmed) return void 0;
3975
+ if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(trimmed))) {
3976
+ return "degraded response: overloaded placeholder";
3977
+ }
3978
+ if (hasKnownLoopSignature(trimmed)) {
3979
+ return "degraded response: repetitive loop output";
3980
+ }
3981
+ try {
3982
+ const parsed = JSON.parse(trimmed);
3983
+ const errorField = parsed.error;
3984
+ let errorText = "";
3985
+ if (typeof errorField === "string") {
3986
+ errorText = errorField;
3987
+ } else if (errorField && typeof errorField === "object") {
3988
+ const errObj = errorField;
3989
+ errorText = [
3990
+ typeof errObj.message === "string" ? errObj.message : "",
3991
+ typeof errObj.type === "string" ? errObj.type : "",
3992
+ typeof errObj.code === "string" ? errObj.code : ""
3993
+ ].filter(Boolean).join(" ");
3994
+ }
3995
+ if (errorText && PROVIDER_ERROR_PATTERNS.some((pattern) => pattern.test(errorText))) {
3996
+ return `degraded response: ${errorText.slice(0, 120)}`;
3997
+ }
3998
+ const assistantContent = extractAssistantContent(parsed);
3999
+ if (!assistantContent) return void 0;
4000
+ if (DEGRADED_RESPONSE_PATTERNS.some((pattern) => pattern.test(assistantContent))) {
4001
+ return "degraded response: overloaded assistant content";
4002
+ }
4003
+ if (hasKnownLoopSignature(assistantContent)) {
4004
+ return "degraded response: repetitive assistant loop";
4005
+ }
4006
+ } catch {
4007
+ }
4008
+ return void 0;
4009
+ }
3928
4010
  var FALLBACK_STATUS_CODES = [
3929
4011
  400,
3930
4012
  // Bad request - sometimes used for billing errors
@@ -4464,6 +4546,22 @@ async function tryModelRequest(upstreamUrl, method, headers, body, modelId, maxT
4464
4546
  isProviderError: isProviderErr
4465
4547
  };
4466
4548
  }
4549
+ const contentType = response.headers.get("content-type") || "";
4550
+ if (contentType.includes("json") || contentType.includes("text")) {
4551
+ try {
4552
+ const responseBody = await response.clone().text();
4553
+ const degradedReason = detectDegradedSuccessResponse(responseBody);
4554
+ if (degradedReason) {
4555
+ return {
4556
+ success: false,
4557
+ errorBody: degradedReason,
4558
+ errorStatus: 503,
4559
+ isProviderError: true
4560
+ };
4561
+ }
4562
+ } catch {
4563
+ }
4564
+ }
4467
4565
  return { success: true, response };
4468
4566
  } catch (err) {
4469
4567
  const errorMsg = err instanceof Error ? err.message : String(err);