@contractspec/lib.ai-providers 3.0.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.
@@ -288,22 +288,30 @@ function getDefaultModel(provider) {
288
288
  }
289
289
 
290
290
  // src/factory.ts
291
- import { anthropic } from "@ai-sdk/anthropic";
292
- import { google } from "@ai-sdk/google";
293
- import { mistral } from "@ai-sdk/mistral";
294
- import { openai } from "@ai-sdk/openai";
295
- import { ollama } from "ollama-ai-provider";
291
+ import { createAnthropic } from "@ai-sdk/anthropic";
292
+ import { createGoogleGenerativeAI } from "@ai-sdk/google";
293
+ import { createMistral } from "@ai-sdk/mistral";
294
+ import { createOpenAI } from "@ai-sdk/openai";
295
+ import { createOllama } from "ollama-ai-provider";
296
296
  class BaseProvider {
297
297
  name;
298
298
  model;
299
299
  mode;
300
300
  config;
301
+ transport;
302
+ authMethod;
303
+ apiVersion;
304
+ customHeaders;
301
305
  cachedModel = null;
302
306
  constructor(config) {
303
307
  this.name = config.provider;
304
308
  this.model = config.model ?? DEFAULT_MODELS[config.provider];
305
309
  this.mode = this.determineMode(config);
306
310
  this.config = config;
311
+ this.transport = config.transport;
312
+ this.authMethod = config.authMethod;
313
+ this.apiVersion = config.apiVersion;
314
+ this.customHeaders = config.customHeaders;
307
315
  }
308
316
  getModel() {
309
317
  if (!this.cachedModel) {
@@ -343,81 +351,33 @@ class BaseProvider {
343
351
  return "managed";
344
352
  }
345
353
  createModel() {
346
- const { baseUrl, proxyUrl } = this.config;
354
+ const { baseUrl, proxyUrl, apiKey } = this.config;
355
+ const headers = this.customHeaders;
356
+ if (this.name === "ollama") {
357
+ const provider = createOllama({ baseURL: baseUrl, headers });
358
+ return provider(this.model);
359
+ }
360
+ if (this.mode === "managed" && proxyUrl) {
361
+ const provider = createOpenAI({ baseURL: proxyUrl, apiKey, headers });
362
+ return provider(this.model);
363
+ }
347
364
  switch (this.name) {
348
- case "ollama": {
349
- const originalBaseUrl = process.env.OLLAMA_BASE_URL;
350
- if (baseUrl && baseUrl !== "http://localhost:11434") {
351
- process.env.OLLAMA_BASE_URL = baseUrl;
352
- }
353
- const ollamaModel = ollama(this.model);
354
- if (originalBaseUrl !== undefined) {
355
- process.env.OLLAMA_BASE_URL = originalBaseUrl;
356
- } else if (baseUrl && baseUrl !== "http://localhost:11434") {
357
- delete process.env.OLLAMA_BASE_URL;
358
- }
359
- return ollamaModel;
365
+ case "openai": {
366
+ const provider = createOpenAI({ apiKey, headers });
367
+ return provider(this.model);
368
+ }
369
+ case "anthropic": {
370
+ const provider = createAnthropic({ apiKey, headers });
371
+ return provider(this.model);
372
+ }
373
+ case "mistral": {
374
+ const provider = createMistral({ apiKey, headers });
375
+ return provider(this.model);
376
+ }
377
+ case "gemini": {
378
+ const provider = createGoogleGenerativeAI({ apiKey, headers });
379
+ return provider(this.model);
360
380
  }
361
- case "openai":
362
- if (this.mode === "managed") {
363
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
364
- if (proxyUrl) {
365
- process.env.OPENAI_BASE_URL = proxyUrl;
366
- }
367
- const model = openai(this.model);
368
- if (originalBaseUrl !== undefined) {
369
- process.env.OPENAI_BASE_URL = originalBaseUrl;
370
- } else if (proxyUrl) {
371
- delete process.env.OPENAI_BASE_URL;
372
- }
373
- return model;
374
- }
375
- return openai(this.model);
376
- case "anthropic":
377
- if (this.mode === "managed") {
378
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
379
- if (proxyUrl) {
380
- process.env.OPENAI_BASE_URL = proxyUrl;
381
- }
382
- const model = openai(this.model);
383
- if (originalBaseUrl !== undefined) {
384
- process.env.OPENAI_BASE_URL = originalBaseUrl;
385
- } else if (proxyUrl) {
386
- delete process.env.OPENAI_BASE_URL;
387
- }
388
- return model;
389
- }
390
- return anthropic(this.model);
391
- case "mistral":
392
- if (this.mode === "managed") {
393
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
394
- if (proxyUrl) {
395
- process.env.OPENAI_BASE_URL = proxyUrl;
396
- }
397
- const model = openai(this.model);
398
- if (originalBaseUrl !== undefined) {
399
- process.env.OPENAI_BASE_URL = originalBaseUrl;
400
- } else if (proxyUrl) {
401
- delete process.env.OPENAI_BASE_URL;
402
- }
403
- return model;
404
- }
405
- return mistral(this.model);
406
- case "gemini":
407
- if (this.mode === "managed") {
408
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
409
- if (proxyUrl) {
410
- process.env.OPENAI_BASE_URL = proxyUrl;
411
- }
412
- const model = openai(this.model);
413
- if (originalBaseUrl !== undefined) {
414
- process.env.OPENAI_BASE_URL = originalBaseUrl;
415
- } else if (proxyUrl) {
416
- delete process.env.OPENAI_BASE_URL;
417
- }
418
- return model;
419
- }
420
- return google(this.model);
421
381
  default:
422
382
  throw new Error(`Unknown provider: ${this.name}`);
423
383
  }
@@ -499,13 +459,17 @@ function createProviderFromEnv() {
499
459
  case "ollama":
500
460
  break;
501
461
  }
462
+ const transport = process.env.CONTRACTSPEC_AI_TRANSPORT;
463
+ const apiVersion = process.env.CONTRACTSPEC_AI_API_VERSION;
502
464
  return createProvider({
503
465
  provider,
504
466
  model,
505
467
  apiKey,
506
468
  baseUrl: process.env.OLLAMA_BASE_URL,
507
469
  proxyUrl: process.env.CONTRACTSPEC_AI_PROXY_URL,
508
- organizationId: process.env.CONTRACTSPEC_ORG_ID
470
+ organizationId: process.env.CONTRACTSPEC_ORG_ID,
471
+ transport,
472
+ apiVersion
509
473
  });
510
474
  }
511
475
  function getAvailableProviders() {
@@ -513,35 +477,45 @@ function getAvailableProviders() {
513
477
  providers.push({
514
478
  provider: "ollama",
515
479
  available: true,
516
- mode: "local"
480
+ mode: "local",
481
+ transports: ["rest", "sdk"],
482
+ authMethods: []
517
483
  });
518
484
  const openaiKey = process.env.OPENAI_API_KEY;
519
485
  providers.push({
520
486
  provider: "openai",
521
487
  available: Boolean(openaiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
522
488
  mode: openaiKey ? "byok" : "managed",
523
- reason: !openaiKey ? "Set OPENAI_API_KEY for BYOK mode" : undefined
489
+ reason: !openaiKey ? "Set OPENAI_API_KEY for BYOK mode" : undefined,
490
+ transports: ["rest", "sdk"],
491
+ authMethods: ["api-key"]
524
492
  });
525
493
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
526
494
  providers.push({
527
495
  provider: "anthropic",
528
496
  available: Boolean(anthropicKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
529
497
  mode: anthropicKey ? "byok" : "managed",
530
- reason: !anthropicKey ? "Set ANTHROPIC_API_KEY for BYOK mode" : undefined
498
+ reason: !anthropicKey ? "Set ANTHROPIC_API_KEY for BYOK mode" : undefined,
499
+ transports: ["rest", "sdk"],
500
+ authMethods: ["api-key"]
531
501
  });
532
502
  const mistralKey = process.env.MISTRAL_API_KEY;
533
503
  providers.push({
534
504
  provider: "mistral",
535
505
  available: Boolean(mistralKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
536
506
  mode: mistralKey ? "byok" : "managed",
537
- reason: !mistralKey ? "Set MISTRAL_API_KEY for BYOK mode" : undefined
507
+ reason: !mistralKey ? "Set MISTRAL_API_KEY for BYOK mode" : undefined,
508
+ transports: ["rest", "sdk"],
509
+ authMethods: ["api-key"]
538
510
  });
539
511
  const geminiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
540
512
  providers.push({
541
513
  provider: "gemini",
542
514
  available: Boolean(geminiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
543
515
  mode: geminiKey ? "byok" : "managed",
544
- reason: !geminiKey ? "Set GOOGLE_API_KEY for BYOK mode" : undefined
516
+ reason: !geminiKey ? "Set GOOGLE_API_KEY for BYOK mode" : undefined,
517
+ transports: ["rest", "sdk"],
518
+ authMethods: ["api-key"]
545
519
  });
546
520
  return providers;
547
521
  }
package/dist/factory.js CHANGED
@@ -289,22 +289,30 @@ function getDefaultModel(provider) {
289
289
  }
290
290
 
291
291
  // src/factory.ts
292
- import { anthropic } from "@ai-sdk/anthropic";
293
- import { google } from "@ai-sdk/google";
294
- import { mistral } from "@ai-sdk/mistral";
295
- import { openai } from "@ai-sdk/openai";
296
- 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";
297
297
  class BaseProvider {
298
298
  name;
299
299
  model;
300
300
  mode;
301
301
  config;
302
+ transport;
303
+ authMethod;
304
+ apiVersion;
305
+ customHeaders;
302
306
  cachedModel = null;
303
307
  constructor(config) {
304
308
  this.name = config.provider;
305
309
  this.model = config.model ?? DEFAULT_MODELS[config.provider];
306
310
  this.mode = this.determineMode(config);
307
311
  this.config = config;
312
+ this.transport = config.transport;
313
+ this.authMethod = config.authMethod;
314
+ this.apiVersion = config.apiVersion;
315
+ this.customHeaders = config.customHeaders;
308
316
  }
309
317
  getModel() {
310
318
  if (!this.cachedModel) {
@@ -344,81 +352,33 @@ class BaseProvider {
344
352
  return "managed";
345
353
  }
346
354
  createModel() {
347
- 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
+ }
348
365
  switch (this.name) {
349
- case "ollama": {
350
- const originalBaseUrl = process.env.OLLAMA_BASE_URL;
351
- if (baseUrl && baseUrl !== "http://localhost:11434") {
352
- process.env.OLLAMA_BASE_URL = baseUrl;
353
- }
354
- const ollamaModel = ollama(this.model);
355
- if (originalBaseUrl !== undefined) {
356
- process.env.OLLAMA_BASE_URL = originalBaseUrl;
357
- } else if (baseUrl && baseUrl !== "http://localhost:11434") {
358
- delete process.env.OLLAMA_BASE_URL;
359
- }
360
- 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);
361
381
  }
362
- case "openai":
363
- if (this.mode === "managed") {
364
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
365
- if (proxyUrl) {
366
- process.env.OPENAI_BASE_URL = proxyUrl;
367
- }
368
- const model = openai(this.model);
369
- if (originalBaseUrl !== undefined) {
370
- process.env.OPENAI_BASE_URL = originalBaseUrl;
371
- } else if (proxyUrl) {
372
- delete process.env.OPENAI_BASE_URL;
373
- }
374
- return model;
375
- }
376
- return openai(this.model);
377
- case "anthropic":
378
- if (this.mode === "managed") {
379
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
380
- if (proxyUrl) {
381
- process.env.OPENAI_BASE_URL = proxyUrl;
382
- }
383
- const model = openai(this.model);
384
- if (originalBaseUrl !== undefined) {
385
- process.env.OPENAI_BASE_URL = originalBaseUrl;
386
- } else if (proxyUrl) {
387
- delete process.env.OPENAI_BASE_URL;
388
- }
389
- return model;
390
- }
391
- return anthropic(this.model);
392
- case "mistral":
393
- if (this.mode === "managed") {
394
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
395
- if (proxyUrl) {
396
- process.env.OPENAI_BASE_URL = proxyUrl;
397
- }
398
- const model = openai(this.model);
399
- if (originalBaseUrl !== undefined) {
400
- process.env.OPENAI_BASE_URL = originalBaseUrl;
401
- } else if (proxyUrl) {
402
- delete process.env.OPENAI_BASE_URL;
403
- }
404
- return model;
405
- }
406
- return mistral(this.model);
407
- case "gemini":
408
- if (this.mode === "managed") {
409
- const originalBaseUrl = process.env.OPENAI_BASE_URL;
410
- if (proxyUrl) {
411
- process.env.OPENAI_BASE_URL = proxyUrl;
412
- }
413
- const model = openai(this.model);
414
- if (originalBaseUrl !== undefined) {
415
- process.env.OPENAI_BASE_URL = originalBaseUrl;
416
- } else if (proxyUrl) {
417
- delete process.env.OPENAI_BASE_URL;
418
- }
419
- return model;
420
- }
421
- return google(this.model);
422
382
  default:
423
383
  throw new Error(`Unknown provider: ${this.name}`);
424
384
  }
@@ -500,13 +460,17 @@ function createProviderFromEnv() {
500
460
  case "ollama":
501
461
  break;
502
462
  }
463
+ const transport = process.env.CONTRACTSPEC_AI_TRANSPORT;
464
+ const apiVersion = process.env.CONTRACTSPEC_AI_API_VERSION;
503
465
  return createProvider({
504
466
  provider,
505
467
  model,
506
468
  apiKey,
507
469
  baseUrl: process.env.OLLAMA_BASE_URL,
508
470
  proxyUrl: process.env.CONTRACTSPEC_AI_PROXY_URL,
509
- organizationId: process.env.CONTRACTSPEC_ORG_ID
471
+ organizationId: process.env.CONTRACTSPEC_ORG_ID,
472
+ transport,
473
+ apiVersion
510
474
  });
511
475
  }
512
476
  function getAvailableProviders() {
@@ -514,35 +478,45 @@ function getAvailableProviders() {
514
478
  providers.push({
515
479
  provider: "ollama",
516
480
  available: true,
517
- mode: "local"
481
+ mode: "local",
482
+ transports: ["rest", "sdk"],
483
+ authMethods: []
518
484
  });
519
485
  const openaiKey = process.env.OPENAI_API_KEY;
520
486
  providers.push({
521
487
  provider: "openai",
522
488
  available: Boolean(openaiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
523
489
  mode: openaiKey ? "byok" : "managed",
524
- 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"]
525
493
  });
526
494
  const anthropicKey = process.env.ANTHROPIC_API_KEY;
527
495
  providers.push({
528
496
  provider: "anthropic",
529
497
  available: Boolean(anthropicKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
530
498
  mode: anthropicKey ? "byok" : "managed",
531
- 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"]
532
502
  });
533
503
  const mistralKey = process.env.MISTRAL_API_KEY;
534
504
  providers.push({
535
505
  provider: "mistral",
536
506
  available: Boolean(mistralKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
537
507
  mode: mistralKey ? "byok" : "managed",
538
- 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"]
539
511
  });
540
512
  const geminiKey = process.env.GOOGLE_API_KEY ?? process.env.GEMINI_API_KEY;
541
513
  providers.push({
542
514
  provider: "gemini",
543
515
  available: Boolean(geminiKey) || Boolean(process.env.CONTRACTSPEC_AI_PROXY_URL),
544
516
  mode: geminiKey ? "byok" : "managed",
545
- 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"]
546
520
  });
547
521
  return providers;
548
522
  }
package/dist/index.d.ts CHANGED
@@ -7,4 +7,7 @@ export * from './types';
7
7
  export * from './factory';
8
8
  export * from './models';
9
9
  export * from './validation';
10
+ export * from './selector-types';
11
+ export { createModelSelector } from './selector';
12
+ export type { ModelSelectorOptions } from './selector';
10
13
  export { getAIProvider, validateProvider as validateLegacyProvider, } from './legacy';