@outputai/llm 0.6.1-dev.aab2335.0 → 0.6.1-next.0d08ff5.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.
Files changed (45) hide show
  1. package/package.json +2 -2
  2. package/src/agent.js +15 -9
  3. package/src/agent.spec.js +295 -214
  4. package/src/ai_model.js +79 -36
  5. package/src/ai_model.spec.js +31 -13
  6. package/src/ai_sdk.js +55 -79
  7. package/src/ai_sdk.spec.js +464 -611
  8. package/src/ai_sdk_options.js +61 -0
  9. package/src/ai_sdk_options.spec.js +164 -0
  10. package/src/cost/index.js +1 -1
  11. package/src/index.d.ts +230 -175
  12. package/src/index.js +2 -2
  13. package/src/prompt/escape.js +65 -0
  14. package/src/prompt/escape.spec.js +159 -0
  15. package/src/{load_content.js → prompt/load_content.js} +1 -22
  16. package/src/{load_content.spec.js → prompt/load_content.spec.js} +6 -6
  17. package/src/prompt/loader.js +49 -0
  18. package/src/prompt/loader.spec.js +274 -0
  19. package/src/{prompt_loader_validation.spec.js → prompt/loader_validation.spec.js} +40 -7
  20. package/src/prompt/parser.js +19 -0
  21. package/src/{parser.spec.js → prompt/parser.spec.js} +74 -29
  22. package/src/prompt/prepare_text.js +27 -0
  23. package/src/prompt/prepare_text.spec.js +141 -0
  24. package/src/{skill.js → prompt/skill.js} +19 -0
  25. package/src/prompt/skill.spec.js +172 -0
  26. package/src/{prompt_validations.js → prompt/validations.js} +32 -6
  27. package/src/{prompt_validations.spec.js → prompt/validations.spec.js} +189 -1
  28. package/src/utils/__fixtures__/image_response.json +38 -0
  29. package/src/utils/__fixtures__/stream_response.json +294 -0
  30. package/src/utils/__fixtures__/text_response.json +201 -0
  31. package/src/utils/error_handler.js +65 -0
  32. package/src/utils/error_handler.spec.js +195 -0
  33. package/src/utils/image.js +10 -0
  34. package/src/utils/image.spec.js +20 -0
  35. package/src/utils/response_wrappers.js +46 -19
  36. package/src/utils/response_wrappers.spec.js +130 -70
  37. package/src/utils/source_extraction.js +17 -27
  38. package/src/utils/trace.js +2 -3
  39. package/src/utils/trace.spec.js +9 -13
  40. package/src/validations.js +54 -2
  41. package/src/validations.spec.js +166 -0
  42. package/src/parser.js +0 -28
  43. package/src/prompt_loader.js +0 -80
  44. package/src/prompt_loader.spec.js +0 -358
  45. package/src/skill.d.ts +0 -49
package/src/index.d.ts CHANGED
@@ -1,20 +1,49 @@
1
1
  import type {
2
+ AgentCallParameters,
2
3
  AgentStreamParameters,
3
4
  GenerateTextResult as AIGenerateTextResult,
5
+ GenerateImageResult as AIGenerateImageResult,
4
6
  StreamTextResult as AIStreamTextResult,
7
+ ToolLoopAgent as AIToolLoopAgent,
8
+ ToolSet,
9
+ StreamTextOnFinishCallback,
10
+ generateText as aiGenerateText,
11
+ streamText as aiStreamText,
12
+ generateImage as aiGenerateImage
13
+ } from 'ai';
14
+ import type { Output as AIOutputNamespace } from 'ai';
15
+
16
+ // Re-export AI SDK types directly (auto-synced with AI SDK updates)
17
+ export type {
18
+ LanguageModelUsage,
19
+ FinishReason,
20
+ LanguageModelResponseMetadata,
21
+ ProviderMetadata,
22
+ CallWarning,
23
+ Warning,
5
24
  CallSettings,
6
25
  ToolSet,
7
26
  ToolChoice,
27
+ Tool,
8
28
  StopCondition,
29
+ StepResult,
9
30
  GenerateTextOnStepFinishCallback,
10
- StreamTextOnStepFinishCallback,
11
- StreamTextTransform,
12
31
  PrepareStepFunction,
32
+ PrepareStepResult,
13
33
  StreamTextOnChunkCallback,
14
34
  StreamTextOnFinishCallback,
15
- StreamTextOnErrorCallback
35
+ StreamTextOnErrorCallback,
36
+ StreamTextTransform,
37
+ TextStreamPart
16
38
  } from 'ai';
17
- import type { Output as AIOutput } from 'ai';
39
+
40
+ // Re-export the tool helper function, Output, smoothStream, stop condition helpers, and jsonSchema
41
+ export { tool, Output, smoothStream, stepCountIs, hasToolCall, jsonSchema } from 'ai';
42
+
43
+ // Web search tool factories
44
+ export { tavilySearch, tavilyExtract, tavilyCrawl, tavilyMap } from '@tavily/ai-sdk';
45
+ export { webSearch as exaSearch } from '@exalabs/ai-sdk';
46
+ export { perplexitySearch } from '@perplexity-ai/ai-sdk';
18
47
 
19
48
  /**
20
49
  * Represents a single message in a prompt conversation.
@@ -55,6 +84,9 @@ export type Prompt = {
55
84
  /** Name of the prompt file */
56
85
  name: string;
57
86
 
87
+ /** Directory containing the resolved prompt file */
88
+ promptFileDir?: string;
89
+
58
90
  /** General configuration for the LLM */
59
91
  config: {
60
92
  /** LLM provider (built-in: 'anthropic', 'openai', 'azure', 'vertex', 'bedrock', 'perplexity'; or any registered custom provider) */
@@ -69,6 +101,24 @@ export type Prompt = {
69
101
  /** Maximum number of tokens in the response */
70
102
  maxTokens?: number;
71
103
 
104
+ /** Number of images to generate */
105
+ n?: number;
106
+
107
+ /** Maximum images to request per provider call */
108
+ maxImagesPerCall?: number;
109
+
110
+ /** Image size, for example `1024x1024` */
111
+ size?: `${number}x${number}`;
112
+
113
+ /** Image aspect ratio, for example `16:9` */
114
+ aspectRatio?: `${number}:${number}`;
115
+
116
+ /** Random seed for deterministic image generation when supported */
117
+ seed?: number;
118
+
119
+ /** Skill file or directory paths resolved relative to the prompt file */
120
+ skills?: string | string[];
121
+
72
122
  /**
73
123
  * Provider-specific tools with configuration.
74
124
  *
@@ -97,121 +147,143 @@ export type Prompt = {
97
147
 
98
148
  /** Array of messages in the conversation */
99
149
  messages: PromptMessage[];
100
- };
101
150
 
102
- // Re-export AI SDK types directly (auto-synced with AI SDK updates)
103
- export type {
104
- LanguageModelUsage,
105
- FinishReason,
106
- LanguageModelResponseMetadata,
107
- ProviderMetadata,
108
- CallWarning,
109
- Warning,
110
- CallSettings,
111
- ToolSet,
112
- ToolChoice,
113
- Tool,
114
- StopCondition,
115
- StepResult,
116
- GenerateTextOnStepFinishCallback,
117
- PrepareStepFunction,
118
- PrepareStepResult,
119
- StreamTextOnChunkCallback,
120
- StreamTextOnFinishCallback,
121
- StreamTextOnErrorCallback,
122
- StreamTextTransform,
123
- TextStreamPart
124
- } from 'ai';
125
-
126
- // Re-export the tool helper function, Output, smoothStream, stop condition helpers, and jsonSchema
127
- export { tool, Output, smoothStream, stepCountIs, hasToolCall, jsonSchema } from 'ai';
151
+ /** Plain prompt instructions for non-chat prompt files */
152
+ instructions?: string | null;
153
+ };
128
154
 
129
- // Web search tool factories
130
- export { tavilySearch, tavilyExtract, tavilyCrawl, tavilyMap } from '@tavily/ai-sdk';
131
- export { webSearch as exaSearch } from '@exalabs/ai-sdk';
132
- export { perplexitySearch } from '@perplexity-ai/ai-sdk';
155
+ /**
156
+ * An instruction package that an agent can load on demand via the load_skill tool.
157
+ *
158
+ * Skills are declared in prompt frontmatter or passed inline to generation APIs.
159
+ */
160
+ export type Skill = {
161
+ name: string;
162
+ description?: string;
163
+ instructions: string;
164
+ };
133
165
 
134
166
  /**
135
- * Common AI SDK options that can be passed through to all generate functions.
136
- * These options are passed directly to the underlying AI SDK call.
167
+ * The skills argument for async generation APIs. Either a static list or a function
168
+ * that receives the call input and may resolve skills asynchronously.
137
169
  */
138
- type AiSdkOptions = Partial<Omit<CallSettings, 'maxOutputTokens'>>;
170
+ export type SkillsArg<Input = unknown> = Skill[] |
171
+ ( ( input: Input ) => Skill[] | Promise<Skill[]> );
172
+
173
+ /** Prompt-owned AI SDK fields supplied by Output prompt files. */
174
+ type PromptOwnedTextOptions = 'model' | 'messages' | 'prompt';
175
+ type AnyAiOutput = AIOutputNamespace.Output<unknown, unknown, unknown>;
139
176
 
140
177
  /**
141
- * AI SDK options specific to generateText, including tool calling and multi-step support.
178
+ * AI SDK options accepted by generateText, with prompt-owned fields supplied by Output prompt files.
179
+ *
142
180
  * @typeParam Tools - The tools available for the model to call
143
181
  */
144
- type GenerateTextAiSdkOptions<
182
+ export type GenerateTextAiSdkOptions<
145
183
  Tools extends ToolSet = ToolSet,
146
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
147
- > = AiSdkOptions & {
148
- /** Tools the model can call */
149
- tools?: Tools;
150
- /** Tool choice strategy: 'auto', 'none', 'required', or specific tool */
151
- toolChoice?: ToolChoice<Tools>;
152
- /** Limit which tools are active without changing types */
153
- activeTools?: Array<keyof Tools>;
154
- /** Maximum number of automatic tool execution rounds (multi-step) */
155
- maxSteps?: number;
156
- /** Custom stop conditions for multi-step execution */
157
- stopWhen?: StopCondition<Tools> | StopCondition<Tools>[];
158
- /** Callback after each step completes */
159
- onStepFinish?: GenerateTextOnStepFinishCallback<Tools>;
160
- /** Customize each step before execution */
161
- prepareStep?: PrepareStepFunction<Tools>;
162
- /** Structured output specification (e.g., Output.object({ schema })) */
163
- output?: Output;
164
- };
184
+ OutputSpec extends AnyAiOutput = AnyAiOutput
185
+ > = Omit<Parameters<typeof aiGenerateText<Tools, OutputSpec>>[0], PromptOwnedTextOptions>;
165
186
 
166
187
  /**
167
- * AI SDK options specific to streamText, including tool calling, multi-step, and streaming callbacks.
188
+ * AI SDK options accepted by streamText, with prompt-owned fields supplied by Output prompt files.
189
+ *
168
190
  * @typeParam Tools - The tools available for the model to call
169
191
  */
170
- type StreamTextAiSdkOptions<
192
+ export type StreamTextAiSdkOptions<
171
193
  Tools extends ToolSet = ToolSet,
172
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
173
- > = AiSdkOptions & {
174
- /** Tools the model can call */
175
- tools?: Tools;
176
- /** Tool choice strategy: 'auto', 'none', 'required', or specific tool */
177
- toolChoice?: ToolChoice<Tools>;
178
- /** Limit which tools are active without changing types */
179
- activeTools?: Array<keyof Tools>;
180
- /** Maximum number of automatic tool execution rounds (multi-step) */
181
- maxSteps?: number;
182
- /** Custom stop conditions for multi-step execution */
183
- stopWhen?: StopCondition<Tools> | StopCondition<Tools>[];
184
- /** Callback after each step completes */
185
- onStepFinish?: StreamTextOnStepFinishCallback<Tools>;
186
- /** Customize each step before execution */
187
- prepareStep?: PrepareStepFunction<Tools>;
188
- /** Structured output specification (e.g., Output.object({ schema })) */
189
- output?: Output;
190
- /** Callback for each stream chunk */
191
- onChunk?: StreamTextOnChunkCallback<Tools>;
192
- /** Callback when stream finishes. Called after internal tracing records the result. */
193
- onFinish?: StreamTextOnFinishCallback<Tools>;
194
- /** Callback when stream errors. Called after internal tracing records the error. */
195
- onError?: StreamTextOnErrorCallback;
196
- /** Stream transformation (e.g., smoothStream()) */
197
- experimental_transform?: StreamTextTransform<Tools> | Array<StreamTextTransform<Tools>>;
198
- };
194
+ OutputSpec extends AnyAiOutput = AnyAiOutput
195
+ > = Omit<Parameters<typeof aiStreamText<Tools, OutputSpec>>[0], PromptOwnedTextOptions>;
199
196
 
200
197
  /**
201
- * Like {@link StreamTextAiSdkOptions} but `onFinish` receives {@link WrappedStreamTextOnFinishEvent} (adds `cost`).
198
+ * AI SDK options specific to generateImage.
199
+ *
200
+ * `model` and `prompt` are omitted because Output supplies them from the prompt file.
202
201
  */
203
- type OutputStreamTextAiSdkOptions<
204
- Tools extends ToolSet = ToolSet,
205
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
206
- > = Omit<StreamTextAiSdkOptions<Tools, Output>, 'onFinish'> & {
207
- onFinish?: WrappedStreamTextOnFinishCallback<Tools>;
208
- };
202
+ export type GenerateImageAiSdkOptions = Omit<Parameters<typeof aiGenerateImage>[0], 'model' | 'prompt'>;
203
+ type GenerateImagePrompt = Parameters<typeof aiGenerateImage>[0]['prompt'];
204
+ type GenerateImagePromptWithImages = Exclude<GenerateImagePrompt, string>;
205
+ type GenerateImageInput = GenerateImagePromptWithImages['images'][number];
209
206
 
210
207
  /** Agent {@link Agent.stream} options: same as AI SDK plus wrapped `onFinish` (adds `cost`). */
211
208
  export type OutputAgentStreamParameters = Omit<AgentStreamParameters<never, ToolSet>, 'onFinish'> & {
212
209
  onFinish?: WrappedStreamTextOnFinishCallback<ToolSet>;
213
210
  };
214
211
 
212
+ /** Agent constructor options, with prompt-owned model/instructions/tools supplied by Output prompt files and skills. */
213
+ export type OutputAgentConstructorParameters<
214
+ OutputSpec extends AnyAiOutput = AnyAiOutput
215
+ > = Omit<ConstructorParameters<typeof AIToolLoopAgent>[0], 'model' | 'instructions' | 'tools' | 'output'> & {
216
+ /** Prompt file name (e.g. 'my_agent@v1') */
217
+ prompt: string;
218
+ /** Override the stack-resolved prompt directory */
219
+ promptDir?: string;
220
+ /** Variables to render the prompt template at construction time */
221
+ variables?: Record<string, unknown>;
222
+ /** Structured output specification */
223
+ output?: OutputSpec;
224
+ /** Static skill packages made available to the LLM */
225
+ skills?: Skill[];
226
+ /** AI SDK tools available during the reasoning loop */
227
+ tools?: ConstructorParameters<typeof AIToolLoopAgent>[0]['tools'];
228
+ /** Maximum tool-loop iterations when stopWhen is not specified (default: 10) */
229
+ maxSteps?: number;
230
+ /** Pluggable conversation store — opt-in, stateless by default */
231
+ conversationStore?: ConversationStore;
232
+ };
233
+
234
+ /** Agent generate options accepted by the underlying AI SDK agent. */
235
+ export type OutputAgentGenerateParameters = AgentCallParameters<never, ToolSet>;
236
+
237
+ /** Parameters accepted by {@link generateText}. */
238
+ export type GenerateTextParameters<
239
+ Tools extends ToolSet = ToolSet,
240
+ OutputSpec extends AnyAiOutput = AnyAiOutput
241
+ > = {
242
+ /** Prompt file name */
243
+ prompt: string;
244
+ /** Variables to interpolate into the prompt file */
245
+ variables?: Record<string, string | number | boolean>;
246
+ /** Override the stack-resolved prompt directory */
247
+ promptDir?: string;
248
+ /** Skill packages to provide to the LLM through the `load_skill` tool */
249
+ skills?: SkillsArg<Record<string, string | number | boolean> | undefined>;
250
+ /** Used to create a default `stepCountIs(maxSteps)` when tools are present and `stopWhen` is omitted */
251
+ maxSteps?: number;
252
+ } & GenerateTextAiSdkOptions<Tools, OutputSpec>;
253
+
254
+ /** Parameters accepted by {@link streamText}. */
255
+ export type StreamTextParameters<
256
+ Tools extends ToolSet = ToolSet,
257
+ OutputSpec extends AnyAiOutput = AnyAiOutput
258
+ > = {
259
+ /** Prompt file name */
260
+ prompt: string;
261
+ /** Variables to interpolate into the prompt file */
262
+ variables?: Record<string, string | number | boolean>;
263
+ /** Override the stack-resolved prompt directory */
264
+ promptDir?: string;
265
+ /** Skill packages to provide to the LLM through the `load_skill` tool. Function resolvers must be synchronous. */
266
+ skills?: Skill[] | ( ( input: Record<string, string | number | boolean> | undefined ) => Skill[] );
267
+ /** Used to create a default `stepCountIs(maxSteps)` when tools are present and `stopWhen` is omitted */
268
+ maxSteps?: number;
269
+ /** Callback when stream finishes. Receives the wrapped event with optional `cost`. */
270
+ onFinish?: WrappedStreamTextOnFinishCallback<Tools>;
271
+ } & Omit<StreamTextAiSdkOptions<Tools, OutputSpec>, 'onFinish'>;
272
+
273
+ /** Parameters accepted by {@link generateImage}. */
274
+ export type GenerateImageParameters = {
275
+ /** Prompt file name */
276
+ prompt: string;
277
+ /** Variables to interpolate into the prompt file */
278
+ variables?: Record<string, string | number | boolean>;
279
+ /** Override the stack-resolved prompt directory */
280
+ promptDir?: string;
281
+ /** Runtime image inputs for image-to-image generation */
282
+ images?: GenerateImageInput[];
283
+ /** Optional mask for image editing */
284
+ mask?: GenerateImagePromptWithImages['mask'];
285
+ } & GenerateImageAiSdkOptions;
286
+
215
287
  /** A source extracted from search tool results during multi-step LLM execution. */
216
288
  export type ExtractedSource = {
217
289
  type: 'source';
@@ -264,9 +336,9 @@ export type WrappedStreamTextOnFinishCallback<Tools extends ToolSet = ToolSet> =
264
336
  */
265
337
  export type GenerateTextResult<
266
338
  Tools extends ToolSet = ToolSet,
267
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
268
- > = AIGenerateTextResult<Tools, Output> & {
269
- /** Unified field name alias for 'text' - provides consistency across all generate* functions */
339
+ OutputSpec extends AnyAiOutput = AnyAiOutput
340
+ > = AIGenerateTextResult<Tools, OutputSpec> & {
341
+ /** Unified field name alias for 'text' */
270
342
  result: string;
271
343
  /** Calculated cost in USD for the LLM call (present after wrapping; `total` may be null if pricing is unavailable) */
272
344
  cost?: LLMCallCost;
@@ -274,6 +346,14 @@ export type GenerateTextResult<
274
346
  sources: ExtractedSource[];
275
347
  };
276
348
 
349
+ /** Result from generateImage including a unified `result` field pointing at the first image. */
350
+ export type GenerateImageResult = AIGenerateImageResult & {
351
+ /** Unified field name alias for `image` */
352
+ result: AIGenerateImageResult['image'];
353
+ /** Calculated cost for the image generation call when pricing data is available. */
354
+ cost?: LLMCallCost;
355
+ };
356
+
277
357
  /**
278
358
  * Loads a prompt file and interpolates variables into its content.
279
359
  *
@@ -283,7 +363,8 @@ export type GenerateTextResult<
283
363
  */
284
364
  export function loadPrompt(
285
365
  name: string,
286
- variables?: Record<string, string | number | boolean>
366
+ variables?: Record<string, string | number | boolean>,
367
+ promptDir?: string
287
368
  ): Prompt;
288
369
 
289
370
  /**
@@ -317,59 +398,68 @@ export function getRegisteredProviders(): string[];
317
398
  *
318
399
  * This function is a wrapper over the AI SDK's `generateText`.
319
400
  * The prompt file sets `model`, `messages`, `temperature`, `maxTokens`, and `providerOptions`.
320
- * Additional AI SDK options (tools, maxRetries, etc.) can be passed through.
401
+ * All other AI SDK `generateText` options are accepted via {@link GenerateTextAiSdkOptions}, including
402
+ * tools, tool choice, structured output, callbacks, retries, and sampling settings.
321
403
  *
322
- * @param args - Generation arguments.
323
- * @param args.prompt - Prompt file name.
324
- * @param args.variables - Variables to interpolate.
325
- * @param args.tools - Tools the model can call (optional).
326
- * @param args.toolChoice - Tool selection strategy (optional).
404
+ * @param args - Generation arguments. See {@link GenerateTextParameters}.
327
405
  * @returns AI SDK response with text and metadata.
328
406
  */
329
407
  export function generateText<
330
408
  Tools extends ToolSet = ToolSet,
331
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
409
+ OutputSpec extends AnyAiOutput = AnyAiOutput
332
410
  >(
333
- args: {
334
- prompt: string,
335
- variables?: Record<string, string | number | boolean>,
336
- promptDir?: string,
337
- /**
338
- * Skill packages to provide to the LLM. Injects `{{ _system_skills }}` and adds the `load_skill` tool.
339
- * Can be a static array or a function that receives the resolved variables and returns skills.
340
- */
341
- skills?: import( './skill.js' ).Skill[] |
342
- ( ( variables?: Record<string, string | number | boolean> ) => import( './skill.js' ).Skill[] | Promise<import( './skill.js' ).Skill[]> )
343
- } & GenerateTextAiSdkOptions<Tools, Output>
344
- ): Promise<GenerateTextResult<Tools, Output>>;
411
+ args: GenerateTextParameters<Tools, OutputSpec>
412
+ ): Promise<GenerateTextResult<Tools, OutputSpec>>;
345
413
 
346
414
  /**
347
415
  * Use an LLM model to stream text generation.
348
416
  *
349
417
  * This function is a wrapper over the AI SDK's `streamText`.
350
418
  * The prompt file sets `model`, `messages`, `temperature`, `maxTokens`, and `providerOptions`.
351
- * Additional AI SDK options (tools, onChunk, onFinish, onError, etc.) can be passed through.
419
+ * All other AI SDK `streamText` options are accepted via {@link StreamTextAiSdkOptions}, except
420
+ * `onFinish`, which Output wraps to add optional cost data.
352
421
  *
353
- * @param args - Generation arguments.
354
- * @param args.prompt - Prompt file name.
355
- * @param args.variables - Variables to interpolate.
356
- * @param args.onChunk - Callback for each stream chunk (optional).
357
- * @param args.onFinish - Callback when stream finishes; receives {@link WrappedStreamTextOnFinishEvent} (`cost` optional).
358
- * @param args.onError - Callback when stream errors (optional).
422
+ * @param args - Streaming arguments. See {@link StreamTextParameters}.
359
423
  * @returns AI SDK stream result with textStream, fullStream, and metadata promises.
360
424
  */
361
425
  export function streamText<
362
426
  Tools extends ToolSet = ToolSet,
363
- Output extends AIOutput<unknown, unknown> = AIOutput<unknown, unknown>
427
+ OutputSpec extends AnyAiOutput = AnyAiOutput
364
428
  >(
365
- args: {
366
- prompt: string,
367
- variables?: Record<string, string | number | boolean>
368
- } & OutputStreamTextAiSdkOptions<Tools, Output>
369
- ): AIStreamTextResult<Tools, Output>;
429
+ args: StreamTextParameters<Tools, OutputSpec>
430
+ ): AIStreamTextResult<Tools, OutputSpec>;
431
+
432
+ /**
433
+ * Use an image model to generate images from a prompt file.
434
+ *
435
+ * The prompt file supplies AI SDK `model` and `prompt`. All other AI SDK `generateImage`
436
+ * options are accepted via {@link GenerateImageAiSdkOptions}, including `n`, `size`,
437
+ * `aspectRatio`, `seed`, provider options, retries, abort signal, and headers.
438
+ *
439
+ * @param args - Image generation arguments. See {@link GenerateImageParameters}.
440
+ * @returns AI SDK image response with `result` aliasing the first image.
441
+ */
442
+ export function generateImage(
443
+ args: GenerateImageParameters
444
+ ): Promise<GenerateImageResult>;
370
445
 
371
- export { skill } from './skill.js';
372
- export type { Skill, SkillsArg } from './skill.js';
446
+ /**
447
+ * Create an inline skill instruction package.
448
+ *
449
+ * @example
450
+ * ```ts
451
+ * const researchSkill = skill( {
452
+ * name: 'web_research',
453
+ * description: 'Search and synthesize web information',
454
+ * instructions: '# Web Research\n1. Break into queries\n2. Search\n3. Cite sources'
455
+ * } );
456
+ * ```
457
+ */
458
+ export function skill( params: {
459
+ name: string;
460
+ description?: string;
461
+ instructions: string;
462
+ } ): Skill;
373
463
 
374
464
  /** Pluggable conversation store for multi-turn Agent interactions. */
375
465
  export interface ConversationStore {
@@ -403,57 +493,22 @@ export function createMemoryConversationStore(): ConversationStore;
403
493
  * const r1 = await chatbot.generate({ messages: [{ role: 'user', content: 'Hello' }] });
404
494
  * ```
405
495
  */
406
- export declare class Agent extends import( 'ai' ).ToolLoopAgent {
407
- constructor( params: {
408
- /** Prompt file name (e.g. 'my_agent@v1') */
409
- prompt: string;
410
- /** Override the stack-resolved prompt directory */
411
- promptDir?: string;
412
- /** Variables to render the prompt template at construction time */
413
- variables?: Record<string, unknown>;
414
- /** Static skill packages made available to the LLM */
415
- skills?: import( './skill.js' ).Skill[];
416
- /** AI SDK tools available during the reasoning loop */
417
- tools?: ToolSet;
418
- /** Maximum tool-loop iterations when stopWhen is not specified (default: 10) */
419
- maxSteps?: number;
420
- /** Custom stop condition(s) — overrides maxSteps */
421
- stopWhen?: import( 'ai' ).StopCondition | import( 'ai' ).StopCondition[];
422
- /** Structured output specification */
423
- output?: import( 'ai' ).Output<unknown, unknown>;
424
- /** Pluggable conversation store — opt-in, stateless by default */
425
- conversationStore?: ConversationStore;
426
- /** Callback after each step */
427
- onStepFinish?: import( 'ai' ).GenerateTextOnStepFinishCallback<ToolSet>;
428
- /** Customize each step before execution */
429
- prepareStep?: import( 'ai' ).PrepareStepFunction<ToolSet>;
430
- /** Generation temperature (overrides prompt file value) */
431
- temperature?: number;
432
- /** Top-p sampling */
433
- topP?: number;
434
- /** Top-k sampling */
435
- topK?: number;
436
- /** Random seed for deterministic output */
437
- seed?: number;
438
- /** Maximum retry attempts (default: 2) */
439
- maxRetries?: number;
440
- } );
496
+ export declare class Agent<
497
+ OutputSpec extends AnyAiOutput = AnyAiOutput
498
+ > extends AIToolLoopAgent<never, ToolSet, OutputSpec> {
499
+ constructor( params: OutputAgentConstructorParameters<OutputSpec> );
441
500
 
442
501
  /**
443
502
  * Run the agent and return when complete.
444
503
  * Same augmented shape as {@link generateText}: `result`, optional `cost`, merged `sources`.
445
504
  */
446
- generate( options?: {
447
- messages?: import( 'ai' ).ModelMessage[];
448
- abortSignal?: AbortSignal;
449
- onStepFinish?: import( 'ai' ).GenerateTextOnStepFinishCallback<ToolSet>;
450
- } ): Promise<GenerateTextResult<ToolSet, import( 'ai' ).Output<unknown, unknown>>>;
505
+ generate( options?: OutputAgentGenerateParameters ): Promise<GenerateTextResult<ToolSet, OutputSpec>>;
451
506
 
452
507
  /**
453
508
  * Stream the agent's response.
454
509
  * `onFinish` receives {@link WrappedStreamTextOnFinishEvent} (`cost` optional), matching {@link streamText}.
455
510
  */
456
511
  stream( options?: OutputAgentStreamParameters ): Promise<
457
- AIStreamTextResult<ToolSet, import( 'ai' ).Output<unknown, unknown>>
512
+ AIStreamTextResult<ToolSet, OutputSpec>
458
513
  >;
459
- };
514
+ }
package/src/index.js CHANGED
@@ -1,6 +1,6 @@
1
- export { generateText, streamText } from './ai_sdk.js';
1
+ export { generateText, streamText, generateImage } from './ai_sdk.js';
2
2
  export { Agent, createMemoryConversationStore, skill } from './agent.js';
3
- export { loadPrompt } from './prompt_loader.js';
3
+ export { loadPrompt } from './prompt/loader.js';
4
4
  export { registerProvider, getRegisteredProviders } from './ai_model.js';
5
5
  export { tavilySearch, tavilyExtract, tavilyCrawl, tavilyMap } from '@tavily/ai-sdk';
6
6
  export { webSearch as exaSearch } from '@exalabs/ai-sdk';
@@ -0,0 +1,65 @@
1
+ import { encodeXML, decodeXML } from 'entities';
2
+ import { isPlainObject } from '@outputai/core/sdk_utils';
3
+
4
+ const VAR_SAFE_FILTER = '__var_safe';
5
+
6
+ /**
7
+ * XML-escapes a value.
8
+ * @param {unknown} value - Any value to escape
9
+ * @returns {string} Escaped value or '' if original value was null/undefined
10
+ */
11
+ export const encodeFilter = value => [ null, undefined ].includes( value ) ? '' : encodeXML( String( value ) );
12
+
13
+ /**
14
+ * Sets up the encoder filter on a Liquid instance.
15
+ * @param {object} liquid - LiquidJS instance
16
+ */
17
+ export const setupLiquidEncodeFilter = liquid => liquid.registerFilter( VAR_SAFE_FILTER, encodeFilter );
18
+
19
+ /**
20
+ * Matches {% raw %}...{% endraw %} or {{ ... }} tags
21
+ */
22
+ const VAR_OR_RAW = /(\{%\s*raw\s*%\}[\s\S]*?\{%\s*endraw\s*%\})|\{\{\s*([\s\S]+?)\s*\}\}/g;
23
+
24
+ /**
25
+ * Escapes Liquid templates so rendered variable content cannot be parsed as message blocks.
26
+ *
27
+ * Appends `| __var_safe` to every `{{ ... }}` expression so variable output is XML-escaped
28
+ * by the filter registered on Liquid before parsePrompt tokenizes message blocks.
29
+ *
30
+ * Without this, a variable whose value contains `<system>` or `</user>` would inject extra
31
+ * message blocks.
32
+ *
33
+ * Raw regions `{% raw %} ... {% endraw %}` are emitted verbatim by Liquid and preserved
34
+ * unchanged.
35
+ *
36
+ * Note: The `g` flag advances past any matched raw regions, so `{{ ... }}` inside them are
37
+ * preserved as well.
38
+ *
39
+ * @param {string} raw - Raw string value
40
+ * @returns {string} Escaped string
41
+ */
42
+ export const escape = raw =>
43
+ raw.replace( VAR_OR_RAW, ( _, rawRegion, expressionContent ) =>
44
+ rawRegion === undefined ? `{{ ${expressionContent.trim()} | ${VAR_SAFE_FILTER} }}` : rawRegion
45
+ );
46
+
47
+ /**
48
+ * Recursively XML-decodes a value.
49
+ * @param {unknown} value - Value to decode
50
+ * @returns {unknown} Decoded value
51
+ */
52
+ export const decode = value => {
53
+ if ( typeof value === 'string' ) {
54
+ return decodeXML( value );
55
+ }
56
+ if ( Array.isArray( value ) ) {
57
+ return value.map( decode );
58
+ }
59
+ if ( isPlainObject( value ) ) {
60
+ return Object.fromEntries(
61
+ Object.entries( value ).map( ( [ k, v ] ) => [ k, decode( v ) ] )
62
+ );
63
+ }
64
+ return value;
65
+ };