@outputai/llm 0.6.1-next.fc6a93e.0 → 0.7.1-dev.144d64f.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 +20 -12
- package/src/agent.js +5 -4
- package/src/agent.spec.js +62 -19
- package/src/ai_model.js +25 -146
- package/src/ai_model.spec.js +185 -762
- package/src/ai_provider.js +86 -0
- package/src/ai_provider.spec.js +147 -0
- package/src/ai_sdk_options.js +2 -1
- package/src/ai_sdk_options.spec.js +28 -0
- package/src/cost/index.js +7 -2
- package/src/cost/index.spec.js +5 -2
- package/src/index.d.ts +64 -16
- package/src/index.js +1 -4
- package/src/prompt/block_options.js +58 -0
- package/src/prompt/block_options.spec.js +71 -0
- package/src/prompt/blocks.js +47 -0
- package/src/prompt/blocks.spec.js +63 -0
- package/src/prompt/parser.js +2 -5
- package/src/prompt/parser.spec.js +19 -0
- package/src/prompt/validations.js +12 -3
- package/src/prompt/validations.spec.js +114 -0
- package/src/utils/error_handler.js +25 -8
- package/src/utils/error_handler.spec.js +17 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/llm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.1-dev.144d64f.0",
|
|
4
4
|
"description": "Framework abstraction to interact with LLM models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -9,21 +9,29 @@
|
|
|
9
9
|
"./src"
|
|
10
10
|
],
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"@ai-sdk/amazon-bedrock": "4.0.96",
|
|
13
|
-
"@ai-sdk/anthropic": "3.0.71",
|
|
14
|
-
"@ai-sdk/azure": "3.0.54",
|
|
15
|
-
"@ai-sdk/google-vertex": "4.0.112",
|
|
16
|
-
"@ai-sdk/openai": "3.0.53",
|
|
17
|
-
"@ai-sdk/perplexity": "3.0.29",
|
|
18
|
-
"@exalabs/ai-sdk": "2.0.1",
|
|
19
|
-
"@perplexity-ai/ai-sdk": "0.1.3",
|
|
20
|
-
"@tavily/ai-sdk": "0.4.1",
|
|
21
|
-
"ai": "6.0.168",
|
|
22
12
|
"entities": "8.0.0",
|
|
23
13
|
"gray-matter": "4.0.3",
|
|
24
14
|
"liquidjs": "10.25.7",
|
|
25
15
|
"undici": "8.1.0",
|
|
26
|
-
"@outputai/core": "0.
|
|
16
|
+
"@outputai/core": "0.7.1-dev.144d64f.0"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"ai": "6.0.168",
|
|
20
|
+
"@ai-sdk/amazon-bedrock": "4.0.111",
|
|
21
|
+
"@ai-sdk/anthropic": "3.0.81",
|
|
22
|
+
"@ai-sdk/azure": "3.0.68",
|
|
23
|
+
"@ai-sdk/google-vertex": "4.0.140",
|
|
24
|
+
"@ai-sdk/openai": "3.0.67",
|
|
25
|
+
"@ai-sdk/perplexity": "3.0.33"
|
|
26
|
+
},
|
|
27
|
+
"peerDependencies": {
|
|
28
|
+
"ai": ">=6 <7",
|
|
29
|
+
"@ai-sdk/amazon-bedrock": ">=4 <5",
|
|
30
|
+
"@ai-sdk/anthropic": ">=3 <4",
|
|
31
|
+
"@ai-sdk/azure": ">=3 <4",
|
|
32
|
+
"@ai-sdk/google-vertex": ">=4 <5",
|
|
33
|
+
"@ai-sdk/openai": ">=3 <4",
|
|
34
|
+
"@ai-sdk/perplexity": ">=3 <4"
|
|
27
35
|
},
|
|
28
36
|
"license": "Apache-2.0",
|
|
29
37
|
"publishConfig": {
|
package/src/agent.js
CHANGED
|
@@ -5,7 +5,7 @@ import { loadAiSdkTextOptions } from './ai_sdk_options.js';
|
|
|
5
5
|
import { prepareTextPrompt } from './prompt/prepare_text.js';
|
|
6
6
|
import { startTrace, endTraceWithError } from './utils/trace.js';
|
|
7
7
|
import { wrapTextResponse, wrapStreamOnFinishResponse } from './utils/response_wrappers.js';
|
|
8
|
-
import { ROLE, isRole
|
|
8
|
+
import { ROLE, isRole } from './utils/message.js';
|
|
9
9
|
export { skill } from './prompt/skill.js';
|
|
10
10
|
|
|
11
11
|
export const createMemoryConversationStore = () => {
|
|
@@ -47,12 +47,13 @@ export class Agent extends AIToolLoopAgent {
|
|
|
47
47
|
|
|
48
48
|
// Extract system messages as `instructions` for the ToolLoopAgent constructor
|
|
49
49
|
// and keep user messages for generate() calls — avoids provider errors
|
|
50
|
-
// with multiple system messages during multi-step tool loops
|
|
51
|
-
|
|
50
|
+
// with multiple system messages during multi-step tool loops.
|
|
51
|
+
// Pass message objects (not a string) so per-message providerOptions are preserved.
|
|
52
|
+
const systemMessages = allMessages.filter( isRole( ROLE.SYSTEM ) );
|
|
52
53
|
|
|
53
54
|
super( {
|
|
54
55
|
...constructorOptions,
|
|
55
|
-
...(
|
|
56
|
+
...( systemMessages.length > 0 ? { instructions: systemMessages } : {} ),
|
|
56
57
|
...( tools ? { tools } : {} ),
|
|
57
58
|
stopWhen: stopWhen ?? stepCountIs( maxSteps ),
|
|
58
59
|
...rest
|
package/src/agent.spec.js
CHANGED
|
@@ -86,7 +86,8 @@ vi.mock( './utils/trace.js', () => ( {
|
|
|
86
86
|
|
|
87
87
|
vi.mock( './utils/response_wrappers.js', () => ( {
|
|
88
88
|
wrapTextResponse: ( ...args ) => wrapMocks.wrapTextResponse( ...args ),
|
|
89
|
-
wrapStreamOnFinishResponse: ( ...args ) =>
|
|
89
|
+
wrapStreamOnFinishResponse: ( ...args ) =>
|
|
90
|
+
wrapMocks.wrapStreamOnFinishResponse( ...args )
|
|
90
91
|
} ) );
|
|
91
92
|
|
|
92
93
|
vi.mock( './prompt/skill.js', () => ( {
|
|
@@ -131,7 +132,9 @@ describe( 'Agent', () => {
|
|
|
131
132
|
aiMocks.superConstructor.mockReset();
|
|
132
133
|
aiMocks.superGenerate.mockReset().mockResolvedValue( aiResponse );
|
|
133
134
|
aiMocks.superStream.mockReset().mockReturnValue( { textStream: 'stream' } );
|
|
134
|
-
aiMocks.stepCountIs
|
|
135
|
+
aiMocks.stepCountIs
|
|
136
|
+
.mockReset()
|
|
137
|
+
.mockImplementation( count => ( { type: 'step-count', count } ) );
|
|
135
138
|
|
|
136
139
|
promptMocks.prepareTextPrompt.mockReset().mockReturnValue( {
|
|
137
140
|
loadedPrompt,
|
|
@@ -143,7 +146,9 @@ describe( 'Agent', () => {
|
|
|
143
146
|
traceMocks.startTrace.mockReset().mockReturnValue( 'trace-id' );
|
|
144
147
|
traceMocks.endTraceWithError.mockReset();
|
|
145
148
|
|
|
146
|
-
wrapMocks.wrapTextResponse
|
|
149
|
+
wrapMocks.wrapTextResponse
|
|
150
|
+
.mockReset()
|
|
151
|
+
.mockImplementation( async ( { response } ) => response );
|
|
147
152
|
wrapMocks.wrapStreamOnFinishResponse.mockReset().mockReturnValue( {
|
|
148
153
|
onFinish: vi.fn()
|
|
149
154
|
} );
|
|
@@ -175,7 +180,9 @@ describe( 'Agent', () => {
|
|
|
175
180
|
|
|
176
181
|
it( 'prepares the prompt using the resolved invocation dir', async () => {
|
|
177
182
|
const { Agent } = await importSut();
|
|
178
|
-
const skills = [
|
|
183
|
+
const skills = [
|
|
184
|
+
{ name: 'style', description: 'Style', instructions: '# Style' }
|
|
185
|
+
];
|
|
179
186
|
const tools = { search: { description: 'Search' } };
|
|
180
187
|
|
|
181
188
|
new Agent( {
|
|
@@ -199,9 +206,11 @@ describe( 'Agent', () => {
|
|
|
199
206
|
|
|
200
207
|
new Agent( { prompt: 'test@v1', promptDir: '/explicit/prompts' } );
|
|
201
208
|
|
|
202
|
-
expect( promptMocks.prepareTextPrompt ).toHaveBeenCalledWith(
|
|
203
|
-
|
|
204
|
-
|
|
209
|
+
expect( promptMocks.prepareTextPrompt ).toHaveBeenCalledWith(
|
|
210
|
+
expect.objectContaining( {
|
|
211
|
+
promptDir: '/explicit/prompts'
|
|
212
|
+
} )
|
|
213
|
+
);
|
|
205
214
|
} );
|
|
206
215
|
|
|
207
216
|
it( 'constructs ToolLoopAgent with text options, instructions, tools, and default stopWhen', async () => {
|
|
@@ -215,12 +224,33 @@ describe( 'Agent', () => {
|
|
|
215
224
|
model,
|
|
216
225
|
providerOptions: { test: true },
|
|
217
226
|
temperature: 0.3,
|
|
218
|
-
instructions: 'You are concise.',
|
|
227
|
+
instructions: [ { role: 'system', content: 'You are concise.' } ],
|
|
219
228
|
tools: preparedTools,
|
|
220
229
|
stopWhen: { type: 'step-count', count: 10 }
|
|
221
230
|
} );
|
|
222
231
|
} );
|
|
223
232
|
|
|
233
|
+
it( 'preserves per-message providerOptions on system messages passed as instructions', async () => {
|
|
234
|
+
const { Agent } = await importSut();
|
|
235
|
+
const systemMessage = {
|
|
236
|
+
role: 'system',
|
|
237
|
+
content: 'You are concise.',
|
|
238
|
+
providerOptions: { anthropic: { cacheControl: { type: 'ephemeral' } } }
|
|
239
|
+
};
|
|
240
|
+
optionMocks.loadAiSdkTextOptions.mockReturnValueOnce( {
|
|
241
|
+
model,
|
|
242
|
+
messages: [ systemMessage, { role: 'user', content: 'Hello' } ]
|
|
243
|
+
} );
|
|
244
|
+
|
|
245
|
+
new Agent( { prompt: 'test@v1' } );
|
|
246
|
+
|
|
247
|
+
expect( aiMocks.superConstructor ).toHaveBeenCalledWith(
|
|
248
|
+
expect.objectContaining( {
|
|
249
|
+
instructions: [ systemMessage ]
|
|
250
|
+
} )
|
|
251
|
+
);
|
|
252
|
+
} );
|
|
253
|
+
|
|
224
254
|
it( 'omits tools when prompt preparation returns null tools', async () => {
|
|
225
255
|
const { Agent } = await importSut();
|
|
226
256
|
promptMocks.prepareTextPrompt.mockReturnValueOnce( {
|
|
@@ -234,7 +264,7 @@ describe( 'Agent', () => {
|
|
|
234
264
|
model,
|
|
235
265
|
providerOptions: { test: true },
|
|
236
266
|
temperature: 0.3,
|
|
237
|
-
instructions: 'You are concise.',
|
|
267
|
+
instructions: [ { role: 'system', content: 'You are concise.' } ],
|
|
238
268
|
stopWhen: { type: 'step-count', count: 10 }
|
|
239
269
|
} );
|
|
240
270
|
} );
|
|
@@ -246,9 +276,11 @@ describe( 'Agent', () => {
|
|
|
246
276
|
new Agent( { prompt: 'test@v1', stopWhen } );
|
|
247
277
|
|
|
248
278
|
expect( aiMocks.stepCountIs ).not.toHaveBeenCalled();
|
|
249
|
-
expect( aiMocks.superConstructor ).toHaveBeenCalledWith(
|
|
250
|
-
|
|
251
|
-
|
|
279
|
+
expect( aiMocks.superConstructor ).toHaveBeenCalledWith(
|
|
280
|
+
expect.objectContaining( {
|
|
281
|
+
stopWhen
|
|
282
|
+
} )
|
|
283
|
+
);
|
|
252
284
|
} );
|
|
253
285
|
|
|
254
286
|
it( 'passes custom constructor options through', async () => {
|
|
@@ -256,10 +288,12 @@ describe( 'Agent', () => {
|
|
|
256
288
|
|
|
257
289
|
new Agent( { prompt: 'test@v1', temperature: 0.8, seed: 42 } );
|
|
258
290
|
|
|
259
|
-
expect( aiMocks.superConstructor ).toHaveBeenCalledWith(
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
291
|
+
expect( aiMocks.superConstructor ).toHaveBeenCalledWith(
|
|
292
|
+
expect.objectContaining( {
|
|
293
|
+
temperature: 0.8,
|
|
294
|
+
seed: 42
|
|
295
|
+
} )
|
|
296
|
+
);
|
|
263
297
|
} );
|
|
264
298
|
|
|
265
299
|
it( 'keeps only user prompt messages as initial generate messages', async () => {
|
|
@@ -275,7 +309,9 @@ describe( 'Agent', () => {
|
|
|
275
309
|
|
|
276
310
|
it( 'combines initial, stored, and caller messages for generate', async () => {
|
|
277
311
|
const store = {
|
|
278
|
-
getMessages: vi.fn( () => [
|
|
312
|
+
getMessages: vi.fn( () => [
|
|
313
|
+
{ role: 'assistant', content: 'Stored reply' }
|
|
314
|
+
] ),
|
|
279
315
|
addMessages: vi.fn()
|
|
280
316
|
};
|
|
281
317
|
const callerMessage = { role: 'user', content: 'New question' };
|
|
@@ -336,7 +372,9 @@ describe( 'Agent', () => {
|
|
|
336
372
|
|
|
337
373
|
it( 'streams with initial, stored, and caller messages', async () => {
|
|
338
374
|
const store = {
|
|
339
|
-
getMessages: vi.fn( () => [
|
|
375
|
+
getMessages: vi.fn( () => [
|
|
376
|
+
{ role: 'assistant', content: 'Stored reply' }
|
|
377
|
+
] ),
|
|
340
378
|
addMessages: vi.fn()
|
|
341
379
|
};
|
|
342
380
|
const onFinish = vi.fn();
|
|
@@ -345,7 +383,12 @@ describe( 'Agent', () => {
|
|
|
345
383
|
const { Agent } = await importSut();
|
|
346
384
|
const agent = new Agent( { prompt: 'test@v1', conversationStore: store } );
|
|
347
385
|
|
|
348
|
-
const result = await agent.stream( {
|
|
386
|
+
const result = await agent.stream( {
|
|
387
|
+
messages: [ callerMessage ],
|
|
388
|
+
onFinish,
|
|
389
|
+
onError,
|
|
390
|
+
maxRetries: 1
|
|
391
|
+
} );
|
|
349
392
|
|
|
350
393
|
expect( traceMocks.startTrace ).toHaveBeenCalledWith( {
|
|
351
394
|
name: 'Agent.stream',
|
package/src/ai_model.js
CHANGED
|
@@ -1,89 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { createAzure } from '@ai-sdk/azure';
|
|
4
|
-
import { createVertex } from '@ai-sdk/google-vertex';
|
|
5
|
-
import { createOpenAI } from '@ai-sdk/openai';
|
|
6
|
-
import { createPerplexity } from '@ai-sdk/perplexity';
|
|
7
|
-
import { ValidationError, z } from '@outputai/core';
|
|
8
|
-
import { Agent, fetch } from 'undici';
|
|
9
|
-
|
|
10
|
-
const dispatcher = new Agent( {
|
|
11
|
-
headersTimeout: 15 * 60 * 1000, // 15 min
|
|
12
|
-
bodyTimeout: 15 * 60 * 1000
|
|
13
|
-
} );
|
|
14
|
-
|
|
15
|
-
const customFetch = ( input, init ) => fetch( input, { dispatcher, ...init } );
|
|
16
|
-
const initProvider = factory => factory( { fetch: customFetch } );
|
|
17
|
-
|
|
18
|
-
export const builtInProviders = {
|
|
19
|
-
azure: initProvider( createAzure ),
|
|
20
|
-
anthropic: initProvider( createAnthropic ),
|
|
21
|
-
openai: initProvider( createOpenAI ),
|
|
22
|
-
vertex: initProvider( createVertex ),
|
|
23
|
-
bedrock: initProvider( createAmazonBedrock ),
|
|
24
|
-
perplexity: initProvider( createPerplexity )
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
export const providers = { ...builtInProviders };
|
|
28
|
-
|
|
29
|
-
const registerProviderSchema = z.object( {
|
|
30
|
-
name: z.string().min( 1, 'Provider name must be a non-empty string' ),
|
|
31
|
-
providerFn: z.function()
|
|
32
|
-
} );
|
|
33
|
-
|
|
34
|
-
const modelPromptSchema = z.object( {
|
|
35
|
-
config: z.object( {
|
|
36
|
-
provider: z.string().min( 1 ),
|
|
37
|
-
model: z.string().min( 1 )
|
|
38
|
-
} ).loose()
|
|
39
|
-
} ).loose();
|
|
40
|
-
|
|
41
|
-
const toolsPromptSchema = z.object( {
|
|
42
|
-
config: z.object( {
|
|
43
|
-
provider: z.string().min( 1 ),
|
|
44
|
-
tools: z.record( z.string(), z.record( z.string(), z.unknown() ) ).optional()
|
|
45
|
-
} ).loose()
|
|
46
|
-
} ).loose();
|
|
47
|
-
|
|
48
|
-
const toolConfigSchema = z.record( z.string(), z.unknown() );
|
|
49
|
-
|
|
50
|
-
const parseModelPrompt = prompt => {
|
|
51
|
-
const result = modelPromptSchema.safeParse( prompt );
|
|
52
|
-
if ( !result.success ) {
|
|
53
|
-
throw new ValidationError( `Invalid model prompt config: ${z.prettifyError( result.error )}` );
|
|
54
|
-
}
|
|
55
|
-
return result.data.config;
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
const parseToolsPrompt = prompt => {
|
|
59
|
-
const result = toolsPromptSchema.safeParse( prompt );
|
|
60
|
-
if ( !result.success ) {
|
|
61
|
-
throw new ValidationError( `Invalid tools prompt config: ${z.prettifyError( result.error )}` );
|
|
62
|
-
}
|
|
63
|
-
return result.data.config;
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Register or override an AI SDK provider factory by name.
|
|
68
|
-
*
|
|
69
|
-
* @param {string} name - Provider name used in prompt frontmatter
|
|
70
|
-
* @param {Function} providerFn - Factory function that receives a model id
|
|
71
|
-
* @returns {void}
|
|
72
|
-
*/
|
|
73
|
-
export function registerProvider( name, providerFn ) {
|
|
74
|
-
const result = registerProviderSchema.safeParse( { name, providerFn } );
|
|
75
|
-
if ( !result.success ) {
|
|
76
|
-
throw new ValidationError( `Invalid provider registration: ${z.prettifyError( result.error )}` );
|
|
77
|
-
}
|
|
78
|
-
providers[name] = providerFn;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/**
|
|
82
|
-
* List all currently registered provider names.
|
|
83
|
-
*
|
|
84
|
-
* @returns {string[]} Provider names
|
|
85
|
-
*/
|
|
86
|
-
export const getRegisteredProviders = () => Object.keys( providers );
|
|
1
|
+
import { ValidationError } from '@outputai/core';
|
|
2
|
+
import { getProvider } from './ai_provider.js';
|
|
87
3
|
|
|
88
4
|
/**
|
|
89
5
|
* Load a text model from a loaded prompt config.
|
|
@@ -91,19 +7,7 @@ export const getRegisteredProviders = () => Object.keys( providers );
|
|
|
91
7
|
* @param {object} prompt - Loaded prompt object with `config.provider` and `config.model`
|
|
92
8
|
* @returns {unknown} AI SDK language model
|
|
93
9
|
*/
|
|
94
|
-
export
|
|
95
|
-
const config = parseModelPrompt( prompt );
|
|
96
|
-
const { provider: providerName, model: modelName } = config;
|
|
97
|
-
|
|
98
|
-
const provider = providers[providerName];
|
|
99
|
-
|
|
100
|
-
if ( !provider ) {
|
|
101
|
-
const availableProviders = Object.keys( providers ).join( ', ' );
|
|
102
|
-
throw new Error( `Invalid provider "${providerName}". Valid providers: ${availableProviders}` );
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
return provider( modelName );
|
|
106
|
-
}
|
|
10
|
+
export const loadTextModel = prompt => getProvider( prompt.config.provider )( prompt.config.model );
|
|
107
11
|
|
|
108
12
|
/**
|
|
109
13
|
* Load an image model from a loaded prompt config.
|
|
@@ -111,24 +15,16 @@ export function loadTextModel( prompt ) {
|
|
|
111
15
|
* @param {object} prompt - Loaded prompt object with `config.provider` and `config.model`
|
|
112
16
|
* @returns {unknown} AI SDK image model
|
|
113
17
|
*/
|
|
114
|
-
export
|
|
115
|
-
const
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
const provider = providers[providerName];
|
|
119
|
-
|
|
120
|
-
if ( !provider ) {
|
|
121
|
-
const availableProviders = Object.keys( providers ).join( ', ' );
|
|
122
|
-
throw new Error( `Invalid provider "${providerName}". Valid providers: ${availableProviders}` );
|
|
123
|
-
}
|
|
18
|
+
export const loadImageModel = prompt => {
|
|
19
|
+
const { provider: providerName, model } = prompt.config;
|
|
20
|
+
const provider = getProvider( prompt.config.provider );
|
|
124
21
|
|
|
125
22
|
const imageModelFactory = provider.image ?? provider.imageModel;
|
|
126
23
|
if ( typeof imageModelFactory !== 'function' ) {
|
|
127
|
-
throw new
|
|
24
|
+
throw new ValidationError( `Provider "${providerName}" does not support image models.` );
|
|
128
25
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
26
|
+
return imageModelFactory( model );
|
|
27
|
+
};
|
|
132
28
|
|
|
133
29
|
/**
|
|
134
30
|
* Load provider-specific tools configured in a prompt.
|
|
@@ -136,46 +32,29 @@ export function loadImageModel( prompt ) {
|
|
|
136
32
|
* @param {object} prompt - Loaded prompt object with `config.provider` and optional `config.tools`
|
|
137
33
|
* @returns {Record<string, unknown> | null} AI SDK tools, or null when none are configured
|
|
138
34
|
*/
|
|
139
|
-
export
|
|
140
|
-
const
|
|
141
|
-
const { tools: toolsConfig, provider: providerName } = config;
|
|
35
|
+
export const loadTools = prompt => {
|
|
36
|
+
const { tools: promptTools, provider: providerName } = prompt.config;
|
|
142
37
|
|
|
143
|
-
if (
|
|
38
|
+
if ( Object.keys( promptTools ?? {} ).length === 0 ) {
|
|
144
39
|
return null;
|
|
145
40
|
}
|
|
146
41
|
|
|
147
|
-
const provider =
|
|
148
|
-
|
|
149
|
-
if ( !provider ) {
|
|
150
|
-
const availableProviders = Object.keys( providers ).join( ', ' );
|
|
151
|
-
throw new Error( `Invalid provider "${providerName}". Valid providers: ${availableProviders}` );
|
|
152
|
-
}
|
|
42
|
+
const provider = getProvider( providerName );
|
|
153
43
|
|
|
154
|
-
if ( !provider.tools
|
|
155
|
-
throw new
|
|
44
|
+
if ( !provider.tools ) {
|
|
45
|
+
throw new ValidationError( `Provider "${providerName}" does not support provider-specific tools.` );
|
|
156
46
|
}
|
|
157
47
|
|
|
158
|
-
const
|
|
48
|
+
const supportedTools = Object.keys( provider.tools );
|
|
49
|
+
const invalidTools = Object.keys( promptTools ).filter( name => !supportedTools.includes( name ) );
|
|
159
50
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
if ( !toolFactory || typeof toolFactory !== 'function' ) {
|
|
164
|
-
const availableTools = Object.keys( provider.tools )
|
|
165
|
-
.filter( key => typeof provider.tools[key] === 'function' )
|
|
166
|
-
.join( ', ' );
|
|
167
|
-
const toolsMessage = availableTools ? `Available tools: ${availableTools}` : 'No tools are available';
|
|
168
|
-
|
|
169
|
-
throw new Error( `Unknown tool "${toolName}" for provider "${providerName}". ${toolsMessage}` );
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const result = toolConfigSchema.safeParse( toolConfig );
|
|
173
|
-
if ( !result.success ) {
|
|
174
|
-
throw new ValidationError( `Invalid config for tool "${toolName}": ${z.prettifyError( result.error )}` );
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
tools[toolName] = toolFactory( toolConfig );
|
|
51
|
+
if ( invalidTools.length > 0 ) {
|
|
52
|
+
throw new ValidationError( `Invalid tool(s) ${invalidTools.join( ', ' )} for provider "${providerName}". \
|
|
53
|
+
Available: ${supportedTools.join( ', ' )}.` );
|
|
178
54
|
}
|
|
179
55
|
|
|
180
|
-
return
|
|
181
|
-
|
|
56
|
+
// load all tools and return in an object
|
|
57
|
+
return Object.fromEntries(
|
|
58
|
+
Object.entries( promptTools ).map( ( [ name, args ] ) => [ name, provider.tools[name]( args ) ] )
|
|
59
|
+
);
|
|
60
|
+
};
|