@output.ai/llm 0.2.11 → 0.2.13-dev.pr306-3f50755

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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@output.ai/llm",
3
- "version": "0.2.11",
3
+ "version": "0.2.13-dev.pr306-3f50755",
4
4
  "description": "Framework abstraction to interact with LLM models",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/ai_sdk.js CHANGED
@@ -51,6 +51,9 @@ const aiSdkOptionsFromPrompt = prompt => {
51
51
 
52
52
  if ( prompt.config.maxTokens ) {
53
53
  options.maxOutputTokens = prompt.config.maxTokens;
54
+ } else if ( prompt.config.provider === 'anthropic' ) {
55
+ // Override Anthropic SDK's low 4096 default - Claude models support up to 64k output tokens
56
+ options.maxOutputTokens = 64000;
54
57
  }
55
58
 
56
59
  const tools = loadTools( prompt );
@@ -221,6 +221,7 @@ describe( 'ai_sdk', () => {
221
221
  expect( aiFns.generateText ).toHaveBeenCalledWith( {
222
222
  model: 'MODEL',
223
223
  messages: promptWithProviderOptions.messages,
224
+ maxOutputTokens: 64000,
224
225
  providerOptions: {
225
226
  thinking: {
226
227
  type: 'enabled',
@@ -339,6 +340,7 @@ describe( 'ai_sdk', () => {
339
340
  enum: [ 'A', 'B', 'C' ],
340
341
  model: 'MODEL',
341
342
  messages: promptWithMixedOptions.messages,
343
+ maxOutputTokens: 64000,
342
344
  providerOptions: {
343
345
  thinking: {
344
346
  type: 'enabled',
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Type-level tests for generateText multi-step options.
3
+ * These tests verify that TypeScript accepts the new options without casting to `any`.
4
+ */
5
+ import { describe, it, expect, vi, expectTypeOf } from 'vitest';
6
+ import type { ToolSet } from 'ai';
7
+ import type { generateText, GenerateTextResult } from './index.d.ts';
8
+
9
+ // Mock generateText for type-checking tests
10
+ const mockGenerateText = vi.fn() as unknown as typeof generateText;
11
+
12
+ describe( 'generateText type definitions', () => {
13
+ describe( 'maxSteps option', () => {
14
+ it( 'should accept maxSteps as a valid option', () => {
15
+ // This function definition verifies TypeScript accepts maxSteps
16
+ const callWithMaxSteps = () =>
17
+ mockGenerateText( {
18
+ prompt: 'test-prompt',
19
+ maxSteps: 5
20
+ } );
21
+
22
+ expect( callWithMaxSteps ).toBeDefined();
23
+ } );
24
+
25
+ it( 'should accept maxSteps with tools', () => {
26
+ const callWithToolsAndMaxSteps = () =>
27
+ mockGenerateText( {
28
+ prompt: 'test-prompt',
29
+ tools: {} as ToolSet,
30
+ maxSteps: 5
31
+ } );
32
+
33
+ expect( callWithToolsAndMaxSteps ).toBeDefined();
34
+ } );
35
+
36
+ it( 'should accept maxSteps with variables and tools (user pattern)', () => {
37
+ // This test mimics the exact user pattern that was failing
38
+ const providerConfig = {
39
+ promptName: 'test-prompt',
40
+ tools: {} as ToolSet
41
+ };
42
+ const query = 'test query';
43
+ const input = {
44
+ successCriteria: 'Answer with relevant information',
45
+ sourceRequirements: '',
46
+ searchDepth: 'basic',
47
+ importance: 'low'
48
+ };
49
+ const previousFindings = '';
50
+ const iteration = 1;
51
+
52
+ const callWithUserPattern = () =>
53
+ mockGenerateText( {
54
+ prompt: providerConfig.promptName,
55
+ variables: {
56
+ query,
57
+ successCriteria: input.successCriteria || 'Answer with relevant information',
58
+ sourceRequirements: input.sourceRequirements || '',
59
+ searchDepth: input.searchDepth || 'basic',
60
+ priority: input.importance || 'low',
61
+ previousFindings: previousFindings || '',
62
+ iteration: String( iteration ),
63
+ currentDate: new Date().toISOString().split( 'T' )[0]
64
+ },
65
+ tools: providerConfig.tools,
66
+ maxSteps: 5 // Allow up to 5 tool execution rounds
67
+ } );
68
+
69
+ expect( callWithUserPattern ).toBeDefined();
70
+ } );
71
+ } );
72
+
73
+ describe( 'stopWhen option', () => {
74
+ it( 'should accept stopWhen callback', () => {
75
+ const callWithStopWhen = () =>
76
+ mockGenerateText( {
77
+ prompt: 'test-prompt',
78
+ tools: {} as ToolSet,
79
+ maxSteps: 10,
80
+ stopWhen: ( { steps } ) => steps.length >= 3
81
+ } );
82
+
83
+ expect( callWithStopWhen ).toBeDefined();
84
+ } );
85
+ } );
86
+
87
+ describe( 'onStepFinish callback', () => {
88
+ it( 'should accept onStepFinish callback', () => {
89
+ const callWithOnStepFinish = () =>
90
+ mockGenerateText( {
91
+ prompt: 'test-prompt',
92
+ tools: {} as ToolSet,
93
+ maxSteps: 5,
94
+ onStepFinish: async step => {
95
+ // step.text should be accessible
96
+ console.log( step.text );
97
+ }
98
+ } );
99
+
100
+ expect( callWithOnStepFinish ).toBeDefined();
101
+ } );
102
+ } );
103
+
104
+ describe( 'prepareStep callback', () => {
105
+ it( 'should accept prepareStep callback with correct parameters', () => {
106
+ const callWithPrepareStep = () =>
107
+ mockGenerateText( {
108
+ prompt: 'test-prompt',
109
+ tools: {} as ToolSet,
110
+ maxSteps: 5,
111
+ prepareStep: ( { steps, stepNumber } ) => {
112
+ // steps and stepNumber should be accessible
113
+ if ( stepNumber > 3 || steps.length > 2 ) {
114
+ return { toolChoice: 'none' as const };
115
+ }
116
+ return {};
117
+ }
118
+ } );
119
+
120
+ expect( callWithPrepareStep ).toBeDefined();
121
+ } );
122
+ } );
123
+
124
+ describe( 'GenerateTextResult type', () => {
125
+ it( 'should be generic over TOOLS', () => {
126
+ // Verify GenerateTextResult accepts a TOOLS type parameter
127
+ type Result = GenerateTextResult<ToolSet>;
128
+
129
+ // Result should have steps, text, and result properties
130
+ expectTypeOf<Result>().toHaveProperty( 'steps' );
131
+ expectTypeOf<Result>().toHaveProperty( 'text' );
132
+ expectTypeOf<Result>().toHaveProperty( 'result' );
133
+ } );
134
+
135
+ it( 'should have result as string alias for text', () => {
136
+ type Result = GenerateTextResult;
137
+ expectTypeOf<Result['result']>().toBeString();
138
+ expectTypeOf<Result['text']>().toBeString();
139
+ } );
140
+ } );
141
+
142
+ describe( 'combined multi-step options', () => {
143
+ it( 'should accept all multi-step options together', () => {
144
+ const callWithAllOptions = () =>
145
+ mockGenerateText( {
146
+ prompt: 'test-prompt',
147
+ variables: { topic: 'testing' },
148
+ tools: {} as ToolSet,
149
+ toolChoice: 'auto',
150
+ maxSteps: 5,
151
+ stopWhen: ( { steps } ) => steps.length >= 3,
152
+ onStepFinish: async step => {
153
+ console.log( 'Step:', step.text );
154
+ },
155
+ prepareStep: ( { stepNumber } ) => {
156
+ return stepNumber > 3 ? { toolChoice: 'required' as const } : {};
157
+ }
158
+ } );
159
+
160
+ expect( callWithAllOptions ).toBeDefined();
161
+ } );
162
+ } );
163
+ } );
package/src/index.d.ts CHANGED
@@ -4,7 +4,10 @@ import type {
4
4
  GenerateObjectResult as AIGenerateObjectResult,
5
5
  CallSettings,
6
6
  ToolSet,
7
- ToolChoice
7
+ ToolChoice,
8
+ StopCondition,
9
+ GenerateTextOnStepFinishCallback,
10
+ PrepareStepFunction
8
11
  } from 'ai';
9
12
 
10
13
  /**
@@ -100,12 +103,20 @@ export type {
100
103
  CallSettings,
101
104
  ToolSet,
102
105
  ToolChoice,
103
- Tool
106
+ Tool,
107
+ StopCondition,
108
+ StepResult,
109
+ GenerateTextOnStepFinishCallback,
110
+ PrepareStepFunction,
111
+ PrepareStepResult
104
112
  } from 'ai';
105
113
 
106
114
  // Re-export the tool helper function for creating tools
107
115
  export { tool } from 'ai';
108
116
 
117
+ // Re-export stop condition helpers for multi-step workflows
118
+ export { stepCountIs, hasToolCall } from 'ai';
119
+
109
120
  /**
110
121
  * Common AI SDK options that can be passed through to all generate functions.
111
122
  * These options are passed directly to the underlying AI SDK call.
@@ -113,7 +124,7 @@ export { tool } from 'ai';
113
124
  type AiSdkOptions = Partial<Omit<CallSettings, 'maxOutputTokens'>>;
114
125
 
115
126
  /**
116
- * AI SDK options specific to generateText, including tool calling support.
127
+ * AI SDK options specific to generateText, including tool calling and multi-step support.
117
128
  * @typeParam TOOLS - The tools available for the model to call
118
129
  */
119
130
  type GenerateTextAiSdkOptions<TOOLS extends ToolSet = ToolSet> = AiSdkOptions & {
@@ -123,14 +134,23 @@ type GenerateTextAiSdkOptions<TOOLS extends ToolSet = ToolSet> = AiSdkOptions &
123
134
  toolChoice?: ToolChoice<TOOLS>;
124
135
  /** Limit which tools are active without changing types */
125
136
  activeTools?: Array<keyof TOOLS>;
137
+ /** Maximum number of automatic tool execution rounds (multi-step) */
138
+ maxSteps?: number;
139
+ /** Custom stop conditions for multi-step execution */
140
+ stopWhen?: StopCondition<TOOLS> | StopCondition<TOOLS>[];
141
+ /** Callback after each step completes */
142
+ onStepFinish?: GenerateTextOnStepFinishCallback<TOOLS>;
143
+ /** Customize each step before execution */
144
+ prepareStep?: PrepareStepFunction<TOOLS>;
126
145
  };
127
146
 
128
147
  /**
129
148
  * Result from generateText including full AI SDK response metadata.
130
149
  * Extends AI SDK's GenerateTextResult with a unified `result` field.
150
+ * @typeParam TOOLS - The tools available for the model to call (preserves typing on steps)
131
151
  */
132
- export type GenerateTextResult =
133
- AIGenerateTextResult<Record<string, never>, unknown> & {
152
+ export type GenerateTextResult<TOOLS extends ToolSet = ToolSet> =
153
+ AIGenerateTextResult<TOOLS, unknown> & {
134
154
  /** Unified field name alias for 'text' - provides consistency across all generate* functions */
135
155
  result: string;
136
156
  };
@@ -177,7 +197,7 @@ export function generateText<TOOLS extends ToolSet = ToolSet>(
177
197
  prompt: string,
178
198
  variables?: Record<string, string | number | boolean>
179
199
  } & GenerateTextAiSdkOptions<TOOLS>
180
- ): Promise<GenerateTextResult>;
200
+ ): Promise<GenerateTextResult<TOOLS>>;
181
201
 
182
202
  /**
183
203
  * Use an LLM model to generate an object with a fixed schema.