@hebo-ai/gateway 0.6.2-rc0 → 0.6.2

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 (134) hide show
  1. package/README.md +3 -3
  2. package/dist/endpoints/chat-completions/converters.js +26 -21
  3. package/dist/endpoints/chat-completions/handler.js +2 -0
  4. package/dist/endpoints/chat-completions/otel.js +1 -1
  5. package/dist/endpoints/chat-completions/schema.d.ts +4 -18
  6. package/dist/endpoints/chat-completions/schema.js +14 -17
  7. package/dist/endpoints/embeddings/handler.js +2 -0
  8. package/dist/endpoints/embeddings/otel.js +5 -0
  9. package/dist/endpoints/embeddings/schema.d.ts +6 -0
  10. package/dist/endpoints/embeddings/schema.js +4 -1
  11. package/dist/endpoints/models/converters.js +3 -3
  12. package/dist/lifecycle.js +2 -2
  13. package/dist/logger/default.js +3 -3
  14. package/dist/logger/index.d.ts +2 -5
  15. package/dist/middleware/common.js +1 -0
  16. package/dist/middleware/utils.js +0 -3
  17. package/dist/models/amazon/middleware.js +8 -5
  18. package/dist/models/anthropic/middleware.js +13 -13
  19. package/dist/models/catalog.js +5 -1
  20. package/dist/models/cohere/middleware.js +7 -5
  21. package/dist/models/google/middleware.d.ts +1 -1
  22. package/dist/models/google/middleware.js +29 -25
  23. package/dist/models/openai/middleware.js +13 -9
  24. package/dist/models/voyage/middleware.js +2 -1
  25. package/dist/providers/bedrock/middleware.js +21 -23
  26. package/dist/providers/registry.js +3 -0
  27. package/dist/telemetry/fetch.js +7 -2
  28. package/dist/telemetry/gen-ai.js +15 -12
  29. package/dist/telemetry/memory.d.ts +1 -1
  30. package/dist/telemetry/memory.js +30 -14
  31. package/dist/telemetry/span.js +1 -1
  32. package/dist/telemetry/stream.js +30 -23
  33. package/dist/utils/env.js +4 -2
  34. package/dist/utils/preset.js +1 -0
  35. package/dist/utils/response.js +3 -1
  36. package/package.json +36 -50
  37. package/src/config.ts +0 -98
  38. package/src/endpoints/chat-completions/converters.test.ts +0 -631
  39. package/src/endpoints/chat-completions/converters.ts +0 -899
  40. package/src/endpoints/chat-completions/handler.test.ts +0 -391
  41. package/src/endpoints/chat-completions/handler.ts +0 -201
  42. package/src/endpoints/chat-completions/index.ts +0 -4
  43. package/src/endpoints/chat-completions/otel.test.ts +0 -315
  44. package/src/endpoints/chat-completions/otel.ts +0 -214
  45. package/src/endpoints/chat-completions/schema.ts +0 -364
  46. package/src/endpoints/embeddings/converters.ts +0 -51
  47. package/src/endpoints/embeddings/handler.test.ts +0 -133
  48. package/src/endpoints/embeddings/handler.ts +0 -137
  49. package/src/endpoints/embeddings/index.ts +0 -4
  50. package/src/endpoints/embeddings/otel.ts +0 -40
  51. package/src/endpoints/embeddings/schema.ts +0 -36
  52. package/src/endpoints/models/converters.ts +0 -56
  53. package/src/endpoints/models/handler.test.ts +0 -122
  54. package/src/endpoints/models/handler.ts +0 -37
  55. package/src/endpoints/models/index.ts +0 -3
  56. package/src/endpoints/models/schema.ts +0 -37
  57. package/src/errors/ai-sdk.ts +0 -99
  58. package/src/errors/gateway.ts +0 -17
  59. package/src/errors/openai.ts +0 -57
  60. package/src/errors/utils.ts +0 -47
  61. package/src/gateway.ts +0 -50
  62. package/src/index.ts +0 -19
  63. package/src/lifecycle.ts +0 -135
  64. package/src/logger/default.ts +0 -105
  65. package/src/logger/index.ts +0 -42
  66. package/src/middleware/common.test.ts +0 -215
  67. package/src/middleware/common.ts +0 -163
  68. package/src/middleware/debug.ts +0 -37
  69. package/src/middleware/matcher.ts +0 -161
  70. package/src/middleware/utils.ts +0 -34
  71. package/src/models/amazon/index.ts +0 -2
  72. package/src/models/amazon/middleware.test.ts +0 -133
  73. package/src/models/amazon/middleware.ts +0 -79
  74. package/src/models/amazon/presets.ts +0 -104
  75. package/src/models/anthropic/index.ts +0 -2
  76. package/src/models/anthropic/middleware.test.ts +0 -643
  77. package/src/models/anthropic/middleware.ts +0 -148
  78. package/src/models/anthropic/presets.ts +0 -191
  79. package/src/models/catalog.ts +0 -13
  80. package/src/models/cohere/index.ts +0 -2
  81. package/src/models/cohere/middleware.test.ts +0 -138
  82. package/src/models/cohere/middleware.ts +0 -76
  83. package/src/models/cohere/presets.ts +0 -186
  84. package/src/models/google/index.ts +0 -2
  85. package/src/models/google/middleware.test.ts +0 -298
  86. package/src/models/google/middleware.ts +0 -137
  87. package/src/models/google/presets.ts +0 -118
  88. package/src/models/meta/index.ts +0 -1
  89. package/src/models/meta/presets.ts +0 -143
  90. package/src/models/openai/index.ts +0 -2
  91. package/src/models/openai/middleware.test.ts +0 -189
  92. package/src/models/openai/middleware.ts +0 -103
  93. package/src/models/openai/presets.ts +0 -280
  94. package/src/models/types.ts +0 -114
  95. package/src/models/voyage/index.ts +0 -2
  96. package/src/models/voyage/middleware.test.ts +0 -28
  97. package/src/models/voyage/middleware.ts +0 -23
  98. package/src/models/voyage/presets.ts +0 -126
  99. package/src/providers/anthropic/canonical.ts +0 -17
  100. package/src/providers/anthropic/index.ts +0 -1
  101. package/src/providers/bedrock/canonical.ts +0 -87
  102. package/src/providers/bedrock/index.ts +0 -2
  103. package/src/providers/bedrock/middleware.test.ts +0 -303
  104. package/src/providers/bedrock/middleware.ts +0 -128
  105. package/src/providers/cohere/canonical.ts +0 -26
  106. package/src/providers/cohere/index.ts +0 -1
  107. package/src/providers/groq/canonical.ts +0 -21
  108. package/src/providers/groq/index.ts +0 -1
  109. package/src/providers/openai/canonical.ts +0 -16
  110. package/src/providers/openai/index.ts +0 -1
  111. package/src/providers/registry.test.ts +0 -44
  112. package/src/providers/registry.ts +0 -165
  113. package/src/providers/types.ts +0 -20
  114. package/src/providers/vertex/canonical.ts +0 -17
  115. package/src/providers/vertex/index.ts +0 -1
  116. package/src/providers/voyage/canonical.ts +0 -16
  117. package/src/providers/voyage/index.ts +0 -1
  118. package/src/telemetry/ai-sdk.ts +0 -46
  119. package/src/telemetry/baggage.ts +0 -27
  120. package/src/telemetry/fetch.ts +0 -62
  121. package/src/telemetry/gen-ai.ts +0 -113
  122. package/src/telemetry/http.ts +0 -62
  123. package/src/telemetry/index.ts +0 -1
  124. package/src/telemetry/memory.ts +0 -36
  125. package/src/telemetry/span.ts +0 -85
  126. package/src/telemetry/stream.ts +0 -64
  127. package/src/types.ts +0 -223
  128. package/src/utils/env.ts +0 -7
  129. package/src/utils/headers.ts +0 -27
  130. package/src/utils/preset.ts +0 -65
  131. package/src/utils/request.test.ts +0 -75
  132. package/src/utils/request.ts +0 -52
  133. package/src/utils/response.ts +0 -84
  134. package/src/utils/url.ts +0 -26
@@ -1,118 +0,0 @@
1
- import type { CanonicalProviderId } from "../../providers/types";
2
- import type { CanonicalModelId, CatalogModel } from "../types";
3
-
4
- import { presetFor, type DeepPartial } from "../../utils/preset";
5
-
6
- const GEMINI_BASE = {
7
- modalities: {
8
- input: ["text", "image", "pdf", "file", "audio", "video"] as const,
9
- output: ["text"] as const,
10
- },
11
- capabilities: [
12
- "attachments",
13
- "reasoning",
14
- "tool_call",
15
- "structured_output",
16
- "temperature",
17
- ] as const,
18
- context: 1048576,
19
- providers: ["vertex"] as const satisfies readonly CanonicalProviderId[],
20
- } satisfies DeepPartial<CatalogModel>;
21
-
22
- const GEMINI_EMBEDDINGS_BASE = {
23
- modalities: {
24
- input: ["text"] as const,
25
- output: ["embedding"] as const,
26
- },
27
- providers: ["vertex"] as const satisfies readonly CanonicalProviderId[],
28
- } satisfies DeepPartial<CatalogModel>;
29
-
30
- export const geminiEmbedding001 = presetFor<CanonicalModelId, CatalogModel>()(
31
- "google/embedding-001" as const,
32
- {
33
- ...GEMINI_EMBEDDINGS_BASE,
34
- name: "Gemini Embedding 001",
35
- created: "2025-05-20",
36
- context: 8192,
37
- } satisfies CatalogModel,
38
- );
39
-
40
- export const gemini3FlashPreview = presetFor<CanonicalModelId, CatalogModel>()(
41
- "google/gemini-3-flash-preview" as const,
42
- {
43
- ...GEMINI_BASE,
44
- name: "Gemini 3 Flash (Preview)",
45
- created: "2025-12-17",
46
- knowledge: "2025-01",
47
- } satisfies DeepPartial<CatalogModel>,
48
- );
49
-
50
- export const gemini31FlashLitePreview = presetFor<CanonicalModelId, CatalogModel>()(
51
- "google/gemini-3.1-flash-lite-preview" as const,
52
- {
53
- ...GEMINI_BASE,
54
- name: "Gemini 3.1 Flash-Lite (Preview)",
55
- created: "2026-03-03",
56
- knowledge: "2025-01",
57
- } satisfies DeepPartial<CatalogModel>,
58
- );
59
-
60
- export const gemini31ProPreview = presetFor<CanonicalModelId, CatalogModel>()(
61
- "google/gemini-3.1-pro-preview" as const,
62
- {
63
- ...GEMINI_BASE,
64
- name: "Gemini 3.1 Pro (Preview)",
65
- created: "2026-02-19",
66
- knowledge: "2025-01",
67
- } satisfies DeepPartial<CatalogModel>,
68
- );
69
-
70
- export const gemini25FlashLite = presetFor<CanonicalModelId, CatalogModel>()(
71
- "google/gemini-2.5-flash-lite" as const,
72
- {
73
- ...GEMINI_BASE,
74
- name: "Gemini 2.5 Flash Lite",
75
- created: "2025-06-17",
76
- knowledge: "2025-01",
77
- } satisfies DeepPartial<CatalogModel>,
78
- );
79
-
80
- export const gemini25Flash = presetFor<CanonicalModelId, CatalogModel>()(
81
- "google/gemini-2.5-flash" as const,
82
- {
83
- ...GEMINI_BASE,
84
- name: "Gemini 2.5 Flash",
85
- created: "2025-03-20",
86
- knowledge: "2025-01",
87
- } satisfies DeepPartial<CatalogModel>,
88
- );
89
-
90
- export const gemini25Pro = presetFor<CanonicalModelId, CatalogModel>()(
91
- "google/gemini-2.5-pro" as const,
92
- {
93
- ...GEMINI_BASE,
94
- name: "Gemini 2.5 Pro",
95
- created: "2025-03-20",
96
- knowledge: "2025-01",
97
- } satisfies DeepPartial<CatalogModel>,
98
- );
99
-
100
- const geminiAtomic = {
101
- "v2.5": [gemini25FlashLite, gemini25Flash, gemini25Pro],
102
- "v3-preview": [gemini3FlashPreview, gemini31FlashLitePreview, gemini31ProPreview],
103
- embeddings: [geminiEmbedding001],
104
- } as const;
105
-
106
- const geminiGroups = {
107
- "v2.x": [...geminiAtomic["v2.5"]],
108
- "v3.x": [...geminiAtomic["v3-preview"]],
109
- } as const;
110
-
111
- export const gemini = {
112
- ...geminiAtomic,
113
- ...geminiGroups,
114
- latest: [...geminiAtomic["v2.5"]],
115
- preview: [...geminiAtomic["v3-preview"]],
116
- embeddings: [...geminiAtomic["embeddings"]],
117
- all: Object.values(geminiAtomic).flat(),
118
- } as const;
@@ -1 +0,0 @@
1
- export * from "./presets";
@@ -1,143 +0,0 @@
1
- import type { CanonicalProviderId } from "../../providers/types";
2
- import type { CanonicalModelId, CatalogModel } from "../types";
3
-
4
- import { presetFor, type DeepPartial } from "../../utils/preset";
5
-
6
- const LLAMA_3_BASE = {
7
- modalities: {
8
- input: ["text", "file"] as const,
9
- output: ["text"] as const,
10
- },
11
- capabilities: ["attachments", "tool_call", "temperature"] as const,
12
- context: 128000,
13
- providers: ["groq", "bedrock", "vertex"] as const satisfies readonly CanonicalProviderId[],
14
- } satisfies DeepPartial<CatalogModel>;
15
-
16
- export const llama31_8b = presetFor<CanonicalModelId, CatalogModel>()(
17
- "meta/llama-3.1-8b" as const,
18
- {
19
- ...LLAMA_3_BASE,
20
- name: "Llama 3.1 8B",
21
- created: "2024-07-23",
22
- knowledge: "2023-12",
23
- } satisfies CatalogModel,
24
- );
25
-
26
- export const llama31_70b = presetFor<CanonicalModelId, CatalogModel>()(
27
- "meta/llama-3.1-70b" as const,
28
- {
29
- ...LLAMA_3_BASE,
30
- name: "Llama 3.1 70B",
31
- created: "2024-07-23",
32
- knowledge: "2023-12",
33
- } satisfies CatalogModel,
34
- );
35
-
36
- export const llama31_405b = presetFor<CanonicalModelId, CatalogModel>()(
37
- "meta/llama-3.1-405b" as const,
38
- {
39
- ...LLAMA_3_BASE,
40
- name: "Llama 3.1 405B",
41
- created: "2024-07-23",
42
- knowledge: "2023-12",
43
- } satisfies CatalogModel,
44
- );
45
-
46
- export const llama32_1b = presetFor<CanonicalModelId, CatalogModel>()(
47
- "meta/llama-3.2-1b" as const,
48
- {
49
- ...LLAMA_3_BASE,
50
- name: "Llama 3.2 1B",
51
- created: "2024-09-25",
52
- knowledge: "2023-12",
53
- } satisfies CatalogModel,
54
- );
55
-
56
- export const llama32_3b = presetFor<CanonicalModelId, CatalogModel>()(
57
- "meta/llama-3.2-3b" as const,
58
- {
59
- ...LLAMA_3_BASE,
60
- name: "Llama 3.2 3B",
61
- created: "2024-09-25",
62
- knowledge: "2023-12",
63
- } satisfies CatalogModel,
64
- );
65
-
66
- export const llama32_11b = presetFor<CanonicalModelId, CatalogModel>()(
67
- "meta/llama-3.2-11b" as const,
68
- {
69
- ...LLAMA_3_BASE,
70
- name: "Llama 3.2 11B",
71
- created: "2024-09-25",
72
- knowledge: "2023-12",
73
- } satisfies CatalogModel,
74
- );
75
-
76
- export const llama32_90b = presetFor<CanonicalModelId, CatalogModel>()(
77
- "meta/llama-3.2-90b" as const,
78
- {
79
- ...LLAMA_3_BASE,
80
- name: "Llama 3.2 90B",
81
- created: "2024-09-25",
82
- knowledge: "2023-12",
83
- } satisfies CatalogModel,
84
- );
85
-
86
- export const llama33_70b = presetFor<CanonicalModelId, CatalogModel>()(
87
- "meta/llama-3.3-70b" as const,
88
- {
89
- ...LLAMA_3_BASE,
90
- name: "Llama 3.3 70B",
91
- created: "2024-12-06",
92
- knowledge: "2023-12",
93
- } satisfies CatalogModel,
94
- );
95
-
96
- const LLAMA_4_BASE = {
97
- modalities: {
98
- input: ["text", "image", "file"] as const,
99
- output: ["text"] as const,
100
- },
101
- capabilities: ["attachments", "tool_call", "temperature"] as const,
102
- context: 1000000,
103
- providers: ["groq", "vertex", "bedrock"] as const,
104
- } satisfies DeepPartial<CatalogModel>;
105
-
106
- export const llama4Scout = presetFor<CanonicalModelId, CatalogModel>()(
107
- "meta/llama-4-scout" as const,
108
- {
109
- ...LLAMA_4_BASE,
110
- name: "Llama 4 Scout",
111
- created: "2025-08-05",
112
- knowledge: "2024-06",
113
- } satisfies CatalogModel,
114
- );
115
-
116
- export const llama4Maverick = presetFor<CanonicalModelId, CatalogModel>()(
117
- "meta/llama-4-maverick" as const,
118
- {
119
- ...LLAMA_4_BASE,
120
- name: "Llama 4 Maverick",
121
- created: "2025-08-05",
122
- knowledge: "2024-06",
123
- } satisfies CatalogModel,
124
- );
125
-
126
- const llamaAtomic = {
127
- "v3.1": [llama31_8b, llama31_70b, llama31_405b],
128
- "v3.2": [llama32_1b, llama32_3b, llama32_11b, llama32_90b],
129
- "v3.3": [llama33_70b],
130
- v4: [llama4Scout, llama4Maverick],
131
- } as const;
132
-
133
- const llamaGroups = {
134
- "v3.x": [...llamaAtomic["v3.1"], ...llamaAtomic["v3.2"], ...llamaAtomic["v3.3"]],
135
- "v4.x": [...llamaAtomic["v4"]],
136
- } as const;
137
-
138
- export const llama = {
139
- ...llamaAtomic,
140
- ...llamaGroups,
141
- latest: [...llamaAtomic["v4"]],
142
- all: Object.values(llamaAtomic).flat(),
143
- } as const;
@@ -1,2 +0,0 @@
1
- export * from "./presets";
2
- export * from "./middleware";
@@ -1,189 +0,0 @@
1
- import { MockLanguageModelV3 } from "ai/test";
2
- import { expect, test } from "bun:test";
3
-
4
- import { modelMiddlewareMatcher } from "../../middleware/matcher";
5
- import { CANONICAL_MODEL_IDS } from "../../models/types";
6
- import {
7
- openAIDimensionsMiddleware,
8
- openAIPromptCachingMiddleware,
9
- openAIReasoningMiddleware,
10
- } from "./middleware";
11
-
12
- test("openAI middleware > matching patterns", () => {
13
- const languageMatching = [
14
- "openai/gpt-5",
15
- "openai/gpt-5.2-chat",
16
- "openai/gpt-5.3-codex",
17
- "openai/gpt-oss-20b",
18
- ] satisfies (typeof CANONICAL_MODEL_IDS)[number][];
19
-
20
- const languageNonMatching = [
21
- "openai/text-embedding-3-small",
22
- "anthropic/claude-sonnet-3.7",
23
- ] satisfies (typeof CANONICAL_MODEL_IDS)[number][];
24
-
25
- for (const id of languageMatching) {
26
- const middleware = modelMiddlewareMatcher.resolve({ kind: "text", modelId: id });
27
- expect(middleware).toContain(openAIReasoningMiddleware);
28
- expect(middleware).toContain(openAIPromptCachingMiddleware);
29
- }
30
-
31
- for (const id of languageNonMatching) {
32
- const middleware = modelMiddlewareMatcher.resolve({ kind: "text", modelId: id });
33
- expect(middleware).not.toContain(openAIReasoningMiddleware);
34
- }
35
-
36
- const embeddingMatching = [
37
- "openai/text-embedding-3-small",
38
- "openai/text-embedding-3-large",
39
- ] satisfies (typeof CANONICAL_MODEL_IDS)[number][];
40
-
41
- const embeddingNonMatching = ["openai/gpt-5"] satisfies (typeof CANONICAL_MODEL_IDS)[number][];
42
-
43
- for (const id of embeddingMatching) {
44
- const middleware = modelMiddlewareMatcher.resolve({ kind: "embedding", modelId: id });
45
- expect(middleware).toContain(openAIDimensionsMiddleware);
46
- }
47
-
48
- for (const id of embeddingNonMatching) {
49
- const middleware = modelMiddlewareMatcher.resolve({ kind: "embedding", modelId: id });
50
- expect(middleware).not.toContain(openAIDimensionsMiddleware);
51
- }
52
- });
53
-
54
- test("openAIPromptCachingMiddleware > should map key and retention", async () => {
55
- const params = {
56
- prompt: [],
57
- providerOptions: {
58
- unknown: {
59
- prompt_cache_key: "tenant:shared:legal-v1",
60
- prompt_cache_retention: "24h",
61
- },
62
- },
63
- };
64
-
65
- const result = await openAIPromptCachingMiddleware.transformParams!({
66
- type: "generate",
67
- params,
68
- model: new MockLanguageModelV3({ modelId: "openai/gpt-5" }),
69
- });
70
-
71
- expect(result.providerOptions).toEqual({
72
- openai: {
73
- promptCacheKey: "tenant:shared:legal-v1",
74
- promptCacheRetention: "24h",
75
- },
76
- unknown: {},
77
- });
78
- });
79
-
80
- test("openAIReasoningMiddleware > should map reasoning effort to OpenAI provider options", async () => {
81
- const params = {
82
- prompt: [],
83
- providerOptions: {
84
- unknown: {
85
- reasoning: { enabled: true, effort: "high" },
86
- },
87
- },
88
- };
89
-
90
- const result = await openAIReasoningMiddleware.transformParams!({
91
- type: "generate",
92
- params,
93
- model: new MockLanguageModelV3({ modelId: "openai/gpt-5" }),
94
- });
95
-
96
- expect(result).toEqual({
97
- prompt: [],
98
- providerOptions: {
99
- openai: {
100
- reasoningEffort: "high",
101
- },
102
- unknown: {},
103
- },
104
- });
105
- });
106
-
107
- test("openAIReasoningMiddleware > should disable reasoning when requested (standard model)", async () => {
108
- const params = {
109
- prompt: [],
110
- providerOptions: {
111
- unknown: {
112
- reasoning: { enabled: false },
113
- },
114
- },
115
- };
116
-
117
- const result = await openAIReasoningMiddleware.transformParams!({
118
- type: "generate",
119
- params,
120
- model: new MockLanguageModelV3({ modelId: "openai/gpt-5" }),
121
- });
122
-
123
- expect(result).toEqual({
124
- prompt: [],
125
- providerOptions: {
126
- openai: {
127
- reasoningEffort: "none",
128
- },
129
- unknown: {},
130
- },
131
- });
132
- });
133
-
134
- test("openAIReasoningMiddleware > should map reasoning for gpt-oss models", async () => {
135
- const cases = [
136
- { reasoning: { enabled: false }, expected: "low" },
137
- { reasoning: { enabled: true }, expected: "low" },
138
- { reasoning: { enabled: true, effort: "none" }, expected: "low" },
139
- { reasoning: { enabled: true, effort: "minimal" }, expected: "low" },
140
- { reasoning: { enabled: true, effort: "low" }, expected: "low" },
141
- { reasoning: { enabled: true, effort: "medium" }, expected: "medium" },
142
- { reasoning: { enabled: true, effort: "high" }, expected: "high" },
143
- { reasoning: { enabled: true, effort: "xhigh" }, expected: "high" },
144
- ] as const;
145
-
146
- await Promise.all(
147
- cases.map(async ({ reasoning, expected }) => {
148
- const params = {
149
- prompt: [],
150
- providerOptions: {
151
- unknown: { reasoning },
152
- },
153
- };
154
-
155
- const result = await openAIReasoningMiddleware.transformParams!({
156
- type: "generate",
157
- params,
158
- model: new MockLanguageModelV3({ modelId: "openai/gpt-oss-20b" }),
159
- });
160
-
161
- expect(result.providerOptions?.openai.reasoningEffort).toBe(expected);
162
- }),
163
- );
164
- });
165
-
166
- test("openAIReasoningMiddleware > should default reasoning effort when enabled without effort", async () => {
167
- const params = {
168
- prompt: [],
169
- providerOptions: {
170
- unknown: {
171
- reasoning: { enabled: true },
172
- },
173
- },
174
- };
175
-
176
- const result = await openAIReasoningMiddleware.transformParams!({
177
- type: "generate",
178
- params,
179
- model: new MockLanguageModelV3({ modelId: "openai/gpt-5" }),
180
- });
181
-
182
- expect(result).toEqual({
183
- prompt: [],
184
- providerOptions: {
185
- openai: {},
186
- unknown: {},
187
- },
188
- });
189
- });
@@ -1,103 +0,0 @@
1
- import type { EmbeddingModelMiddleware, LanguageModelMiddleware } from "ai";
2
-
3
- import type {
4
- ChatCompletionsReasoningConfig,
5
- ChatCompletionsReasoningEffort,
6
- } from "../../endpoints/chat-completions/schema";
7
-
8
- import { modelMiddlewareMatcher } from "../../middleware/matcher";
9
-
10
- // Convert `dimensions` (OpenAI) to `dimensions` (OpenAI)
11
- export const openAIDimensionsMiddleware: EmbeddingModelMiddleware = {
12
- specificationVersion: "v3",
13
- // oxlint-disable-next-line require-await
14
- transformParams: async ({ params }) => {
15
- const unknown = params.providerOptions?.["unknown"];
16
- if (!unknown) return params;
17
-
18
- const dimensions = unknown["dimensions"] as number;
19
- if (!dimensions) return params;
20
-
21
- (params.providerOptions!["openai"] ??= {})["dimensions"] = dimensions;
22
- delete unknown["dimensions"];
23
-
24
- return params;
25
- },
26
- };
27
-
28
- function mapGptOssReasoningEffort(
29
- effort?: ChatCompletionsReasoningEffort,
30
- ): "low" | "medium" | "high" {
31
- switch (effort) {
32
- case "medium":
33
- return "medium";
34
- case "high":
35
- case "xhigh":
36
- case "max":
37
- return "high";
38
- default:
39
- return "low";
40
- }
41
- }
42
-
43
- export const openAIReasoningMiddleware: LanguageModelMiddleware = {
44
- specificationVersion: "v3",
45
- // oxlint-disable-next-line require-await
46
- transformParams: async ({ params, model }) => {
47
- const unknown = params.providerOptions?.["unknown"];
48
- if (!unknown) return params;
49
-
50
- const reasoning = unknown["reasoning"] as ChatCompletionsReasoningConfig;
51
- if (!reasoning) return params;
52
-
53
- const target = (params.providerOptions!["openai"] ??= {});
54
- const isGptOss = model.modelId.includes("gpt-oss");
55
-
56
- if (isGptOss) {
57
- // FUTURE: warn that unable to disable reasoning for gpt-oss models
58
- target["reasoningEffort"] = mapGptOssReasoningEffort(reasoning.effort);
59
- } else if (reasoning.enabled === false) {
60
- target["reasoningEffort"] = "none";
61
- } else if (reasoning.effort) {
62
- target["reasoningEffort"] = reasoning.effort;
63
- }
64
-
65
- // FUTURE: warn that reasoning.max_tokens (not supported) was ignored
66
-
67
- delete unknown["reasoning"];
68
-
69
- return params;
70
- },
71
- };
72
-
73
- // https://developers.openai.com/api/docs/guides/prompt-caching/
74
- export const openAIPromptCachingMiddleware: LanguageModelMiddleware = {
75
- specificationVersion: "v3",
76
- // oxlint-disable-next-line require-await
77
- transformParams: async ({ params }) => {
78
- const unknown = params.providerOptions?.["unknown"];
79
- if (!unknown) return params;
80
-
81
- const key = unknown["prompt_cache_key"] as string | undefined;
82
- const retention = unknown["prompt_cache_retention"] as "in_memory" | "24h" | undefined;
83
-
84
- if (key || retention) {
85
- const target = (params.providerOptions!["openai"] ??= {});
86
- if (key) target["promptCacheKey"] = key;
87
- if (retention) target["promptCacheRetention"] = retention;
88
- }
89
-
90
- delete unknown["prompt_cache_key"];
91
- delete unknown["prompt_cache_retention"];
92
-
93
- return params;
94
- },
95
- };
96
-
97
- modelMiddlewareMatcher.useForModel("openai/text-embedding-*", {
98
- embedding: [openAIDimensionsMiddleware],
99
- });
100
-
101
- modelMiddlewareMatcher.useForModel("openai/gpt-*", {
102
- language: [openAIReasoningMiddleware, openAIPromptCachingMiddleware],
103
- });