diff --git a/src/looking_glass/output-parser.ts b/src/looking_glass/output-parser.ts index eafdb0a..349a956 100644 --- a/src/looking_glass/output-parser.ts +++ b/src/looking_glass/output-parser.ts @@ -20,7 +20,7 @@ const agentOutputSchema = z.object({ type AgentOutput = z.infer export class ProceduresOutputParser extends AgentActionOutputParser { - lc_namespace = ['looking_glass', 'output-parser'] + lc_namespace = ['looking_glass', 'procedures-output-parser'] async parse(output: string): Promise { output += '}' diff --git a/src/looking_glass/stray-cat.ts b/src/looking_glass/stray-cat.ts index 2e49e3e..2d242e8 100644 --- a/src/looking_glass/stray-cat.ts +++ b/src/looking_glass/stray-cat.ts @@ -172,16 +172,17 @@ export class StrayCat { async run(msg: Message, save = true) { log.info(`Received message from user "${this.userId}":`) log.info(msg) + const response = this.userMessage = madHatter.executeHook('beforeReadMessage', msg, this) + + // TODO: Find another way to handle this if (response.text.length > cheshireCat.embedderSize) { log.warn(`The input is too long. Storing it as document...`) - rabbitHole.ingestContent(this, response.text) + await rabbitHole.ingestContent(this, response.text) return } - try { - await this.recallRelevantMemories() - } + try { await this.recallRelevantMemories() } catch (error) { log.error(error) return diff --git a/src/mad_hatter/form.ts b/src/mad_hatter/form.ts index b447a49..cebd9b8 100644 --- a/src/mad_hatter/form.ts +++ b/src/mad_hatter/form.ts @@ -7,7 +7,7 @@ import { PromptTemplate } from '@langchain/core/prompts' import { kebabCase } from 'scule' import type { AgentFastReply, StrayCat } from '@lg' import { log } from '@logger' -import { parsedEnv } from '@utils' +import { parseJson, parsedEnv } from '@utils' export enum FormState { /** @@ -246,12 +246,11 @@ Updated JSON: structure += '\n}' const json = (await extractionChain.invoke({ structure, stop: ['```'] })).output - - log.debug(`Form JSON after parser:\n${json}`) - let output: Record = {} + try { - output = safeDestr(json) + output = parseJson(json, this.schema) + log.debug('Form JSON after parsing:\n', output) } catch (error) { output = {} diff --git a/src/utils.ts b/src/utils.ts index 6ad43cc..9e52d69 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,6 +4,7 @@ import { readFileSync, readdirSync } from 'node:fs' import { type CriteriaLike, loadEvaluator } from 'langchain/evaluation' import { z } from 'zod' import { extendZodWithOpenApi } from 'zod-openapi' +import { safeDestr } from 'destr' extendZodWithOpenApi(z) @@ -205,3 +206,16 @@ export function getZodDefaults(schema: T, discriminant?: else if (schema instanceof z.ZodDefault) return schema._def.defaultValue() else return undefined } + +/** + * Parses a JSON string using the specified Zod schema. + * It also cleans a few common issues with generated JSON strings. + * @param text The JSON string to parse. + * @param schema The Zod schema to use for parsing. + * @throws If the JSON string is invalid or does not match the schema. + */ +export async function parseJson(text: string, schema: T) { + const cleaned = text.trim().replace('\_', '_').replace('\-', '-') + const json = cleaned.includes('```') ? text.split(/```(?:json)?/)[1]! : text + return await schema.parseAsync(safeDestr(json)) as z.infer +}