@plurnk/plurnk-providers 1.7.0 → 1.8.0
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/.env.defaults +25 -13
- package/README.md +8 -1
- package/SPEC.md +93 -15
- package/dist/AiSdkProvider.d.ts +6 -3
- package/dist/AiSdkProvider.d.ts.map +1 -1
- package/dist/AiSdkProvider.js +108 -51
- package/dist/AiSdkProvider.js.map +1 -1
- package/dist/Mock.d.ts +1 -0
- package/dist/Mock.d.ts.map +1 -1
- package/dist/Mock.js +2 -0
- package/dist/Mock.js.map +1 -1
- package/dist/Pool.d.ts +2 -0
- package/dist/Pool.d.ts.map +1 -1
- package/dist/Pool.js +3 -0
- package/dist/Pool.js.map +1 -1
- package/dist/ProviderRegistry.d.ts.map +1 -1
- package/dist/ProviderRegistry.js +11 -10
- package/dist/ProviderRegistry.js.map +1 -1
- package/dist/accounting.d.ts.map +1 -1
- package/dist/accounting.js +7 -6
- package/dist/accounting.js.map +1 -1
- package/dist/aiSdkTransport.d.ts +2 -1
- package/dist/aiSdkTransport.d.ts.map +1 -1
- package/dist/aiSdkTransport.js +29 -6
- package/dist/aiSdkTransport.js.map +1 -1
- package/dist/catalogProvider.d.ts +4 -1
- package/dist/catalogProvider.d.ts.map +1 -1
- package/dist/catalogProvider.js +94 -3
- package/dist/catalogProvider.js.map +1 -1
- package/dist/compatibleProvider.d.ts.map +1 -1
- package/dist/compatibleProvider.js +2 -0
- package/dist/compatibleProvider.js.map +1 -1
- package/dist/cost.d.ts.map +1 -1
- package/dist/cost.js +5 -4
- package/dist/cost.js.map +1 -1
- package/dist/discover.d.ts +2 -0
- package/dist/discover.d.ts.map +1 -1
- package/dist/discover.js +13 -2
- package/dist/discover.js.map +1 -1
- package/dist/env.d.ts +3 -2
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +11 -4
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +9 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/notices.d.ts +1 -1
- package/dist/notices.d.ts.map +1 -1
- package/dist/openai.d.ts +1 -1
- package/dist/openai.d.ts.map +1 -1
- package/dist/openai.js +1 -1
- package/dist/openai.js.map +1 -1
- package/dist/sdkModels.d.ts +2 -0
- package/dist/sdkModels.d.ts.map +1 -1
- package/dist/sdkModels.js +163 -19
- package/dist/sdkModels.js.map +1 -1
- package/dist/types.d.ts +8 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +10 -1
- package/dist/types.js.map +1 -1
- package/package.json +9 -9
- package/src/AiSdkProvider.test.ts +206 -32
- package/src/AiSdkProvider.ts +140 -54
- package/src/Mock.ts +2 -0
- package/src/Pool.test.ts +1 -0
- package/src/Pool.ts +5 -0
- package/src/ProviderRegistry.test.ts +27 -14
- package/src/ProviderRegistry.ts +19 -10
- package/src/accounting.test.ts +6 -2
- package/src/accounting.ts +7 -6
- package/src/aiSdkTransport.ts +32 -7
- package/src/catalogProvider.test.ts +151 -19
- package/src/catalogProvider.ts +125 -3
- package/src/compatibleProvider.test.ts +13 -10
- package/src/compatibleProvider.ts +2 -0
- package/src/cost.ts +5 -4
- package/src/discover.test.ts +27 -0
- package/src/discover.ts +20 -3
- package/src/env.test.ts +23 -8
- package/src/env.ts +17 -8
- package/src/index.ts +16 -8
- package/src/notices.ts +1 -1
- package/src/openai.ts +1 -1
- package/src/providerDefaults.test.ts +50 -0
- package/src/sdkModels.test.ts +142 -8
- package/src/sdkModels.ts +201 -19
- package/src/types.ts +16 -0
package/src/sdkModels.ts
CHANGED
|
@@ -9,7 +9,13 @@ import { createOpenAI } from "@ai-sdk/openai";
|
|
|
9
9
|
import { createTogetherAI } from "@ai-sdk/togetherai";
|
|
10
10
|
import { createXai } from "@ai-sdk/xai";
|
|
11
11
|
import { createOpenRouter } from "@openrouter/ai-sdk-provider";
|
|
12
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
isProviderCredentialName,
|
|
14
|
+
lookupProvider,
|
|
15
|
+
providerCatalogSnapshot,
|
|
16
|
+
type ProviderInfo,
|
|
17
|
+
} from "@plurnk/plurnk-models";
|
|
18
|
+
import { Validator, type ModelReadiness, type ModelReadinessCause } from "@plurnk/plurnk-contracts";
|
|
13
19
|
import type { LanguageModel } from "ai";
|
|
14
20
|
import { providerCostNormalizer } from "./accounting.ts";
|
|
15
21
|
import type { AiSdkProviderOptions, CacheAffinity } from "./AiSdkProvider.ts";
|
|
@@ -30,10 +36,57 @@ export type SdkModel = {
|
|
|
30
36
|
};
|
|
31
37
|
|
|
32
38
|
const cacheControl = { type: "ephemeral" as const };
|
|
39
|
+
// The release generator admits only packages implemented by this package.
|
|
40
|
+
// Derive runtime readiness from that same pinned provider projection instead
|
|
41
|
+
// of maintaining a second support list beside the construction switch.
|
|
42
|
+
const supportedSdkPackages = new Set(
|
|
43
|
+
Object.values(providerCatalogSnapshot()).map(({ npm }) => npm),
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
const openRouterHeaders = (
|
|
47
|
+
provider: string,
|
|
48
|
+
env: NodeJS.ProcessEnv,
|
|
49
|
+
catalog: ProviderInfo,
|
|
50
|
+
): Readonly<Record<string, string>> => {
|
|
51
|
+
if (catalog.id !== "openrouter") return {};
|
|
52
|
+
if (env.OPENROUTER_X_TITLE !== undefined) {
|
|
53
|
+
throw new Error(`${provider} provider: OPENROUTER_X_TITLE was renamed to OPENROUTER_APP_TITLE.`);
|
|
54
|
+
}
|
|
55
|
+
const referer = env.OPENROUTER_HTTP_REFERER?.trim();
|
|
56
|
+
if (referer === undefined || referer === "") return {};
|
|
57
|
+
let parsed: URL;
|
|
58
|
+
try {
|
|
59
|
+
parsed = new URL(referer);
|
|
60
|
+
} catch (cause) {
|
|
61
|
+
throw new Error(`${provider} provider: OPENROUTER_HTTP_REFERER must be an absolute HTTP(S) URL.`, { cause });
|
|
62
|
+
}
|
|
63
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
64
|
+
throw new Error(`${provider} provider: OPENROUTER_HTTP_REFERER must be an absolute HTTP(S) URL.`);
|
|
65
|
+
}
|
|
66
|
+
const title = env.OPENROUTER_APP_TITLE?.trim();
|
|
67
|
+
return {
|
|
68
|
+
"HTTP-Referer": parsed.href,
|
|
69
|
+
...(title === undefined || title === "" ? {} : { "X-OpenRouter-Title": title }),
|
|
70
|
+
};
|
|
71
|
+
};
|
|
33
72
|
|
|
34
73
|
const envPrefix = (provider: string): string =>
|
|
35
74
|
provider.replaceAll(/[^a-zA-Z0-9]/g, "_").toUpperCase();
|
|
36
75
|
|
|
76
|
+
// {§provider-fact-authority} — one credential declaration holds exactly one
|
|
77
|
+
// name. An ordered fallback list would paper over an operator/catalog naming
|
|
78
|
+
// mismatch; that mismatch belongs at its owning boundary instead.
|
|
79
|
+
const singleCredentialName = (provider: string, value: string): string => {
|
|
80
|
+
const name = value.trim();
|
|
81
|
+
if (name.length === 0) throw new Error(`${provider} provider: API_KEY_ENV must name one environment variable.`);
|
|
82
|
+
if (name.includes(",")) {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`${provider} provider: API_KEY_ENV holds one exact name, never an ordered fallback; reconcile the operator environment with the Models.dev contract instead.`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
return name;
|
|
88
|
+
};
|
|
89
|
+
|
|
37
90
|
export const configuredProviderInfo = (
|
|
38
91
|
provider: string,
|
|
39
92
|
env: NodeJS.ProcessEnv,
|
|
@@ -41,13 +94,14 @@ export const configuredProviderInfo = (
|
|
|
41
94
|
const prefix = `PLURNK_PROVIDERS_PROVIDER_${envPrefix(provider)}`;
|
|
42
95
|
const npm = env[`${prefix}_NPM`];
|
|
43
96
|
if (npm === undefined || npm.length === 0) return null;
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
97
|
+
const declared = env[`${prefix}_API_KEY_ENV`];
|
|
98
|
+
const keyNames = declared === undefined
|
|
99
|
+
? []
|
|
100
|
+
: [singleCredentialName(provider, declared)];
|
|
48
101
|
const api = env[`${prefix}_BASE_URL`];
|
|
49
102
|
return {
|
|
50
103
|
id: provider,
|
|
104
|
+
name: provider,
|
|
51
105
|
npm,
|
|
52
106
|
env: keyNames,
|
|
53
107
|
...(api === undefined || api.length === 0 ? {} : { api }),
|
|
@@ -62,6 +116,11 @@ const firstSet = (env: NodeJS.ProcessEnv, names: readonly string[]): string | un
|
|
|
62
116
|
return undefined;
|
|
63
117
|
};
|
|
64
118
|
|
|
119
|
+
const isSet = (env: NodeJS.ProcessEnv, name: string): boolean => {
|
|
120
|
+
const value = env[name];
|
|
121
|
+
return value !== undefined && value.length > 0;
|
|
122
|
+
};
|
|
123
|
+
|
|
65
124
|
const configuredKeyNames = (
|
|
66
125
|
provider: string,
|
|
67
126
|
env: NodeJS.ProcessEnv,
|
|
@@ -70,7 +129,125 @@ const configuredKeyNames = (
|
|
|
70
129
|
const configured = env[`PLURNK_PROVIDERS_PROVIDER_${envPrefix(provider)}_API_KEY_ENV`];
|
|
71
130
|
return configured === undefined || configured.length === 0
|
|
72
131
|
? catalog.env
|
|
73
|
-
:
|
|
132
|
+
: [singleCredentialName(provider, configured)];
|
|
133
|
+
};
|
|
134
|
+
|
|
135
|
+
const credentialCandidates = (
|
|
136
|
+
provider: string,
|
|
137
|
+
env: NodeJS.ProcessEnv,
|
|
138
|
+
catalog: ProviderInfo,
|
|
139
|
+
): readonly string[] => {
|
|
140
|
+
const names = configuredKeyNames(provider, env, catalog);
|
|
141
|
+
const credentials = names.filter(isProviderCredentialName);
|
|
142
|
+
return credentials.length > 0 ? credentials : names;
|
|
143
|
+
};
|
|
144
|
+
|
|
145
|
+
const configuredBaseUrl = (
|
|
146
|
+
provider: string,
|
|
147
|
+
env: NodeJS.ProcessEnv,
|
|
148
|
+
catalog: ProviderInfo,
|
|
149
|
+
override?: string,
|
|
150
|
+
): string | undefined => {
|
|
151
|
+
const prefix = envPrefix(provider);
|
|
152
|
+
return override
|
|
153
|
+
?? env[`PLURNK_PROVIDERS_PROVIDER_${prefix}_BASE_URL`]
|
|
154
|
+
?? env[`${prefix}_BASE_URL`]
|
|
155
|
+
?? catalog.api;
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
const templateEnvironmentNames = (value: string | undefined): readonly string[] => value === undefined
|
|
159
|
+
? []
|
|
160
|
+
: [...new Set([...value.matchAll(/\$\{([A-Z0-9_]+)\}/g)].map((match) => match[1]!))];
|
|
161
|
+
|
|
162
|
+
const missingCause = (
|
|
163
|
+
kind: ModelReadinessCause["kind"],
|
|
164
|
+
alternatives: readonly (readonly string[])[],
|
|
165
|
+
): ModelReadinessCause => ({
|
|
166
|
+
kind,
|
|
167
|
+
alternatives: alternatives.map((alternative) => [...alternative]) as ModelReadinessCause["alternatives"],
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const bedrockReadinessCauses = (
|
|
171
|
+
env: NodeJS.ProcessEnv,
|
|
172
|
+
hasExplicitBaseUrl: boolean,
|
|
173
|
+
): ModelReadinessCause[] => {
|
|
174
|
+
const bearer = isSet(env, "AWS_BEARER_TOKEN_BEDROCK");
|
|
175
|
+
const sigv4 = isSet(env, "AWS_ACCESS_KEY_ID") && isSet(env, "AWS_SECRET_ACCESS_KEY");
|
|
176
|
+
const region = isSet(env, "AWS_REGION") || isSet(env, "AWS_DEFAULT_REGION");
|
|
177
|
+
if (bearer) {
|
|
178
|
+
return hasExplicitBaseUrl || region
|
|
179
|
+
? []
|
|
180
|
+
: [missingCause("configuration", [["AWS_REGION"], ["AWS_DEFAULT_REGION"]])];
|
|
181
|
+
}
|
|
182
|
+
if (sigv4) {
|
|
183
|
+
return region
|
|
184
|
+
? []
|
|
185
|
+
: [missingCause("configuration", [["AWS_REGION"], ["AWS_DEFAULT_REGION"]])];
|
|
186
|
+
}
|
|
187
|
+
return [missingCause("credential", hasExplicitBaseUrl
|
|
188
|
+
? [
|
|
189
|
+
["AWS_BEARER_TOKEN_BEDROCK"],
|
|
190
|
+
["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"],
|
|
191
|
+
["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_DEFAULT_REGION"],
|
|
192
|
+
]
|
|
193
|
+
: [
|
|
194
|
+
["AWS_BEARER_TOKEN_BEDROCK", "AWS_REGION"],
|
|
195
|
+
["AWS_BEARER_TOKEN_BEDROCK", "AWS_DEFAULT_REGION"],
|
|
196
|
+
["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_REGION"],
|
|
197
|
+
["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY", "AWS_DEFAULT_REGION"],
|
|
198
|
+
])];
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
// Local evidence only: this shares the exact environment and endpoint rules
|
|
202
|
+
// used by createSdkModel, but never probes a provider or validates a secret.
|
|
203
|
+
export const providerReadiness = (
|
|
204
|
+
provider: string,
|
|
205
|
+
env: NodeJS.ProcessEnv,
|
|
206
|
+
baseUrlOverride?: string,
|
|
207
|
+
): ModelReadiness | null => {
|
|
208
|
+
const catalog = lookupProvider(provider) ?? configuredProviderInfo(provider, env);
|
|
209
|
+
if (catalog === null) return null;
|
|
210
|
+
if (!supportedSdkPackages.has(catalog.npm)) return null;
|
|
211
|
+
const rawUrl = configuredBaseUrl(provider, env, catalog, baseUrlOverride);
|
|
212
|
+
const missingCoordinates = templateEnvironmentNames(rawUrl).filter((name) => !isSet(env, name));
|
|
213
|
+
const causes: ModelReadinessCause[] = missingCoordinates.length === 0
|
|
214
|
+
? []
|
|
215
|
+
: [missingCause("configuration", [missingCoordinates])];
|
|
216
|
+
|
|
217
|
+
if (catalog.npm === "@ai-sdk/amazon-bedrock") {
|
|
218
|
+
causes.push(...bedrockReadinessCauses(env, rawUrl !== undefined));
|
|
219
|
+
} else {
|
|
220
|
+
const candidates = credentialCandidates(provider, env, catalog);
|
|
221
|
+
const credentialRequired = catalog.npm !== "@ai-sdk/openai-compatible" || candidates.length > 0;
|
|
222
|
+
if (credentialRequired && candidates.length === 0) {
|
|
223
|
+
causes.push(missingCause("configuration", [[
|
|
224
|
+
`PLURNK_PROVIDERS_PROVIDER_${envPrefix(provider)}_API_KEY_ENV`,
|
|
225
|
+
]]));
|
|
226
|
+
} else if (credentialRequired && firstSet(env, candidates) === undefined) {
|
|
227
|
+
causes.push(missingCause("credential", candidates.map((name) => [name])));
|
|
228
|
+
}
|
|
229
|
+
if (catalog.npm === "@ai-sdk/openai-compatible" && rawUrl === undefined) {
|
|
230
|
+
const prefix = envPrefix(provider);
|
|
231
|
+
causes.push(missingCause("configuration", [
|
|
232
|
+
[`PLURNK_PROVIDERS_PROVIDER_${prefix}_BASE_URL`],
|
|
233
|
+
[`${prefix}_BASE_URL`],
|
|
234
|
+
]));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
return Validator.assertModelReadiness({ ready: causes.length === 0, causes });
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
const assertProviderReady = (
|
|
241
|
+
provider: string,
|
|
242
|
+
env: NodeJS.ProcessEnv,
|
|
243
|
+
baseUrlOverride?: string,
|
|
244
|
+
): void => {
|
|
245
|
+
const readiness = providerReadiness(provider, env, baseUrlOverride);
|
|
246
|
+
if (readiness === null || readiness.ready) return;
|
|
247
|
+
const requirements = readiness.causes
|
|
248
|
+
.map(({ alternatives }) => alternatives.map((group) => group.join(" and ")).join(" or "))
|
|
249
|
+
.join("; ");
|
|
250
|
+
throw new Error(`${provider} provider: ${requirements} must be set`);
|
|
74
251
|
};
|
|
75
252
|
|
|
76
253
|
const expandEnv = (value: string, env: NodeJS.ProcessEnv, provider: string): string =>
|
|
@@ -88,11 +265,11 @@ const baseUrl = (
|
|
|
88
265
|
catalog: ProviderInfo,
|
|
89
266
|
override?: string,
|
|
90
267
|
): string | undefined => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const value =
|
|
268
|
+
// {§provider-fact-authority} — distinct sources, one precedence: the PLURNK
|
|
269
|
+
// knob, then the provider-native convention (OPENAI_BASE_URL etc.), then
|
|
270
|
+
// the catalog. This is not an alias fallback: each source is a different
|
|
271
|
+
// owner, and the catalog remains the last authority.
|
|
272
|
+
const value = configuredBaseUrl(provider, env, catalog, override);
|
|
96
273
|
return value === undefined ? undefined : expandEnv(value, env, provider).replace(/\/+$/, "");
|
|
97
274
|
};
|
|
98
275
|
|
|
@@ -101,9 +278,11 @@ const requireApiKey = (
|
|
|
101
278
|
env: NodeJS.ProcessEnv,
|
|
102
279
|
catalog: ProviderInfo,
|
|
103
280
|
): string => {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
281
|
+
// {§provider-fact-authority} — a catalog `env` list mixes credentials with
|
|
282
|
+
// non-secret coordinates; the credential is the credential-named one.
|
|
283
|
+
const candidates = credentialCandidates(provider, env, catalog);
|
|
284
|
+
const key = firstSet(env, candidates);
|
|
285
|
+
if (key === undefined) throw new Error(`${provider} provider: ${candidates.join(" or ")} must be set`);
|
|
107
286
|
return key;
|
|
108
287
|
};
|
|
109
288
|
|
|
@@ -115,6 +294,10 @@ export const createSdkModel = (
|
|
|
115
294
|
): SdkModel | null => {
|
|
116
295
|
const catalog = lookupProvider(provider) ?? configuredProviderInfo(provider, env);
|
|
117
296
|
if (catalog === null) return null;
|
|
297
|
+
if (!supportedSdkPackages.has(catalog.npm)) {
|
|
298
|
+
throw new Error(`${provider} provider: Models.dev declares unsupported AI SDK package ${catalog.npm}`);
|
|
299
|
+
}
|
|
300
|
+
assertProviderReady(provider, env, baseUrlOverride);
|
|
118
301
|
const url = baseUrl(provider, env, catalog, baseUrlOverride);
|
|
119
302
|
const normalizeCost = providerCostNormalizer(catalog.npm);
|
|
120
303
|
|
|
@@ -192,7 +375,9 @@ export const createSdkModel = (
|
|
|
192
375
|
apiKey: env.AWS_BEARER_TOKEN_BEDROCK,
|
|
193
376
|
baseURL: url,
|
|
194
377
|
}).languageModel(model),
|
|
195
|
-
|
|
378
|
+
...(model.includes("anthropic")
|
|
379
|
+
? { additiveReasoningProvider: "bedrock" as const }
|
|
380
|
+
: {}),
|
|
196
381
|
catalog,
|
|
197
382
|
};
|
|
198
383
|
case "@openrouter/ai-sdk-provider":
|
|
@@ -200,10 +385,7 @@ export const createSdkModel = (
|
|
|
200
385
|
languageModel: createOpenRouter({
|
|
201
386
|
apiKey: requireApiKey(provider, env, catalog),
|
|
202
387
|
baseURL: url,
|
|
203
|
-
headers:
|
|
204
|
-
...(env.OPENROUTER_HTTP_REFERER === undefined ? {} : { "HTTP-Referer": env.OPENROUTER_HTTP_REFERER }),
|
|
205
|
-
...(env.OPENROUTER_X_TITLE === undefined ? {} : { "X-Title": env.OPENROUTER_X_TITLE }),
|
|
206
|
-
},
|
|
388
|
+
headers: openRouterHeaders(provider, env, catalog),
|
|
207
389
|
}).languageModel(model),
|
|
208
390
|
...(catalog.id === "openrouter"
|
|
209
391
|
? { cacheAffinity: { target: "header" as const, name: "x-session-id" } }
|
package/src/types.ts
CHANGED
|
@@ -12,6 +12,7 @@ import type {
|
|
|
12
12
|
import type {
|
|
13
13
|
ProviderCost,
|
|
14
14
|
ProviderRequestAccounting,
|
|
15
|
+
ReasoningPolicy,
|
|
15
16
|
} from "@plurnk/plurnk-contracts";
|
|
16
17
|
|
|
17
18
|
export type {
|
|
@@ -19,8 +20,21 @@ export type {
|
|
|
19
20
|
ProviderCost,
|
|
20
21
|
ProviderRequestAccounting,
|
|
21
22
|
ProviderUsage,
|
|
23
|
+
ReasoningPolicy,
|
|
22
24
|
} from "@plurnk/plurnk-contracts";
|
|
23
25
|
|
|
26
|
+
export class UnsupportedReasoningPolicyError extends Error {
|
|
27
|
+
readonly policy: ReasoningPolicy;
|
|
28
|
+
readonly supported: readonly ReasoningPolicy[];
|
|
29
|
+
|
|
30
|
+
constructor(source: string, policy: ReasoningPolicy, supported: readonly ReasoningPolicy[]) {
|
|
31
|
+
super(`${source}: reasoning policy '${policy}' is unsupported; supported policies: ${supported.join(", ")}`);
|
|
32
|
+
this.name = "UnsupportedReasoningPolicyError";
|
|
33
|
+
this.policy = policy;
|
|
34
|
+
this.supported = supported;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
export interface ChatMessage {
|
|
25
39
|
role: "system" | "user" | "assistant";
|
|
26
40
|
content: string;
|
|
@@ -277,6 +291,8 @@ export interface Provider {
|
|
|
277
291
|
readonly maxOutputTokens: number | null;
|
|
278
292
|
readonly outputBudget: number | null;
|
|
279
293
|
readonly reasoningBudget: number | null;
|
|
294
|
+
// Exact durable policies this adapter can represent without coercion.
|
|
295
|
+
readonly supportedReasoningPolicies: readonly ReasoningPolicy[];
|
|
280
296
|
readonly inputCapacity: number | null;
|
|
281
297
|
readonly model: string;
|
|
282
298
|
// Optional: the backend's self-reported served model id, from a
|