Add AI model pricing, Bedrock provider, and InferenceProvider/ModelFamily split (#18155)
## Summary - **Model pricing overhaul**: All model constants updated with accurate pricing in dollars per 1M tokens, including cached input rates, cache creation rates, and tiered >200k context pricing - **New providers**: Added Google (Gemini 3.x), Mistral, and AWS Bedrock as inference providers. Bedrock serves Claude Opus 4.6 and Sonnet 4.6 via AWS, with proper credential handling following the existing S3/SES pattern - **InferenceProvider/ModelFamily split**: Refactored `ModelProvider` into two orthogonal enums — `InferenceProvider` (who serves the model: auth, SDK, metadata format) and `ModelFamily` (who created it: token counting semantics). This eliminates growing `||` chains for token normalization checks like `excludesCachedTokens` - **Billing improvements**: Reasoning tokens charged at output rate, cache token discounts applied accurately, real errors thrown to Sentry on billing failures ## Test plan - [x] All existing unit tests updated and passing (23 tests across 3 test files) - [x] Lint passes for both twenty-server and twenty-front - [ ] CI checks pass Made with [Cursor](https://cursor.com) --------- Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+48
-11
@@ -1,12 +1,23 @@
|
||||
export enum ModelProvider {
|
||||
export enum InferenceProvider {
|
||||
NONE = 'none',
|
||||
OPENAI = 'openai',
|
||||
ANTHROPIC = 'anthropic',
|
||||
BEDROCK = 'bedrock',
|
||||
GOOGLE = 'google',
|
||||
MISTRAL = 'mistral',
|
||||
OPENAI_COMPATIBLE = 'open_ai_compatible',
|
||||
XAI = 'xai',
|
||||
GROQ = 'groq',
|
||||
}
|
||||
|
||||
export enum ModelFamily {
|
||||
OPENAI = 'openai',
|
||||
ANTHROPIC = 'anthropic',
|
||||
GOOGLE = 'google',
|
||||
MISTRAL = 'mistral',
|
||||
XAI = 'xai',
|
||||
}
|
||||
|
||||
export const DEFAULT_FAST_MODEL = 'default-fast-model' as const;
|
||||
export const DEFAULT_SMART_MODEL = 'default-smart-model' as const;
|
||||
|
||||
@@ -14,27 +25,41 @@ export type ModelId =
|
||||
| typeof DEFAULT_FAST_MODEL
|
||||
| typeof DEFAULT_SMART_MODEL
|
||||
// OpenAI models
|
||||
| 'gpt-5.2'
|
||||
| 'gpt-5-mini'
|
||||
| 'gpt-4.1'
|
||||
| 'gpt-4.1-mini'
|
||||
| 'gpt-4o'
|
||||
| 'gpt-4o-mini'
|
||||
| 'gpt-4-turbo'
|
||||
| 'gpt-4.1'
|
||||
| 'gpt-4.1-mini'
|
||||
| 'o3'
|
||||
| 'o4-mini'
|
||||
// Anthropic models
|
||||
| 'claude-opus-4-6'
|
||||
| 'claude-sonnet-4-6'
|
||||
| 'claude-sonnet-4-5-20250929'
|
||||
| 'claude-haiku-4-5-20251001'
|
||||
| 'claude-opus-4-5-20251101'
|
||||
| 'claude-opus-4-20250514'
|
||||
| 'claude-sonnet-4-20250514'
|
||||
| 'claude-3-5-haiku-20241022'
|
||||
| 'claude-opus-4-5-20251101'
|
||||
| 'claude-sonnet-4-5-20250929'
|
||||
| 'claude-haiku-4-5-20251001'
|
||||
// xAI models
|
||||
| 'grok-3'
|
||||
| 'grok-3-mini'
|
||||
| 'grok-4'
|
||||
| 'grok-4-1-fast-reasoning'
|
||||
| 'grok-3'
|
||||
| 'grok-3-mini'
|
||||
// Google models
|
||||
| 'gemini-3.1-pro-preview'
|
||||
| 'gemini-3-flash-preview'
|
||||
| 'gemini-2.5-pro'
|
||||
| 'gemini-2.5-flash'
|
||||
// Bedrock models (Anthropic via AWS)
|
||||
| 'anthropic.claude-opus-4-6-v1'
|
||||
| 'anthropic.claude-sonnet-4-6'
|
||||
// Groq models
|
||||
| 'openai/gpt-oss-120b'
|
||||
// Mistral models
|
||||
| 'mistral-large-latest'
|
||||
| string; // Allow custom model names
|
||||
|
||||
export type SupportedFileType =
|
||||
@@ -48,13 +73,25 @@ export type SupportedFileType =
|
||||
| 'text/csv'
|
||||
| 'application/json';
|
||||
|
||||
export type LongContextCost = {
|
||||
inputCostPerMillionTokens: number;
|
||||
outputCostPerMillionTokens: number;
|
||||
cachedInputCostPerMillionTokens?: number;
|
||||
cacheCreationCostPerMillionTokens?: number;
|
||||
thresholdTokens: number;
|
||||
};
|
||||
|
||||
export interface AIModelConfig {
|
||||
modelId: ModelId;
|
||||
label: string;
|
||||
description: string;
|
||||
provider: ModelProvider;
|
||||
inputCostPer1kTokensInCents: number;
|
||||
outputCostPer1kTokensInCents: number;
|
||||
modelFamily: ModelFamily;
|
||||
inferenceProvider: InferenceProvider;
|
||||
inputCostPerMillionTokens: number;
|
||||
outputCostPerMillionTokens: number;
|
||||
cachedInputCostPerMillionTokens?: number;
|
||||
cacheCreationCostPerMillionTokens?: number;
|
||||
longContextCost?: LongContextCost;
|
||||
contextWindowTokens: number;
|
||||
maxOutputTokens: number;
|
||||
supportedFileTypes?: SupportedFileType[];
|
||||
|
||||
+53
-47
@@ -6,21 +6,24 @@ import { AiModelRegistryService } from 'src/engine/metadata-modules/ai/ai-models
|
||||
import {
|
||||
AI_MODELS,
|
||||
DEFAULT_SMART_MODEL,
|
||||
ModelProvider,
|
||||
InferenceProvider,
|
||||
} from './ai-models.const';
|
||||
|
||||
describe('AI_MODELS', () => {
|
||||
it('should have at least one model per provider', () => {
|
||||
const providers = [
|
||||
ModelProvider.OPENAI,
|
||||
ModelProvider.ANTHROPIC,
|
||||
ModelProvider.XAI,
|
||||
ModelProvider.GROQ,
|
||||
it('should have at least one model per inference provider', () => {
|
||||
const inferenceProviders = [
|
||||
InferenceProvider.OPENAI,
|
||||
InferenceProvider.ANTHROPIC,
|
||||
InferenceProvider.BEDROCK,
|
||||
InferenceProvider.GOOGLE,
|
||||
InferenceProvider.XAI,
|
||||
InferenceProvider.GROQ,
|
||||
InferenceProvider.MISTRAL,
|
||||
];
|
||||
|
||||
providers.forEach((provider) => {
|
||||
inferenceProviders.forEach((inferenceProvider) => {
|
||||
const modelsForProvider = AI_MODELS.filter(
|
||||
(model) => model.provider === provider,
|
||||
(model) => model.inferenceProvider === inferenceProvider,
|
||||
);
|
||||
|
||||
expect(modelsForProvider.length).toBeGreaterThan(0);
|
||||
@@ -32,9 +35,10 @@ describe('AI_MODELS', () => {
|
||||
expect(model.modelId).toBeDefined();
|
||||
expect(model.label).toBeDefined();
|
||||
expect(model.description).toBeDefined();
|
||||
expect(model.provider).toBeDefined();
|
||||
expect(model.inputCostPer1kTokensInCents).toBeDefined();
|
||||
expect(model.outputCostPer1kTokensInCents).toBeDefined();
|
||||
expect(model.modelFamily).toBeDefined();
|
||||
expect(model.inferenceProvider).toBeDefined();
|
||||
expect(model.inputCostPerMillionTokens).toBeDefined();
|
||||
expect(model.outputCostPerMillionTokens).toBeDefined();
|
||||
expect(model.contextWindowTokens).toBeGreaterThan(0);
|
||||
expect(model.maxOutputTokens).toBeGreaterThan(0);
|
||||
});
|
||||
@@ -47,17 +51,21 @@ describe('AI_MODELS', () => {
|
||||
expect(uniqueModelIds.size).toBe(modelIds.length);
|
||||
});
|
||||
|
||||
it('should have at least one non-deprecated model per provider', () => {
|
||||
const providers = [
|
||||
ModelProvider.OPENAI,
|
||||
ModelProvider.ANTHROPIC,
|
||||
ModelProvider.XAI,
|
||||
ModelProvider.GROQ,
|
||||
it('should have at least one non-deprecated model per inference provider', () => {
|
||||
const inferenceProviders = [
|
||||
InferenceProvider.OPENAI,
|
||||
InferenceProvider.ANTHROPIC,
|
||||
InferenceProvider.BEDROCK,
|
||||
InferenceProvider.GOOGLE,
|
||||
InferenceProvider.XAI,
|
||||
InferenceProvider.GROQ,
|
||||
InferenceProvider.MISTRAL,
|
||||
];
|
||||
|
||||
providers.forEach((provider) => {
|
||||
inferenceProviders.forEach((inferenceProvider) => {
|
||||
const activeModelsForProvider = AI_MODELS.filter(
|
||||
(model) => model.provider === provider && !model.deprecated,
|
||||
(model) =>
|
||||
model.inferenceProvider === inferenceProvider && !model.deprecated,
|
||||
);
|
||||
|
||||
expect(activeModelsForProvider.length).toBeGreaterThan(0);
|
||||
@@ -88,35 +96,35 @@ describe('AiModelRegistryService', () => {
|
||||
});
|
||||
|
||||
it('should return effective model config for DEFAULT_SMART_MODEL', () => {
|
||||
MOCK_CONFIG_SERVICE.get.mockReturnValue('gpt-4o');
|
||||
MOCK_CONFIG_SERVICE.get.mockReturnValue('gpt-5.2');
|
||||
|
||||
expect(() => SERVICE.getEffectiveModelConfig(DEFAULT_SMART_MODEL)).toThrow(
|
||||
'No AI models are available. Please configure at least one AI provider API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY, or GROQ_API_KEY).',
|
||||
'No AI models are available. Please configure at least one AI provider (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_BEDROCK_REGION, GOOGLE_API_KEY, XAI_API_KEY, GROQ_API_KEY, or MISTRAL_API_KEY).',
|
||||
);
|
||||
});
|
||||
|
||||
it('should return effective model config for DEFAULT_SMART_MODEL when models are available', () => {
|
||||
MOCK_CONFIG_SERVICE.get.mockReturnValue('gpt-4o');
|
||||
MOCK_CONFIG_SERVICE.get.mockReturnValue('gpt-5.2');
|
||||
|
||||
jest.spyOn(SERVICE, 'getAvailableModels').mockReturnValue([
|
||||
{
|
||||
modelId: 'gpt-4o',
|
||||
provider: ModelProvider.OPENAI,
|
||||
modelId: 'gpt-5.2',
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
model: {} as any,
|
||||
},
|
||||
]);
|
||||
|
||||
jest.spyOn(SERVICE, 'getModel').mockReturnValue({
|
||||
modelId: 'gpt-4o',
|
||||
provider: ModelProvider.OPENAI,
|
||||
modelId: 'gpt-5.2',
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
model: {} as any,
|
||||
});
|
||||
|
||||
const RESULT = SERVICE.getEffectiveModelConfig(DEFAULT_SMART_MODEL);
|
||||
|
||||
expect(RESULT).toBeDefined();
|
||||
expect(RESULT.modelId).toBe('gpt-4o');
|
||||
expect(RESULT.provider).toBe(ModelProvider.OPENAI);
|
||||
expect(RESULT.modelId).toBe('gpt-5.2');
|
||||
expect(RESULT.inferenceProvider).toBe(InferenceProvider.OPENAI);
|
||||
});
|
||||
|
||||
it('should return effective model config for DEFAULT_SMART_MODEL with custom model', () => {
|
||||
@@ -125,14 +133,14 @@ describe('AiModelRegistryService', () => {
|
||||
jest.spyOn(SERVICE, 'getAvailableModels').mockReturnValue([
|
||||
{
|
||||
modelId: 'mistral',
|
||||
provider: ModelProvider.OPENAI_COMPATIBLE,
|
||||
inferenceProvider: InferenceProvider.OPENAI_COMPATIBLE,
|
||||
model: {} as any,
|
||||
},
|
||||
]);
|
||||
|
||||
jest.spyOn(SERVICE, 'getModel').mockReturnValue({
|
||||
modelId: 'mistral',
|
||||
provider: ModelProvider.OPENAI_COMPATIBLE,
|
||||
inferenceProvider: InferenceProvider.OPENAI_COMPATIBLE,
|
||||
model: {} as any,
|
||||
});
|
||||
|
||||
@@ -140,25 +148,24 @@ describe('AiModelRegistryService', () => {
|
||||
|
||||
expect(RESULT).toBeDefined();
|
||||
expect(RESULT.modelId).toBe('mistral');
|
||||
expect(RESULT.provider).toBe(ModelProvider.OPENAI_COMPATIBLE);
|
||||
expect(RESULT.inferenceProvider).toBe(InferenceProvider.OPENAI_COMPATIBLE);
|
||||
expect(RESULT.label).toBe('mistral');
|
||||
expect(RESULT.inputCostPer1kTokensInCents).toBe(0);
|
||||
expect(RESULT.outputCostPer1kTokensInCents).toBe(0);
|
||||
expect(RESULT.inputCostPerMillionTokens).toBe(0);
|
||||
expect(RESULT.outputCostPerMillionTokens).toBe(0);
|
||||
});
|
||||
|
||||
it('should return effective model config for specific model', () => {
|
||||
const RESULT = SERVICE.getEffectiveModelConfig('gpt-4o-mini');
|
||||
const RESULT = SERVICE.getEffectiveModelConfig('gpt-5.2');
|
||||
|
||||
expect(RESULT).toBeDefined();
|
||||
expect(RESULT.modelId).toBe('gpt-4o-mini');
|
||||
expect(RESULT.provider).toBe(ModelProvider.OPENAI);
|
||||
expect(RESULT.modelId).toBe('gpt-5.2');
|
||||
expect(RESULT.inferenceProvider).toBe(InferenceProvider.OPENAI);
|
||||
});
|
||||
|
||||
it('should return effective model config for custom model', () => {
|
||||
// Mock that the custom model exists in registry
|
||||
jest.spyOn(SERVICE, 'getModel').mockReturnValue({
|
||||
modelId: 'mistral',
|
||||
provider: ModelProvider.OPENAI_COMPATIBLE,
|
||||
inferenceProvider: InferenceProvider.OPENAI_COMPATIBLE,
|
||||
model: {} as any,
|
||||
});
|
||||
|
||||
@@ -166,10 +173,10 @@ describe('AiModelRegistryService', () => {
|
||||
|
||||
expect(RESULT).toBeDefined();
|
||||
expect(RESULT.modelId).toBe('mistral');
|
||||
expect(RESULT.provider).toBe(ModelProvider.OPENAI_COMPATIBLE);
|
||||
expect(RESULT.inferenceProvider).toBe(InferenceProvider.OPENAI_COMPATIBLE);
|
||||
expect(RESULT.label).toBe('mistral');
|
||||
expect(RESULT.inputCostPer1kTokensInCents).toBe(0);
|
||||
expect(RESULT.outputCostPer1kTokensInCents).toBe(0);
|
||||
expect(RESULT.inputCostPerMillionTokens).toBe(0);
|
||||
expect(RESULT.outputCostPerMillionTokens).toBe(0);
|
||||
});
|
||||
|
||||
it('should throw error for non-existent model', () => {
|
||||
@@ -181,9 +188,8 @@ describe('AiModelRegistryService', () => {
|
||||
});
|
||||
|
||||
it('should find first available model from comma-separated list', () => {
|
||||
// First model not available, second model available
|
||||
MOCK_CONFIG_SERVICE.get.mockReturnValue(
|
||||
'gpt-4.1-mini,claude-haiku-4-5-20251001,grok-3-mini',
|
||||
'gpt-5-mini,claude-haiku-4-5-20251001,gemini-3-flash-preview',
|
||||
);
|
||||
|
||||
const getModelSpy = jest
|
||||
@@ -192,7 +198,7 @@ describe('AiModelRegistryService', () => {
|
||||
if (modelId === 'claude-haiku-4-5-20251001') {
|
||||
return {
|
||||
modelId: 'claude-haiku-4-5-20251001',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
model: {} as any,
|
||||
};
|
||||
}
|
||||
@@ -204,7 +210,7 @@ describe('AiModelRegistryService', () => {
|
||||
|
||||
expect(result).toBeDefined();
|
||||
expect(result.modelId).toBe('claude-haiku-4-5-20251001');
|
||||
expect(getModelSpy).toHaveBeenCalledWith('gpt-4.1-mini');
|
||||
expect(getModelSpy).toHaveBeenCalledWith('gpt-5-mini');
|
||||
expect(getModelSpy).toHaveBeenCalledWith('claude-haiku-4-5-20251001');
|
||||
});
|
||||
|
||||
@@ -215,7 +221,7 @@ describe('AiModelRegistryService', () => {
|
||||
jest.spyOn(SERVICE, 'getAvailableModels').mockReturnValue([
|
||||
{
|
||||
modelId: 'fallback-model',
|
||||
provider: ModelProvider.OPENAI_COMPATIBLE,
|
||||
inferenceProvider: InferenceProvider.OPENAI_COMPATIBLE,
|
||||
model: {} as any,
|
||||
},
|
||||
]);
|
||||
|
||||
+8
-1
@@ -1,7 +1,8 @@
|
||||
export {
|
||||
DEFAULT_FAST_MODEL,
|
||||
DEFAULT_SMART_MODEL,
|
||||
ModelProvider,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
type AIModelConfig,
|
||||
type ModelId,
|
||||
type SupportedFileType,
|
||||
@@ -9,13 +10,19 @@ export {
|
||||
|
||||
import { type AIModelConfig } from './ai-models-types.const';
|
||||
import { ANTHROPIC_MODELS } from './anthropic-models.const';
|
||||
import { BEDROCK_MODELS } from './bedrock-models.const';
|
||||
import { GOOGLE_MODELS } from './google-models.const';
|
||||
import { GROQ_MODELS } from './groq-models.const';
|
||||
import { MISTRAL_MODELS } from './mistral-models.const';
|
||||
import { OPENAI_MODELS } from './openai-models.const';
|
||||
import { XAI_MODELS } from './xai-models.const';
|
||||
|
||||
export const AI_MODELS: AIModelConfig[] = [
|
||||
...OPENAI_MODELS,
|
||||
...ANTHROPIC_MODELS,
|
||||
...BEDROCK_MODELS,
|
||||
...GOOGLE_MODELS,
|
||||
...XAI_MODELS,
|
||||
...GROQ_MODELS,
|
||||
...MISTRAL_MODELS,
|
||||
];
|
||||
|
||||
+164
-54
@@ -1,15 +1,64 @@
|
||||
import { type AIModelConfig, ModelProvider } from './ai-models-types.const';
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
// Active models
|
||||
{
|
||||
modelId: 'claude-opus-4-5-20251101',
|
||||
label: 'Claude Opus 4.5',
|
||||
modelId: 'claude-opus-4-6',
|
||||
label: 'Claude Opus 4.6',
|
||||
description:
|
||||
'Most powerful Claude model excelling in complex reasoning, coding, and agentic tasks',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 0.5,
|
||||
outputCostPer1kTokensInCents: 2.5,
|
||||
'Flagship Claude model for software engineering, scientific reasoning, and agent teams',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 5.0,
|
||||
outputCostPerMillionTokens: 25.0,
|
||||
cachedInputCostPerMillionTokens: 0.5,
|
||||
cacheCreationCostPerMillionTokens: 6.25,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 10.0,
|
||||
outputCostPerMillionTokens: 37.5,
|
||||
cachedInputCostPerMillionTokens: 1.0,
|
||||
cacheCreationCostPerMillionTokens: 12.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 1000000,
|
||||
maxOutputTokens: 128000,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'claude-sonnet-4-6',
|
||||
label: 'Claude Sonnet 4.6',
|
||||
description:
|
||||
'Most capable Sonnet model with strong coding, computer use, and agent planning',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.3,
|
||||
cacheCreationCostPerMillionTokens: 3.75,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 6.0,
|
||||
outputCostPerMillionTokens: 22.5,
|
||||
cachedInputCostPerMillionTokens: 0.6,
|
||||
cacheCreationCostPerMillionTokens: 7.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 64000,
|
||||
supportedFileTypes: [
|
||||
@@ -31,10 +80,20 @@ export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
modelId: 'claude-sonnet-4-5-20250929',
|
||||
label: 'Claude Sonnet 4.5',
|
||||
description:
|
||||
'Advanced model for coding tasks and complex agent-based workflows with 1M context',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 0.3,
|
||||
outputCostPer1kTokensInCents: 1.5,
|
||||
'Previous gen Sonnet with 1M native context for long-context workflows',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.3,
|
||||
cacheCreationCostPerMillionTokens: 3.75,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 6.0,
|
||||
outputCostPerMillionTokens: 22.5,
|
||||
cachedInputCostPerMillionTokens: 0.6,
|
||||
cacheCreationCostPerMillionTokens: 7.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 1000000,
|
||||
maxOutputTokens: 64000,
|
||||
supportedFileTypes: [
|
||||
@@ -55,11 +114,13 @@ export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'claude-haiku-4-5-20251001',
|
||||
label: 'Claude Haiku 4.5',
|
||||
description:
|
||||
'Fast and cost-effective model optimized for high-speed processing',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 0.1,
|
||||
outputCostPer1kTokensInCents: 0.5,
|
||||
description: 'Fast and cost-effective model for high-speed processing',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 1.0,
|
||||
outputCostPerMillionTokens: 5.0,
|
||||
cachedInputCostPerMillionTokens: 0.1,
|
||||
cacheCreationCostPerMillionTokens: 1.25,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 64000,
|
||||
supportedFileTypes: [
|
||||
@@ -77,43 +138,27 @@ export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'claude-3-5-haiku-20241022',
|
||||
label: 'Claude Haiku 3.5',
|
||||
description:
|
||||
'Fast and efficient model optimized for speed and cost-effectiveness',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 0.08,
|
||||
outputCostPer1kTokensInCents: 0.4,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: false,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Deprecated models - kept for backward compatibility with existing agents
|
||||
{
|
||||
modelId: 'claude-opus-4-20250514',
|
||||
label: 'Claude Opus 4',
|
||||
description:
|
||||
'Most powerful Claude model with extended thinking for complex reasoning tasks',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 1.5,
|
||||
outputCostPer1kTokensInCents: 7.5,
|
||||
modelId: 'claude-opus-4-5-20251101',
|
||||
label: 'Claude Opus 4.5',
|
||||
description: 'Previous flagship model superseded by Opus 4.6',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 5.0,
|
||||
outputCostPerMillionTokens: 25.0,
|
||||
cachedInputCostPerMillionTokens: 0.5,
|
||||
cacheCreationCostPerMillionTokens: 6.25,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 10.0,
|
||||
outputCostPerMillionTokens: 37.5,
|
||||
cachedInputCostPerMillionTokens: 1.0,
|
||||
cacheCreationCostPerMillionTokens: 12.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 8192,
|
||||
maxOutputTokens: 64000,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
@@ -133,11 +178,20 @@ export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'claude-sonnet-4-20250514',
|
||||
label: 'Claude Sonnet 4',
|
||||
description:
|
||||
'Balanced model with strong performance and extended thinking capabilities',
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inputCostPer1kTokensInCents: 0.3,
|
||||
outputCostPer1kTokensInCents: 1.5,
|
||||
description: 'Previous gen Sonnet superseded by Sonnet 4.6',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.3,
|
||||
cacheCreationCostPerMillionTokens: 3.75,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 6.0,
|
||||
outputCostPerMillionTokens: 22.5,
|
||||
cachedInputCostPerMillionTokens: 0.6,
|
||||
cacheCreationCostPerMillionTokens: 7.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: [
|
||||
@@ -156,4 +210,60 @@ export const ANTHROPIC_MODELS: AIModelConfig[] = [
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
{
|
||||
modelId: 'claude-opus-4-20250514',
|
||||
label: 'Claude Opus 4',
|
||||
description: 'Legacy Opus model with extended thinking',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 15.0,
|
||||
outputCostPerMillionTokens: 75.0,
|
||||
cachedInputCostPerMillionTokens: 1.5,
|
||||
cacheCreationCostPerMillionTokens: 18.75,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
{
|
||||
modelId: 'claude-3-5-haiku-20241022',
|
||||
label: 'Claude Haiku 3.5',
|
||||
description: 'Legacy fast model superseded by Haiku 4.5',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
inputCostPerMillionTokens: 0.8,
|
||||
outputCostPerMillionTokens: 4.0,
|
||||
cachedInputCostPerMillionTokens: 0.08,
|
||||
cacheCreationCostPerMillionTokens: 1.0,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: false,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
];
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const BEDROCK_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'anthropic.claude-opus-4-6-v1',
|
||||
label: 'Claude Opus 4.6 (Bedrock)',
|
||||
description:
|
||||
'Flagship Claude model via AWS Bedrock for enterprise deployments',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.BEDROCK,
|
||||
inputCostPerMillionTokens: 5.0,
|
||||
outputCostPerMillionTokens: 25.0,
|
||||
cachedInputCostPerMillionTokens: 0.5,
|
||||
cacheCreationCostPerMillionTokens: 6.25,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 10.0,
|
||||
outputCostPerMillionTokens: 37.5,
|
||||
cachedInputCostPerMillionTokens: 1.0,
|
||||
cacheCreationCostPerMillionTokens: 12.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 1000000,
|
||||
maxOutputTokens: 128000,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'anthropic.claude-sonnet-4-6',
|
||||
label: 'Claude Sonnet 4.6 (Bedrock)',
|
||||
description:
|
||||
'Balanced Claude model via AWS Bedrock with strong coding and agent planning',
|
||||
modelFamily: ModelFamily.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.BEDROCK,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.3,
|
||||
cacheCreationCostPerMillionTokens: 3.75,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 6.0,
|
||||
outputCostPerMillionTokens: 22.5,
|
||||
cachedInputCostPerMillionTokens: 0.6,
|
||||
cacheCreationCostPerMillionTokens: 7.5,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 64000,
|
||||
supportedFileTypes: [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/gif',
|
||||
'image/webp',
|
||||
'application/pdf',
|
||||
'text/plain',
|
||||
'text/html',
|
||||
'text/csv',
|
||||
],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
];
|
||||
+81
@@ -0,0 +1,81 @@
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const GOOGLE_MODELS: AIModelConfig[] = [
|
||||
// Active models
|
||||
{
|
||||
modelId: 'gemini-3.1-pro-preview',
|
||||
label: 'Gemini 3.1 Pro',
|
||||
description:
|
||||
'Most advanced Gemini model for reasoning, coding, and agentic workflows',
|
||||
modelFamily: ModelFamily.GOOGLE,
|
||||
inferenceProvider: InferenceProvider.GOOGLE,
|
||||
inputCostPerMillionTokens: 2.0,
|
||||
outputCostPerMillionTokens: 12.0,
|
||||
cachedInputCostPerMillionTokens: 0.2,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 4.0,
|
||||
outputCostPerMillionTokens: 18.0,
|
||||
cachedInputCostPerMillionTokens: 0.4,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 1048576,
|
||||
maxOutputTokens: 65536,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
},
|
||||
{
|
||||
modelId: 'gemini-3-flash-preview',
|
||||
label: 'Gemini 3 Flash',
|
||||
description: 'Fast frontier-class Gemini model at low cost with 1M context',
|
||||
modelFamily: ModelFamily.GOOGLE,
|
||||
inferenceProvider: InferenceProvider.GOOGLE,
|
||||
inputCostPerMillionTokens: 0.5,
|
||||
outputCostPerMillionTokens: 3.0,
|
||||
cachedInputCostPerMillionTokens: 0.05,
|
||||
contextWindowTokens: 1048576,
|
||||
maxOutputTokens: 65536,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
},
|
||||
|
||||
// Deprecated models - kept for backward compatibility with existing agents
|
||||
{
|
||||
modelId: 'gemini-2.5-pro',
|
||||
label: 'Gemini 2.5 Pro',
|
||||
description: 'Previous gen Gemini Pro superseded by 3.1 Pro',
|
||||
modelFamily: ModelFamily.GOOGLE,
|
||||
inferenceProvider: InferenceProvider.GOOGLE,
|
||||
inputCostPerMillionTokens: 1.25,
|
||||
outputCostPerMillionTokens: 10.0,
|
||||
cachedInputCostPerMillionTokens: 0.315,
|
||||
longContextCost: {
|
||||
inputCostPerMillionTokens: 2.5,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
thresholdTokens: 200_000,
|
||||
},
|
||||
contextWindowTokens: 1048576,
|
||||
maxOutputTokens: 65536,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
deprecated: true,
|
||||
},
|
||||
{
|
||||
modelId: 'gemini-2.5-flash',
|
||||
label: 'Gemini 2.5 Flash',
|
||||
description: 'Previous gen Flash superseded by Gemini 3 Flash',
|
||||
modelFamily: ModelFamily.GOOGLE,
|
||||
inferenceProvider: InferenceProvider.GOOGLE,
|
||||
inputCostPerMillionTokens: 0.3,
|
||||
outputCostPerMillionTokens: 2.5,
|
||||
cachedInputCostPerMillionTokens: 0.075,
|
||||
contextWindowTokens: 1048576,
|
||||
maxOutputTokens: 65536,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
deprecated: true,
|
||||
},
|
||||
];
|
||||
+11
-5
@@ -1,14 +1,20 @@
|
||||
import { type AIModelConfig, ModelProvider } from './ai-models-types.const';
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const GROQ_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'openai/gpt-oss-120b',
|
||||
label: 'GPT-OSS 120B (Groq)',
|
||||
description:
|
||||
'Large-scale open-source model with browser search, served via Groq inference',
|
||||
provider: ModelProvider.GROQ,
|
||||
inputCostPer1kTokensInCents: 0.059,
|
||||
outputCostPer1kTokensInCents: 0.079,
|
||||
'Large-scale open-source model with ultra-fast inference via Groq',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.GROQ,
|
||||
inputCostPerMillionTokens: 0.15,
|
||||
outputCostPerMillionTokens: 0.6,
|
||||
cachedInputCostPerMillionTokens: 0.075,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 16384,
|
||||
},
|
||||
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const MISTRAL_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'mistral-large-latest',
|
||||
label: 'Mistral Large',
|
||||
description:
|
||||
'Flagship Mistral model with strong reasoning and 256K context',
|
||||
modelFamily: ModelFamily.MISTRAL,
|
||||
inferenceProvider: InferenceProvider.MISTRAL,
|
||||
inputCostPerMillionTokens: 0.5,
|
||||
outputCostPerMillionTokens: 1.5,
|
||||
contextWindowTokens: 256000,
|
||||
maxOutputTokens: 8192,
|
||||
},
|
||||
];
|
||||
+84
-38
@@ -1,15 +1,54 @@
|
||||
import { type AIModelConfig, ModelProvider } from './ai-models-types.const';
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
// Active models
|
||||
{
|
||||
modelId: 'gpt-5.2',
|
||||
label: 'GPT-5.2',
|
||||
description:
|
||||
'Most advanced OpenAI model for coding, agentic tasks, and complex reasoning',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 1.75,
|
||||
outputCostPerMillionTokens: 14.0,
|
||||
cachedInputCostPerMillionTokens: 0.175,
|
||||
contextWindowTokens: 400000,
|
||||
maxOutputTokens: 128000,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'gpt-5-mini',
|
||||
label: 'GPT-5 Mini',
|
||||
description: 'Fast and cost-efficient GPT-5 variant for well-defined tasks',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 0.25,
|
||||
outputCostPerMillionTokens: 2.0,
|
||||
cachedInputCostPerMillionTokens: 0.025,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 32768,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'gpt-4.1',
|
||||
label: 'GPT-4.1',
|
||||
description:
|
||||
'Advanced model excelling in coding, instruction following, and long-context comprehension',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.2,
|
||||
outputCostPer1kTokensInCents: 0.8,
|
||||
description: 'Strong model with 1M context, cost-effective output pricing',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 2.0,
|
||||
outputCostPerMillionTokens: 8.0,
|
||||
cachedInputCostPerMillionTokens: 0.5,
|
||||
contextWindowTokens: 1047576,
|
||||
maxOutputTokens: 32768,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -20,11 +59,12 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'gpt-4.1-mini',
|
||||
label: 'GPT-4.1 Mini',
|
||||
description:
|
||||
'Fast and cost-efficient version of GPT-4.1 optimized for low latency',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.04,
|
||||
outputCostPer1kTokensInCents: 0.16,
|
||||
description: 'Budget-friendly model with 1M context for lightweight tasks',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 0.4,
|
||||
outputCostPerMillionTokens: 1.6,
|
||||
cachedInputCostPerMillionTokens: 0.1,
|
||||
contextWindowTokens: 1047576,
|
||||
maxOutputTokens: 32768,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -32,14 +72,18 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
webSearch: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Deprecated models - kept for backward compatibility with existing agents
|
||||
{
|
||||
modelId: 'o3',
|
||||
label: 'o3',
|
||||
description:
|
||||
'Powerful reasoning model excelling in complex queries, coding, math, and science',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.2,
|
||||
outputCostPer1kTokensInCents: 0.8,
|
||||
'Reasoning model for complex queries, coding, math, and science',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 2.0,
|
||||
outputCostPerMillionTokens: 8.0,
|
||||
cachedInputCostPerMillionTokens: 0.5,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 100000,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -47,15 +91,18 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
{
|
||||
modelId: 'o4-mini',
|
||||
label: 'o4-mini',
|
||||
description:
|
||||
'Cost-effective reasoning model excelling in math, coding, and visual tasks',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.11,
|
||||
outputCostPer1kTokensInCents: 0.44,
|
||||
'Cost-effective reasoning model for math, coding, and visual tasks',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 1.1,
|
||||
outputCostPerMillionTokens: 4.4,
|
||||
cachedInputCostPerMillionTokens: 0.275,
|
||||
contextWindowTokens: 200000,
|
||||
maxOutputTokens: 100000,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -63,17 +110,18 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
|
||||
// Deprecated models - kept for backward compatibility with existing agents
|
||||
{
|
||||
modelId: 'gpt-4o',
|
||||
label: 'GPT-4o',
|
||||
description:
|
||||
'Most advanced multimodal model with strong reasoning, vision, and coding capabilities',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.25,
|
||||
outputCostPer1kTokensInCents: 1.0,
|
||||
'Previous generation multimodal model with strong reasoning and vision',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 2.5,
|
||||
outputCostPerMillionTokens: 10.0,
|
||||
cachedInputCostPerMillionTokens: 1.25,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 16384,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -85,11 +133,12 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'gpt-4o-mini',
|
||||
label: 'GPT-4o Mini',
|
||||
description:
|
||||
'Fast and cost-efficient model for lightweight tasks and high-volume operations',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 0.015,
|
||||
outputCostPer1kTokensInCents: 0.06,
|
||||
description: 'Previous generation fast model for lightweight tasks',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 0.15,
|
||||
outputCostPerMillionTokens: 0.6,
|
||||
cachedInputCostPerMillionTokens: 0.075,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 16384,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -101,17 +150,14 @@ export const OPENAI_MODELS: AIModelConfig[] = [
|
||||
{
|
||||
modelId: 'gpt-4-turbo',
|
||||
label: 'GPT-4 Turbo',
|
||||
description:
|
||||
'Previous generation high-performance model with vision capabilities',
|
||||
provider: ModelProvider.OPENAI,
|
||||
inputCostPer1kTokensInCents: 1.0,
|
||||
outputCostPer1kTokensInCents: 3.0,
|
||||
description: 'Legacy high-performance model with vision capabilities',
|
||||
modelFamily: ModelFamily.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
inputCostPerMillionTokens: 10.0,
|
||||
outputCostPerMillionTokens: 30.0,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 4096,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
nativeCapabilities: {
|
||||
webSearch: false,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
];
|
||||
|
||||
+43
-27
@@ -1,32 +1,21 @@
|
||||
import { type AIModelConfig, ModelProvider } from './ai-models-types.const';
|
||||
import {
|
||||
type AIModelConfig,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
} from './ai-models-types.const';
|
||||
|
||||
export const XAI_MODELS: AIModelConfig[] = [
|
||||
// Active models
|
||||
{
|
||||
modelId: 'grok-4-1-fast-reasoning',
|
||||
label: 'Grok 4.1 Fast',
|
||||
description:
|
||||
'Next-generation tool-calling agent with 2M context for advanced agentic workflows',
|
||||
provider: ModelProvider.XAI,
|
||||
inputCostPer1kTokensInCents: 0.02,
|
||||
outputCostPer1kTokensInCents: 0.05,
|
||||
contextWindowTokens: 2000000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
twitterSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'grok-4',
|
||||
label: 'Grok-4',
|
||||
description:
|
||||
'Most capable Grok model with enhanced reasoning, web and Twitter search',
|
||||
provider: ModelProvider.XAI,
|
||||
inputCostPer1kTokensInCents: 0.3,
|
||||
outputCostPer1kTokensInCents: 1.5,
|
||||
modelFamily: ModelFamily.XAI,
|
||||
inferenceProvider: InferenceProvider.XAI,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.75,
|
||||
contextWindowTokens: 256000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -35,14 +24,37 @@ export const XAI_MODELS: AIModelConfig[] = [
|
||||
twitterSearch: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
modelId: 'grok-4-1-fast-reasoning',
|
||||
label: 'Grok 4.1 Fast',
|
||||
description:
|
||||
'Next-generation tool-calling agent with 2M context for advanced agentic workflows',
|
||||
modelFamily: ModelFamily.XAI,
|
||||
inferenceProvider: InferenceProvider.XAI,
|
||||
inputCostPerMillionTokens: 0.2,
|
||||
outputCostPerMillionTokens: 0.5,
|
||||
cachedInputCostPerMillionTokens: 0.05,
|
||||
contextWindowTokens: 2000000,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
doesSupportThinking: true,
|
||||
nativeCapabilities: {
|
||||
webSearch: true,
|
||||
twitterSearch: true,
|
||||
},
|
||||
},
|
||||
|
||||
// Deprecated models - kept for backward compatibility with existing agents
|
||||
{
|
||||
modelId: 'grok-3',
|
||||
label: 'Grok-3',
|
||||
description:
|
||||
'Advanced model with web and Twitter search, optimized for real-time information',
|
||||
provider: ModelProvider.XAI,
|
||||
inputCostPer1kTokensInCents: 0.3,
|
||||
outputCostPer1kTokensInCents: 1.5,
|
||||
modelFamily: ModelFamily.XAI,
|
||||
inferenceProvider: InferenceProvider.XAI,
|
||||
inputCostPerMillionTokens: 3.0,
|
||||
outputCostPerMillionTokens: 15.0,
|
||||
cachedInputCostPerMillionTokens: 0.75,
|
||||
contextWindowTokens: 131072,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -50,15 +62,18 @@ export const XAI_MODELS: AIModelConfig[] = [
|
||||
webSearch: true,
|
||||
twitterSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
{
|
||||
modelId: 'grok-3-mini',
|
||||
label: 'Grok-3 Mini',
|
||||
description:
|
||||
'Lightweight model with web and Twitter search for fast, cost-effective operations',
|
||||
provider: ModelProvider.XAI,
|
||||
inputCostPer1kTokensInCents: 0.03,
|
||||
outputCostPer1kTokensInCents: 0.05,
|
||||
modelFamily: ModelFamily.XAI,
|
||||
inferenceProvider: InferenceProvider.XAI,
|
||||
inputCostPerMillionTokens: 0.3,
|
||||
outputCostPerMillionTokens: 0.5,
|
||||
cachedInputCostPerMillionTokens: 0.07,
|
||||
contextWindowTokens: 131072,
|
||||
maxOutputTokens: 8192,
|
||||
supportedFileTypes: ['image/png', 'image/jpeg', 'image/gif', 'image/webp'],
|
||||
@@ -66,5 +81,6 @@ export const XAI_MODELS: AIModelConfig[] = [
|
||||
webSearch: true,
|
||||
twitterSearch: true,
|
||||
},
|
||||
deprecated: true,
|
||||
},
|
||||
];
|
||||
|
||||
+43
-9
@@ -6,23 +6,30 @@ import { ProviderOptions } from '@ai-sdk/provider-utils';
|
||||
import { ToolSet } from 'ai';
|
||||
|
||||
import { AGENT_CONFIG } from 'src/engine/metadata-modules/ai/ai-agent/constants/agent-config.const';
|
||||
import { ModelProvider } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { RegisteredAIModel } from 'src/engine/metadata-modules/ai/ai-models/services/ai-model-registry.service';
|
||||
import { InferenceProvider } from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import {
|
||||
AiModelRegistryService,
|
||||
RegisteredAIModel,
|
||||
} from 'src/engine/metadata-modules/ai/ai-models/services/ai-model-registry.service';
|
||||
import { FlatAgentWithRoleId } from 'src/engine/metadata-modules/flat-agent/types/flat-agent.type';
|
||||
|
||||
@Injectable()
|
||||
export class AgentModelConfigService {
|
||||
constructor() {}
|
||||
constructor(
|
||||
private readonly aiModelRegistryService: AiModelRegistryService,
|
||||
) {}
|
||||
|
||||
getProviderOptions(
|
||||
model: RegisteredAIModel,
|
||||
agent: FlatAgentWithRoleId,
|
||||
): ProviderOptions {
|
||||
switch (model.provider) {
|
||||
case ModelProvider.XAI:
|
||||
switch (model.inferenceProvider) {
|
||||
case InferenceProvider.XAI:
|
||||
return this.getXaiProviderOptions(agent);
|
||||
case ModelProvider.ANTHROPIC:
|
||||
case InferenceProvider.ANTHROPIC:
|
||||
return this.getAnthropicProviderOptions(model);
|
||||
case InferenceProvider.BEDROCK:
|
||||
return this.getBedrockProviderOptions(model);
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
@@ -38,13 +45,25 @@ export class AgentModelConfigService {
|
||||
return tools;
|
||||
}
|
||||
|
||||
switch (model.provider) {
|
||||
case ModelProvider.ANTHROPIC:
|
||||
switch (model.inferenceProvider) {
|
||||
case InferenceProvider.ANTHROPIC:
|
||||
if (agent.modelConfiguration.webSearch?.enabled) {
|
||||
tools.web_search = anthropic.tools.webSearch_20250305();
|
||||
}
|
||||
break;
|
||||
case ModelProvider.OPENAI:
|
||||
case InferenceProvider.BEDROCK: {
|
||||
if (agent.modelConfiguration.webSearch?.enabled) {
|
||||
const bedrockProvider =
|
||||
this.aiModelRegistryService.getBedrockProvider();
|
||||
|
||||
if (bedrockProvider) {
|
||||
tools.web_search =
|
||||
bedrockProvider.tools.webSearch_20250305() as ToolSet[string];
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case InferenceProvider.OPENAI:
|
||||
if (agent.modelConfiguration.webSearch?.enabled) {
|
||||
tools.web_search = openai.tools.webSearch();
|
||||
}
|
||||
@@ -99,4 +118,19 @@ export class AgentModelConfigService {
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getBedrockProviderOptions(model: RegisteredAIModel): ProviderOptions {
|
||||
if (!model.doesSupportThinking) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return {
|
||||
bedrock: {
|
||||
thinking: {
|
||||
type: 'enabled',
|
||||
budgetTokens: AGENT_CONFIG.REASONING_BUDGET_TOKENS,
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
+129
-23
@@ -1,7 +1,13 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import {
|
||||
createAmazonBedrock,
|
||||
type AmazonBedrockProvider,
|
||||
} from '@ai-sdk/amazon-bedrock';
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { google } from '@ai-sdk/google';
|
||||
import { groq } from '@ai-sdk/groq';
|
||||
import { mistral } from '@ai-sdk/mistral';
|
||||
import { createOpenAI, openai } from '@ai-sdk/openai';
|
||||
import { xai } from '@ai-sdk/xai';
|
||||
import { type LanguageModel } from 'ai';
|
||||
@@ -15,17 +21,21 @@ import {
|
||||
AI_MODELS,
|
||||
DEFAULT_FAST_MODEL,
|
||||
DEFAULT_SMART_MODEL,
|
||||
ModelProvider,
|
||||
InferenceProvider,
|
||||
ModelFamily,
|
||||
type AIModelConfig,
|
||||
} from 'src/engine/metadata-modules/ai/ai-models/constants/ai-models.const';
|
||||
import { ANTHROPIC_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/anthropic-models.const';
|
||||
import { BEDROCK_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/bedrock-models.const';
|
||||
import { GOOGLE_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/google-models.const';
|
||||
import { GROQ_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/groq-models.const';
|
||||
import { MISTRAL_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/mistral-models.const';
|
||||
import { OPENAI_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/openai-models.const';
|
||||
import { XAI_MODELS } from 'src/engine/metadata-modules/ai/ai-models/constants/xai-models.const';
|
||||
|
||||
export interface RegisteredAIModel {
|
||||
modelId: string;
|
||||
provider: ModelProvider;
|
||||
inferenceProvider: InferenceProvider;
|
||||
model: LanguageModel;
|
||||
doesSupportThinking?: boolean;
|
||||
}
|
||||
@@ -33,13 +43,19 @@ export interface RegisteredAIModel {
|
||||
@Injectable()
|
||||
export class AiModelRegistryService {
|
||||
private modelRegistry: Map<string, RegisteredAIModel> = new Map();
|
||||
private bedrockProvider: AmazonBedrockProvider | null = null;
|
||||
|
||||
constructor(private twentyConfigService: TwentyConfigService) {
|
||||
this.buildModelRegistry();
|
||||
}
|
||||
|
||||
getBedrockProvider(): AmazonBedrockProvider | null {
|
||||
return this.bedrockProvider;
|
||||
}
|
||||
|
||||
private buildModelRegistry(): void {
|
||||
this.modelRegistry.clear();
|
||||
this.bedrockProvider = null;
|
||||
|
||||
const openaiApiKey = this.twentyConfigService.get('OPENAI_API_KEY');
|
||||
|
||||
@@ -65,6 +81,24 @@ export class AiModelRegistryService {
|
||||
this.registerGroqModels();
|
||||
}
|
||||
|
||||
const googleApiKey = this.twentyConfigService.get('GOOGLE_API_KEY');
|
||||
|
||||
if (googleApiKey) {
|
||||
this.registerGoogleModels();
|
||||
}
|
||||
|
||||
const mistralApiKey = this.twentyConfigService.get('MISTRAL_API_KEY');
|
||||
|
||||
if (mistralApiKey) {
|
||||
this.registerMistralModels();
|
||||
}
|
||||
|
||||
const bedrockRegion = this.twentyConfigService.get('AWS_BEDROCK_REGION');
|
||||
|
||||
if (bedrockRegion) {
|
||||
this.registerBedrockModels(bedrockRegion);
|
||||
}
|
||||
|
||||
const openaiCompatibleBaseUrl = this.twentyConfigService.get(
|
||||
'OPENAI_COMPATIBLE_BASE_URL',
|
||||
);
|
||||
@@ -84,7 +118,7 @@ export class AiModelRegistryService {
|
||||
OPENAI_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
provider: ModelProvider.OPENAI,
|
||||
inferenceProvider: InferenceProvider.OPENAI,
|
||||
model: openai(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
@@ -95,7 +129,7 @@ export class AiModelRegistryService {
|
||||
ANTHROPIC_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
provider: ModelProvider.ANTHROPIC,
|
||||
inferenceProvider: InferenceProvider.ANTHROPIC,
|
||||
model: anthropic(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
@@ -106,7 +140,7 @@ export class AiModelRegistryService {
|
||||
XAI_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
provider: ModelProvider.XAI,
|
||||
inferenceProvider: InferenceProvider.XAI,
|
||||
model: xai(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
@@ -117,13 +151,63 @@ export class AiModelRegistryService {
|
||||
GROQ_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
provider: ModelProvider.GROQ,
|
||||
inferenceProvider: InferenceProvider.GROQ,
|
||||
model: groq(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private registerGoogleModels(): void {
|
||||
GOOGLE_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
inferenceProvider: InferenceProvider.GOOGLE,
|
||||
model: google(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private registerMistralModels(): void {
|
||||
MISTRAL_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
inferenceProvider: InferenceProvider.MISTRAL,
|
||||
model: mistral(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private registerBedrockModels(region: string): void {
|
||||
const accessKeyId = this.twentyConfigService.get(
|
||||
'AWS_BEDROCK_ACCESS_KEY_ID',
|
||||
);
|
||||
const secretAccessKey = this.twentyConfigService.get(
|
||||
'AWS_BEDROCK_SECRET_ACCESS_KEY',
|
||||
);
|
||||
const sessionToken = this.twentyConfigService.get(
|
||||
'AWS_BEDROCK_SESSION_TOKEN',
|
||||
);
|
||||
|
||||
this.bedrockProvider = createAmazonBedrock({
|
||||
region,
|
||||
...(accessKeyId && secretAccessKey
|
||||
? { accessKeyId, secretAccessKey, sessionToken }
|
||||
: {}),
|
||||
});
|
||||
|
||||
BEDROCK_MODELS.forEach((modelConfig) => {
|
||||
this.modelRegistry.set(modelConfig.modelId, {
|
||||
modelId: modelConfig.modelId,
|
||||
inferenceProvider: InferenceProvider.BEDROCK,
|
||||
model: this.bedrockProvider!(modelConfig.modelId),
|
||||
doesSupportThinking: modelConfig.doesSupportThinking,
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private registerOpenAICompatibleModels(
|
||||
baseUrl: string,
|
||||
modelNamesString: string,
|
||||
@@ -142,7 +226,7 @@ export class AiModelRegistryService {
|
||||
modelNames.forEach((modelId) => {
|
||||
this.modelRegistry.set(modelId, {
|
||||
modelId,
|
||||
provider: ModelProvider.OPENAI_COMPATIBLE,
|
||||
inferenceProvider: InferenceProvider.OPENAI_COMPATIBLE,
|
||||
model: provider(modelId),
|
||||
});
|
||||
});
|
||||
@@ -189,7 +273,7 @@ export class AiModelRegistryService {
|
||||
|
||||
if (!model) {
|
||||
throw new AgentException(
|
||||
'No AI models are available. Please configure at least one AI provider API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY, or GROQ_API_KEY).',
|
||||
'No AI models are available. Please configure at least one AI provider (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_BEDROCK_REGION, GOOGLE_API_KEY, XAI_API_KEY, GROQ_API_KEY, or MISTRAL_API_KEY).',
|
||||
AgentExceptionCode.API_KEY_NOT_CONFIGURED,
|
||||
);
|
||||
}
|
||||
@@ -211,7 +295,7 @@ export class AiModelRegistryService {
|
||||
|
||||
if (!model) {
|
||||
throw new AgentException(
|
||||
'No AI models are available. Please configure at least one AI provider API key (OPENAI_API_KEY, ANTHROPIC_API_KEY, XAI_API_KEY, or GROQ_API_KEY).',
|
||||
'No AI models are available. Please configure at least one AI provider (OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_BEDROCK_REGION, GOOGLE_API_KEY, XAI_API_KEY, GROQ_API_KEY, or MISTRAL_API_KEY).',
|
||||
AgentExceptionCode.API_KEY_NOT_CONFIGURED,
|
||||
);
|
||||
}
|
||||
@@ -221,7 +305,6 @@ export class AiModelRegistryService {
|
||||
|
||||
getEffectiveModelConfig(modelId: string): AIModelConfig {
|
||||
if (modelId === DEFAULT_FAST_MODEL || modelId === DEFAULT_SMART_MODEL) {
|
||||
// getDefaultSpeedModel/getDefaultPerformanceModel will throw AgentException if no models available
|
||||
const defaultModel =
|
||||
modelId === DEFAULT_FAST_MODEL
|
||||
? this.getDefaultSpeedModel()
|
||||
@@ -265,15 +348,29 @@ export class AiModelRegistryService {
|
||||
modelId: registeredModel.modelId,
|
||||
label: registeredModel.modelId,
|
||||
description: `Custom model: ${registeredModel.modelId}`,
|
||||
provider: registeredModel.provider,
|
||||
inputCostPer1kTokensInCents: 0,
|
||||
outputCostPer1kTokensInCents: 0,
|
||||
modelFamily: this.inferModelFamily(registeredModel.inferenceProvider),
|
||||
inferenceProvider: registeredModel.inferenceProvider,
|
||||
inputCostPerMillionTokens: 0,
|
||||
outputCostPerMillionTokens: 0,
|
||||
contextWindowTokens: 128000,
|
||||
maxOutputTokens: 4096,
|
||||
};
|
||||
}
|
||||
|
||||
// Force refresh the registry (useful if config changes)
|
||||
private inferModelFamily(inferenceProvider: InferenceProvider): ModelFamily {
|
||||
const providerToFamily: Partial<Record<InferenceProvider, ModelFamily>> = {
|
||||
[InferenceProvider.OPENAI]: ModelFamily.OPENAI,
|
||||
[InferenceProvider.ANTHROPIC]: ModelFamily.ANTHROPIC,
|
||||
[InferenceProvider.BEDROCK]: ModelFamily.ANTHROPIC,
|
||||
[InferenceProvider.GOOGLE]: ModelFamily.GOOGLE,
|
||||
[InferenceProvider.MISTRAL]: ModelFamily.MISTRAL,
|
||||
[InferenceProvider.XAI]: ModelFamily.XAI,
|
||||
[InferenceProvider.GROQ]: ModelFamily.OPENAI,
|
||||
};
|
||||
|
||||
return providerToFamily[inferenceProvider] ?? ModelFamily.OPENAI;
|
||||
}
|
||||
|
||||
refreshRegistry(): void {
|
||||
this.buildModelRegistry();
|
||||
}
|
||||
@@ -283,7 +380,7 @@ export class AiModelRegistryService {
|
||||
agent?.modelId ?? DEFAULT_SMART_MODEL,
|
||||
);
|
||||
|
||||
await this.validateApiKey(aiModel.provider);
|
||||
await this.validateApiKey(aiModel.inferenceProvider);
|
||||
const registeredModel = this.getModel(aiModel.modelId);
|
||||
|
||||
if (!registeredModel) {
|
||||
@@ -296,23 +393,32 @@ export class AiModelRegistryService {
|
||||
return registeredModel;
|
||||
}
|
||||
|
||||
async validateApiKey(provider: ModelProvider): Promise<void> {
|
||||
async validateApiKey(inferenceProvider: InferenceProvider): Promise<void> {
|
||||
let apiKey: string | undefined;
|
||||
|
||||
switch (provider) {
|
||||
case ModelProvider.OPENAI:
|
||||
switch (inferenceProvider) {
|
||||
case InferenceProvider.OPENAI:
|
||||
apiKey = this.twentyConfigService.get('OPENAI_API_KEY');
|
||||
break;
|
||||
case ModelProvider.ANTHROPIC:
|
||||
case InferenceProvider.ANTHROPIC:
|
||||
apiKey = this.twentyConfigService.get('ANTHROPIC_API_KEY');
|
||||
break;
|
||||
case ModelProvider.XAI:
|
||||
case InferenceProvider.XAI:
|
||||
apiKey = this.twentyConfigService.get('XAI_API_KEY');
|
||||
break;
|
||||
case ModelProvider.GROQ:
|
||||
case InferenceProvider.GROQ:
|
||||
apiKey = this.twentyConfigService.get('GROQ_API_KEY');
|
||||
break;
|
||||
case ModelProvider.OPENAI_COMPATIBLE:
|
||||
case InferenceProvider.GOOGLE:
|
||||
apiKey = this.twentyConfigService.get('GOOGLE_API_KEY');
|
||||
break;
|
||||
case InferenceProvider.MISTRAL:
|
||||
apiKey = this.twentyConfigService.get('MISTRAL_API_KEY');
|
||||
break;
|
||||
case InferenceProvider.BEDROCK:
|
||||
apiKey = this.twentyConfigService.get('AWS_BEDROCK_REGION');
|
||||
break;
|
||||
case InferenceProvider.OPENAI_COMPATIBLE:
|
||||
apiKey = this.twentyConfigService.get('OPENAI_COMPATIBLE_API_KEY');
|
||||
break;
|
||||
default:
|
||||
@@ -321,7 +427,7 @@ export class AiModelRegistryService {
|
||||
|
||||
if (!apiKey) {
|
||||
throw new AgentException(
|
||||
`${provider.toUpperCase()} API key not configured. Please set the appropriate environment variable.`,
|
||||
`${inferenceProvider.toUpperCase()} API key not configured. Please set the appropriate environment variable.`,
|
||||
AgentExceptionCode.API_KEY_NOT_CONFIGURED,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user