@outputai/llm 0.6.1-next.65cd087.0 → 0.6.1-next.83742db.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
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@outputai/llm",
|
|
3
|
-
"version": "0.6.1-next.
|
|
3
|
+
"version": "0.6.1-next.83742db.0",
|
|
4
4
|
"description": "Framework abstraction to interact with LLM models",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"gray-matter": "4.0.3",
|
|
24
24
|
"liquidjs": "10.25.7",
|
|
25
25
|
"undici": "8.1.0",
|
|
26
|
-
"@outputai/core": "0.6.1-next.
|
|
26
|
+
"@outputai/core": "0.6.1-next.83742db.0"
|
|
27
27
|
},
|
|
28
28
|
"license": "Apache-2.0",
|
|
29
29
|
"publishConfig": {
|
|
@@ -13,6 +13,9 @@ import {
|
|
|
13
13
|
} from 'ai';
|
|
14
14
|
import { FatalError } from '@outputai/core';
|
|
15
15
|
|
|
16
|
+
// AI SDK does not expose a dedicated schema-mismatch discriminator for NoObjectGeneratedError.
|
|
17
|
+
const NO_OBJECT_SCHEMA_MISMATCH_MESSAGE = 'No object generated: response did not match schema.';
|
|
18
|
+
|
|
16
19
|
/**
|
|
17
20
|
* Recursively search an error cause chain until finds an error which is instance of given prototype.
|
|
18
21
|
*
|
|
@@ -25,7 +28,7 @@ export const findInstanceInCauseChain = ( error, _class, depth = 0 ) => {
|
|
|
25
28
|
if ( !error || typeof error !== 'object' ) {
|
|
26
29
|
return null;
|
|
27
30
|
}
|
|
28
|
-
if ( typeof _class === 'string' && error.constructor
|
|
31
|
+
if ( typeof _class === 'string' && error.constructor?.name === _class ) {
|
|
29
32
|
return error;
|
|
30
33
|
}
|
|
31
34
|
if ( typeof _class === 'function' && error instanceof _class ) {
|
|
@@ -42,20 +45,34 @@ const toFatalError = ( error, extraMessage = '' ) => new FatalError(
|
|
|
42
45
|
{ cause: error }
|
|
43
46
|
);
|
|
44
47
|
|
|
48
|
+
/**
|
|
49
|
+
* Map an AI SDK error to a framework specific error:
|
|
50
|
+
*
|
|
51
|
+
* - AI SDK Unrecoverable errors become FatalErrors, check code to see options.
|
|
52
|
+
* - NoObjectGeneratedError from invalid schema are reinitialized with a better message.
|
|
53
|
+
* - Other errors are preserved.
|
|
54
|
+
* @param {object} error - Original Error
|
|
55
|
+
* @returns {object} A new Error
|
|
56
|
+
*/
|
|
45
57
|
export const mapAiError = error => {
|
|
46
58
|
if ( error instanceof FatalError ) {
|
|
47
59
|
return error;
|
|
48
60
|
}
|
|
49
61
|
|
|
50
|
-
// NoObjectGeneratedError can be thrown when the response doesn't match the schema
|
|
51
|
-
// This
|
|
52
|
-
if ( NoObjectGeneratedError.isInstance( error ) && error.message.includes(
|
|
62
|
+
// NoObjectGeneratedError can be thrown when the response doesn't match the schema.
|
|
63
|
+
// This re-creates the error with a better message, making it easier to debug.
|
|
64
|
+
if ( NoObjectGeneratedError.isInstance( error ) && error.message.includes( NO_OBJECT_SCHEMA_MISMATCH_MESSAGE ) ) {
|
|
53
65
|
const zodError = findInstanceInCauseChain( error, 'ZodError' );
|
|
54
66
|
if ( zodError && zodError.issues?.length > 0 ) {
|
|
55
|
-
const { path, message } = zodError.issues
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
67
|
+
const [ { path, message } ] = zodError.issues;
|
|
68
|
+
return new NoObjectGeneratedError( {
|
|
69
|
+
message: `${error.message} First issue is "${message}" at path [${path.join( ', ' )}].`,
|
|
70
|
+
cause: error.cause,
|
|
71
|
+
text: error.text,
|
|
72
|
+
response: error.response,
|
|
73
|
+
usage: error.usage,
|
|
74
|
+
finishReason: error.finishReason
|
|
75
|
+
} );
|
|
59
76
|
}
|
|
60
77
|
return error;
|
|
61
78
|
}
|
|
@@ -171,6 +171,13 @@ describe( 'findInstanceInCauseChain', () => {
|
|
|
171
171
|
expect( findInstanceInCauseChain( 'not an error', Error ) ).toBeNull();
|
|
172
172
|
} );
|
|
173
173
|
|
|
174
|
+
it( 'returns null for object causes without constructors', () => {
|
|
175
|
+
const cause = Object.create( null );
|
|
176
|
+
const error = new FirstCustomError( 'first', { cause } );
|
|
177
|
+
|
|
178
|
+
expect( findInstanceInCauseChain( error, 'SecondCustomError' ) ).toBeNull();
|
|
179
|
+
} );
|
|
180
|
+
|
|
174
181
|
it( 'stops searching after the depth limit', () => {
|
|
175
182
|
const makeErrorChain = depth => depth === 0 ?
|
|
176
183
|
new SecondCustomError( 'target' ) :
|
|
@@ -204,17 +211,25 @@ describe( 'mapAiError', () => {
|
|
|
204
211
|
const error = new NoObjectGeneratedError( {
|
|
205
212
|
message: 'No object generated: response did not match schema.',
|
|
206
213
|
text: '{"items":[{}]}',
|
|
214
|
+
response: { id: 'response-1' },
|
|
215
|
+
usage: { totalTokens: 10 },
|
|
216
|
+
finishReason: 'stop',
|
|
207
217
|
cause: validationError
|
|
208
218
|
} );
|
|
209
219
|
|
|
210
220
|
const result = mapAiError( error );
|
|
211
221
|
|
|
212
222
|
expect( result ).not.toBe( error );
|
|
213
|
-
expect(
|
|
223
|
+
expect( NoObjectGeneratedError.isInstance( result ) ).toBe( true );
|
|
224
|
+
expect( result.name ).toBe( 'AI_NoObjectGeneratedError' );
|
|
214
225
|
expect( result.message ).toBe(
|
|
215
226
|
'No object generated: response did not match schema. First issue is "Expected string" at path [items, 0, title].'
|
|
216
227
|
);
|
|
217
|
-
expect( result.cause ).toBe(
|
|
228
|
+
expect( result.cause ).toBe( validationError );
|
|
229
|
+
expect( result.text ).toBe( error.text );
|
|
230
|
+
expect( result.response ).toBe( error.response );
|
|
231
|
+
expect( result.usage ).toBe( error.usage );
|
|
232
|
+
expect( result.finishReason ).toBe( error.finishReason );
|
|
218
233
|
} );
|
|
219
234
|
|
|
220
235
|
it( 'preserves NoObjectGeneratedError schema mismatches when no schema issue is available', () => {
|