{"version":3,"file":"toolCallLimit.cjs","names":["z","z4","createMiddleware","AIMessage","ToolMessage"],"sources":["../../../src/agents/middleware/toolCallLimit.ts"],"sourcesContent":["import { AIMessage, ToolMessage } from \"@langchain/core/messages\";\nimport { z as z4 } from \"zod/v4\";\nimport { z } from \"zod/v3\";\nimport type { InferInteropZodInput } from \"@langchain/core/utils/types\";\nimport type { ToolCall } from \"@langchain/core/messages/tool\";\n\nimport { createMiddleware } from \"../middleware.js\";\n\n/**\n * Build the error message content for ToolMessage when limit is exceeded.\n *\n * This message is sent to the model, so it should not reference thread/run concepts\n * that the model has no notion of.\n *\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A concise message instructing the model not to call the tool again.\n */\nfunction buildToolMessageContent(toolName: string | undefined): string {\n  // Always instruct the model not to call again, regardless of which limit was hit\n  if (toolName) {\n    return `Tool call limit exceeded. Do not call '${toolName}' again.`;\n  }\n  return \"Tool call limit exceeded. Do not make additional tool calls.\";\n}\n\nconst VALID_EXIT_BEHAVIORS = [\"continue\", \"error\", \"end\"] as const;\nconst DEFAULT_EXIT_BEHAVIOR = \"continue\";\n\n/**\n * Build the final AI message content for 'end' behavior.\n *\n * This message is displayed to the user, so it should include detailed information\n * about which limits were exceeded.\n *\n * @param threadCount - Current thread tool call count.\n * @param runCount - Current run tool call count.\n * @param threadLimit - Thread tool call limit (if set).\n * @param runLimit - Run tool call limit (if set).\n * @param toolName - Tool name being limited (if specific tool), or undefined for all tools.\n * @returns A formatted message describing which limits were exceeded.\n */\nfunction buildFinalAIMessageContent(\n  threadCount: number,\n  runCount: number,\n  threadLimit: number | undefined,\n  runLimit: number | undefined,\n  toolName: string | undefined\n): string {\n  const toolDesc = toolName ? `'${toolName}' tool` : \"Tool\";\n  const exceededLimits: string[] = [];\n\n  if (threadLimit !== undefined && threadCount > threadLimit) {\n    exceededLimits.push(\n      `thread limit exceeded (${threadCount}/${threadLimit} calls)`\n    );\n  }\n  if (runLimit !== undefined && runCount > runLimit) {\n    exceededLimits.push(`run limit exceeded (${runCount}/${runLimit} calls)`);\n  }\n\n  const limitsText = exceededLimits.join(\" and \");\n  return `${toolDesc} call limit reached: ${limitsText}.`;\n}\n\n/**\n * Schema for the exit behavior.\n */\nconst exitBehaviorSchema = z\n  .enum(VALID_EXIT_BEHAVIORS)\n  .default(DEFAULT_EXIT_BEHAVIOR);\n\n/**\n * Exception raised when tool call limits are exceeded.\n *\n * This exception is raised when the configured exit behavior is 'error'\n * and either the thread or run tool call limit has been exceeded.\n */\nexport class ToolCallLimitExceededError extends Error {\n  /**\n   * Current thread tool call count.\n   */\n  threadCount: number;\n  /**\n   * Current run tool call count.\n   */\n  runCount: number;\n  /**\n   * Thread tool call limit (if set).\n   */\n  threadLimit: number | undefined;\n  /**\n   * Run tool call limit (if set).\n   */\n  runLimit: number | undefined;\n  /**\n   * Tool name being limited (if specific tool), or undefined for all tools.\n   */\n  toolName: string | undefined;\n\n  constructor(\n    threadCount: number,\n    runCount: number,\n    threadLimit: number | undefined,\n    runLimit: number | undefined,\n    toolName: string | undefined = undefined\n  ) {\n    const message = buildFinalAIMessageContent(\n      threadCount,\n      runCount,\n      threadLimit,\n      runLimit,\n      toolName\n    );\n    super(message);\n\n    this.name = \"ToolCallLimitExceededError\";\n    this.threadCount = threadCount;\n    this.runCount = runCount;\n    this.threadLimit = threadLimit;\n    this.runLimit = runLimit;\n    this.toolName = toolName;\n  }\n}\n\n/**\n * Options for configuring the Tool Call Limit middleware.\n */\nexport const ToolCallLimitOptionsSchema = z.object({\n  /**\n   * Name of the specific tool to limit. If undefined, limits apply to all tools.\n   */\n  toolName: z.string().optional(),\n  /**\n   * Maximum number of tool calls allowed per thread.\n   * undefined means no limit.\n   */\n  threadLimit: z.number().optional(),\n  /**\n   * Maximum number of tool calls allowed per run.\n   * undefined means no limit.\n   */\n  runLimit: z.number().optional(),\n  /**\n   * What to do when limits are exceeded.\n   * - \"continue\": Block exceeded tools with error messages, let other tools continue (default)\n   * - \"error\": Raise a ToolCallLimitExceededError exception\n   * - \"end\": Stop execution immediately, injecting a ToolMessage and an AI message\n   *   for the single tool call that exceeded the limit. Raises NotImplementedError\n   *   if there are multiple tool calls.\n   *\n   * @default \"continue\"\n   */\n  exitBehavior: exitBehaviorSchema,\n});\n\nexport type ToolCallLimitConfig = InferInteropZodInput<\n  typeof ToolCallLimitOptionsSchema\n>;\n\n/**\n * Middleware state schema to track the number of model calls made at the thread and run level.\n */\nconst stateSchema = z.object({\n  threadToolCallCount: z.record(z.string(), z.number()).default({}),\n  runToolCallCount: z.record(z.string(), z.number()).default({}),\n});\n\nconst DEFAULT_TOOL_COUNT_KEY = \"__all__\";\n\n/**\n * Middleware that tracks tool call counts and enforces limits.\n *\n * This middleware monitors the number of tool calls made during agent execution\n * and can terminate the agent when specified limits are reached. It supports\n * both thread-level and run-level call counting with configurable exit behaviors.\n *\n * Thread-level: The middleware counts all tool calls in the entire message history\n * and persists this count across multiple runs (invocations) of the agent.\n *\n * Run-level: The middleware counts tool calls made after the last HumanMessage,\n * representing the current run (invocation) of the agent.\n *\n * @param options - Configuration options for the middleware\n * @param options.toolName - Name of the specific tool to limit. If undefined, limits apply to all tools.\n * @param options.threadLimit - Maximum number of tool calls allowed per thread. undefined means no limit.\n * @param options.runLimit - Maximum number of tool calls allowed per run. undefined means no limit.\n * @param options.exitBehavior - What to do when limits are exceeded.\n *   - \"continue\": Block exceeded tools with error messages, let other tools continue. Model decides when to end. (default)\n *   - \"error\": Raise a ToolCallLimitExceededError exception\n *   - \"end\": Stop execution immediately with a ToolMessage + AI message for the single tool call that exceeded the limit. Raises NotImplementedError if there are multiple tool calls.\n *\n * @throws {Error} If both limits are undefined, if exitBehavior is invalid, or if runLimit exceeds threadLimit.\n * @throws {NotImplementedError} If exitBehavior is \"end\" and there are multiple tool calls.\n *\n * @example Continue execution with blocked tools (default)\n * ```ts\n * import { toolCallLimitMiddleware } from \"@langchain/langchain/agents/middleware\";\n * import { createAgent } from \"@langchain/langchain/agents\";\n *\n * // Block exceeded tools but let other tools and model continue\n * const limiter = toolCallLimitMiddleware({\n *   threadLimit: 20,\n *   runLimit: 10,\n *   exitBehavior: \"continue\", // default\n * });\n *\n * const agent = createAgent({\n *   model: \"openai:gpt-4o\",\n *   middleware: [limiter]\n * });\n * ```\n *\n * @example Stop immediately when limit exceeded\n * ```ts\n * // End execution immediately with an AI message\n * const limiter = toolCallLimitMiddleware({\n *   runLimit: 5,\n *   exitBehavior: \"end\"\n * });\n *\n * const agent = createAgent({\n *   model: \"openai:gpt-4o\",\n *   middleware: [limiter]\n * });\n * ```\n *\n * @example Raise exception on limit\n * ```ts\n * // Strict limit with exception handling\n * const limiter = toolCallLimitMiddleware({\n *   toolName: \"search\",\n *   threadLimit: 5,\n *   exitBehavior: \"error\"\n * });\n *\n * const agent = createAgent({\n *   model: \"openai:gpt-4o\",\n *   middleware: [limiter]\n * });\n *\n * try {\n *   const result = await agent.invoke({ messages: [new HumanMessage(\"Task\")] });\n * } catch (error) {\n *   if (error instanceof ToolCallLimitExceededError) {\n *     console.log(`Search limit exceeded: ${error}`);\n *   }\n * }\n * ```\n */\nexport function toolCallLimitMiddleware(options: ToolCallLimitConfig) {\n  /**\n   * Validate that at least one limit is specified\n   */\n  if (options.threadLimit === undefined && options.runLimit === undefined) {\n    throw new Error(\n      \"At least one limit must be specified (threadLimit or runLimit)\"\n    );\n  }\n\n  /**\n   * Validate exitBehavior (Zod schema already validates, but provide helpful error)\n   */\n  const exitBehavior = options.exitBehavior ?? DEFAULT_EXIT_BEHAVIOR;\n  const parseResult = exitBehaviorSchema.safeParse(exitBehavior);\n  if (!parseResult.success) {\n    throw new Error(z4.prettifyError(parseResult.error).slice(2));\n  }\n\n  /**\n   * Validate that runLimit does not exceed threadLimit\n   */\n  if (\n    options.threadLimit !== undefined &&\n    options.runLimit !== undefined &&\n    options.runLimit > options.threadLimit\n  ) {\n    throw new Error(\n      `runLimit (${options.runLimit}) cannot exceed threadLimit (${options.threadLimit}). ` +\n        \"The run limit should be less than or equal to the thread limit.\"\n    );\n  }\n\n  /**\n   * Generate the middleware name based on the tool name\n   */\n  const middlewareName = options.toolName\n    ? `ToolCallLimitMiddleware[${options.toolName}]`\n    : \"ToolCallLimitMiddleware\";\n\n  return createMiddleware({\n    name: middlewareName,\n    stateSchema,\n    afterModel: {\n      canJumpTo: [\"end\"],\n      hook: (state) => {\n        /**\n         * Get the last AI message to check for tool calls\n         */\n        const lastAIMessage = [...state.messages]\n          .reverse()\n          .find(AIMessage.isInstance);\n\n        if (!lastAIMessage || !lastAIMessage.tool_calls) {\n          return undefined;\n        }\n\n        /**\n         * Helper to check if limit would be exceeded by one more call\n         */\n        const wouldExceedLimit = (\n          threadCount: number,\n          runCount: number\n        ): boolean => {\n          return (\n            (options.threadLimit !== undefined &&\n              threadCount + 1 > options.threadLimit) ||\n            (options.runLimit !== undefined && runCount + 1 > options.runLimit)\n          );\n        };\n\n        /**\n         * Helper to check if a tool call matches our filter\n         */\n        const matchesToolFilter = (toolCall: { name?: string }): boolean => {\n          return (\n            options.toolName === undefined || toolCall.name === options.toolName\n          );\n        };\n\n        /**\n         * Separate tool calls into allowed and blocked based on limits\n         */\n        const separateToolCalls = (\n          toolCalls: ToolCall[],\n          threadCount: number,\n          runCount: number\n        ): {\n          allowed: ToolCall[];\n          blocked: ToolCall[];\n          finalThreadCount: number;\n          finalRunCount: number;\n        } => {\n          const allowed: ToolCall[] = [];\n          const blocked: ToolCall[] = [];\n          let tempThreadCount = threadCount;\n          let tempRunCount = runCount;\n\n          for (const toolCall of toolCalls) {\n            if (!matchesToolFilter(toolCall)) {\n              // Tool call doesn't match our filter, skip it\n              continue;\n            }\n\n            if (wouldExceedLimit(tempThreadCount, tempRunCount)) {\n              blocked.push(toolCall);\n            } else {\n              allowed.push(toolCall);\n              tempThreadCount += 1;\n              tempRunCount += 1;\n            }\n          }\n\n          return {\n            allowed,\n            blocked,\n            finalThreadCount: tempThreadCount,\n            finalRunCount: tempRunCount + blocked.length,\n          };\n        };\n\n        /**\n         * Get the count key for this middleware instance\n         */\n        const countKey = options.toolName ?? DEFAULT_TOOL_COUNT_KEY;\n\n        /**\n         * Get current counts\n         */\n        const threadCounts = { ...(state.threadToolCallCount ?? {}) };\n        const runCounts = { ...(state.runToolCallCount ?? {}) };\n        const currentThreadCount = threadCounts[countKey] ?? 0;\n        const currentRunCount = runCounts[countKey] ?? 0;\n\n        /**\n         * Separate tool calls into allowed and blocked\n         */\n        const { allowed, blocked, finalThreadCount, finalRunCount } =\n          separateToolCalls(\n            lastAIMessage.tool_calls,\n            currentThreadCount,\n            currentRunCount\n          );\n\n        /**\n         * Update counts:\n         * - Thread count includes only allowed calls (blocked calls don't count towards thread-level tracking)\n         * - Run count includes blocked calls since they were attempted in this run\n         */\n        threadCounts[countKey] = finalThreadCount;\n        runCounts[countKey] = finalRunCount;\n\n        /**\n         * If no tool calls are blocked, just update counts\n         */\n        if (blocked.length === 0) {\n          if (allowed.length > 0) {\n            return {\n              threadToolCallCount: threadCounts,\n              runToolCallCount: runCounts,\n            };\n          }\n          return undefined;\n        }\n\n        /**\n         * Handle different exit behaviors\n         */\n        if (exitBehavior === \"error\") {\n          // Use hypothetical thread count to show which limit was exceeded\n          const hypotheticalThreadCount = finalThreadCount + blocked.length;\n          throw new ToolCallLimitExceededError(\n            hypotheticalThreadCount,\n            finalRunCount,\n            options.threadLimit,\n            options.runLimit,\n            options.toolName\n          );\n        }\n\n        /**\n         * Build tool message content (sent to model - no thread/run details)\n         */\n        const toolMsgContent = buildToolMessageContent(options.toolName);\n\n        /**\n         * Inject artificial error ToolMessages for blocked tool calls\n         */\n        const artificialMessages: Array<ToolMessage | AIMessage> = blocked.map(\n          (toolCall) =>\n            new ToolMessage({\n              content: toolMsgContent,\n              tool_call_id: toolCall.id!,\n              name: toolCall.name,\n              status: \"error\",\n            })\n        );\n\n        if (exitBehavior === \"end\") {\n          /**\n           * Check if there are tool calls to other tools that would continue executing\n           * For tool-specific limiters: check for calls to other tools\n           * For global limiters: check if there are multiple different tool types\n           */\n          let otherTools: ToolCall[] = [];\n          if (options.toolName !== undefined) {\n            /**\n             * Tool-specific limiter: check for calls to other tools\n             */\n            otherTools = lastAIMessage.tool_calls.filter(\n              (tc) => tc.name !== options.toolName\n            );\n          } else {\n            /**\n             * Global limiter: check if there are multiple different tool types\n             * If there are allowed calls, those would execute\n             * But even if all are blocked, we can't handle multiple tool types with \"end\"\n             */\n            const uniqueToolNames = new Set(\n              lastAIMessage.tool_calls.map((tc) => tc.name).filter(Boolean)\n            );\n            if (uniqueToolNames.size > 1) {\n              /**\n               * Multiple different tool types - use allowed calls to show which ones\n               */\n              otherTools =\n                allowed.length > 0 ? allowed : lastAIMessage.tool_calls;\n            }\n          }\n\n          if (otherTools.length > 0) {\n            const toolNames = Array.from(\n              new Set(otherTools.map((tc) => tc.name).filter(Boolean))\n            ).join(\", \");\n            throw new Error(\n              `Cannot end execution with other tool calls pending. Found calls to: ${toolNames}. Use 'continue' or 'error' behavior instead.`\n            );\n          }\n\n          /**\n           * Build final AI message content (displayed to user - includes thread/run details)\n           * Use hypothetical thread count (what it would have been if call wasn't blocked)\n           * to show which limit was actually exceeded\n           */\n          const hypotheticalThreadCount = finalThreadCount + blocked.length;\n          const finalMsgContent = buildFinalAIMessageContent(\n            hypotheticalThreadCount,\n            finalRunCount,\n            options.threadLimit,\n            options.runLimit,\n            options.toolName\n          );\n          artificialMessages.push(new AIMessage(finalMsgContent));\n\n          return {\n            threadToolCallCount: threadCounts,\n            runToolCallCount: runCounts,\n            jumpTo: \"end\" as const,\n            messages: artificialMessages,\n          };\n        }\n\n        /**\n         * For exit_behavior=\"continue\", return error messages to block exceeded tools\n         */\n        return {\n          threadToolCallCount: threadCounts,\n          runToolCallCount: runCounts,\n          messages: artificialMessages,\n        };\n      },\n    },\n    /**\n     * reset the run tool call count after the agent execution completes\n     */\n    afterAgent: () => ({\n      runToolCallCount: {},\n    }),\n  });\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAS,wBAAwB,UAAsC;AAErE,KAAI,SACF,QAAO,0CAA0C,SAAS;AAE5D,QAAO;;AAGT,MAAM,uBAAuB;CAAC;CAAY;CAAS;CAAM;AACzD,MAAM,wBAAwB;;;;;;;;;;;;;;AAe9B,SAAS,2BACP,aACA,UACA,aACA,UACA,UACQ;CACR,MAAM,WAAW,WAAW,IAAI,SAAS,UAAU;CACnD,MAAM,iBAA2B,EAAE;AAEnC,KAAI,gBAAgB,KAAA,KAAa,cAAc,YAC7C,gBAAe,KACb,0BAA0B,YAAY,GAAG,YAAY,SACtD;AAEH,KAAI,aAAa,KAAA,KAAa,WAAW,SACvC,gBAAe,KAAK,uBAAuB,SAAS,GAAG,SAAS,SAAS;AAI3E,QAAO,GAAG,SAAS,uBADA,eAAe,KAAK,QAAQ,CACM;;;;;AAMvD,MAAM,qBAAqBA,OAAAA,EACxB,KAAK,qBAAqB,CAC1B,QAAQ,sBAAsB;;;;;;;AAQjC,IAAa,6BAAb,cAAgD,MAAM;;;;CAIpD;;;;CAIA;;;;CAIA;;;;CAIA;;;;CAIA;CAEA,YACE,aACA,UACA,aACA,UACA,WAA+B,KAAA,GAC/B;EACA,MAAM,UAAU,2BACd,aACA,UACA,aACA,UACA,SACD;AACD,QAAM,QAAQ;AAEd,OAAK,OAAO;AACZ,OAAK,cAAc;AACnB,OAAK,WAAW;AAChB,OAAK,cAAc;AACnB,OAAK,WAAW;AAChB,OAAK,WAAW;;;AAOsBA,OAAAA,EAAE,OAAO;CAIjD,UAAUA,OAAAA,EAAE,QAAQ,CAAC,UAAU;CAK/B,aAAaA,OAAAA,EAAE,QAAQ,CAAC,UAAU;CAKlC,UAAUA,OAAAA,EAAE,QAAQ,CAAC,UAAU;CAW/B,cAAc;CACf,CAAC;;;;AASF,MAAM,cAAcA,OAAAA,EAAE,OAAO;CAC3B,qBAAqBA,OAAAA,EAAE,OAAOA,OAAAA,EAAE,QAAQ,EAAEA,OAAAA,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;CACjE,kBAAkBA,OAAAA,EAAE,OAAOA,OAAAA,EAAE,QAAQ,EAAEA,OAAAA,EAAE,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;CAC/D,CAAC;AAEF,MAAM,yBAAyB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkF/B,SAAgB,wBAAwB,SAA8B;;;;AAIpE,KAAI,QAAQ,gBAAgB,KAAA,KAAa,QAAQ,aAAa,KAAA,EAC5D,OAAM,IAAI,MACR,iEACD;;;;CAMH,MAAM,eAAe,QAAQ,gBAAgB;CAC7C,MAAM,cAAc,mBAAmB,UAAU,aAAa;AAC9D,KAAI,CAAC,YAAY,QACf,OAAM,IAAI,MAAMC,OAAAA,EAAG,cAAc,YAAY,MAAM,CAAC,MAAM,EAAE,CAAC;;;;AAM/D,KACE,QAAQ,gBAAgB,KAAA,KACxB,QAAQ,aAAa,KAAA,KACrB,QAAQ,WAAW,QAAQ,YAE3B,OAAM,IAAI,MACR,aAAa,QAAQ,SAAS,+BAA+B,QAAQ,YAAY,oEAElF;AAUH,QAAOC,mBAAAA,iBAAiB;EACtB,MALqB,QAAQ,WAC3B,2BAA2B,QAAQ,SAAS,KAC5C;EAIF;EACA,YAAY;GACV,WAAW,CAAC,MAAM;GAClB,OAAO,UAAU;;;;IAIf,MAAM,gBAAgB,CAAC,GAAG,MAAM,SAAS,CACtC,SAAS,CACT,KAAKC,yBAAAA,UAAU,WAAW;AAE7B,QAAI,CAAC,iBAAiB,CAAC,cAAc,WACnC;;;;IAMF,MAAM,oBACJ,aACA,aACY;AACZ,YACG,QAAQ,gBAAgB,KAAA,KACvB,cAAc,IAAI,QAAQ,eAC3B,QAAQ,aAAa,KAAA,KAAa,WAAW,IAAI,QAAQ;;;;;IAO9D,MAAM,qBAAqB,aAAyC;AAClE,YACE,QAAQ,aAAa,KAAA,KAAa,SAAS,SAAS,QAAQ;;;;;IAOhE,MAAM,qBACJ,WACA,aACA,aAMG;KACH,MAAM,UAAsB,EAAE;KAC9B,MAAM,UAAsB,EAAE;KAC9B,IAAI,kBAAkB;KACtB,IAAI,eAAe;AAEnB,UAAK,MAAM,YAAY,WAAW;AAChC,UAAI,CAAC,kBAAkB,SAAS,CAE9B;AAGF,UAAI,iBAAiB,iBAAiB,aAAa,CACjD,SAAQ,KAAK,SAAS;WACjB;AACL,eAAQ,KAAK,SAAS;AACtB,0BAAmB;AACnB,uBAAgB;;;AAIpB,YAAO;MACL;MACA;MACA,kBAAkB;MAClB,eAAe,eAAe,QAAQ;MACvC;;;;;IAMH,MAAM,WAAW,QAAQ,YAAY;;;;IAKrC,MAAM,eAAe,EAAE,GAAI,MAAM,uBAAuB,EAAE,EAAG;IAC7D,MAAM,YAAY,EAAE,GAAI,MAAM,oBAAoB,EAAE,EAAG;IACvD,MAAM,qBAAqB,aAAa,aAAa;IACrD,MAAM,kBAAkB,UAAU,aAAa;;;;IAK/C,MAAM,EAAE,SAAS,SAAS,kBAAkB,kBAC1C,kBACE,cAAc,YACd,oBACA,gBACD;;;;;;AAOH,iBAAa,YAAY;AACzB,cAAU,YAAY;;;;AAKtB,QAAI,QAAQ,WAAW,GAAG;AACxB,SAAI,QAAQ,SAAS,EACnB,QAAO;MACL,qBAAqB;MACrB,kBAAkB;MACnB;AAEH;;;;;AAMF,QAAI,iBAAiB,QAGnB,OAAM,IAAI,2BADsB,mBAAmB,QAAQ,QAGzD,eACA,QAAQ,aACR,QAAQ,UACR,QAAQ,SACT;;;;IAMH,MAAM,iBAAiB,wBAAwB,QAAQ,SAAS;;;;IAKhE,MAAM,qBAAqD,QAAQ,KAChE,aACC,IAAIC,yBAAAA,YAAY;KACd,SAAS;KACT,cAAc,SAAS;KACvB,MAAM,SAAS;KACf,QAAQ;KACT,CAAC,CACL;AAED,QAAI,iBAAiB,OAAO;;;;;;KAM1B,IAAI,aAAyB,EAAE;AAC/B,SAAI,QAAQ,aAAa,KAAA;;;;AAIvB,kBAAa,cAAc,WAAW,QACnC,OAAO,GAAG,SAAS,QAAQ,SAC7B;cAOuB,IAAI,IAC1B,cAAc,WAAW,KAAK,OAAO,GAAG,KAAK,CAAC,OAAO,QAAQ,CAC9D,CACmB,OAAO;;;;AAIzB,kBACE,QAAQ,SAAS,IAAI,UAAU,cAAc;AAInD,SAAI,WAAW,SAAS,GAAG;MACzB,MAAM,YAAY,MAAM,KACtB,IAAI,IAAI,WAAW,KAAK,OAAO,GAAG,KAAK,CAAC,OAAO,QAAQ,CAAC,CACzD,CAAC,KAAK,KAAK;AACZ,YAAM,IAAI,MACR,uEAAuE,UAAU,+CAClF;;KASH,MAAM,kBAAkB,2BADQ,mBAAmB,QAAQ,QAGzD,eACA,QAAQ,aACR,QAAQ,UACR,QAAQ,SACT;AACD,wBAAmB,KAAK,IAAID,yBAAAA,UAAU,gBAAgB,CAAC;AAEvD,YAAO;MACL,qBAAqB;MACrB,kBAAkB;MAClB,QAAQ;MACR,UAAU;MACX;;;;;AAMH,WAAO;KACL,qBAAqB;KACrB,kBAAkB;KAClB,UAAU;KACX;;GAEJ;EAID,mBAAmB,EACjB,kBAAkB,EAAE,EACrB;EACF,CAAC"}