|
|
import { BaseOutputParser, OutputParserException } from './base-parser.js';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export class JsonOutputParser extends BaseOutputParser {
|
|
|
constructor(options = {}) {
|
|
|
super();
|
|
|
this.schema = options.schema;
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
async parse(text) {
|
|
|
try {
|
|
|
|
|
|
const jsonText = this._extractJson(text);
|
|
|
const parsed = JSON.parse(jsonText);
|
|
|
|
|
|
|
|
|
if (this.schema) {
|
|
|
this._validateSchema(parsed);
|
|
|
}
|
|
|
|
|
|
return parsed;
|
|
|
} catch (error) {
|
|
|
throw new OutputParserException(
|
|
|
`Failed to parse JSON: ${error.message}`,
|
|
|
text,
|
|
|
error
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_extractJson(text) {
|
|
|
|
|
|
try {
|
|
|
JSON.parse(text.trim());
|
|
|
return text.trim();
|
|
|
} catch {
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
const markdownMatch = text.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
|
if (markdownMatch) {
|
|
|
return markdownMatch[1].trim();
|
|
|
}
|
|
|
|
|
|
|
|
|
const jsonObjectMatch = text.match(/\{[\s\S]*\}/);
|
|
|
if (jsonObjectMatch) {
|
|
|
return jsonObjectMatch[0];
|
|
|
}
|
|
|
|
|
|
const jsonArrayMatch = text.match(/\[[\s\S]*\]/);
|
|
|
if (jsonArrayMatch) {
|
|
|
return jsonArrayMatch[0];
|
|
|
}
|
|
|
|
|
|
|
|
|
return text.trim();
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_validateSchema(parsed) {
|
|
|
if (!this.schema) return;
|
|
|
|
|
|
for (const [key, type] of Object.entries(this.schema)) {
|
|
|
if (!(key in parsed)) {
|
|
|
throw new Error(`Missing required field: ${key}`);
|
|
|
}
|
|
|
|
|
|
const actualType = typeof parsed[key];
|
|
|
if (actualType !== type) {
|
|
|
throw new Error(
|
|
|
`Field ${key} should be ${type}, got ${actualType}`
|
|
|
);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
getFormatInstructions() {
|
|
|
let instructions = 'Respond with valid JSON.';
|
|
|
|
|
|
if (this.schema) {
|
|
|
const schemaDesc = Object.entries(this.schema)
|
|
|
.map(([key, type]) => `"${key}": ${type}`)
|
|
|
.join(', ');
|
|
|
instructions += ` Schema: { ${schemaDesc} }`;
|
|
|
}
|
|
|
|
|
|
return instructions;
|
|
|
}
|
|
|
} |