@auto-engineer/model-factory 1.58.0 → 1.60.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/package.json CHANGED
@@ -22,7 +22,7 @@
22
22
  "publishConfig": {
23
23
  "access": "public"
24
24
  },
25
- "version": "1.58.0",
25
+ "version": "1.60.0",
26
26
  "scripts": {
27
27
  "build": "tsc && tsx ../../scripts/fix-esm-imports.ts",
28
28
  "test": "vitest run --reporter=dot",
@@ -1,11 +1,5 @@
1
1
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
2
2
 
3
- const stubModel = (provider: string) => (model: string) => ({
4
- specificationVersion: 'v3',
5
- modelId: model,
6
- provider,
7
- });
8
-
9
3
  vi.mock('@ai-sdk/openai-compatible', () => ({
10
4
  createOpenAICompatible: ({ name, baseURL, apiKey }: { name: string; baseURL: string; apiKey: string }) => ({
11
5
  chatModel: (model: string) => ({
@@ -16,11 +10,6 @@ vi.mock('@ai-sdk/openai-compatible', () => ({
16
10
  }),
17
11
  }));
18
12
 
19
- vi.mock('@ai-sdk/openai', () => ({ createOpenAI: () => stubModel('openai') }));
20
- vi.mock('@ai-sdk/anthropic', () => ({ createAnthropic: () => stubModel('anthropic') }));
21
- vi.mock('@ai-sdk/google', () => ({ createGoogleGenerativeAI: () => stubModel('google') }));
22
- vi.mock('@ai-sdk/xai', () => ({ createXai: () => stubModel('xai') }));
23
-
24
13
  const savedEnv = { ...process.env };
25
14
 
26
15
  beforeEach(() => {
@@ -31,169 +20,61 @@ afterEach(() => {
31
20
  process.env = { ...savedEnv };
32
21
  });
33
22
 
34
- describe('createModelFromEnv', () => {
35
- describe('custom provider', () => {
36
- it('creates model using CUSTOM_PROVIDER env vars with default model', async () => {
37
- process.env.CUSTOM_PROVIDER_NAME = 'litellm';
38
- process.env.CUSTOM_PROVIDER_BASE_URL = 'https://gateway.example.com/v1';
39
- process.env.CUSTOM_PROVIDER_API_KEY = 'sk-test';
40
- process.env.DEFAULT_AI_PROVIDER = 'custom';
41
-
42
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
43
- const model = createModelFromEnv();
44
-
45
- expect(model).toEqual({
46
- specificationVersion: 'v3',
47
- modelId: DEFAULT_MODELS.custom,
48
- provider: 'litellm:https://gateway.example.com/v1:sk-test',
49
- });
50
- });
51
-
52
- it('uses options.model override', async () => {
53
- process.env.CUSTOM_PROVIDER_BASE_URL = 'https://gw.example.com/v1';
54
-
55
- const { createModelFromEnv } = await import('./index.js');
56
- const model = createModelFromEnv({ model: 'my-custom-model' });
57
-
58
- expect(model).toEqual({
59
- specificationVersion: 'v3',
60
- modelId: 'my-custom-model',
61
- provider: 'custom:https://gw.example.com/v1:',
62
- });
63
- });
64
-
65
- it('uses DEFAULT_AI_MODEL env var when options.model is unset', async () => {
66
- process.env.CUSTOM_PROVIDER_BASE_URL = 'https://gw.example.com/v1';
67
- process.env.DEFAULT_AI_MODEL = 'env-override-model';
68
-
69
- const { createModelFromEnv } = await import('./index.js');
70
- const model = createModelFromEnv();
23
+ function setRequiredEnv(overrides?: Partial<Record<string, string>>) {
24
+ process.env.CUSTOM_PROVIDER_NAME = 'litellm';
25
+ process.env.CUSTOM_PROVIDER_BASE_URL = 'https://gateway.example.com/v1';
26
+ process.env.CUSTOM_PROVIDER_API_KEY = 'sk-test';
27
+ process.env.CUSTOM_PROVIDER_DEFAULT_MODEL = 'xai/grok-code-fast-1';
28
+ if (overrides) {
29
+ for (const [key, value] of Object.entries(overrides)) {
30
+ if (value === undefined) {
31
+ delete process.env[key];
32
+ } else {
33
+ process.env[key] = value;
34
+ }
35
+ }
36
+ }
37
+ }
71
38
 
72
- expect(model).toEqual({
73
- specificationVersion: 'v3',
74
- modelId: 'env-override-model',
75
- provider: 'custom:https://gw.example.com/v1:',
76
- });
77
- });
78
-
79
- it('defaults to custom provider when DEFAULT_AI_PROVIDER is unset', async () => {
80
- process.env.CUSTOM_PROVIDER_BASE_URL = 'https://gw.example.com/v1';
81
- delete process.env.DEFAULT_AI_PROVIDER;
82
-
83
- const { createModelFromEnv } = await import('./index.js');
84
- const model = createModelFromEnv();
85
-
86
- expect(model).toEqual(
87
- expect.objectContaining({
88
- specificationVersion: 'v3',
89
- provider: 'custom:https://gw.example.com/v1:',
90
- }),
91
- );
92
- });
93
-
94
- it('throws when CUSTOM_PROVIDER_BASE_URL is missing', async () => {
95
- process.env.DEFAULT_AI_PROVIDER = 'custom';
96
- delete process.env.CUSTOM_PROVIDER_BASE_URL;
39
+ describe('createModelFromEnv', () => {
40
+ it('creates model from all 4 env vars', async () => {
41
+ setRequiredEnv();
97
42
 
98
- const { createModelFromEnv } = await import('./index.js');
43
+ const { createModelFromEnv } = await import('./index.js');
44
+ const model = createModelFromEnv();
99
45
 
100
- expect(() => createModelFromEnv()).toThrow('CUSTOM_PROVIDER_BASE_URL is required when using the custom provider');
46
+ expect(model).toEqual({
47
+ specificationVersion: 'v3',
48
+ modelId: 'xai/grok-code-fast-1',
49
+ provider: 'litellm:https://gateway.example.com/v1:sk-test',
101
50
  });
102
51
  });
103
52
 
104
- describe('direct providers', () => {
105
- it('creates openai model with default model name', async () => {
106
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
107
- const model = createModelFromEnv({ provider: 'openai' });
108
-
109
- expect(model).toEqual({
110
- specificationVersion: 'v3',
111
- modelId: DEFAULT_MODELS.openai,
112
- provider: 'openai',
113
- });
114
- });
53
+ it('throws when CUSTOM_PROVIDER_NAME is missing', async () => {
54
+ setRequiredEnv({ CUSTOM_PROVIDER_NAME: undefined });
115
55
 
116
- it('creates anthropic model with default model name', async () => {
117
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
118
- const model = createModelFromEnv({ provider: 'anthropic' });
119
-
120
- expect(model).toEqual({
121
- specificationVersion: 'v3',
122
- modelId: DEFAULT_MODELS.anthropic,
123
- provider: 'anthropic',
124
- });
125
- });
126
-
127
- it('creates google model with default model name', async () => {
128
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
129
- const model = createModelFromEnv({ provider: 'google' });
130
-
131
- expect(model).toEqual({
132
- specificationVersion: 'v3',
133
- modelId: DEFAULT_MODELS.google,
134
- provider: 'google',
135
- });
136
- });
137
-
138
- it('creates xai model with default model name', async () => {
139
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
140
- const model = createModelFromEnv({ provider: 'xai' });
141
-
142
- expect(model).toEqual({
143
- specificationVersion: 'v3',
144
- modelId: DEFAULT_MODELS.xai,
145
- provider: 'xai',
146
- });
147
- });
148
-
149
- it('reads provider from DEFAULT_AI_PROVIDER env var', async () => {
150
- process.env.DEFAULT_AI_PROVIDER = 'anthropic';
151
-
152
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
153
- const model = createModelFromEnv();
154
-
155
- expect(model).toEqual({
156
- specificationVersion: 'v3',
157
- modelId: DEFAULT_MODELS.anthropic,
158
- provider: 'anthropic',
159
- });
160
- });
161
-
162
- it('options.provider overrides DEFAULT_AI_PROVIDER env var', async () => {
163
- process.env.DEFAULT_AI_PROVIDER = 'openai';
164
-
165
- const { createModelFromEnv, DEFAULT_MODELS } = await import('./index.js');
166
- const model = createModelFromEnv({ provider: 'xai' });
56
+ const { createModelFromEnv } = await import('./index.js');
57
+ expect(() => createModelFromEnv()).toThrow('Missing required environment variable: CUSTOM_PROVIDER_NAME');
58
+ });
167
59
 
168
- expect(model).toEqual({
169
- specificationVersion: 'v3',
170
- modelId: DEFAULT_MODELS.xai,
171
- provider: 'xai',
172
- });
173
- });
60
+ it('throws when CUSTOM_PROVIDER_BASE_URL is missing', async () => {
61
+ setRequiredEnv({ CUSTOM_PROVIDER_BASE_URL: undefined });
174
62
 
175
- it('uses options.model for direct provider', async () => {
176
- const { createModelFromEnv } = await import('./index.js');
177
- const model = createModelFromEnv({ provider: 'openai', model: 'gpt-4-turbo' });
63
+ const { createModelFromEnv } = await import('./index.js');
64
+ expect(() => createModelFromEnv()).toThrow('Missing required environment variable: CUSTOM_PROVIDER_BASE_URL');
65
+ });
178
66
 
179
- expect(model).toEqual({
180
- specificationVersion: 'v3',
181
- modelId: 'gpt-4-turbo',
182
- provider: 'openai',
183
- });
184
- });
67
+ it('throws when CUSTOM_PROVIDER_API_KEY is missing', async () => {
68
+ setRequiredEnv({ CUSTOM_PROVIDER_API_KEY: undefined });
185
69
 
186
- it('uses DEFAULT_AI_MODEL env var for direct provider', async () => {
187
- process.env.DEFAULT_AI_MODEL = 'custom-model-name';
70
+ const { createModelFromEnv } = await import('./index.js');
71
+ expect(() => createModelFromEnv()).toThrow('Missing required environment variable: CUSTOM_PROVIDER_API_KEY');
72
+ });
188
73
 
189
- const { createModelFromEnv } = await import('./index.js');
190
- const model = createModelFromEnv({ provider: 'openai' });
74
+ it('throws when CUSTOM_PROVIDER_DEFAULT_MODEL is missing', async () => {
75
+ setRequiredEnv({ CUSTOM_PROVIDER_DEFAULT_MODEL: undefined });
191
76
 
192
- expect(model).toEqual({
193
- specificationVersion: 'v3',
194
- modelId: 'custom-model-name',
195
- provider: 'openai',
196
- });
197
- });
77
+ const { createModelFromEnv } = await import('./index.js');
78
+ expect(() => createModelFromEnv()).toThrow('Missing required environment variable: CUSTOM_PROVIDER_DEFAULT_MODEL');
198
79
  });
199
80
  });
package/src/index.ts CHANGED
@@ -1,49 +1,19 @@
1
- import { createAnthropic } from '@ai-sdk/anthropic';
2
- import { createGoogleGenerativeAI } from '@ai-sdk/google';
3
- import { createOpenAI } from '@ai-sdk/openai';
4
1
  import { createOpenAICompatible } from '@ai-sdk/openai-compatible';
5
- import { createXai } from '@ai-sdk/xai';
6
2
  import type { LanguageModel } from 'ai';
7
3
 
8
- export type Provider = 'openai' | 'anthropic' | 'google' | 'xai' | 'custom';
9
-
10
- export const DEFAULT_MODELS: Record<Provider, string> = {
11
- openai: 'gpt-4o',
12
- anthropic: 'claude-sonnet-4-20250514',
13
- google: 'gemini-2.0-flash',
14
- xai: 'grok-3',
15
- custom: 'claude-sonnet-4-20250514',
16
- };
17
-
18
- interface CreateModelOptions {
19
- provider?: Provider;
20
- model?: string;
4
+ function requireEnv(name: string): string {
5
+ const value = process.env[name];
6
+ if (!value) {
7
+ throw new Error(`Missing required environment variable: ${name}`);
8
+ }
9
+ return value;
21
10
  }
22
11
 
23
- export function createModelFromEnv(options?: CreateModelOptions): LanguageModel {
24
- const provider = options?.provider ?? (process.env.DEFAULT_AI_PROVIDER as Provider | undefined) ?? 'custom';
25
- const modelName = options?.model ?? process.env.DEFAULT_AI_MODEL ?? DEFAULT_MODELS[provider];
26
-
27
- if (provider === 'custom') {
28
- const name = process.env.CUSTOM_PROVIDER_NAME ?? 'custom';
29
- const baseURL = process.env.CUSTOM_PROVIDER_BASE_URL;
30
- const apiKey = process.env.CUSTOM_PROVIDER_API_KEY ?? '';
12
+ export function createModelFromEnv(): LanguageModel {
13
+ const name = requireEnv('CUSTOM_PROVIDER_NAME');
14
+ const baseURL = requireEnv('CUSTOM_PROVIDER_BASE_URL');
15
+ const apiKey = requireEnv('CUSTOM_PROVIDER_API_KEY');
16
+ const model = requireEnv('CUSTOM_PROVIDER_DEFAULT_MODEL');
31
17
 
32
- if (!baseURL) {
33
- throw new Error('CUSTOM_PROVIDER_BASE_URL is required when using the custom provider');
34
- }
35
-
36
- return createOpenAICompatible({ name, baseURL, apiKey }).chatModel(modelName) as unknown as LanguageModel;
37
- }
38
-
39
- switch (provider) {
40
- case 'openai':
41
- return createOpenAI()(modelName) as unknown as LanguageModel;
42
- case 'anthropic':
43
- return createAnthropic()(modelName) as unknown as LanguageModel;
44
- case 'google':
45
- return createGoogleGenerativeAI()(modelName) as unknown as LanguageModel;
46
- case 'xai':
47
- return createXai()(modelName) as unknown as LanguageModel;
48
- }
18
+ return createOpenAICompatible({ name, baseURL, apiKey }).chatModel(model) as unknown as LanguageModel;
49
19
  }