2024-10-17 23:29:19 -07:00
import type { JSONSchema7 } from 'json-schema' ;
2023-11-29 03:13:55 -08:00
import {
jsonParse ,
type IExecuteFunctions ,
type INodeType ,
type INodeTypeDescription ,
type SupplyData ,
NodeOperationError ,
NodeConnectionType ,
} from 'n8n-workflow' ;
2024-10-22 01:46:58 -07:00
import type { z } from 'zod' ;
2024-10-17 23:29:19 -07:00
2024-05-22 05:29:32 -07:00
import {
inputSchemaField ,
jsonSchemaExampleField ,
schemaTypeField ,
} from '../../../utils/descriptions' ;
2024-10-22 01:46:58 -07:00
import { N8nStructuredOutputParser } from '../../../utils/output_parsers/N8nOutputParser' ;
2024-10-17 23:29:19 -07:00
import { convertJsonSchemaToZod , generateSchema } from '../../../utils/schemaParsing' ;
import { getConnectionHintNoticeField } from '../../../utils/sharedFields' ;
2023-11-29 03:13:55 -08:00
export class OutputParserStructured implements INodeType {
description : INodeTypeDescription = {
displayName : 'Structured Output Parser' ,
name : 'outputParserStructured' ,
icon : 'fa:code' ,
group : [ 'transform' ] ,
2024-05-22 05:29:32 -07:00
version : [ 1 , 1.1 , 1.2 ] ,
defaultVersion : 1.2 ,
2023-11-29 03:13:55 -08:00
description : 'Return data in a defined JSON format' ,
defaults : {
name : 'Structured Output Parser' ,
} ,
codex : {
alias : [ 'json' , 'zod' ] ,
categories : [ 'AI' ] ,
subcategories : {
AI : [ 'Output Parsers' ] ,
} ,
resources : {
primaryDocumentation : [
{
url : 'https://docs.n8n.io/integrations/builtin/cluster-nodes/sub-nodes/n8n-nodes-langchain.outputparserstructured/' ,
} ,
] ,
} ,
} ,
// eslint-disable-next-line n8n-nodes-base/node-class-description-inputs-wrong-regular-node
inputs : [ ] ,
// eslint-disable-next-line n8n-nodes-base/node-class-description-outputs-wrong
outputs : [ NodeConnectionType . AiOutputParser ] ,
outputNames : [ 'Output Parser' ] ,
properties : [
getConnectionHintNoticeField ( [ NodeConnectionType . AiChain , NodeConnectionType . AiAgent ] ) ,
2024-05-22 05:29:32 -07:00
{ . . . schemaTypeField , displayOptions : { show : { '@version' : [ { _cnd : { gte : 1.2 } } ] } } } ,
{
. . . jsonSchemaExampleField ,
default : ` {
"state" : "California" ,
"cities" : [ "Los Angeles" , "San Francisco" , "San Diego" ]
} ` ,
} ,
{
. . . inputSchemaField ,
default : ` {
"type" : "object" ,
"properties" : {
"state" : {
"type" : "string"
} ,
"cities" : {
"type" : "array" ,
"items" : {
"type" : "string"
}
}
}
} ` ,
} ,
2023-11-29 03:13:55 -08:00
{
displayName : 'JSON Schema' ,
name : 'jsonSchema' ,
type : 'json' ,
description : 'JSON Schema to structure and validate the output against' ,
default : ` {
"type" : "object" ,
"properties" : {
"state" : {
"type" : "string"
} ,
"cities" : {
"type" : "array" ,
"items" : {
"type" : "string"
}
}
}
} ` ,
typeOptions : {
rows : 10 ,
} ,
required : true ,
2024-05-22 05:29:32 -07:00
displayOptions : {
show : {
'@version' : [ { _cnd : { lte : 1.1 } } ] ,
} ,
} ,
2023-11-29 03:13:55 -08:00
} ,
{
displayName :
'The schema has to be defined in the <a target="_blank" href="https://json-schema.org/">JSON Schema</a> format. Look at <a target="_blank" href="https://json-schema.org/learn/miscellaneous-examples.html">this</a> page for examples.' ,
name : 'notice' ,
type : 'notice' ,
default : '' ,
2024-05-22 05:29:32 -07:00
displayOptions : {
hide : {
schemaType : [ 'fromJson' ] ,
} ,
} ,
2023-11-29 03:13:55 -08:00
} ,
] ,
} ;
async supplyData ( this : IExecuteFunctions , itemIndex : number ) : Promise < SupplyData > {
2024-05-22 05:29:32 -07:00
const schemaType = this . getNodeParameter ( 'schemaType' , itemIndex , '' ) as 'fromJson' | 'manual' ;
// We initialize these even though one of them will always be empty
// it makes it easer to navigate the ternary operator
const jsonExample = this . getNodeParameter ( 'jsonSchemaExample' , itemIndex , '' ) as string ;
let inputSchema : string ;
2023-11-29 03:13:55 -08:00
2024-05-22 05:29:32 -07:00
if ( this . getNode ( ) . typeVersion <= 1.1 ) {
inputSchema = this . getNodeParameter ( 'jsonSchema' , itemIndex , '' ) as string ;
} else {
inputSchema = this . getNodeParameter ( 'inputSchema' , itemIndex , '' ) as string ;
2023-11-29 03:13:55 -08:00
}
2024-05-22 05:29:32 -07:00
const jsonSchema =
schemaType === 'fromJson' ? generateSchema ( jsonExample ) : jsonParse < JSONSchema7 > ( inputSchema ) ;
2023-11-29 03:13:55 -08:00
2024-10-17 23:29:19 -07:00
const zodSchema = convertJsonSchemaToZod < z.ZodSchema < object > > ( jsonSchema ) ;
2024-04-29 04:59:55 -07:00
const nodeVersion = this . getNode ( ) . typeVersion ;
try {
2024-10-22 01:46:58 -07:00
const parser = await N8nStructuredOutputParser . fromZodJsonSchema (
zodSchema ,
nodeVersion ,
this ,
) ;
2024-04-29 04:59:55 -07:00
return {
2024-10-22 01:46:58 -07:00
response : parser ,
2024-04-29 04:59:55 -07:00
} ;
} catch ( error ) {
throw new NodeOperationError ( this . getNode ( ) , 'Error during parsing of JSON Schema.' ) ;
}
2023-11-29 03:13:55 -08:00
}
}