langchain
Version:
Typescript bindings for langchain
1 lines • 22 kB
Source Map (JSON)
{"version":3,"file":"moderation.cjs","names":["initChatModel","AIMessage","HumanMessage","ToolMessage","createMiddleware"],"sources":["../../../../../src/agents/middleware/provider/openai/moderation.ts"],"sourcesContent":["import type { BaseMessage } from \"@langchain/core/messages\";\nimport { AIMessage, HumanMessage, ToolMessage } from \"@langchain/core/messages\";\nimport type { BaseChatModel } from \"@langchain/core/language_models/chat_models\";\nimport { BaseLanguageModel } from \"@langchain/core/language_models/base\";\n\nimport { initChatModel } from \"../../../../chat_models/universal.js\";\nimport { createMiddleware } from \"../../../middleware.js\";\nimport type { MiddlewareResult, AgentMiddleware } from \"../../types.js\";\nimport type { AgentBuiltInState } from \"../../../runtime.js\";\n\n/**\n * OpenAI model interface.\n */\ninterface OpenAIModel extends BaseLanguageModel {\n getName: () => string;\n _getClientOptions: () => unknown;\n client: {\n moderations: {\n create: (\n input: {\n input: string | string[];\n model: string;\n },\n options?: unknown\n ) => Promise<ModerationResponse>;\n };\n };\n}\n\n/**\n * Check if the model is an OpenAI model that supports moderation.\n * @param model - The model to check.\n * @returns Whether the model is an OpenAI model that supports moderation.\n */\nfunction isOpenAIModel(model: unknown): model is OpenAIModel {\n if (\n !model ||\n typeof model !== \"object\" ||\n model === null ||\n !(\"client\" in model) ||\n !(\"_getClientOptions\" in model) ||\n typeof model._getClientOptions !== \"function\"\n ) {\n return false;\n }\n\n /**\n * client may not yet be initialized, so we need to check if the model has a _getClientOptions method.\n */\n model._getClientOptions();\n return (\n typeof model.client === \"object\" &&\n model.client !== null &&\n \"moderations\" in model.client &&\n typeof model.client.moderations === \"object\" &&\n model.client.moderations !== null &&\n \"create\" in model.client.moderations &&\n typeof model.client.moderations.create === \"function\"\n );\n}\n\n/**\n * Stage where a violation occurred.\n */\nexport type ViolationStage = \"input\" | \"output\" | \"tool\";\n\n/**\n * Default template for violation messages.\n */\nconst DEFAULT_VIOLATION_TEMPLATE =\n \"I'm sorry, but I can't comply with that request. It was flagged for {categories}.\";\n\n/**\n * Result of moderation.\n * @see https://platform.openai.com/docs/api-reference/moderations/object\n */\ninterface ModerationResult {\n flagged: boolean;\n categories: Record<string, boolean>;\n category_scores: Record<string, number>;\n category_applied_input_types: Record<string, string[]>;\n}\n\n/**\n * Moderation response.\n * @see https://platform.openai.com/docs/api-reference/moderations/create\n */\ninterface ModerationResponse {\n id: string;\n model: string;\n results: ModerationResult[];\n}\n\ntype ModerationModel =\n | \"omni-moderation-latest\"\n | \"omni-moderation-2024-09-26\"\n | \"text-moderation-latest\"\n | \"text-moderation-stable\";\n\n/**\n * Error raised when OpenAI flags content and `exitBehavior` is set to `\"error\"`.\n */\nexport class OpenAIModerationError extends Error {\n content: string;\n stage: ViolationStage;\n result: ModerationResult;\n originalMessage: string;\n\n constructor({\n content,\n stage,\n result,\n message,\n }: {\n content: string;\n stage: ViolationStage;\n result: ModerationResult;\n message: string;\n }) {\n super(message);\n this.name = \"OpenAIModerationError\";\n this.content = content;\n this.stage = stage;\n this.result = result;\n this.originalMessage = message;\n }\n}\n\n/**\n * Options for configuring the OpenAI Moderation middleware.\n */\nexport interface OpenAIModerationMiddlewareOptions {\n /**\n * OpenAI model to use for moderation. Can be either a model name or a BaseChatModel instance.\n * @example\n * ```ts\n * const model = new ChatOpenAI({ model: \"gpt-4o-mini\" });\n * const middleware = openAIModerationMiddleware({ model });\n * const agent = createAgent({\n * model,\n * middleware: [middleware],\n * });\n * ```\n * @example\n * ```ts\n * const middleware = openAIModerationMiddleware({ model: \"gpt-4o-mini\" });\n * const agent = createAgent({\n * model: \"gpt-5\",\n * middleware: [middleware],\n * });\n * ```\n */\n model: string | BaseChatModel;\n\n /**\n * Moderation model to use.\n * @default \"omni-moderation-latest\"\n */\n moderationModel?: ModerationModel;\n\n /**\n * Whether to check user input messages.\n * @default true\n */\n checkInput?: boolean;\n\n /**\n * Whether to check model output messages.\n * @default true\n */\n checkOutput?: boolean;\n\n /**\n * Whether to check tool result messages.\n * @default false\n */\n checkToolResults?: boolean;\n\n /**\n * How to handle violations.\n * - `\"error\"`: Throw an error when content is flagged\n * - `\"end\"`: End the agent execution and return a violation message\n * - `\"replace\"`: Replace the flagged content with a violation message\n * @default \"end\"\n */\n exitBehavior?: \"error\" | \"end\" | \"replace\";\n\n /**\n * Custom template for violation messages.\n * Available placeholders: `{categories}`, `{category_scores}`, `{original_content}`\n */\n violationMessage?: string;\n}\n\n/**\n * Middleware that moderates agent traffic using OpenAI's moderation endpoint.\n *\n * This middleware checks messages for content policy violations at different stages:\n * - Input: User messages before they reach the model\n * - Output: AI model responses\n * - Tool results: Results returned from tool executions\n *\n * @param options - Configuration options for the middleware\n * @param options.model - OpenAI model to use for moderation. Can be either a model name or a BaseChatModel instance.\n * @param options.moderationModel - Moderation model to use.\n * @param options.checkInput - Whether to check user input messages.\n * @param options.checkOutput - Whether to check model output messages.\n * @param options.checkToolResults - Whether to check tool result messages.\n * @param options.exitBehavior - How to handle violations.\n * @param options.violationMessage - Custom template for violation messages.\n * @returns Middleware function that can be used to moderate agent traffic.\n *\n * @example Using model instance\n * ```ts\n * import { createAgent, openAIModerationMiddleware } from \"langchain\";\n *\n * const middleware = openAIModerationMiddleware({\n * checkInput: true,\n * checkOutput: true,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [...],\n * middleware: [middleware],\n * });\n * ```\n *\n * @example Using model name\n * ```ts\n * import { createAgent, openAIModerationMiddleware } from \"langchain\";\n *\n * const middleware = openAIModerationMiddleware({\n * model: \"gpt-4o-mini\",\n * checkInput: true,\n * checkOutput: true,\n * exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n * model: \"openai:gpt-4o\",\n * tools: [...],\n * middleware: [middleware],\n * });\n * ```\n *\n * @example Custom violation message\n * ```ts\n * const middleware = openAIModerationMiddleware({\n * violationMessage: \"Content flagged: {categories}. Scores: {category_scores}\"\n * });\n * ```\n */\nexport function openAIModerationMiddleware(\n options: OpenAIModerationMiddlewareOptions\n): AgentMiddleware {\n const {\n model,\n moderationModel = \"omni-moderation-latest\",\n checkInput = true,\n checkOutput = true,\n checkToolResults = false,\n exitBehavior = \"end\",\n violationMessage,\n } = options;\n\n let openaiModel: OpenAIModel | undefined;\n const initModerationModel = async (): Promise<OpenAIModel> => {\n if (openaiModel) {\n return openaiModel;\n }\n\n const resolvedModel =\n typeof model === \"string\" ? await initChatModel(model) : model;\n\n /**\n * Check if the model is an OpenAI model.\n */\n if (!resolvedModel.getName().includes(\"ChatOpenAI\")) {\n throw new Error(\n `Model must be an OpenAI model to use moderation middleware. Got: ${resolvedModel.getName()}`\n );\n }\n\n /**\n * check if OpenAI model package supports moderation.\n */\n if (!isOpenAIModel(resolvedModel)) {\n throw new Error(\n \"Model must support moderation to use moderation middleware.\"\n );\n }\n\n openaiModel = resolvedModel as unknown as OpenAIModel;\n return openaiModel;\n };\n\n /**\n * Extract text content from a message.\n */\n const extractText = (message: BaseMessage): string | null => {\n if (message.content == null) {\n return null;\n }\n const text = message.text;\n return text || null;\n };\n\n /**\n * Find the last index of a message type in the messages array.\n */\n const findLastIndex = (\n messages: BaseMessage[],\n messageType: typeof AIMessage | typeof HumanMessage | typeof ToolMessage\n ): number | null => {\n for (let idx = messages.length - 1; idx >= 0; idx--) {\n if (messageType.isInstance(messages[idx])) {\n return idx;\n }\n }\n return null;\n };\n\n /**\n * Format violation message from moderation result.\n */\n const formatViolationMessage = (\n content: string,\n result: ModerationResult\n ): string => {\n // Convert categories to array of flagged category names\n const categories: string[] = [];\n const categoriesObj = result.categories as unknown as Record<\n string,\n boolean\n >;\n for (const [name, flagged] of Object.entries(categoriesObj)) {\n if (flagged) {\n categories.push(name.replace(/_/g, \" \"));\n }\n }\n\n const categoryLabel =\n categories.length > 0\n ? categories.join(\", \")\n : \"OpenAI's safety policies\";\n\n const template = violationMessage || DEFAULT_VIOLATION_TEMPLATE;\n const scoresJson = JSON.stringify(\n result.category_scores as unknown as Record<string, number>,\n null,\n 2\n );\n\n try {\n return template\n .replace(\"{categories}\", categoryLabel)\n .replace(\"{category_scores}\", scoresJson)\n .replace(\"{original_content}\", content);\n } catch {\n return template;\n }\n };\n\n function moderateContent(\n input: string | string[],\n params?: { model?: ModerationModel; options?: unknown }\n ): Promise<ModerationResponse> {\n const clientOptions = openaiModel?._getClientOptions?.();\n const moderationModel = params?.model ?? \"omni-moderation-latest\";\n const moderationRequest = {\n input,\n model: moderationModel,\n };\n return openaiModel!.client.moderations.create(\n moderationRequest,\n clientOptions\n );\n }\n\n /**\n * Apply violation handling based on exit behavior.\n */\n const applyViolation = (\n messages: BaseMessage[],\n index: number | null,\n stage: ViolationStage,\n content: string,\n result: ModerationResult\n ): MiddlewareResult<Partial<AgentBuiltInState>> | undefined => {\n const violationText = formatViolationMessage(content, result);\n\n if (exitBehavior === \"error\") {\n throw new OpenAIModerationError({\n content,\n stage,\n result,\n message: violationText,\n });\n }\n\n if (exitBehavior === \"end\") {\n return {\n jumpTo: \"end\",\n messages: [new AIMessage({ content: violationText })],\n };\n }\n\n if (index == null) {\n return undefined;\n }\n\n /**\n * Replace the original message with a new message that contains the violation text.\n */\n const newMessages = [...messages];\n const original = newMessages[index];\n const MessageConstructor = Object.getPrototypeOf(original).constructor;\n newMessages[index] = new MessageConstructor({\n ...original,\n content: violationText,\n });\n\n return { messages: newMessages };\n };\n\n /**\n * Moderate user input messages.\n */\n const moderateUserMessage = async (\n messages: BaseMessage[]\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | null> => {\n const idx = findLastIndex(messages, HumanMessage);\n if (idx == null) {\n return null;\n }\n\n const message = messages[idx];\n const text = extractText(message);\n if (!text) {\n return null;\n }\n\n await initModerationModel();\n const response = await moderateContent(text, {\n model: moderationModel,\n });\n\n const flaggedResult = response.results.find((result) => result.flagged);\n if (!flaggedResult) {\n return null;\n }\n\n return applyViolation(messages, idx, \"input\", text, flaggedResult);\n };\n\n /**\n * Moderate tool result messages.\n */\n const moderateToolMessages = async (\n messages: BaseMessage[]\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | null> => {\n const lastAiIdx = findLastIndex(messages, AIMessage);\n if (lastAiIdx == null) {\n return null;\n }\n\n const working = [...messages];\n let modified = false;\n\n for (let idx = lastAiIdx + 1; idx < working.length; idx++) {\n const msg = working[idx];\n if (!ToolMessage.isInstance(msg)) {\n continue;\n }\n\n const text = extractText(msg);\n if (!text) {\n continue;\n }\n\n await initModerationModel();\n const response = await moderateContent(text, {\n model: moderationModel,\n });\n const flaggedResult = response.results.find((result) => result.flagged);\n if (!flaggedResult) {\n continue;\n }\n\n const action = applyViolation(working, idx, \"tool\", text, flaggedResult);\n if (action) {\n if (\"jumpTo\" in action) {\n return action;\n }\n if (\"messages\" in action) {\n working.splice(\n 0,\n working.length,\n ...(action.messages as BaseMessage[])\n );\n modified = true;\n }\n }\n }\n\n if (modified) {\n return { messages: working };\n }\n\n return null;\n };\n\n /**\n * Moderate model output messages.\n */\n const moderateOutput = async (\n messages: BaseMessage[]\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | null> => {\n const lastAiIdx = findLastIndex(messages, AIMessage);\n if (lastAiIdx == null) {\n return null;\n }\n\n const aiMessage = messages[lastAiIdx];\n const text = extractText(aiMessage);\n if (!text) {\n return null;\n }\n\n await initModerationModel();\n const response = await moderateContent(text, {\n model: moderationModel,\n });\n const flaggedResult = response.results.find((result) => result.flagged);\n if (!flaggedResult) {\n return null;\n }\n\n return applyViolation(messages, lastAiIdx, \"output\", text, flaggedResult);\n };\n\n /**\n * Moderate inputs (user messages and tool results) before model call.\n */\n const moderateInputs = async (\n messages: BaseMessage[]\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | null> => {\n const working = [...messages];\n let modified = false;\n\n if (checkToolResults) {\n const action = await moderateToolMessages(working);\n if (action) {\n if (\"jumpTo\" in action) {\n return action;\n }\n if (\"messages\" in action) {\n working.splice(\n 0,\n working.length,\n ...(action.messages as BaseMessage[])\n );\n modified = true;\n }\n }\n }\n\n if (checkInput) {\n const action = await moderateUserMessage(working);\n if (action) {\n if (\"jumpTo\" in action) {\n return action;\n }\n if (\"messages\" in action) {\n working.splice(\n 0,\n working.length,\n ...(action.messages as BaseMessage[])\n );\n modified = true;\n }\n }\n }\n\n if (modified) {\n return { messages: working };\n }\n\n return null;\n };\n\n return createMiddleware({\n name: \"OpenAIModerationMiddleware\",\n beforeModel: {\n hook: async (\n state\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | undefined> => {\n if (!checkInput && !checkToolResults) {\n return undefined;\n }\n\n const messages = state.messages || [];\n if (messages.length === 0) {\n return undefined;\n }\n\n return (await moderateInputs(messages)) ?? undefined;\n },\n canJumpTo: [\"end\"],\n },\n afterModel: {\n hook: async (\n state\n ): Promise<MiddlewareResult<Partial<AgentBuiltInState>> | undefined> => {\n if (!checkOutput) {\n return undefined;\n }\n\n const messages = state.messages || [];\n if (messages.length === 0) {\n return undefined;\n }\n\n return (await moderateOutput(messages)) ?? undefined;\n },\n canJumpTo: [\"end\"],\n },\n });\n}\n"],"mappings":";;;;;;;;;AAkCA,SAAS,cAAc,OAAsC;CAC3D,IACE,CAAC,SACD,OAAO,UAAU,YACjB,UAAU,QACV,EAAE,YAAY,UACd,EAAE,uBAAuB,UACzB,OAAO,MAAM,sBAAsB,YAEnC,OAAO;;;;CAMT,MAAM,kBAAkB;CACxB,OACE,OAAO,MAAM,WAAW,YACxB,MAAM,WAAW,QACjB,iBAAiB,MAAM,UACvB,OAAO,MAAM,OAAO,gBAAgB,YACpC,MAAM,OAAO,gBAAgB,QAC7B,YAAY,MAAM,OAAO,eACzB,OAAO,MAAM,OAAO,YAAY,WAAW;AAE/C;;;;AAUA,MAAM,6BACJ;;;;AAgCF,IAAa,wBAAb,cAA2C,MAAM;CAC/C;CACA;CACA;CACA;CAEA,YAAY,EACV,SACA,OACA,QACA,WAMC;EACD,MAAM,OAAO;EACb,KAAK,OAAO;EACZ,KAAK,UAAU;EACf,KAAK,QAAQ;EACb,KAAK,SAAS;EACd,KAAK,kBAAkB;CACzB;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgIA,SAAgB,2BACd,SACiB;CACjB,MAAM,EACJ,OACA,kBAAkB,0BAClB,aAAa,MACb,cAAc,MACd,mBAAmB,OACnB,eAAe,OACf,qBACE;CAEJ,IAAI;CACJ,MAAM,sBAAsB,YAAkC;EAC5D,IAAI,aACF,OAAO;EAGT,MAAM,gBACJ,OAAO,UAAU,WAAW,MAAMA,8BAAAA,cAAc,KAAK,IAAI;;;;EAK3D,IAAI,CAAC,cAAc,QAAQ,CAAC,CAAC,SAAS,YAAY,GAChD,MAAM,IAAI,MACR,oEAAoE,cAAc,QAAQ,GAC5F;;;;EAMF,IAAI,CAAC,cAAc,aAAa,GAC9B,MAAM,IAAI,MACR,6DACF;EAGF,cAAc;EACd,OAAO;CACT;;;;CAKA,MAAM,eAAe,YAAwC;EAC3D,IAAI,QAAQ,WAAW,MACrB,OAAO;EAGT,OADa,QAAQ,QACN;CACjB;;;;CAKA,MAAM,iBACJ,UACA,gBACkB;EAClB,KAAK,IAAI,MAAM,SAAS,SAAS,GAAG,OAAO,GAAG,OAC5C,IAAI,YAAY,WAAW,SAAS,IAAI,GACtC,OAAO;EAGX,OAAO;CACT;;;;CAKA,MAAM,0BACJ,SACA,WACW;EAEX,MAAM,aAAuB,CAAC;EAC9B,MAAM,gBAAgB,OAAO;EAI7B,KAAK,MAAM,CAAC,MAAM,YAAY,OAAO,QAAQ,aAAa,GACxD,IAAI,SACF,WAAW,KAAK,KAAK,QAAQ,MAAM,GAAG,CAAC;EAI3C,MAAM,gBACJ,WAAW,SAAS,IAChB,WAAW,KAAK,IAAI,IACpB;EAEN,MAAM,WAAW,oBAAoB;EACrC,MAAM,aAAa,KAAK,UACtB,OAAO,iBACP,MACA,CACF;EAEA,IAAI;GACF,OAAO,SACJ,QAAQ,gBAAgB,aAAa,CAAC,CACtC,QAAQ,qBAAqB,UAAU,CAAC,CACxC,QAAQ,sBAAsB,OAAO;EAC1C,QAAQ;GACN,OAAO;EACT;CACF;CAEA,SAAS,gBACP,OACA,QAC6B;EAC7B,MAAM,gBAAgB,aAAa,oBAAoB;EAEvD,MAAM,oBAAoB;GACxB;GACA,OAHsB,QAAQ,SAAS;EAIzC;EACA,OAAO,YAAa,OAAO,YAAY,OACrC,mBACA,aACF;CACF;;;;CAKA,MAAM,kBACJ,UACA,OACA,OACA,SACA,WAC6D;EAC7D,MAAM,gBAAgB,uBAAuB,SAAS,MAAM;EAE5D,IAAI,iBAAiB,SACnB,MAAM,IAAI,sBAAsB;GAC9B;GACA;GACA;GACA,SAAS;EACX,CAAC;EAGH,IAAI,iBAAiB,OACnB,OAAO;GACL,QAAQ;GACR,UAAU,CAAC,IAAIC,yBAAAA,UAAU,EAAE,SAAS,cAAc,CAAC,CAAC;EACtD;EAGF,IAAI,SAAS,MACX;;;;EAMF,MAAM,cAAc,CAAC,GAAG,QAAQ;EAChC,MAAM,WAAW,YAAY;EAC7B,MAAM,qBAAqB,OAAO,eAAe,QAAQ,CAAC,CAAC;EAC3D,YAAY,SAAS,IAAI,mBAAmB;GAC1C,GAAG;GACH,SAAS;EACX,CAAC;EAED,OAAO,EAAE,UAAU,YAAY;CACjC;;;;CAKA,MAAM,sBAAsB,OAC1B,aACiE;EACjE,MAAM,MAAM,cAAc,UAAUC,yBAAAA,YAAY;EAChD,IAAI,OAAO,MACT,OAAO;EAGT,MAAM,UAAU,SAAS;EACzB,MAAM,OAAO,YAAY,OAAO;EAChC,IAAI,CAAC,MACH,OAAO;EAGT,MAAM,oBAAoB;EAK1B,MAAM,iBAAgB,MAJC,gBAAgB,MAAM,EAC3C,OAAO,gBACT,CAAC,EAAA,CAE8B,QAAQ,MAAM,WAAW,OAAO,OAAO;EACtE,IAAI,CAAC,eACH,OAAO;EAGT,OAAO,eAAe,UAAU,KAAK,SAAS,MAAM,aAAa;CACnE;;;;CAKA,MAAM,uBAAuB,OAC3B,aACiE;EACjE,MAAM,YAAY,cAAc,UAAUD,yBAAAA,SAAS;EACnD,IAAI,aAAa,MACf,OAAO;EAGT,MAAM,UAAU,CAAC,GAAG,QAAQ;EAC5B,IAAI,WAAW;EAEf,KAAK,IAAI,MAAM,YAAY,GAAG,MAAM,QAAQ,QAAQ,OAAO;GACzD,MAAM,MAAM,QAAQ;GACpB,IAAI,CAACE,yBAAAA,YAAY,WAAW,GAAG,GAC7B;GAGF,MAAM,OAAO,YAAY,GAAG;GAC5B,IAAI,CAAC,MACH;GAGF,MAAM,oBAAoB;GAI1B,MAAM,iBAAgB,MAHC,gBAAgB,MAAM,EAC3C,OAAO,gBACT,CAAC,EAAA,CAC8B,QAAQ,MAAM,WAAW,OAAO,OAAO;GACtE,IAAI,CAAC,eACH;GAGF,MAAM,SAAS,eAAe,SAAS,KAAK,QAAQ,MAAM,aAAa;GACvE,IAAI,QAAQ;IACV,IAAI,YAAY,QACd,OAAO;IAET,IAAI,cAAc,QAAQ;KACxB,QAAQ,OACN,GACA,QAAQ,QACR,GAAI,OAAO,QACb;KACA,WAAW;IACb;GACF;EACF;EAEA,IAAI,UACF,OAAO,EAAE,UAAU,QAAQ;EAG7B,OAAO;CACT;;;;CAKA,MAAM,iBAAiB,OACrB,aACiE;EACjE,MAAM,YAAY,cAAc,UAAUF,yBAAAA,SAAS;EACnD,IAAI,aAAa,MACf,OAAO;EAGT,MAAM,YAAY,SAAS;EAC3B,MAAM,OAAO,YAAY,SAAS;EAClC,IAAI,CAAC,MACH,OAAO;EAGT,MAAM,oBAAoB;EAI1B,MAAM,iBAAgB,MAHC,gBAAgB,MAAM,EAC3C,OAAO,gBACT,CAAC,EAAA,CAC8B,QAAQ,MAAM,WAAW,OAAO,OAAO;EACtE,IAAI,CAAC,eACH,OAAO;EAGT,OAAO,eAAe,UAAU,WAAW,UAAU,MAAM,aAAa;CAC1E;;;;CAKA,MAAM,iBAAiB,OACrB,aACiE;EACjE,MAAM,UAAU,CAAC,GAAG,QAAQ;EAC5B,IAAI,WAAW;EAEf,IAAI,kBAAkB;GACpB,MAAM,SAAS,MAAM,qBAAqB,OAAO;GACjD,IAAI,QAAQ;IACV,IAAI,YAAY,QACd,OAAO;IAET,IAAI,cAAc,QAAQ;KACxB,QAAQ,OACN,GACA,QAAQ,QACR,GAAI,OAAO,QACb;KACA,WAAW;IACb;GACF;EACF;EAEA,IAAI,YAAY;GACd,MAAM,SAAS,MAAM,oBAAoB,OAAO;GAChD,IAAI,QAAQ;IACV,IAAI,YAAY,QACd,OAAO;IAET,IAAI,cAAc,QAAQ;KACxB,QAAQ,OACN,GACA,QAAQ,QACR,GAAI,OAAO,QACb;KACA,WAAW;IACb;GACF;EACF;EAEA,IAAI,UACF,OAAO,EAAE,UAAU,QAAQ;EAG7B,OAAO;CACT;CAEA,OAAOG,mBAAAA,iBAAiB;EACtB,MAAM;EACN,aAAa;GACX,MAAM,OACJ,UACsE;IACtE,IAAI,CAAC,cAAc,CAAC,kBAClB;IAGF,MAAM,WAAW,MAAM,YAAY,CAAC;IACpC,IAAI,SAAS,WAAW,GACtB;IAGF,OAAQ,MAAM,eAAe,QAAQ,KAAM,KAAA;GAC7C;GACA,WAAW,CAAC,KAAK;EACnB;EACA,YAAY;GACV,MAAM,OACJ,UACsE;IACtE,IAAI,CAAC,aACH;IAGF,MAAM,WAAW,MAAM,YAAY,CAAC;IACpC,IAAI,SAAS,WAAW,GACtB;IAGF,OAAQ,MAAM,eAAe,QAAQ,KAAM,KAAA;GAC7C;GACA,WAAW,CAAC,KAAK;EACnB;CACF,CAAC;AACH"}