@hebo-ai/gateway 0.10.3 → 0.10.5

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/README.md CHANGED
@@ -218,7 +218,7 @@ Out-of-the-box model presets:
218
218
  Nova: `nova` (`v1`, `v2`, `v1.x`, `v2.x`, `latest`, `embeddings`, `all`)
219
219
 
220
220
  - **Anthropic** — `@hebo-ai/gateway/models/anthropic`
221
- Claude: `claude` (`v4.6`, `v4.5`, `v4.1`, `v4`, `v3.7`, `v3.5`, `v3`, `v4.x`, `v3.x`, `haiku`, `sonnet`, `opus`, `latest`, `all`)
221
+ Claude: `claude` (`v4.7`, `v4.6`, `v4.5`, `v4.1`, `v4`, `v3.7`, `v3.5`, `v3`, `v4.x`, `v3.x`, `haiku`, `sonnet`, `opus`, `latest`, `all`)
222
222
 
223
223
  - **Cohere** — `@hebo-ai/gateway/models/cohere`
224
224
  Command: `command` (`A`, `R`, `latest`, `all`)
@@ -730,7 +730,7 @@ Normalization rules:
730
730
 
731
731
  - `enabled` -> fall-back to model default if none provided
732
732
  - `max_tokens`: fall-back to model default if model supports
733
- - `effort` supports: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`
733
+ - `effort` supports: `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`
734
734
  - Generic `effort` -> budget = percentage of `max_tokens`
735
735
  - `none`: 0%
736
736
  - `minimal`: 10%
@@ -738,6 +738,7 @@ Normalization rules:
738
738
  - `medium`: 50% (default)
739
739
  - `high`: 80%
740
740
  - `xhigh`: 95%
741
+ - `max`: 100%
741
742
 
742
743
  Reasoning output is surfaced as extension to the `completion` object.
743
744
 
@@ -737,6 +737,7 @@ declare const ChatCompletionsInputsSchema: z.ZodObject<{
737
737
  medium: "medium";
738
738
  high: "high";
739
739
  xhigh: "xhigh";
740
+ max: "max";
740
741
  }>>;
741
742
  service_tier: z.ZodOptional<z.ZodEnum<{
742
743
  default: "default";
@@ -768,6 +769,7 @@ declare const ChatCompletionsInputsSchema: z.ZodObject<{
768
769
  medium: "medium";
769
770
  high: "high";
770
771
  xhigh: "xhigh";
772
+ max: "max";
771
773
  }>>;
772
774
  max_tokens: z.ZodOptional<z.ZodNumber>;
773
775
  exclude: z.ZodOptional<z.ZodBoolean>;
@@ -997,6 +999,7 @@ export declare const ChatCompletionsBodySchema: z.ZodObject<{
997
999
  medium: "medium";
998
1000
  high: "high";
999
1001
  xhigh: "xhigh";
1002
+ max: "max";
1000
1003
  }>>;
1001
1004
  service_tier: z.ZodOptional<z.ZodEnum<{
1002
1005
  default: "default";
@@ -1028,6 +1031,7 @@ export declare const ChatCompletionsBodySchema: z.ZodObject<{
1028
1031
  medium: "medium";
1029
1032
  high: "high";
1030
1033
  xhigh: "xhigh";
1034
+ max: "max";
1031
1035
  }>>;
1032
1036
  max_tokens: z.ZodOptional<z.ZodNumber>;
1033
1037
  exclude: z.ZodOptional<z.ZodBoolean>;
@@ -482,18 +482,6 @@ export class MessagesTransformStream extends TransformStream {
482
482
  break;
483
483
  }
484
484
  case "reasoning-delta": {
485
- controller.enqueue({
486
- event: "content_block_delta",
487
- data: {
488
- type: "content_block_delta",
489
- index: blockIndex,
490
- delta: { type: "thinking_delta", thinking: part.text },
491
- },
492
- });
493
- break;
494
- }
495
- case "reasoning-end": {
496
- // Emit signature delta if available from provider metadata
497
485
  const { signature } = extractReasoningMetadata(part.providerMetadata);
498
486
  if (signature) {
499
487
  controller.enqueue({
@@ -505,6 +493,19 @@ export class MessagesTransformStream extends TransformStream {
505
493
  },
506
494
  });
507
495
  }
496
+ else {
497
+ controller.enqueue({
498
+ event: "content_block_delta",
499
+ data: {
500
+ type: "content_block_delta",
501
+ index: blockIndex,
502
+ delta: { type: "thinking_delta", thinking: part.text },
503
+ },
504
+ });
505
+ }
506
+ break;
507
+ }
508
+ case "reasoning-end": {
508
509
  controller.enqueue({
509
510
  event: "content_block_stop",
510
511
  data: { type: "content_block_stop", index: blockIndex },
@@ -1489,6 +1489,7 @@ declare const ResponsesInputsSchema: z.ZodObject<{
1489
1489
  medium: "medium";
1490
1490
  high: "high";
1491
1491
  xhigh: "xhigh";
1492
+ max: "max";
1492
1493
  }>>;
1493
1494
  max_tokens: z.ZodOptional<z.ZodNumber>;
1494
1495
  exclude: z.ZodOptional<z.ZodBoolean>;
@@ -1524,6 +1525,7 @@ declare const ResponsesInputsSchema: z.ZodObject<{
1524
1525
  medium: "medium";
1525
1526
  high: "high";
1526
1527
  xhigh: "xhigh";
1528
+ max: "max";
1527
1529
  }>>;
1528
1530
  extra_body: z.ZodOptional<z.ZodType<import("@ai-sdk/provider").SharedV3ProviderMetadata, unknown, z.core.$ZodTypeInternals<import("@ai-sdk/provider").SharedV3ProviderMetadata, unknown>>>;
1529
1531
  }, z.core.$strip>;
@@ -1984,6 +1986,7 @@ export declare const ResponsesBodySchema: z.ZodObject<{
1984
1986
  medium: "medium";
1985
1987
  high: "high";
1986
1988
  xhigh: "xhigh";
1989
+ max: "max";
1987
1990
  }>>;
1988
1991
  max_tokens: z.ZodOptional<z.ZodNumber>;
1989
1992
  exclude: z.ZodOptional<z.ZodBoolean>;
@@ -2019,6 +2022,7 @@ export declare const ResponsesBodySchema: z.ZodObject<{
2019
2022
  medium: "medium";
2020
2023
  high: "high";
2021
2024
  xhigh: "xhigh";
2025
+ max: "max";
2022
2026
  }>>;
2023
2027
  extra_body: z.ZodOptional<z.ZodType<import("@ai-sdk/provider").SharedV3ProviderMetadata, unknown, z.core.$ZodTypeInternals<import("@ai-sdk/provider").SharedV3ProviderMetadata, unknown>>>;
2024
2028
  model: z.ZodString;
@@ -24,6 +24,7 @@ export declare const ReasoningEffortSchema: z.ZodEnum<{
24
24
  medium: "medium";
25
25
  high: "high";
26
26
  xhigh: "xhigh";
27
+ max: "max";
27
28
  }>;
28
29
  export type ReasoningEffort = z.infer<typeof ReasoningEffortSchema>;
29
30
  export declare const ReasoningSummarySchema: z.ZodEnum<{
@@ -42,6 +43,7 @@ export declare const ReasoningConfigSchema: z.ZodObject<{
42
43
  medium: "medium";
43
44
  high: "high";
44
45
  xhigh: "xhigh";
46
+ max: "max";
45
47
  }>>;
46
48
  max_tokens: z.ZodOptional<z.ZodNumber>;
47
49
  exclude: z.ZodOptional<z.ZodBoolean>;
@@ -11,7 +11,15 @@ export const CacheControlSchema = z.object({
11
11
  ttl: z.enum(["5m", "1h", "24h"]).optional(),
12
12
  });
13
13
  export const ProviderMetadataSchema = z.record(z.string(), z.record(z.string(), z.any()));
14
- export const ReasoningEffortSchema = z.enum(["none", "minimal", "low", "medium", "high", "xhigh"]);
14
+ export const ReasoningEffortSchema = z.enum([
15
+ "none",
16
+ "minimal",
17
+ "low",
18
+ "medium",
19
+ "high",
20
+ "xhigh",
21
+ "max",
22
+ ]);
15
23
  export const ReasoningSummarySchema = z.enum(["auto", "concise", "detailed", "none"]);
16
24
  export const ReasoningConfigSchema = z.object({
17
25
  enabled: z.optional(z.boolean()),
package/dist/lifecycle.js CHANGED
@@ -53,7 +53,8 @@ export const winterCgHandler = (run, config) => {
53
53
  requestId: ctx.requestId,
54
54
  err: reason ?? ctx.request.signal.reason,
55
55
  });
56
- span.recordError(reason);
56
+ const isUpstreamError = reason instanceof GatewayError && reason.code.startsWith("UPSTREAM_");
57
+ span.recordError(reason, realStatus >= 500 || isUpstreamError);
57
58
  }
58
59
  span.setAttributes({ "http.response.status_code_effective": realStatus });
59
60
  if (ctx.operation === "chat" ||
@@ -19,6 +19,9 @@ export function calculateReasoningBudgetFromEffort(effort, maxTokens, minTokens
19
19
  case "xhigh":
20
20
  percentage = 0.95;
21
21
  break;
22
+ case "max":
23
+ percentage = 1.0;
24
+ break;
22
25
  }
23
26
  return Math.max(minTokens, Math.floor(maxTokens * percentage));
24
27
  }
@@ -28,6 +28,7 @@ function mapNovaEffort(effort) {
28
28
  return "medium";
29
29
  case "high":
30
30
  case "xhigh":
31
+ case "max":
31
32
  return "high";
32
33
  }
33
34
  return undefined;
@@ -1,5 +1,5 @@
1
1
  import type { LanguageModelMiddleware } from "ai";
2
2
  import type { ChatCompletionsReasoningEffort } from "../../endpoints/chat-completions/schema";
3
- export declare function mapClaudeReasoningEffort(effort: ChatCompletionsReasoningEffort, modelId: string): "low" | "medium" | "high" | "max" | undefined;
3
+ export declare function mapClaudeReasoningEffort(effort: ChatCompletionsReasoningEffort, modelId: string): "low" | "medium" | "high" | "xhigh" | "max" | undefined;
4
4
  export declare const claudeReasoningMiddleware: LanguageModelMiddleware;
5
5
  export declare const claudePromptCachingMiddleware: LanguageModelMiddleware;
@@ -6,11 +6,28 @@ const isClaude = (family, version) => {
6
6
  modelId.includes(`claude-${family}-${dashed}`);
7
7
  };
8
8
  const isClaude4 = (modelId) => modelId.includes("claude-") && modelId.includes("-4");
9
+ const isOpus47 = isClaude("opus", "4.7");
9
10
  const isOpus46 = isClaude("opus", "4.6");
10
11
  const isOpus45 = isClaude("opus", "4.5");
11
12
  const isOpus4 = isClaude("opus", "4");
12
13
  const isSonnet46 = isClaude("sonnet", "4.6");
13
14
  export function mapClaudeReasoningEffort(effort, modelId) {
15
+ if (isOpus47(modelId)) {
16
+ switch (effort) {
17
+ case "none":
18
+ case "minimal":
19
+ case "low":
20
+ return "low";
21
+ case "medium":
22
+ return "medium";
23
+ case "high":
24
+ return "high";
25
+ case "xhigh":
26
+ return "xhigh";
27
+ case "max":
28
+ return "max";
29
+ }
30
+ }
14
31
  if (isOpus46(modelId)) {
15
32
  switch (effort) {
16
33
  case "none":
@@ -22,6 +39,7 @@ export function mapClaudeReasoningEffort(effort, modelId) {
22
39
  case "high":
23
40
  return "high";
24
41
  case "xhigh":
42
+ case "max":
25
43
  return "max";
26
44
  }
27
45
  }
@@ -34,11 +52,14 @@ export function mapClaudeReasoningEffort(effort, modelId) {
34
52
  return "medium";
35
53
  case "high":
36
54
  case "xhigh":
55
+ case "max":
37
56
  return "high";
38
57
  }
39
58
  return undefined;
40
59
  }
41
60
  function getMaxOutputTokens(modelId) {
61
+ if (isOpus47(modelId))
62
+ return 128_000;
42
63
  if (isOpus46(modelId))
43
64
  return 128_000;
44
65
  if (isOpus45(modelId))
@@ -69,9 +90,13 @@ export const claudeReasoningMiddleware = {
69
90
  }
70
91
  else if (reasoning.effort) {
71
92
  if (isClaude4(modelId)) {
93
+ // @ts-expect-error AI SDK type missing "xhigh" effort level (native on Opus 4.7+)
72
94
  target.effort = mapClaudeReasoningEffort(reasoning.effort, modelId);
73
95
  }
74
- if (isOpus46(modelId)) {
96
+ if (isOpus47(modelId)) {
97
+ target.thinking = { type: "adaptive" };
98
+ }
99
+ else if (isOpus46(modelId)) {
75
100
  target.thinking = clampedMaxTokens
76
101
  ? // @ts-expect-error AI SDK type missing type:adaptive with budgetToken
77
102
  { type: "adaptive", budgetTokens: clampedMaxTokens }
@@ -107,6 +107,18 @@ export declare const claudeOpus45: import("../../utils/preset").Preset<"anthropi
107
107
  context: number;
108
108
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
109
109
  }>;
110
+ export declare const claudeOpus47: import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
111
+ name: string;
112
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
113
+ context: number;
114
+ created: string;
115
+ knowledge: string;
116
+ modalities: {
117
+ input: readonly ["text", "image", "pdf", "file"];
118
+ output: readonly ["text"];
119
+ };
120
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
121
+ }>;
110
122
  export declare const claudeOpus46: import("../../utils/preset").Preset<"anthropic/claude-opus-4.6", CatalogModel, {
111
123
  name: string;
112
124
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
@@ -144,7 +156,18 @@ export declare const claudeOpus4: import("../../utils/preset").Preset<"anthropic
144
156
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
145
157
  }>;
146
158
  export declare const claude: {
147
- readonly latest: readonly [import("../../utils/preset").Preset<"anthropic/claude-sonnet-4.6", CatalogModel, {
159
+ readonly latest: readonly [import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
160
+ name: string;
161
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
162
+ context: number;
163
+ created: string;
164
+ knowledge: string;
165
+ modalities: {
166
+ input: readonly ["text", "image", "pdf", "file"];
167
+ output: readonly ["text"];
168
+ };
169
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
170
+ }>, import("../../utils/preset").Preset<"anthropic/claude-sonnet-4.6", CatalogModel, {
148
171
  name: string;
149
172
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
150
173
  created: string;
@@ -266,6 +289,17 @@ export declare const claude: {
266
289
  };
267
290
  context: number;
268
291
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
292
+ }> | import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
293
+ name: string;
294
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
295
+ context: number;
296
+ created: string;
297
+ knowledge: string;
298
+ modalities: {
299
+ input: readonly ["text", "image", "pdf", "file"];
300
+ output: readonly ["text"];
301
+ };
302
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
269
303
  }> | import("../../utils/preset").Preset<"anthropic/claude-opus-4.6", CatalogModel, {
270
304
  name: string;
271
305
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
@@ -300,7 +334,18 @@ export declare const claude: {
300
334
  context: number;
301
335
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
302
336
  }>)[];
303
- readonly "v4.x": readonly [import("../../utils/preset").Preset<"anthropic/claude-sonnet-4.6", CatalogModel, {
337
+ readonly "v4.x": readonly [import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
338
+ name: string;
339
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
340
+ context: number;
341
+ created: string;
342
+ knowledge: string;
343
+ modalities: {
344
+ input: readonly ["text", "image", "pdf", "file"];
345
+ output: readonly ["text"];
346
+ };
347
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
348
+ }>, import("../../utils/preset").Preset<"anthropic/claude-sonnet-4.6", CatalogModel, {
304
349
  name: string;
305
350
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
306
351
  created: string;
@@ -434,6 +479,18 @@ export declare const claude: {
434
479
  context: number;
435
480
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
436
481
  }>];
482
+ readonly "v4.7": readonly [import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
483
+ name: string;
484
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
485
+ context: number;
486
+ created: string;
487
+ knowledge: string;
488
+ modalities: {
489
+ input: readonly ["text", "image", "pdf", "file"];
490
+ output: readonly ["text"];
491
+ };
492
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
493
+ }>];
437
494
  readonly "v4.6": readonly [import("../../utils/preset").Preset<"anthropic/claude-sonnet-4.6", CatalogModel, {
438
495
  name: string;
439
496
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
@@ -663,7 +720,18 @@ export declare const claude: {
663
720
  context: number;
664
721
  providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
665
722
  }>];
666
- readonly opus: readonly [import("../../utils/preset").Preset<"anthropic/claude-opus-4.6", CatalogModel, {
723
+ readonly opus: readonly [import("../../utils/preset").Preset<"anthropic/claude-opus-4.7", CatalogModel, {
724
+ name: string;
725
+ capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
726
+ context: number;
727
+ created: string;
728
+ knowledge: string;
729
+ modalities: {
730
+ input: readonly ["text", "image", "pdf", "file"];
731
+ output: readonly ["text"];
732
+ };
733
+ providers: readonly ["anthropic", "bedrock", "vertex", "azure"];
734
+ }>, import("../../utils/preset").Preset<"anthropic/claude-opus-4.6", CatalogModel, {
667
735
  name: string;
668
736
  capabilities: ("reasoning" | "temperature" | "attachments" | "tool_call" | "structured_output")[];
669
737
  created: string;
@@ -87,6 +87,15 @@ export const claudeOpus45 = presetFor()("anthropic/claude-opus-4.5", {
87
87
  created: "2025-11-01",
88
88
  knowledge: "2025-05",
89
89
  });
90
+ export const claudeOpus47 = presetFor()("anthropic/claude-opus-4.7", {
91
+ ...CLAUDE_BASE,
92
+ ...CLAUDE_PDF_MODALITIES,
93
+ name: "Claude Opus 4.7",
94
+ capabilities: [...CLAUDE_BASE.capabilities, "reasoning"],
95
+ context: 1_000_000,
96
+ created: "2026-04-16",
97
+ knowledge: "2026-01",
98
+ });
90
99
  export const claudeOpus46 = presetFor()("anthropic/claude-opus-4.6", {
91
100
  ...CLAUDE_BASE,
92
101
  ...CLAUDE_PDF_MODALITIES,
@@ -112,6 +121,7 @@ export const claudeOpus4 = presetFor()("anthropic/claude-opus-4", {
112
121
  knowledge: "2025-03",
113
122
  });
114
123
  const claudeAtomic = {
124
+ "v4.7": [claudeOpus47],
115
125
  "v4.6": [claudeSonnet46, claudeOpus46],
116
126
  "v4.5": [claudeHaiku45, claudeSonnet45, claudeOpus45],
117
127
  "v4.1": [claudeOpus41],
@@ -121,10 +131,11 @@ const claudeAtomic = {
121
131
  v3: [claudeHaiku3],
122
132
  haiku: [claudeHaiku45, claudeHaiku35, claudeHaiku3],
123
133
  sonnet: [claudeSonnet46, claudeSonnet45, claudeSonnet4, claudeSonnet37, claudeSonnet35],
124
- opus: [claudeOpus46, claudeOpus45, claudeOpus41, claudeOpus4],
134
+ opus: [claudeOpus47, claudeOpus46, claudeOpus45, claudeOpus41, claudeOpus4],
125
135
  };
126
136
  const claudeGroups = {
127
137
  "v4.x": [
138
+ ...claudeAtomic["v4.7"],
128
139
  ...claudeAtomic["v4.6"],
129
140
  ...claudeAtomic["v4.5"],
130
141
  ...claudeAtomic["v4.1"],
@@ -135,6 +146,6 @@ const claudeGroups = {
135
146
  export const claude = {
136
147
  ...claudeAtomic,
137
148
  ...claudeGroups,
138
- latest: [...claudeAtomic["v4.6"]],
149
+ latest: [...claudeAtomic["v4.7"], ...claudeAtomic["v4.6"]],
139
150
  all: Object.values(claudeAtomic).flat(),
140
151
  };
@@ -29,6 +29,7 @@ export function mapGeminiReasoningEffort(effort, modelId) {
29
29
  return "medium";
30
30
  case "high":
31
31
  case "xhigh":
32
+ case "max":
32
33
  return "high";
33
34
  }
34
35
  }
@@ -43,6 +44,7 @@ export function mapGeminiReasoningEffort(effort, modelId) {
43
44
  return "medium";
44
45
  case "high":
45
46
  case "xhigh":
47
+ case "max":
46
48
  return "high";
47
49
  }
48
50
  return undefined;
@@ -28,6 +28,7 @@ function mapGptOssReasoningEffort(effort) {
28
28
  return "medium";
29
29
  case "high":
30
30
  case "xhigh":
31
+ case "max":
31
32
  return "high";
32
33
  }
33
34
  return undefined;
@@ -52,7 +53,7 @@ export const openAIReasoningMiddleware = {
52
53
  target.reasoningEffort = "none";
53
54
  }
54
55
  else if (reasoning.effort) {
55
- target.reasoningEffort = reasoning.effort;
56
+ target.reasoningEffort = reasoning.effort === "max" ? "xhigh" : reasoning.effort;
56
57
  }
57
58
  // FUTURE: warn that reasoning.max_tokens (not supported) was ignored
58
59
  delete unknown["reasoning"];
@@ -1,5 +1,5 @@
1
1
  import type { ProviderId } from "../providers/types";
2
- export declare const CANONICAL_MODEL_IDS: readonly ["anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "anthropic/claude-haiku-4.5", "anthropic/claude-sonnet-4.5", "anthropic/claude-opus-4.5", "anthropic/claude-opus-4.1", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "anthropic/claude-sonnet-3.7", "anthropic/claude-sonnet-3.5", "anthropic/claude-haiku-3.5", "anthropic/claude-haiku-3", "openai/gpt-oss-20b", "openai/gpt-oss-120b", "openai/gpt-5", "openai/gpt-5-pro", "openai/gpt-5.2", "openai/gpt-5.2-chat", "openai/gpt-5.2-pro", "openai/gpt-5.2-codex", "openai/gpt-5.3-codex", "openai/gpt-5.3-codex-spark", "openai/gpt-5.3-chat", "openai/gpt-5.4", "openai/gpt-5.4-mini", "openai/gpt-5.4-nano", "openai/gpt-5.4-pro", "openai/gpt-5-mini", "openai/gpt-5-nano", "openai/gpt-5-codex", "openai/gpt-5.1-codex", "openai/gpt-5.1-codex-max", "openai/gpt-5.1-codex-mini", "openai/gpt-5.1-chat", "openai/gpt-5.1", "openai/text-embedding-3-small", "openai/text-embedding-3-large", "amazon/nova-micro", "amazon/nova-lite", "amazon/nova-pro", "amazon/nova-premier", "amazon/nova-2-lite", "amazon/nova-2-multimodal-embeddings", "google/gemini-2.5-flash-lite", "google/gemini-2.5-flash", "google/gemini-2.5-pro", "google/gemini-3-flash-preview", "google/gemini-3.1-flash-lite-preview", "google/gemini-3.1-pro-preview", "google/gemini-embedding-2-preview", "google/embedding-001", "google/gemma-3-1b", "google/gemma-3-4b", "google/gemma-3-12b", "google/gemma-3-27b", "google/gemma-4-e2b", "google/gemma-4-e4b", "google/gemma-4-26b-a4b", "google/gemma-4-31b", "meta/llama-3.1-8b", "meta/llama-3.1-70b", "meta/llama-3.1-405b", "meta/llama-3.2-1b", "meta/llama-3.2-3b", "meta/llama-3.2-11b", "meta/llama-3.2-90b", "meta/llama-3.3-70b", "meta/llama-4-scout", "meta/llama-4-maverick", "cohere/embed-v4.0", "cohere/embed-english-v3.0", "cohere/embed-english-light-v3.0", "cohere/embed-multilingual-v3.0", "cohere/embed-multilingual-light-v3.0", "cohere/command-a", "cohere/command-r7b", "cohere/command-a-translate", "cohere/command-a-reasoning", "cohere/command-a-vision", "cohere/command-r", "cohere/command-r-plus", "voyage/voyage-2-code", "voyage/voyage-2-law", "voyage/voyage-2-finance", "voyage/voyage-3-code", "voyage/voyage-3-large", "voyage/voyage-3.5-lite", "voyage/voyage-3.5", "voyage/voyage-4-lite", "voyage/voyage-4", "voyage/voyage-4-large"];
2
+ export declare const CANONICAL_MODEL_IDS: readonly ["anthropic/claude-opus-4.7", "anthropic/claude-opus-4.6", "anthropic/claude-sonnet-4.6", "anthropic/claude-haiku-4.5", "anthropic/claude-sonnet-4.5", "anthropic/claude-opus-4.5", "anthropic/claude-opus-4.1", "anthropic/claude-opus-4", "anthropic/claude-sonnet-4", "anthropic/claude-sonnet-3.7", "anthropic/claude-sonnet-3.5", "anthropic/claude-haiku-3.5", "anthropic/claude-haiku-3", "openai/gpt-oss-20b", "openai/gpt-oss-120b", "openai/gpt-5", "openai/gpt-5-pro", "openai/gpt-5.2", "openai/gpt-5.2-chat", "openai/gpt-5.2-pro", "openai/gpt-5.2-codex", "openai/gpt-5.3-codex", "openai/gpt-5.3-codex-spark", "openai/gpt-5.3-chat", "openai/gpt-5.4", "openai/gpt-5.4-mini", "openai/gpt-5.4-nano", "openai/gpt-5.4-pro", "openai/gpt-5-mini", "openai/gpt-5-nano", "openai/gpt-5-codex", "openai/gpt-5.1-codex", "openai/gpt-5.1-codex-max", "openai/gpt-5.1-codex-mini", "openai/gpt-5.1-chat", "openai/gpt-5.1", "openai/text-embedding-3-small", "openai/text-embedding-3-large", "amazon/nova-micro", "amazon/nova-lite", "amazon/nova-pro", "amazon/nova-premier", "amazon/nova-2-lite", "amazon/nova-2-multimodal-embeddings", "google/gemini-2.5-flash-lite", "google/gemini-2.5-flash", "google/gemini-2.5-pro", "google/gemini-3-flash-preview", "google/gemini-3.1-flash-lite-preview", "google/gemini-3.1-pro-preview", "google/gemini-embedding-2-preview", "google/embedding-001", "google/gemma-3-1b", "google/gemma-3-4b", "google/gemma-3-12b", "google/gemma-3-27b", "google/gemma-4-e2b", "google/gemma-4-e4b", "google/gemma-4-26b-a4b", "google/gemma-4-31b", "meta/llama-3.1-8b", "meta/llama-3.1-70b", "meta/llama-3.1-405b", "meta/llama-3.2-1b", "meta/llama-3.2-3b", "meta/llama-3.2-11b", "meta/llama-3.2-90b", "meta/llama-3.3-70b", "meta/llama-4-scout", "meta/llama-4-maverick", "cohere/embed-v4.0", "cohere/embed-english-v3.0", "cohere/embed-english-light-v3.0", "cohere/embed-multilingual-v3.0", "cohere/embed-multilingual-light-v3.0", "cohere/command-a", "cohere/command-r7b", "cohere/command-a-translate", "cohere/command-a-reasoning", "cohere/command-a-vision", "cohere/command-r", "cohere/command-r-plus", "voyage/voyage-2-code", "voyage/voyage-2-law", "voyage/voyage-2-finance", "voyage/voyage-3-code", "voyage/voyage-3-large", "voyage/voyage-3.5-lite", "voyage/voyage-3.5", "voyage/voyage-4-lite", "voyage/voyage-4", "voyage/voyage-4-large"];
3
3
  export type CanonicalModelId = (typeof CANONICAL_MODEL_IDS)[number];
4
4
  export type ModelId = CanonicalModelId | (string & {});
5
5
  export type CatalogModel = {
@@ -1,5 +1,6 @@
1
1
  export const CANONICAL_MODEL_IDS = [
2
2
  // Anthropic
3
+ "anthropic/claude-opus-4.7",
3
4
  "anthropic/claude-opus-4.6",
4
5
  "anthropic/claude-sonnet-4.6",
5
6
  "anthropic/claude-haiku-4.5",
@@ -9,6 +9,7 @@ import { withCanonicalIds } from "../registry";
9
9
  const MAPPING = {
10
10
  // Require Inference Profiles and can't be resolved from standard name mapping
11
11
  "anthropic/claude-haiku-4.5": "{ip}anthropic.claude-haiku-4-5-20251001-v1:0",
12
+ "anthropic/claude-opus-4.7": "{ip}anthropic.claude-opus-4-7",
12
13
  "anthropic/claude-sonnet-4.6": "{ip}anthropic.claude-sonnet-4-6",
13
14
  "anthropic/claude-sonnet-4.5": "{ip}anthropic.claude-sonnet-4-5-20250929-v1:0",
14
15
  "anthropic/claude-opus-4.6": "{ip}anthropic.claude-opus-4-6-v1",
@@ -1,6 +1,7 @@
1
1
  import { modelMiddlewareMatcher } from "../../middleware/matcher";
2
2
  import { calculateReasoningBudgetFromEffort } from "../../middleware/utils";
3
- const isClaude46 = (modelId) => modelId.includes("-4-6");
3
+ const BEDROCK_EFFORT_CAPABLE = ["-4-6", "-4-7"];
4
+ const isBedrockEffortCapable = (modelId) => BEDROCK_EFFORT_CAPABLE.some((tag) => modelId.includes(tag));
4
5
  // https://docs.aws.amazon.com/bedrock/latest/userguide/service-tiers-inference.html
5
6
  export const bedrockServiceTierMiddleware = {
6
7
  specificationVersion: "v3",
@@ -83,7 +84,7 @@ export const bedrockClaudeReasoningMiddleware = {
83
84
  }
84
85
  }
85
86
  // FUTURE: bedrock currently does not support "effort" for other 4.x models
86
- if (effort !== undefined && isClaude46(model.modelId)) {
87
+ if (effort !== undefined && isBedrockEffortCapable(model.modelId)) {
87
88
  target.maxReasoningEffort = effort;
88
89
  }
89
90
  delete bedrock.thinking;
@@ -4,7 +4,7 @@ export declare const setSpanTracer: (tracer?: Tracer) => void;
4
4
  export declare const setSpanEventsEnabled: (level?: TelemetrySignalLevel) => void;
5
5
  export declare const startSpan: (name: string, options?: SpanOptions) => import("@opentelemetry/api").Span & {
6
6
  runWithContext: <T>(fn: () => Promise<T> | T) => T | Promise<T>;
7
- recordError: (_error: unknown) => void;
7
+ recordError: (_error: unknown, _setError: boolean) => void;
8
8
  finish: () => void;
9
9
  isExisting: boolean;
10
10
  };
@@ -4,7 +4,7 @@ let spanTracer;
4
4
  let spanEventsEnabled = false;
5
5
  const NOOP_SPAN = {
6
6
  runWithContext: (fn) => fn(),
7
- recordError: (_error) => { },
7
+ recordError: (_error, _setError) => { },
8
8
  finish: () => { },
9
9
  isExisting: true,
10
10
  };
@@ -22,10 +22,12 @@ export const startSpan = (name, options) => {
22
22
  const activeSpan = trace.getActiveSpan();
23
23
  const span = spanTracer.startSpan(name, { kind: activeSpan ? SpanKind.INTERNAL : SpanKind.SERVER, ...options }, parentContext);
24
24
  const runWithContext = (fn) => context.with(trace.setSpan(parentContext, span), fn);
25
- const recordError = (error) => {
25
+ const recordError = (error, setError) => {
26
26
  const err = error instanceof Error ? error : new Error(String(error));
27
27
  span.recordException(err);
28
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
28
+ if (setError) {
29
+ span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
30
+ }
29
31
  };
30
32
  const finish = () => {
31
33
  span.end();
@@ -41,7 +43,7 @@ export const withSpan = async (name, run, options) => {
41
43
  return await started.runWithContext(run);
42
44
  }
43
45
  catch (error) {
44
- started.recordError(error);
46
+ started.recordError(error, true);
45
47
  throw error;
46
48
  }
47
49
  finally {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hebo-ai/gateway",
3
- "version": "0.10.3",
3
+ "version": "0.10.5",
4
4
  "description": "AI gateway as a framework. For full control over models, routing & lifecycle. OpenAI /chat/completions, OpenResponses /responses & Anthropic /messages.",
5
5
  "keywords": [
6
6
  "ai",