@contractspec/lib.ai-providers 2.9.0 → 3.1.1

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/types.d.ts CHANGED
@@ -9,7 +9,7 @@ export type ProviderName = 'ollama' | 'openai' | 'anthropic' | 'mistral' | 'gemi
9
9
  /**
10
10
  * Legacy provider names (for backwards compatibility)
11
11
  */
12
- export type LegacyProviderName = 'claude' | 'openai' | 'ollama' | 'custom';
12
+ export type LegacyProviderName = 'claude' | 'openai' | 'ollama' | 'custom' | 'mistral';
13
13
  /**
14
14
  * Provider mode determines how API keys are resolved
15
15
  */
@@ -30,6 +30,14 @@ export interface ProviderConfig {
30
30
  proxyUrl?: string;
31
31
  /** Organization/tenant ID for managed mode */
32
32
  organizationId?: string;
33
+ /** Transport mode for the provider connection. */
34
+ transport?: 'rest' | 'mcp' | 'sdk';
35
+ /** Auth method used for this provider connection. */
36
+ authMethod?: 'api-key' | 'oauth2' | 'bearer';
37
+ /** Provider API version to target. */
38
+ apiVersion?: string;
39
+ /** Custom headers to include in requests. */
40
+ customHeaders?: Record<string, string>;
33
41
  }
34
42
  /**
35
43
  * Model capability flags
@@ -98,6 +106,10 @@ export interface ProviderAvailability {
98
106
  available: boolean;
99
107
  mode: ProviderMode;
100
108
  reason?: string;
109
+ /** Transports available for this provider. */
110
+ transports?: ('rest' | 'mcp' | 'sdk')[];
111
+ /** Auth methods available for this provider. */
112
+ authMethods?: ('api-key' | 'oauth2' | 'bearer')[];
101
113
  }
102
114
  /**
103
115
  * Legacy Config type for backwards compatibility
@@ -160,11 +160,23 @@ var MODELS = [
160
160
  },
161
161
  costPerMillion: { input: 2, output: 6 }
162
162
  },
163
+ {
164
+ id: "mistral-medium-latest",
165
+ name: "Mistral Medium",
166
+ provider: "mistral",
167
+ contextWindow: 128000,
168
+ capabilities: {
169
+ vision: false,
170
+ tools: true,
171
+ reasoning: false,
172
+ streaming: true
173
+ }
174
+ },
163
175
  {
164
176
  id: "codestral-latest",
165
177
  name: "Codestral",
166
178
  provider: "mistral",
167
- contextWindow: 32000,
179
+ contextWindow: 256000,
168
180
  capabilities: {
169
181
  vision: false,
170
182
  tools: true,
@@ -173,6 +185,42 @@ var MODELS = [
173
185
  },
174
186
  costPerMillion: { input: 0.2, output: 0.6 }
175
187
  },
188
+ {
189
+ id: "devstral-small-latest",
190
+ name: "Devstral Small",
191
+ provider: "mistral",
192
+ contextWindow: 128000,
193
+ capabilities: {
194
+ vision: false,
195
+ tools: true,
196
+ reasoning: true,
197
+ streaming: true
198
+ }
199
+ },
200
+ {
201
+ id: "magistral-medium-latest",
202
+ name: "Magistral Medium",
203
+ provider: "mistral",
204
+ contextWindow: 128000,
205
+ capabilities: {
206
+ vision: false,
207
+ tools: true,
208
+ reasoning: true,
209
+ streaming: true
210
+ }
211
+ },
212
+ {
213
+ id: "pixtral-large-latest",
214
+ name: "Pixtral Large",
215
+ provider: "mistral",
216
+ contextWindow: 128000,
217
+ capabilities: {
218
+ vision: true,
219
+ tools: true,
220
+ reasoning: false,
221
+ streaming: true
222
+ }
223
+ },
176
224
  {
177
225
  id: "mistral-small-latest",
178
226
  name: "Mistral Small",
@@ -241,22 +289,30 @@ function getDefaultModel(provider) {
241
289
  }
242
290
 
243
291
  // src/factory.ts
244
- import { anthropic } from "@ai-sdk/anthropic";
245
- import { google } from "@ai-sdk/google";
246
- import { mistral } from "@ai-sdk/mistral";
247
- import { openai } from "@ai-sdk/openai";
248
- import { ollama } from "ollama-ai-provider";
292
+ import { createAnthropic } from "@ai-sdk/anthropic";
293
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
294
+ import { createMistral } from "@ai-sdk/mistral";
295
+ import { createOpenAI } from "@ai-sdk/openai";
296
+ import { createOllama } from "ollama-ai-provider";
249
297
  class BaseProvider {
250
298
  name;
251
299
  model;
252
300
  mode;
253
301
  config;
302
+ transport;
303
+ authMethod;
304
+ apiVersion;
305
+ customHeaders;
254
306
  cachedModel = null;
255
307
  constructor(config) {
256
308
  this.name = config.provider;
257
309
  this.model = config.model ?? DEFAULT_MODELS[config.provider];
258
310
  this.mode = this.determineMode(config);
259
311
  this.config = config;
312
+ this.transport = config.transport;
313
+ this.authMethod = config.authMethod;
314
+ this.apiVersion = config.apiVersion;
315
+ this.customHeaders = config.customHeaders;
260
316
  }
261
317
  getModel() {
262
318
  if (!this.cachedModel) {
@@ -296,81 +352,33 @@ class BaseProvider {
296
352
  return "managed";
297
353
  }
298
354
  createModel() {
299
- const { baseUrl, proxyUrl } = this.config;
355
+ const { baseUrl, proxyUrl, apiKey } = this.config;
356
+ const headers = this.customHeaders;
357
+ if (this.name === "ollama") {
358
+ const provider = createOllama({ baseURL: baseUrl, headers });
359
+ return provider(this.model);
360
+ }
361
+ if (this.mode === "managed" && proxyUrl) {
362
+ const provider = createOpenAI({ baseURL: proxyUrl, apiKey, headers });
363
+ return provider(this.model);
364
+ }
300
365
  switch (this.name) {
301
- case "ollama": {
302
- const originalBaseUrl = process.env.OLLAMA_BASE_URL;
303
- if (baseUrl && baseUrl !== "http://localhost:11434") {
304
- process.env.OLLAMA_BASE_URL = baseUrl;
305
- }
306
- const ollamaModel = ollama(this.model);
307
- if (originalBaseUrl !== undefined) {
308
- process.env.OLLAMA_BASE_URL = originalBaseUrl;
309
- } else if (baseUrl && baseUrl !== "http://localhost:11434") {
310
- delete process.env.OLLAMA_BASE_URL;
311
- }
312
- return ollamaModel;
366
+ case "openai": {
367
+ const provider = createOpenAI({ apiKey, headers });
368
+ return provider(this.model);
369
+ }
370
+ case "anthropic": {
371
+ const provider = createAnthropic({ apiKey, headers });
372
+ return provider(this.model);
373
+ }
374
+ case "mistral": {
375
+ const provider = createMistral({ apiKey, headers });
376
+ return provider(this.model);
377
+ }
378
+ case "gemini": {
379
+ const provider = createGoogleGenerativeAI({ apiKey, headers });
380
+ return provider(this.model);
313
381
  }
314
- case "openai":
315
- if (this.mode === "managed") {
316
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
317
- if (proxyUrl) {
318
- process.env.OPENAI_BASE_URL = proxyUrl;
319
- }
320
- const model = openai(this.model);
321
- if (originalBaseUrl !== undefined) {
322
- process.env.OPENAI_BASE_URL = originalBaseUrl;
323
- } else if (proxyUrl) {
324
- delete process.env.OPENAI_BASE_URL;
325
- }
326
- return model;
327
- }
328
- return openai(this.model);
329
- case "anthropic":
330
- if (this.mode === "managed") {
331
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
332
- if (proxyUrl) {
333
- process.env.OPENAI_BASE_URL = proxyUrl;
334
- }
335
- const model = openai(this.model);
336
- if (originalBaseUrl !== undefined) {
337
- process.env.OPENAI_BASE_URL = originalBaseUrl;
338
- } else if (proxyUrl) {
339
- delete process.env.OPENAI_BASE_URL;
340
- }
341
- return model;
342
- }
343
- return anthropic(this.model);
344
- case "mistral":
345
- if (this.mode === "managed") {
346
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
347
- if (proxyUrl) {
348
- process.env.OPENAI_BASE_URL = proxyUrl;
349
- }
350
- const model = openai(this.model);
351
- if (originalBaseUrl !== undefined) {
352
- process.env.OPENAI_BASE_URL = originalBaseUrl;
353
- } else if (proxyUrl) {
354
- delete process.env.OPENAI_BASE_URL;
355
- }
356
- return model;
357
- }
358
- return mistral(this.model);
359
- case "gemini":
360
- if (this.mode === "managed") {
361
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
362
- if (proxyUrl) {
363
- process.env.OPENAI_BASE_URL = proxyUrl;
364
- }
365
- const model = openai(this.model);
366
- if (originalBaseUrl !== undefined) {
367
- process.env.OPENAI_BASE_URL = originalBaseUrl;
368
- } else if (proxyUrl) {
369
- delete process.env.OPENAI_BASE_URL;
370
- }
371
- return model;
372
- }
373
- return google(this.model);
374
382
  default:
375
383
  throw new Error(`Unknown provider: ${this.name}`);
376
384
  }
@@ -452,13 +460,17 @@ function createProviderFromEnv() {
452
460
  case "ollama":
453
461
  break;
454
462
  }
463
+ const transport = process.env.CONTRACTSPEC_AI_TRANSPORT;
464
+ const apiVersion = process.env.CONTRACTSPEC_AI_API_VERSION;
455
465
  return createProvider({
456
466
  provider,
457
467
  model,
458
468
  apiKey,
459
469
  baseUrl: process.env.OLLAMA_BASE_URL,
460
470
  proxyUrl: process.env.CONTRACTSPEC_AI_PROXY_URL,
461
- organizationId: process.env.CONTRACTSPEC_ORG_ID
471
+ organizationId: process.env.CONTRACTSPEC_ORG_ID,
472
+ transport,
473
+ apiVersion
462
474
  });
463
475
  }
464
476
  function getAvailableProviders() {
@@ -466,35 +478,45 @@ function getAvailableProviders() {
466
478
  providers.push({
467
479
  provider: "ollama",
468
480
  available: true,
469
- mode: "local"
481
+ mode: "local",
482
+ transports: ["rest", "sdk"],
483
+ authMethods: []
470
484
  });
471
485
  const openaiKey = process.env.OPENAI_API_KEY;
472
486
  providers.push({
473
487
  provider: "openai",
474
488
  available: Boolean(openaiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
475
489
  mode: openaiKey ? "byok" : "managed",
476
- reason: !openaiKey ? "Set OPENAI_API_KEY for BYOK mode" : undefined
490
+ reason: !openaiKey ? "Set OPENAI_API_KEY for BYOK mode" : undefined,
491
+ transports: ["rest", "sdk"],
492
+ authMethods: ["api-key"]
477
493
  });
478
494
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
479
495
  providers.push({
480
496
  provider: "anthropic",
481
497
  available: Boolean(anthropicKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
482
498
  mode: anthropicKey ? "byok" : "managed",
483
- reason: !anthropicKey ? "Set ANTHROPIC_API_KEY for BYOK mode" : undefined
499
+ reason: !anthropicKey ? "Set ANTHROPIC_API_KEY for BYOK mode" : undefined,
500
+ transports: ["rest", "sdk"],
501
+ authMethods: ["api-key"]
484
502
  });
485
503
  const mistralKey = process.env.MISTRAL_API_KEY;
486
504
  providers.push({
487
505
  provider: "mistral",
488
506
  available: Boolean(mistralKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
489
507
  mode: mistralKey ? "byok" : "managed",
490
- reason: !mistralKey ? "Set MISTRAL_API_KEY for BYOK mode" : undefined
508
+ reason: !mistralKey ? "Set MISTRAL_API_KEY for BYOK mode" : undefined,
509
+ transports: ["rest", "sdk"],
510
+ authMethods: ["api-key"]
491
511
  });
492
512
  const geminiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
493
513
  providers.push({
494
514
  provider: "gemini",
495
515
  available: Boolean(geminiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
496
516
  mode: geminiKey ? "byok" : "managed",
497
- reason: !geminiKey ? "Set GOOGLE_API_KEY for BYOK mode" : undefined
517
+ reason: !geminiKey ? "Set GOOGLE_API_KEY for BYOK mode" : undefined,
518
+ transports: ["rest", "sdk"],
519
+ authMethods: ["api-key"]
498
520
  });
499
521
  return providers;
500
522
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contractspec/lib.ai-providers",
3
- "version": "2.9.0",
3
+ "version": "3.1.1",
4
4
  "description": "Unified AI provider abstraction layer",
5
5
  "keywords": [
6
6
  "contractspec",
@@ -33,18 +33,19 @@
33
33
  "typecheck": "tsc --noEmit"
34
34
  },
35
35
  "dependencies": {
36
- "@ai-sdk/anthropic": "3.0.46",
37
- "@ai-sdk/google": "3.0.30",
38
- "@ai-sdk/mistral": "3.0.20",
39
- "@ai-sdk/openai": "3.0.31",
40
- "ai": "6.0.97",
36
+ "@ai-sdk/anthropic": "3.0.58",
37
+ "@ai-sdk/google": "3.0.43",
38
+ "@ai-sdk/mistral": "3.0.24",
39
+ "@ai-sdk/openai": "3.0.41",
40
+ "@contractspec/lib.provider-ranking": "0.1.1",
41
+ "ai": "6.0.116",
41
42
  "ollama-ai-provider": "^1.2.0",
42
43
  "zod": "^4.3.5"
43
44
  },
44
45
  "devDependencies": {
45
- "@contractspec/tool.typescript": "2.9.0",
46
+ "@contractspec/tool.typescript": "3.1.0",
46
47
  "typescript": "^5.9.3",
47
- "@contractspec/tool.bun": "2.9.0"
48
+ "@contractspec/tool.bun": "3.1.0"
48
49
  },
49
50
  "exports": {
50
51
  ".": {
@@ -75,6 +76,20 @@
75
76
  "browser": "./dist/browser/models.js",
76
77
  "default": "./dist/models.js"
77
78
  },
79
+ "./selector": {
80
+ "types": "./dist/selector.d.ts",
81
+ "bun": "./dist/selector.js",
82
+ "node": "./dist/node/selector.js",
83
+ "browser": "./dist/browser/selector.js",
84
+ "default": "./dist/selector.js"
85
+ },
86
+ "./selector-types": {
87
+ "types": "./dist/selector-types.d.ts",
88
+ "bun": "./dist/selector-types.js",
89
+ "node": "./dist/node/selector-types.js",
90
+ "browser": "./dist/browser/selector-types.js",
91
+ "default": "./dist/selector-types.js"
92
+ },
78
93
  "./types": {
79
94
  "types": "./dist/types.d.ts",
80
95
  "bun": "./dist/types.js",
@@ -121,6 +136,20 @@
121
136
  "browser": "./dist/browser/models.js",
122
137
  "default": "./dist/models.js"
123
138
  },
139
+ "./selector": {
140
+ "types": "./dist/selector.d.ts",
141
+ "bun": "./dist/selector.js",
142
+ "node": "./dist/node/selector.js",
143
+ "browser": "./dist/browser/selector.js",
144
+ "default": "./dist/selector.js"
145
+ },
146
+ "./selector-types": {
147
+ "types": "./dist/selector-types.d.ts",
148
+ "bun": "./dist/selector-types.js",
149
+ "node": "./dist/node/selector-types.js",
150
+ "browser": "./dist/browser/selector-types.js",
151
+ "default": "./dist/selector-types.js"
152
+ },
124
153
  "./types": {
125
154
  "types": "./dist/types.d.ts",
126
155
  "bun": "./dist/types.js",