@outputai/llm 0.6.1-dev.daae905.0 → 0.6.1-next.2cc4685.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 +2 -2
- package/src/agent.js +15 -9
- package/src/agent.spec.js +295 -214
- package/src/ai_model.js +79 -36
- package/src/ai_model.spec.js +31 -13
- package/src/ai_sdk.js +55 -79
- package/src/ai_sdk.spec.js +464 -611
- package/src/ai_sdk_options.js +61 -0
- package/src/ai_sdk_options.spec.js +164 -0
- package/src/cost/index.js +1 -1
- package/src/index.d.ts +230 -175
- package/src/index.js +2 -2
- package/src/prompt/escape.js +65 -0
- package/src/prompt/escape.spec.js +159 -0
- package/src/{load_content.js → prompt/load_content.js} +1 -22
- package/src/{load_content.spec.js → prompt/load_content.spec.js} +6 -6
- package/src/prompt/loader.js +49 -0
- package/src/prompt/loader.spec.js +274 -0
- package/src/{prompt_loader_validation.spec.js → prompt/loader_validation.spec.js} +40 -7
- package/src/prompt/parser.js +19 -0
- package/src/{parser.spec.js → prompt/parser.spec.js} +74 -29
- package/src/prompt/prepare_text.js +27 -0
- package/src/prompt/prepare_text.spec.js +141 -0
- package/src/{skill.js → prompt/skill.js} +19 -0
- package/src/prompt/skill.spec.js +172 -0
- package/src/{prompt_validations.js → prompt/validations.js} +32 -6
- package/src/{prompt_validations.spec.js → prompt/validations.spec.js} +189 -1
- package/src/utils/__fixtures__/image_response.json +38 -0
- package/src/utils/__fixtures__/stream_response.json +294 -0
- package/src/utils/__fixtures__/text_response.json +201 -0
- package/src/utils/error_handler.js +65 -0
- package/src/utils/error_handler.spec.js +195 -0
- package/src/utils/image.js +10 -0
- package/src/utils/image.spec.js +20 -0
- package/src/utils/response_wrappers.js +46 -19
- package/src/utils/response_wrappers.spec.js +130 -70
- package/src/utils/source_extraction.js +17 -27
- package/src/utils/trace.js +2 -3
- package/src/utils/trace.spec.js +9 -13
- package/src/validations.js +54 -2
- package/src/validations.spec.js +166 -0
- package/src/parser.js +0 -28
- package/src/prompt_loader.js +0 -80
- package/src/prompt_loader.spec.js +0 -358
- package/src/skill.d.ts +0 -49
package/src/ai_model.js
CHANGED
|
@@ -31,8 +31,45 @@ const registerProviderSchema = z.object( {
|
|
|
31
31
|
providerFn: z.function()
|
|
32
32
|
} );
|
|
33
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
|
+
|
|
34
48
|
const toolConfigSchema = z.record( z.string(), z.unknown() );
|
|
35
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
|
+
*/
|
|
36
73
|
export function registerProvider( name, providerFn ) {
|
|
37
74
|
const result = registerProviderSchema.safeParse( { name, providerFn } );
|
|
38
75
|
if ( !result.success ) {
|
|
@@ -41,25 +78,23 @@ export function registerProvider( name, providerFn ) {
|
|
|
41
78
|
providers[name] = providerFn;
|
|
42
79
|
}
|
|
43
80
|
|
|
81
|
+
/**
|
|
82
|
+
* List all currently registered provider names.
|
|
83
|
+
*
|
|
84
|
+
* @returns {string[]} Provider names
|
|
85
|
+
*/
|
|
44
86
|
export const getRegisteredProviders = () => Object.keys( providers );
|
|
45
87
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Load a text model from a loaded prompt config.
|
|
90
|
+
*
|
|
91
|
+
* @param {object} prompt - Loaded prompt object with `config.provider` and `config.model`
|
|
92
|
+
* @returns {unknown} AI SDK language model
|
|
93
|
+
*/
|
|
94
|
+
export function loadTextModel( prompt ) {
|
|
95
|
+
const config = parseModelPrompt( prompt );
|
|
53
96
|
const { provider: providerName, model: modelName } = config;
|
|
54
97
|
|
|
55
|
-
if ( !providerName ) {
|
|
56
|
-
throw new Error( 'Prompt config is missing "provider" field' );
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
if ( !modelName ) {
|
|
60
|
-
throw new Error( 'Prompt config is missing "model" field' );
|
|
61
|
-
}
|
|
62
|
-
|
|
63
98
|
const provider = providers[providerName];
|
|
64
99
|
|
|
65
100
|
if ( !provider ) {
|
|
@@ -70,34 +105,42 @@ export function loadModel( prompt ) {
|
|
|
70
105
|
return provider( modelName );
|
|
71
106
|
}
|
|
72
107
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
108
|
+
/**
|
|
109
|
+
* Load an image model from a loaded prompt config.
|
|
110
|
+
*
|
|
111
|
+
* @param {object} prompt - Loaded prompt object with `config.provider` and `config.model`
|
|
112
|
+
* @returns {unknown} AI SDK image model
|
|
113
|
+
*/
|
|
114
|
+
export function loadImageModel( prompt ) {
|
|
115
|
+
const config = parseModelPrompt( prompt );
|
|
116
|
+
const { provider: providerName, model: modelName } = config;
|
|
79
117
|
|
|
80
|
-
const
|
|
118
|
+
const provider = providers[providerName];
|
|
81
119
|
|
|
82
|
-
if ( !
|
|
83
|
-
|
|
120
|
+
if ( !provider ) {
|
|
121
|
+
const availableProviders = Object.keys( providers ).join( ', ' );
|
|
122
|
+
throw new Error( `Invalid provider "${providerName}". Valid providers: ${availableProviders}` );
|
|
84
123
|
}
|
|
85
124
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
'Use "tools: { googleSearch: {} }" not "tools: [googleSearch]"'
|
|
90
|
-
);
|
|
125
|
+
const imageModelFactory = provider.image ?? provider.imageModel;
|
|
126
|
+
if ( typeof imageModelFactory !== 'function' ) {
|
|
127
|
+
throw new Error( `Provider "${providerName}" does not support image models.` );
|
|
91
128
|
}
|
|
92
129
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
130
|
+
return imageModelFactory( modelName );
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Load provider-specific tools configured in a prompt.
|
|
135
|
+
*
|
|
136
|
+
* @param {object} prompt - Loaded prompt object with `config.provider` and optional `config.tools`
|
|
137
|
+
* @returns {Record<string, unknown> | null} AI SDK tools, or null when none are configured
|
|
138
|
+
*/
|
|
139
|
+
export function loadTools( prompt ) {
|
|
140
|
+
const config = parseToolsPrompt( prompt );
|
|
141
|
+
const { tools: toolsConfig, provider: providerName } = config;
|
|
99
142
|
|
|
100
|
-
if ( Object.keys( toolsConfig ).length === 0 ) {
|
|
143
|
+
if ( !toolsConfig || Object.keys( toolsConfig ).length === 0 ) {
|
|
101
144
|
return null;
|
|
102
145
|
}
|
|
103
146
|
|
package/src/ai_model.spec.js
CHANGED
|
@@ -2,6 +2,7 @@ import { it, expect, vi, afterEach, describe } from 'vitest';
|
|
|
2
2
|
|
|
3
3
|
const providerFactoryOptions = vi.hoisted( () => ( {} ) );
|
|
4
4
|
const openaiImpl = vi.hoisted( () => vi.fn( model => `openai:${model}` ) );
|
|
5
|
+
const openaiImageImpl = vi.hoisted( () => vi.fn( model => `openai-image:${model}` ) );
|
|
5
6
|
const azureImpl = vi.hoisted( () => vi.fn( model => `azure:${model}` ) );
|
|
6
7
|
const anthropicImpl = vi.hoisted( () => vi.fn( model => `anthropic:${model}` ) );
|
|
7
8
|
const bedrockImpl = vi.hoisted( () => vi.fn( model => `bedrock:${model}` ) );
|
|
@@ -11,6 +12,7 @@ const vertexImpl = vi.hoisted( () => vi.fn( model => `vertex:${model}` ) );
|
|
|
11
12
|
// OpenAI mock with tools support
|
|
12
13
|
vi.mock( '@ai-sdk/openai', () => {
|
|
13
14
|
const openaiMock = ( ...values ) => openaiImpl( ...values );
|
|
15
|
+
openaiMock.image = ( ...values ) => openaiImageImpl( ...values );
|
|
14
16
|
openaiMock.tools = {
|
|
15
17
|
webSearch: ( config = {} ) => ( { type: 'webSearch', config } )
|
|
16
18
|
};
|
|
@@ -93,14 +95,14 @@ vi.mock( '@ai-sdk/google-vertex', () => {
|
|
|
93
95
|
};
|
|
94
96
|
} );
|
|
95
97
|
|
|
96
|
-
import {
|
|
98
|
+
import { loadImageModel, loadTextModel, loadTools, registerProvider, getRegisteredProviders, providers, builtInProviders } from './ai_model.js';
|
|
97
99
|
|
|
98
100
|
afterEach( async () => {
|
|
99
101
|
await vi.resetModules();
|
|
100
102
|
vi.clearAllMocks();
|
|
101
103
|
} );
|
|
102
104
|
|
|
103
|
-
describe( '
|
|
105
|
+
describe( 'loadTextModel', () => {
|
|
104
106
|
it( 'initializes built-in providers with custom fetch', () => {
|
|
105
107
|
expect( providerFactoryOptions ).toMatchObject( {
|
|
106
108
|
azure: { fetch: expect.any( Function ) },
|
|
@@ -113,7 +115,7 @@ describe( 'loadModel', () => {
|
|
|
113
115
|
} );
|
|
114
116
|
|
|
115
117
|
it( 'loads model using selected provider', () => {
|
|
116
|
-
const result =
|
|
118
|
+
const result = loadTextModel( { config: { provider: 'openai', model: 'gpt-4o-mini' } } );
|
|
117
119
|
|
|
118
120
|
expect( result ).toBe( 'openai:gpt-4o-mini' );
|
|
119
121
|
expect( openaiImpl ).toHaveBeenCalledWith( 'gpt-4o-mini' );
|
|
@@ -122,20 +124,36 @@ describe( 'loadModel', () => {
|
|
|
122
124
|
} );
|
|
123
125
|
|
|
124
126
|
it( 'loads model using bedrock provider', () => {
|
|
125
|
-
const result =
|
|
127
|
+
const result = loadTextModel( { config: { provider: 'bedrock', model: 'anthropic.claude-sonnet-4-20250514-v1:0' } } );
|
|
126
128
|
|
|
127
129
|
expect( result ).toBe( 'bedrock:anthropic.claude-sonnet-4-20250514-v1:0' );
|
|
128
130
|
expect( bedrockImpl ).toHaveBeenCalledWith( 'anthropic.claude-sonnet-4-20250514-v1:0' );
|
|
129
131
|
} );
|
|
130
132
|
|
|
131
133
|
it( 'loads model using perplexity provider', () => {
|
|
132
|
-
const result =
|
|
134
|
+
const result = loadTextModel( { config: { provider: 'perplexity', model: 'sonar-pro' } } );
|
|
133
135
|
|
|
134
136
|
expect( result ).toBe( 'perplexity:sonar-pro' );
|
|
135
137
|
expect( perplexityImpl ).toHaveBeenCalledWith( 'sonar-pro' );
|
|
136
138
|
} );
|
|
137
139
|
} );
|
|
138
140
|
|
|
141
|
+
describe( 'loadImageModel', () => {
|
|
142
|
+
it( 'loads image model using provider image factory', () => {
|
|
143
|
+
const result = loadImageModel( { config: { provider: 'openai', model: 'gpt-image-1' } } );
|
|
144
|
+
|
|
145
|
+
expect( result ).toBe( 'openai-image:gpt-image-1' );
|
|
146
|
+
expect( openaiImageImpl ).toHaveBeenCalledWith( 'gpt-image-1' );
|
|
147
|
+
expect( openaiImpl ).not.toHaveBeenCalled();
|
|
148
|
+
} );
|
|
149
|
+
|
|
150
|
+
it( 'throws a clear error when provider does not support image models', () => {
|
|
151
|
+
expect( () => loadImageModel( {
|
|
152
|
+
config: { provider: 'azure', model: 'gpt-image-1' }
|
|
153
|
+
} ) ).toThrow( 'Provider "azure" does not support image models.' );
|
|
154
|
+
} );
|
|
155
|
+
} );
|
|
156
|
+
|
|
139
157
|
describe( 'loadTools', () => {
|
|
140
158
|
// Category 1: Basic Functionality (5 tests)
|
|
141
159
|
describe( 'Basic Functionality', () => {
|
|
@@ -593,7 +611,7 @@ describe( 'loadTools', () => {
|
|
|
593
611
|
provider: 'vertex',
|
|
594
612
|
tools: [ 'googleSearch', 'urlContext' ]
|
|
595
613
|
}
|
|
596
|
-
} ) ).toThrow(
|
|
614
|
+
} ) ).toThrow( /Invalid tools prompt config/ );
|
|
597
615
|
} );
|
|
598
616
|
|
|
599
617
|
it( 'throws error for string format', () => {
|
|
@@ -602,7 +620,7 @@ describe( 'loadTools', () => {
|
|
|
602
620
|
provider: 'vertex',
|
|
603
621
|
tools: 'googleSearch'
|
|
604
622
|
}
|
|
605
|
-
} ) ).toThrow(
|
|
623
|
+
} ) ).toThrow( /Invalid tools prompt config/ );
|
|
606
624
|
} );
|
|
607
625
|
|
|
608
626
|
it( 'throws error for number format', () => {
|
|
@@ -611,7 +629,7 @@ describe( 'loadTools', () => {
|
|
|
611
629
|
provider: 'vertex',
|
|
612
630
|
tools: 123
|
|
613
631
|
}
|
|
614
|
-
} ) ).toThrow(
|
|
632
|
+
} ) ).toThrow( /Invalid tools prompt config/ );
|
|
615
633
|
} );
|
|
616
634
|
|
|
617
635
|
it( 'throws error for provider without tools support', () => {
|
|
@@ -656,7 +674,7 @@ describe( 'loadTools', () => {
|
|
|
656
674
|
provider: 'vertex',
|
|
657
675
|
tools: { googleSearch: null }
|
|
658
676
|
}
|
|
659
|
-
} ) ).toThrow( /Invalid
|
|
677
|
+
} ) ).toThrow( /Invalid tools prompt config.*expected record, received null/s );
|
|
660
678
|
} );
|
|
661
679
|
|
|
662
680
|
it( 'throws error when tool config is a string', () => {
|
|
@@ -665,7 +683,7 @@ describe( 'loadTools', () => {
|
|
|
665
683
|
provider: 'vertex',
|
|
666
684
|
tools: { googleSearch: 'MODE_DYNAMIC' }
|
|
667
685
|
}
|
|
668
|
-
} ) ).toThrow( /Invalid
|
|
686
|
+
} ) ).toThrow( /Invalid tools prompt config.*expected record, received string/s );
|
|
669
687
|
} );
|
|
670
688
|
|
|
671
689
|
it( 'throws error for unknown tool on Bedrock with dynamic tool listing', () => {
|
|
@@ -753,11 +771,11 @@ describe( 'registerProvider', () => {
|
|
|
753
771
|
Object.assign( providers, builtInProviders );
|
|
754
772
|
} );
|
|
755
773
|
|
|
756
|
-
it( 'registers a custom provider and uses it in
|
|
774
|
+
it( 'registers a custom provider and uses it in loadTextModel', () => {
|
|
757
775
|
const customProvider = vi.fn( model => `custom:${model}` );
|
|
758
776
|
registerProvider( 'custom', customProvider );
|
|
759
777
|
|
|
760
|
-
const result =
|
|
778
|
+
const result = loadTextModel( { config: { provider: 'custom', model: 'my-model' } } );
|
|
761
779
|
|
|
762
780
|
expect( result ).toBe( 'custom:my-model' );
|
|
763
781
|
expect( customProvider ).toHaveBeenCalledWith( 'my-model' );
|
|
@@ -767,7 +785,7 @@ describe( 'registerProvider', () => {
|
|
|
767
785
|
const overrideOpenai = vi.fn( model => `override:${model}` );
|
|
768
786
|
registerProvider( 'openai', overrideOpenai );
|
|
769
787
|
|
|
770
|
-
const result =
|
|
788
|
+
const result = loadTextModel( { config: { provider: 'openai', model: 'gpt-custom' } } );
|
|
771
789
|
|
|
772
790
|
expect( result ).toBe( 'override:gpt-custom' );
|
|
773
791
|
} );
|
package/src/ai_sdk.js
CHANGED
|
@@ -1,113 +1,89 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { types as utilTypes } from 'node:util';
|
|
2
2
|
import * as AI from 'ai';
|
|
3
3
|
import { stepCountIs } from 'ai';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
4
|
+
import { ValidationError } from '@outputai/core';
|
|
5
|
+
import { validateGenerateTextArgs, validateStreamTextArgs, validateGenerateImageArgs } from './validations.js';
|
|
6
|
+
import { loadPrompt } from './prompt/loader.js';
|
|
7
7
|
import { startTrace, endTraceWithError } from './utils/trace.js';
|
|
8
|
-
import { wrapTextResponse, wrapStreamOnFinishResponse } from './utils/response_wrappers.js';
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
model: loadModel( prompt ),
|
|
13
|
-
messages: prompt.messages,
|
|
14
|
-
providerOptions: prompt.config.providerOptions
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
if ( Number.isFinite( prompt.config.temperature ) ) {
|
|
18
|
-
options.temperature = prompt.config.temperature;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
if ( prompt.config.maxTokens ) {
|
|
22
|
-
options.maxOutputTokens = prompt.config.maxTokens;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const tools = loadTools( prompt );
|
|
26
|
-
if ( tools ) {
|
|
27
|
-
options.tools = tools;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return options;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
export const hydratePromptTemplate = ( prompt, variables, promptDir, callerSkills, callerTools = {} ) => {
|
|
34
|
-
const meta = loadPrompt( prompt, variables, promptDir );
|
|
35
|
-
|
|
36
|
-
// Resolve skills: explicit frontmatter paths > colocated auto-discovery
|
|
37
|
-
const hasExplicitSkills = meta.config.skills && meta.promptFileDir;
|
|
38
|
-
const frontmatterSkills = hasExplicitSkills ?
|
|
39
|
-
loadPromptSkills( meta.config.skills, meta.promptFileDir ) :
|
|
40
|
-
[];
|
|
41
|
-
const autoSkills = !hasExplicitSkills && meta.promptFileDir ?
|
|
42
|
-
loadColocatedSkills( meta.promptFileDir ) :
|
|
43
|
-
[];
|
|
44
|
-
const resolvedSkills = [ ...frontmatterSkills, ...autoSkills, ...callerSkills ];
|
|
45
|
-
|
|
46
|
-
const tools = resolvedSkills.length > 0 ?
|
|
47
|
-
{ load_skill: buildLoadSkillTool( resolvedSkills ), ...callerTools } :
|
|
48
|
-
callerTools;
|
|
49
|
-
|
|
50
|
-
const skillsMessage = resolvedSkills.length > 0 ?
|
|
51
|
-
{ role: 'system', content: buildSystemSkillsVar( resolvedSkills ) } :
|
|
52
|
-
null;
|
|
53
|
-
|
|
54
|
-
if ( skillsMessage ) {
|
|
55
|
-
// Merge into existing system message to avoid provider errors with multiple system messages
|
|
56
|
-
const systemMsg = meta.messages.find( m => m.role === 'system' );
|
|
57
|
-
if ( systemMsg ) {
|
|
58
|
-
systemMsg.content = `${systemMsg.content}\n\n${skillsMessage.content}`;
|
|
59
|
-
} else {
|
|
60
|
-
meta.messages.unshift( skillsMessage );
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
return { loadedPrompt: meta, allVariables: variables, tools };
|
|
65
|
-
};
|
|
8
|
+
import { wrapTextResponse, wrapStreamOnFinishResponse, wrapImageResponse } from './utils/response_wrappers.js';
|
|
9
|
+
import { loadAiSdkTextOptions, loadAiSdkImageOptions } from './ai_sdk_options.js';
|
|
10
|
+
import { prepareTextPrompt } from './prompt/prepare_text.js';
|
|
11
|
+
import { mapAiError } from './utils/error_handler.js';
|
|
66
12
|
|
|
67
13
|
export async function generateText( { prompt, variables, promptDir, skills = [], maxSteps = 10, ...aiSdkArgs } ) {
|
|
68
|
-
|
|
69
|
-
const { loadedPrompt, allVariables, tools } =
|
|
70
|
-
hydratePromptTemplate( prompt, variables, promptDir, callerSkills, aiSdkArgs.tools );
|
|
71
|
-
const hasTools = Object.keys( tools ).length > 0;
|
|
14
|
+
validateGenerateTextArgs( { prompt, variables, promptDir, skills, maxSteps } );
|
|
72
15
|
|
|
73
|
-
|
|
16
|
+
const parsedSkills = typeof skills === 'function' ? await skills( variables ) : skills;
|
|
17
|
+
const { loadedPrompt, tools } = prepareTextPrompt( { prompt, variables, promptDir, skills: parsedSkills, tools: aiSdkArgs.tools } );
|
|
74
18
|
|
|
75
|
-
const traceId = startTrace( { name: 'generateText', prompt, variables
|
|
19
|
+
const traceId = startTrace( { name: 'generateText', prompt, variables, loadedPrompt } );
|
|
76
20
|
const { model: modelId } = loadedPrompt.config;
|
|
77
21
|
|
|
78
22
|
try {
|
|
79
23
|
const response = await AI.generateText( {
|
|
80
|
-
...
|
|
24
|
+
...loadAiSdkTextOptions( loadedPrompt ),
|
|
81
25
|
maxRetries: 0,
|
|
82
26
|
...aiSdkArgs,
|
|
83
|
-
...(
|
|
84
|
-
...(
|
|
27
|
+
...( tools && { tools } ),
|
|
28
|
+
...( tools && !aiSdkArgs.stopWhen ? { stopWhen: stepCountIs( maxSteps ) } : {} )
|
|
85
29
|
} );
|
|
86
30
|
return wrapTextResponse( { traceId, modelId, response } );
|
|
87
|
-
} catch (
|
|
31
|
+
} catch ( originalError ) {
|
|
32
|
+
const error = mapAiError( originalError );
|
|
88
33
|
endTraceWithError( { traceId, error } );
|
|
89
34
|
throw error;
|
|
90
35
|
}
|
|
91
36
|
}
|
|
92
37
|
|
|
93
|
-
export function streamText( { prompt, variables, onFinish, onError, ...aiSdkArgs } ) {
|
|
94
|
-
validateStreamTextArgs( { prompt, variables } );
|
|
95
|
-
|
|
38
|
+
export function streamText( { prompt, variables, promptDir, skills = [], maxSteps = 10, onFinish, onError: _onError, ...aiSdkArgs } ) {
|
|
39
|
+
validateStreamTextArgs( { prompt, variables, promptDir, skills, maxSteps } );
|
|
40
|
+
|
|
41
|
+
const parsedSkills = typeof skills === 'function' ? skills( variables ) : skills;
|
|
42
|
+
if ( utilTypes.isPromise( parsedSkills ) ) {
|
|
43
|
+
throw new ValidationError( 'streamText() skills must be synchronous because streamText() returns a stream immediately.' );
|
|
44
|
+
}
|
|
45
|
+
const { loadedPrompt, tools } = prepareTextPrompt( { prompt, variables, promptDir, skills: parsedSkills, tools: aiSdkArgs.tools } );
|
|
46
|
+
|
|
96
47
|
const traceId = startTrace( { name: 'streamText', prompt, variables, loadedPrompt } );
|
|
97
48
|
const { model: modelId } = loadedPrompt.config;
|
|
98
49
|
|
|
99
50
|
try {
|
|
100
51
|
return AI.streamText( {
|
|
101
|
-
...
|
|
52
|
+
...loadAiSdkTextOptions( loadedPrompt ),
|
|
102
53
|
maxRetries: 0,
|
|
103
54
|
...aiSdkArgs,
|
|
55
|
+
...( tools && { tools } ),
|
|
56
|
+
...( tools && !aiSdkArgs.stopWhen ? { stopWhen: stepCountIs( maxSteps ) } : {} ),
|
|
104
57
|
...wrapStreamOnFinishResponse( { traceId, modelId, onFinish } ),
|
|
105
58
|
onError( event ) {
|
|
106
|
-
|
|
107
|
-
|
|
59
|
+
const error = mapAiError( event.error );
|
|
60
|
+
endTraceWithError( { traceId, error } );
|
|
61
|
+
_onError?.( { ...event, error } );
|
|
108
62
|
}
|
|
109
63
|
} );
|
|
110
|
-
} catch (
|
|
64
|
+
} catch ( originalError ) {
|
|
65
|
+
const error = mapAiError( originalError );
|
|
66
|
+
endTraceWithError( { traceId, error } );
|
|
67
|
+
throw error;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export async function generateImage( { prompt, variables, promptDir, images, mask, ...aiSdkArgs } ) {
|
|
72
|
+
validateGenerateImageArgs( { prompt, variables, promptDir, images, mask } );
|
|
73
|
+
|
|
74
|
+
const loadedPrompt = loadPrompt( prompt, variables, promptDir );
|
|
75
|
+
const traceId = startTrace( { name: 'generateImage', prompt, variables, loadedPrompt } );
|
|
76
|
+
const { model: modelId } = loadedPrompt.config;
|
|
77
|
+
|
|
78
|
+
try {
|
|
79
|
+
const response = await AI.generateImage( {
|
|
80
|
+
...loadAiSdkImageOptions( { prompt: loadedPrompt, images, mask } ),
|
|
81
|
+
maxRetries: 0,
|
|
82
|
+
...aiSdkArgs
|
|
83
|
+
} );
|
|
84
|
+
return wrapImageResponse( { traceId, modelId, response } );
|
|
85
|
+
} catch ( originalError ) {
|
|
86
|
+
const error = mapAiError( originalError );
|
|
111
87
|
endTraceWithError( { traceId, error } );
|
|
112
88
|
throw error;
|
|
113
89
|
}
|