gitlab-ai-provider 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/gitlab-anthropic-language-model.ts","../src/gitlab-direct-access.ts","../src/gitlab-error.ts","../src/gitlab-openai-language-model.ts","../src/model-mappings.ts","../src/gitlab-workflow-client.ts","../src/version.ts","../src/gitlab-workflow-types.ts","../src/gitlab-workflow-builtins.ts","../src/gitlab-workflow-token-client.ts","../src/gitlab-project-detector.ts","../src/gitlab-project-cache.ts","../src/gitlab-model-discovery.ts","../src/gitlab-model-cache.ts","../src/gitlab-workflow-language-model.ts","../src/gitlab-oauth-types.ts","../src/gitlab-oauth-manager.ts","../src/gitlab-provider.ts"],"sourcesContent":["// Main exports\nexport { createGitLab, gitlab } from './gitlab-provider';\nexport { VERSION } from './version';\nexport type {\n GitLabProvider,\n GitLabProviderSettings,\n GitLabAgenticOptions,\n} from './gitlab-provider';\n\n// Model exports\nexport { GitLabAnthropicLanguageModel } from './gitlab-anthropic-language-model';\nexport type { GitLabAnthropicConfig } from './gitlab-anthropic-language-model';\nexport { GitLabOpenAILanguageModel } from './gitlab-openai-language-model';\nexport type { GitLabOpenAIConfig } from './gitlab-openai-language-model';\n\n// Model mappings exports\nexport {\n MODEL_MAPPINGS,\n MODEL_ID_TO_ANTHROPIC_MODEL,\n getModelMapping,\n getProviderForModelId,\n getValidModelsForProvider,\n getAnthropicModelForModelId,\n getOpenAIModelForModelId,\n getOpenAIApiType,\n isResponsesApiModel,\n} from './model-mappings';\nexport type { ModelProvider, ModelMapping, OpenAIApiType } from './model-mappings';\n\n// Error exports\nexport { GitLabError } from './gitlab-error';\nexport type { GitLabErrorOptions } from './gitlab-error';\n\n// API types exports\nexport type { GitLabOAuthTokenResponse } from './gitlab-api-types';\n\n// OAuth exports\nexport { GitLabOAuthManager } from './gitlab-oauth-manager';\nexport type {\n GitLabOAuthTokens,\n OpenCodeAuth,\n OpenCodeAuthOAuth,\n OpenCodeAuthApi,\n} from './gitlab-oauth-types';\nexport {\n BUNDLED_CLIENT_ID,\n OPENCODE_GITLAB_AUTH_CLIENT_ID,\n GITLAB_COM_URL,\n TOKEN_EXPIRY_SKEW_MS,\n OAUTH_SCOPES,\n} from './gitlab-oauth-types';\n\n// Project detection exports\nexport { GitLabProjectDetector } from './gitlab-project-detector';\nexport type { GitLabProjectDetectorConfig } from './gitlab-project-detector';\nexport { GitLabProjectCache } from './gitlab-project-cache';\nexport type { GitLabProject } from './gitlab-project-cache';\n\n// Direct access exports\nexport { GitLabDirectAccessClient, DEFAULT_AI_GATEWAY_URL } from './gitlab-direct-access';\nexport type { GitLabDirectAccessConfig, DirectAccessToken } from './gitlab-direct-access';\n\n// Workflow (DWS) exports\nexport { GitLabWorkflowLanguageModel } from './gitlab-workflow-language-model';\nexport type {\n GitLabWorkflowLanguageModelConfig,\n WorkflowToolExecutor,\n} from './gitlab-workflow-language-model';\nexport { GitLabWorkflowClient } from './gitlab-workflow-client';\nexport type { WorkflowWebSocketOptions } from './gitlab-workflow-client';\nexport { GitLabWorkflowTokenClient } from './gitlab-workflow-token-client';\nexport type {\n GitLabWorkflowOptions,\n GitLabWorkflowClientConfig,\n McpToolDefinition,\n AdditionalContext,\n GenerateTokenResponse,\n WorkflowAction,\n WorkflowClientEvent,\n WorkflowStatus,\n NewCheckpoint,\n RunMcpTool,\n ClientEvent,\n StartRequest,\n ActionResponsePayload,\n} from './gitlab-workflow-types';\nexport {\n WorkflowType,\n DEFAULT_WORKFLOW_DEFINITION,\n DEFAULT_CLIENT_CAPABILITIES,\n CLIENT_VERSION,\n WS_KEEPALIVE_PING_INTERVAL_MS,\n WS_HEARTBEAT_INTERVAL_MS,\n AGENT_PRIVILEGES,\n DEFAULT_AGENT_PRIVILEGES,\n WORKFLOW_ENVIRONMENT,\n} from './gitlab-workflow-types';\nexport { isWorkflowModel, getWorkflowModelRef } from './model-mappings';\n\n// Model discovery exports\nexport { GitLabModelDiscovery } from './gitlab-model-discovery';\nexport type {\n AiModel,\n AiChatAvailableModels,\n DiscoveredModels,\n ModelDiscoveryConfig,\n} from './gitlab-model-discovery';\n\n// Model cache exports\nexport { GitLabModelCache } from './gitlab-model-cache';\nexport type { ModelCacheEntry } from './gitlab-model-cache';\n","import Anthropic from '@anthropic-ai/sdk';\nimport type { Tool } from '@anthropic-ai/sdk/resources/messages';\nimport { GitLabDirectAccessClient } from './gitlab-direct-access';\nimport { GitLabError } from './gitlab-error';\n\nimport type {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2StreamPart,\n LanguageModelV2FinishReason,\n LanguageModelV2CallWarning,\n LanguageModelV2Content,\n LanguageModelV2Usage,\n LanguageModelV2FunctionTool,\n LanguageModelV2Message,\n LanguageModelV2ToolChoice,\n} from '@ai-sdk/provider';\n\nexport interface GitLabAnthropicConfig {\n provider: string;\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n\n /**\n * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')\n * @default 'claude-sonnet-4-5-20250929'\n */\n anthropicModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n * @default { DuoAgentPlatformNext: true }\n */\n featureFlags?: {\n DuoAgentPlatformNext: true;\n } & Record<string, boolean>;\n\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n\n /**\n * Custom headers for AI Gateway Anthropic proxy requests.\n * Merged with headers from direct_access token response.\n */\n aiGatewayHeaders?: Record<string, string>;\n}\n\n/**\n * GitLab Anthropic Language Model\n *\n * This model uses GitLab's Anthropic proxy to provide native tool calling support\n * for the duo-chat model. It connects to Claude through GitLab's cloud proxy\n * at https://cloud.gitlab.com/ai/v1/proxy/anthropic/\n */\nexport class GitLabAnthropicLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n private readonly config: GitLabAnthropicConfig;\n private readonly directAccessClient: GitLabDirectAccessClient;\n private anthropicClient: Anthropic | null = null;\n\n constructor(modelId: string, config: GitLabAnthropicConfig) {\n this.modelId = modelId;\n this.config = config;\n\n this.directAccessClient = new GitLabDirectAccessClient({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n refreshApiKey: config.refreshApiKey,\n fetch: config.fetch,\n featureFlags: config.featureFlags,\n aiGatewayUrl: config.aiGatewayUrl,\n });\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n /**\n * Get or create an Anthropic client with valid credentials\n * @param forceRefresh - If true, forces a token refresh before creating the client\n */\n private async getAnthropicClient(forceRefresh: boolean = false): Promise<Anthropic> {\n // Get token from GitLab (will use cache unless forceRefresh is true)\n const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);\n\n // Create new client with the token\n // GitLab's proxy expects:\n // - authToken: sets Authorization: Bearer header (NOT apiKey which sets x-api-key)\n // - defaultHeaders: additional headers from the direct access response\n // Filter out x-api-key from headers if present - we use authToken for Bearer auth\n const { 'x-api-key': _removed, ...filteredHeaders } = tokenData.headers;\n\n // Merge: tokenData headers < custom aiGatewayHeaders\n const mergedHeaders = {\n ...filteredHeaders,\n ...this.config.aiGatewayHeaders,\n };\n\n this.anthropicClient = new Anthropic({\n apiKey: null,\n authToken: tokenData.token,\n baseURL: this.directAccessClient.getAnthropicProxyUrl(),\n defaultHeaders: mergedHeaders,\n });\n\n return this.anthropicClient;\n }\n\n /**\n * Check if an error is a token-related authentication error that can be retried\n */\n private isTokenError(error: unknown): boolean {\n if (error instanceof Anthropic.APIError) {\n // 401 Unauthorized - token expired or revoked\n if (error.status === 401) {\n return true;\n }\n // Check for token-related error messages\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('token') &&\n (message.includes('expired') || message.includes('revoked') || message.includes('invalid'))\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if an error is a context overflow error (prompt too long)\n * These should NOT trigger token refresh and should be reported to the user.\n */\n private isContextOverflowError(error: unknown): boolean {\n if (error instanceof Anthropic.APIError) {\n // 400 Bad Request with prompt too long message\n if (error.status === 400) {\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('prompt is too long') ||\n message.includes('prompt too long') ||\n (message.includes('tokens') && message.includes('maximum'))\n ) {\n return true;\n }\n }\n }\n return false;\n }\n\n /**\n * Convert AI SDK tools to Anthropic tool format\n */\n private convertTools(tools?: LanguageModelV2CallOptions['tools']): Tool[] | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => {\n const schema = tool.inputSchema as { properties?: object; required?: string[] } | undefined;\n return {\n name: tool.name,\n description: tool.description || '',\n input_schema: {\n type: 'object' as const,\n properties: schema?.properties || {},\n required: schema?.required || [],\n },\n };\n });\n }\n\n /**\n * Convert AI SDK tool choice to Anthropic format\n */\n private convertToolChoice(\n toolChoice?: LanguageModelV2ToolChoice\n ): Anthropic.MessageCreateParams['tool_choice'] {\n if (!toolChoice) {\n return undefined;\n }\n\n switch (toolChoice.type) {\n case 'auto':\n return { type: 'auto' };\n case 'none':\n // Anthropic doesn't have a direct 'none' - we handle this by not sending tools\n return undefined;\n case 'required':\n return { type: 'any' };\n case 'tool':\n return { type: 'tool', name: toolChoice.toolName };\n default:\n return undefined;\n }\n }\n\n /**\n * Convert AI SDK prompt to Anthropic messages format\n */\n private convertPrompt(prompt: LanguageModelV2Message[]): {\n system?: string;\n messages: Anthropic.MessageParam[];\n } {\n let systemMessage: string | undefined;\n const messages: Anthropic.MessageParam[] = [];\n\n for (const message of prompt) {\n if (message.role === 'system') {\n systemMessage = message.content;\n continue;\n }\n\n if (message.role === 'user') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'file') {\n // Handle file/image content if needed\n // For now, skip non-text content\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n } else if (message.role === 'assistant') {\n const content: Anthropic.ContentBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n content.push({ type: 'text', text: part.text });\n } else if (part.type === 'tool-call') {\n content.push({\n type: 'tool_use',\n id: part.toolCallId,\n name: part.toolName,\n input: typeof part.input === 'string' ? JSON.parse(part.input) : part.input,\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'assistant', content });\n }\n } else if (message.role === 'tool') {\n // Tool results need to be sent as user messages with tool_result content\n const content: Anthropic.ToolResultBlockParam[] = [];\n\n for (const part of message.content) {\n if (part.type === 'tool-result') {\n let resultContent: string;\n\n // Convert tool result output to string\n if (part.output.type === 'text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'json') {\n resultContent = JSON.stringify(part.output.value);\n } else if (part.output.type === 'error-text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'error-json') {\n resultContent = JSON.stringify(part.output.value);\n } else {\n resultContent = JSON.stringify(part.output);\n }\n\n content.push({\n type: 'tool_result',\n tool_use_id: part.toolCallId,\n content: resultContent,\n is_error: part.output.type.startsWith('error'),\n });\n }\n }\n\n if (content.length > 0) {\n messages.push({ role: 'user', content });\n }\n }\n }\n\n return { system: systemMessage, messages };\n }\n\n /**\n * Convert Anthropic finish reason to AI SDK format\n */\n private convertFinishReason(stopReason: string | null): LanguageModelV2FinishReason {\n switch (stopReason) {\n case 'end_turn':\n return 'stop';\n case 'stop_sequence':\n return 'stop';\n case 'max_tokens':\n return 'length';\n case 'tool_use':\n return 'tool-calls';\n default:\n return 'unknown';\n }\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n return this.doGenerateWithRetry(options, false);\n }\n\n private async doGenerateWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n try {\n const response = await client.messages.create({\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n });\n\n const content: LanguageModelV2Content[] = [];\n\n for (const block of response.content) {\n if (block.type === 'text') {\n content.push({\n type: 'text',\n text: block.text,\n });\n } else if (block.type === 'tool_use') {\n content.push({\n type: 'tool-call',\n toolCallId: block.id,\n toolName: block.name,\n input: JSON.stringify(block.input),\n });\n }\n }\n\n const usage: LanguageModelV2Usage = {\n inputTokens: response.usage.input_tokens,\n outputTokens: response.usage.output_tokens,\n totalTokens: response.usage.input_tokens + response.usage.output_tokens,\n };\n\n return {\n content,\n finishReason: this.convertFinishReason(response.stop_reason),\n usage,\n warnings: [],\n };\n } catch (error) {\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (this.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof Anthropic.APIError>;\n throw new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n });\n }\n\n // If this is a token error and we haven't retried yet, refresh token and retry\n if (!isRetry && this.isTokenError(error)) {\n this.directAccessClient.invalidateToken();\n return this.doGenerateWithRetry(options, true);\n }\n\n if (error instanceof Anthropic.APIError) {\n throw new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n });\n }\n throw error;\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n return this.doStreamWithRetry(options, false);\n }\n\n private async doStreamWithRetry(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n const client = await this.getAnthropicClient(isRetry);\n const { system, messages } = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n const requestBody = {\n model: anthropicModel,\n max_tokens: maxTokens,\n system: system,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop_sequences: options.stopSequences,\n stream: true as const,\n };\n\n // Reference to this for use in the stream callback\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n const contentBlocks: Record<\n number,\n | { type: 'text'; id: string }\n | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n > = {};\n\n const usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n\n try {\n const anthropicStream = client.messages.stream(requestBody, {\n signal: options.abortSignal,\n });\n\n // Stream start\n controller.enqueue({\n type: 'stream-start',\n warnings: [],\n });\n\n // Use event-based approach instead of for-await to ensure all events are received\n await new Promise<void>((resolve, reject) => {\n anthropicStream.on('streamEvent', (event) => {\n try {\n switch (event.type) {\n case 'message_start':\n if (event.message.usage) {\n usage.inputTokens = event.message.usage.input_tokens;\n }\n controller.enqueue({\n type: 'response-metadata',\n id: event.message.id,\n modelId: event.message.model,\n });\n break;\n\n case 'content_block_start':\n if (event.content_block.type === 'text') {\n const textId = `text-${event.index}`;\n contentBlocks[event.index] = { type: 'text', id: textId };\n controller.enqueue({\n type: 'text-start',\n id: textId,\n });\n } else if (event.content_block.type === 'tool_use') {\n contentBlocks[event.index] = {\n type: 'tool-call',\n toolCallId: event.content_block.id,\n toolName: event.content_block.name,\n input: '',\n };\n controller.enqueue({\n type: 'tool-input-start',\n id: event.content_block.id,\n toolName: event.content_block.name,\n });\n }\n break;\n\n case 'content_block_delta': {\n const block = contentBlocks[event.index];\n if (event.delta.type === 'text_delta' && block?.type === 'text') {\n controller.enqueue({\n type: 'text-delta',\n id: block.id,\n delta: event.delta.text,\n });\n } else if (\n event.delta.type === 'input_json_delta' &&\n block?.type === 'tool-call'\n ) {\n block.input += event.delta.partial_json;\n controller.enqueue({\n type: 'tool-input-delta',\n id: block.toolCallId,\n delta: event.delta.partial_json,\n });\n }\n break;\n }\n\n case 'content_block_stop': {\n const block = contentBlocks[event.index];\n if (block?.type === 'text') {\n controller.enqueue({\n type: 'text-end',\n id: block.id,\n });\n } else if (block?.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n delete contentBlocks[event.index];\n break;\n }\n\n case 'message_delta':\n if (event.usage) {\n usage.outputTokens = event.usage.output_tokens;\n usage.totalTokens = (usage.inputTokens || 0) + event.usage.output_tokens;\n }\n if (event.delta.stop_reason) {\n finishReason = self.convertFinishReason(event.delta.stop_reason);\n }\n break;\n\n case 'message_stop': {\n controller.enqueue({\n type: 'finish',\n finishReason,\n usage,\n });\n break;\n }\n }\n } catch (error) {\n controller.enqueue({\n type: 'error',\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n });\n\n anthropicStream.on('end', () => {\n resolve();\n });\n\n anthropicStream.on('error', (error) => {\n reject(error);\n });\n });\n\n // Emit any pending tool calls if stream ended without content_block_stop\n for (const [, block] of Object.entries(contentBlocks)) {\n if (block.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n }\n\n controller.close();\n } catch (error) {\n // Emit any pending tool calls before handling the error\n for (const [, block] of Object.entries(contentBlocks)) {\n if (block.type === 'tool-call') {\n controller.enqueue({\n type: 'tool-input-end',\n id: block.toolCallId,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: block.toolCallId,\n toolName: block.toolName,\n input: block.input === '' ? '{}' : block.input,\n });\n }\n }\n\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (self.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof Anthropic.APIError>;\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n // If this is a token error and we haven't retried yet, we need to signal retry\n // For streaming, we close this stream with an error and the caller should retry\n if (!isRetry && self.isTokenError(error)) {\n self.directAccessClient.invalidateToken();\n // Signal that a retry is needed with a special error\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: 'TOKEN_REFRESH_NEEDED',\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n if (error instanceof Anthropic.APIError) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Anthropic API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n }),\n });\n } else {\n controller.enqueue({\n type: 'error',\n error,\n });\n }\n controller.close();\n }\n },\n });\n\n return {\n stream,\n request: { body: requestBody },\n };\n }\n}\n","import { z } from 'zod';\nimport { GitLabError } from './gitlab-error';\n\n/**\n * Response from /api/v4/ai/third_party_agents/direct_access\n */\nexport const directAccessTokenSchema = z.object({\n headers: z.record(z.string()),\n token: z.string(),\n});\n\nexport type DirectAccessToken = z.infer<typeof directAccessTokenSchema>;\n\nexport const DEFAULT_AI_GATEWAY_URL = 'https://cloud.gitlab.com';\n\nexport interface GitLabDirectAccessConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n * Should clear cached credentials and re-fetch from auth provider.\n */\n refreshApiKey?: () => Promise<void>;\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n}\n\n/**\n * Client for GitLab's third-party agents direct access API.\n * This allows routing requests through GitLab's proxy to Anthropic.\n */\nexport class GitLabDirectAccessClient {\n private readonly config: GitLabDirectAccessConfig;\n private readonly fetchFn: typeof fetch;\n private readonly aiGatewayUrl: string;\n private cachedToken: DirectAccessToken | null = null;\n private tokenExpiresAt: number = 0;\n\n constructor(config: GitLabDirectAccessConfig) {\n this.config = config;\n this.fetchFn = config.fetch ?? fetch;\n this.aiGatewayUrl =\n config.aiGatewayUrl || process.env['GITLAB_AI_GATEWAY_URL'] || DEFAULT_AI_GATEWAY_URL;\n }\n\n /**\n * Get a direct access token for the Anthropic proxy.\n * Tokens are cached for 25 minutes (they expire after 30 minutes).\n * @param forceRefresh - If true, ignores the cache and fetches a new token\n */\n async getDirectAccessToken(forceRefresh: boolean = false): Promise<DirectAccessToken> {\n // Check if we have a valid cached token (unless force refresh is requested)\n const now = Date.now();\n if (!forceRefresh && this.cachedToken && this.tokenExpiresAt > now) {\n return this.cachedToken;\n }\n\n // Clear cache if forcing refresh\n if (forceRefresh) {\n this.invalidateToken();\n }\n\n const url = `${this.config.instanceUrl}/api/v4/ai/third_party_agents/direct_access`;\n\n // Prepare request body with feature flags if provided\n const requestBody: Record<string, unknown> = {};\n if (this.config.featureFlags && Object.keys(this.config.featureFlags).length > 0) {\n requestBody.feature_flags = this.config.featureFlags;\n }\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n\n // If we get a 401 and have a refresh callback, try refreshing the API key once\n if (response.status === 401 && this.config.refreshApiKey && !forceRefresh) {\n try {\n // Refresh the API key (this should clear cached credentials and re-fetch from auth)\n await this.config.refreshApiKey();\n\n // Retry the request with the refreshed credentials\n return await this.getDirectAccessToken(true);\n } catch (refreshError) {\n // If refresh fails, throw the original 401 error\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n }\n\n // Provide helpful error message for 403 errors (common with self-hosted instances)\n if (response.status === 403) {\n throw new GitLabError({\n message:\n `Access denied to GitLab AI features (${this.config.instanceUrl}). ` +\n `This may indicate that: (1) GitLab Duo is not enabled on this instance, ` +\n `(2) Your account does not have access to AI features, or ` +\n `(3) The third-party agents feature is not available. ` +\n `Original error: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n\n throw new GitLabError({\n message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n\n const data = await response.json();\n const token = directAccessTokenSchema.parse(data);\n\n // Cache the token for 25 minutes (tokens expire after 30 minutes)\n this.cachedToken = token;\n this.tokenExpiresAt = now + 25 * 60 * 1000;\n\n return token;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to get direct access token: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Get the Anthropic proxy base URL\n */\n getAnthropicProxyUrl(): string {\n const baseUrl = this.aiGatewayUrl.replace(/\\/$/, '');\n return `${baseUrl}/ai/v1/proxy/anthropic/`;\n }\n\n /**\n * Get the OpenAI proxy base URL\n * Note: The OpenAI SDK expects a base URL like https://api.openai.com/v1\n * and appends paths like /chat/completions. So we need /v1 at the end.\n */\n getOpenAIProxyUrl(): string {\n const baseUrl = this.aiGatewayUrl.replace(/\\/$/, '');\n return `${baseUrl}/ai/v1/proxy/openai/v1`;\n }\n\n /**\n * Invalidate the cached token\n */\n invalidateToken(): void {\n this.cachedToken = null;\n this.tokenExpiresAt = 0;\n }\n}\n","export interface GitLabErrorOptions {\n message: string;\n statusCode?: number;\n responseBody?: string;\n cause?: unknown;\n}\n\nexport class GitLabError extends Error {\n readonly statusCode?: number;\n readonly responseBody?: string;\n readonly cause?: unknown;\n\n constructor(options: GitLabErrorOptions) {\n super(options.message);\n this.name = 'GitLabError';\n this.statusCode = options.statusCode;\n this.responseBody = options.responseBody;\n this.cause = options.cause;\n\n // Maintain proper stack trace for where error was thrown (only available on V8)\n if (Error.captureStackTrace) {\n Error.captureStackTrace(this, GitLabError);\n }\n }\n\n static fromResponse(response: Response, body: string): GitLabError {\n return new GitLabError({\n message: `GitLab API error: ${response.status} ${response.statusText}`,\n statusCode: response.status,\n responseBody: body,\n });\n }\n\n isAuthError(): boolean {\n return this.statusCode === 401;\n }\n\n isRateLimitError(): boolean {\n return this.statusCode === 429;\n }\n\n isForbiddenError(): boolean {\n return this.statusCode === 403;\n }\n\n isServerError(): boolean {\n return this.statusCode !== undefined && this.statusCode >= 500;\n }\n\n /**\n * Check if this error is a context overflow error (prompt too long).\n * These errors occur when the conversation exceeds the model's token limit.\n */\n isContextOverflowError(): boolean {\n if (this.statusCode !== 400) {\n return false;\n }\n const message = this.message?.toLowerCase() || '';\n return (\n message.includes('context overflow') ||\n message.includes('prompt is too long') ||\n message.includes('prompt too long') ||\n (message.includes('tokens') && message.includes('maximum'))\n );\n }\n}\n","import OpenAI from 'openai';\nimport { GitLabDirectAccessClient } from './gitlab-direct-access';\nimport { GitLabError } from './gitlab-error';\nimport { isResponsesApiModel } from './model-mappings';\n\nimport type {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2StreamPart,\n LanguageModelV2FinishReason,\n LanguageModelV2CallWarning,\n LanguageModelV2Content,\n LanguageModelV2Usage,\n LanguageModelV2FunctionTool,\n LanguageModelV2Message,\n LanguageModelV2ToolChoice,\n} from '@ai-sdk/provider';\n\nexport interface GitLabOpenAIConfig {\n provider: string;\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n refreshApiKey?: () => Promise<void>;\n openaiModel?: string;\n maxTokens?: number;\n featureFlags?: {\n DuoAgentPlatformNext: true;\n } & Record<string, boolean>;\n aiGatewayUrl?: string;\n /** Whether to use the Responses API instead of Chat Completions API */\n useResponsesApi?: boolean;\n /**\n * Custom headers for AI Gateway OpenAI proxy requests.\n * Merged with headers from direct_access token response.\n */\n aiGatewayHeaders?: Record<string, string>;\n}\n\nexport class GitLabOpenAILanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n private readonly config: GitLabOpenAIConfig;\n private readonly directAccessClient: GitLabDirectAccessClient;\n private readonly useResponsesApi: boolean;\n private openaiClient: OpenAI | null = null;\n\n constructor(modelId: string, config: GitLabOpenAIConfig) {\n this.modelId = modelId;\n this.config = config;\n this.useResponsesApi = config.useResponsesApi ?? isResponsesApiModel(modelId);\n\n this.directAccessClient = new GitLabDirectAccessClient({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n refreshApiKey: config.refreshApiKey,\n fetch: config.fetch,\n featureFlags: config.featureFlags,\n aiGatewayUrl: config.aiGatewayUrl,\n });\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n private async getOpenAIClient(forceRefresh: boolean = false): Promise<OpenAI> {\n const tokenData = await this.directAccessClient.getDirectAccessToken(forceRefresh);\n const { 'x-api-key': _removed, ...filteredHeaders } = tokenData.headers;\n\n // Merge: tokenData headers < custom aiGatewayHeaders\n const mergedHeaders = {\n ...filteredHeaders,\n ...this.config.aiGatewayHeaders,\n };\n\n this.openaiClient = new OpenAI({\n apiKey: tokenData.token,\n baseURL: this.directAccessClient.getOpenAIProxyUrl(),\n defaultHeaders: mergedHeaders,\n });\n\n return this.openaiClient;\n }\n\n private isTokenError(error: unknown): boolean {\n if (error instanceof OpenAI.APIError) {\n if (error.status === 401) {\n return true;\n }\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('token') &&\n (message.includes('expired') || message.includes('revoked') || message.includes('invalid'))\n ) {\n return true;\n }\n }\n return false;\n }\n\n /**\n * Check if an error is a context overflow error (prompt too long)\n * These should NOT trigger token refresh and should be reported to the user.\n */\n private isContextOverflowError(error: unknown): boolean {\n if (error instanceof OpenAI.APIError) {\n // 400 Bad Request with prompt too long message\n if (error.status === 400) {\n const message = error.message?.toLowerCase() || '';\n if (\n message.includes('prompt is too long') ||\n message.includes('prompt too long') ||\n (message.includes('tokens') && message.includes('maximum'))\n ) {\n return true;\n }\n }\n }\n return false;\n }\n\n private convertTools(\n tools?: LanguageModelV2CallOptions['tools']\n ): OpenAI.ChatCompletionTool[] | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => {\n const schema = tool.inputSchema as Record<string, unknown>;\n return {\n type: 'function' as const,\n function: {\n name: tool.name,\n description: tool.description || '',\n // Ensure the schema has type: 'object' as OpenAI requires it\n parameters: {\n type: 'object',\n ...schema,\n },\n },\n };\n });\n }\n\n private convertToolChoice(\n toolChoice?: LanguageModelV2ToolChoice\n ): OpenAI.ChatCompletionToolChoiceOption | undefined {\n if (!toolChoice) {\n return undefined;\n }\n\n switch (toolChoice.type) {\n case 'auto':\n return 'auto';\n case 'none':\n return 'none';\n case 'required':\n return 'required';\n case 'tool':\n return { type: 'function', function: { name: toolChoice.toolName } };\n default:\n return undefined;\n }\n }\n\n private convertPrompt(prompt: LanguageModelV2Message[]): OpenAI.ChatCompletionMessageParam[] {\n const messages: OpenAI.ChatCompletionMessageParam[] = [];\n\n for (const message of prompt) {\n if (message.role === 'system') {\n messages.push({ role: 'system', content: message.content });\n continue;\n }\n\n if (message.role === 'user') {\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text);\n if (textParts.length > 0) {\n messages.push({ role: 'user', content: textParts.join('\\n') });\n }\n } else if (message.role === 'assistant') {\n const textParts: string[] = [];\n const toolCalls: OpenAI.ChatCompletionMessageToolCall[] = [];\n\n for (const part of message.content) {\n if (part.type === 'text') {\n textParts.push(part.text);\n } else if (part.type === 'tool-call') {\n toolCalls.push({\n id: part.toolCallId,\n type: 'function',\n function: {\n name: part.toolName,\n arguments: typeof part.input === 'string' ? part.input : JSON.stringify(part.input),\n },\n });\n }\n }\n\n const assistantMessage: OpenAI.ChatCompletionAssistantMessageParam = {\n role: 'assistant',\n content: textParts.length > 0 ? textParts.join('\\n') : null,\n };\n if (toolCalls.length > 0) {\n assistantMessage.tool_calls = toolCalls;\n }\n messages.push(assistantMessage);\n } else if (message.role === 'tool') {\n for (const part of message.content) {\n if (part.type === 'tool-result') {\n let resultContent: string;\n if (part.output.type === 'text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'json') {\n resultContent = JSON.stringify(part.output.value);\n } else if (part.output.type === 'error-text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'error-json') {\n resultContent = JSON.stringify(part.output.value);\n } else {\n resultContent = JSON.stringify(part.output);\n }\n messages.push({\n role: 'tool',\n tool_call_id: part.toolCallId,\n content: resultContent,\n });\n }\n }\n }\n }\n\n return messages;\n }\n\n private convertFinishReason(\n finishReason: string | null | undefined\n ): LanguageModelV2FinishReason {\n switch (finishReason) {\n case 'stop':\n return 'stop';\n case 'length':\n return 'length';\n case 'tool_calls':\n return 'tool-calls';\n case 'content_filter':\n return 'content-filter';\n default:\n return 'unknown';\n }\n }\n\n /**\n * Convert tools to Responses API format\n */\n private convertToolsForResponses(\n tools?: LanguageModelV2CallOptions['tools']\n ): OpenAI.Responses.FunctionTool[] | undefined {\n if (!tools || tools.length === 0) {\n return undefined;\n }\n\n return tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => {\n // Clone schema and remove $schema field which can confuse the model\n // Zod 4's toJSONSchema() adds \"$schema\": \"https://json-schema.org/draft/2020-12/schema\"\n const schema = { ...(tool.inputSchema as Record<string, unknown>) };\n delete schema['$schema'];\n\n return {\n type: 'function' as const,\n name: tool.name,\n description: tool.description || '',\n parameters: schema,\n strict: false,\n };\n });\n }\n\n /**\n * Convert prompt to Responses API input format\n */\n private convertPromptForResponses(\n prompt: LanguageModelV2Message[]\n ): OpenAI.Responses.ResponseInput {\n const items: OpenAI.Responses.ResponseInputItem[] = [];\n\n for (const message of prompt) {\n if (message.role === 'system') {\n // System messages become instructions, handled separately\n continue;\n }\n\n if (message.role === 'user') {\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => part.text);\n if (textParts.length > 0) {\n items.push({\n type: 'message',\n role: 'user',\n content: textParts.map((text) => ({ type: 'input_text' as const, text })),\n } as OpenAI.Responses.ResponseInputItem);\n }\n } else if (message.role === 'assistant') {\n // Handle text content as output message\n const textParts: string[] = [];\n for (const part of message.content) {\n if (part.type === 'text') {\n textParts.push(part.text);\n } else if (part.type === 'tool-call') {\n // Tool calls are function_call items in Responses API\n items.push({\n type: 'function_call',\n call_id: part.toolCallId,\n name: part.toolName,\n arguments: typeof part.input === 'string' ? part.input : JSON.stringify(part.input),\n } as OpenAI.Responses.ResponseInputItem);\n }\n }\n\n if (textParts.length > 0) {\n items.push({\n type: 'message',\n role: 'assistant',\n content: [{ type: 'output_text', text: textParts.join('\\n'), annotations: [] }],\n } as OpenAI.Responses.ResponseInputItem);\n }\n } else if (message.role === 'tool') {\n for (const part of message.content) {\n if (part.type === 'tool-result') {\n let resultContent: string;\n if (part.output.type === 'text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'json') {\n resultContent = JSON.stringify(part.output.value);\n } else if (part.output.type === 'error-text') {\n resultContent = part.output.value;\n } else if (part.output.type === 'error-json') {\n resultContent = JSON.stringify(part.output.value);\n } else {\n resultContent = JSON.stringify(part.output);\n }\n items.push({\n type: 'function_call_output',\n call_id: part.toolCallId,\n output: resultContent,\n } as OpenAI.Responses.ResponseInputItem);\n }\n }\n }\n }\n\n return items;\n }\n\n /**\n * Extract system instructions from prompt\n */\n private extractSystemInstructions(prompt: LanguageModelV2Message[]): string | undefined {\n const systemMessages = prompt\n .filter((m) => m.role === 'system')\n .map((m) => m.content)\n .join('\\n');\n return systemMessages || undefined;\n }\n\n /**\n * Convert Responses API status to finish reason\n * Note: Responses API returns 'completed' even when making tool calls,\n * so we need to check the content for tool calls separately.\n */\n private convertResponsesStatus(\n status: string | undefined,\n hasToolCalls: boolean = false\n ): LanguageModelV2FinishReason {\n // If we have tool calls, return 'tool-calls' regardless of status\n if (hasToolCalls) {\n return 'tool-calls';\n }\n\n switch (status) {\n case 'completed':\n return 'stop';\n case 'incomplete':\n return 'length';\n case 'cancelled':\n return 'stop';\n case 'failed':\n return 'error';\n default:\n return 'unknown';\n }\n }\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n if (this.useResponsesApi) {\n return this.doGenerateWithResponsesApi(options, false);\n }\n return this.doGenerateWithChatApi(options, false);\n }\n\n private async doGenerateWithChatApi(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n const client = await this.getOpenAIClient(isRetry);\n const messages = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const openaiModel = this.config.openaiModel || 'gpt-4o';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n try {\n const response = await client.chat.completions.create({\n model: openaiModel,\n max_completion_tokens: maxTokens,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop: options.stopSequences,\n });\n\n const choice = response.choices[0];\n const content: LanguageModelV2Content[] = [];\n\n if (choice?.message.content) {\n content.push({ type: 'text', text: choice.message.content });\n }\n\n if (choice?.message.tool_calls) {\n for (const toolCall of choice.message.tool_calls) {\n if (toolCall.type === 'function') {\n content.push({\n type: 'tool-call',\n toolCallId: toolCall.id,\n toolName: toolCall.function.name,\n input: toolCall.function.arguments,\n });\n }\n }\n }\n\n const usage: LanguageModelV2Usage = {\n inputTokens: response.usage?.prompt_tokens || 0,\n outputTokens: response.usage?.completion_tokens || 0,\n totalTokens: response.usage?.total_tokens || 0,\n };\n\n return {\n content,\n finishReason: this.convertFinishReason(choice?.finish_reason),\n usage,\n warnings: [],\n };\n } catch (error) {\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (this.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof OpenAI.APIError>;\n throw new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n });\n }\n\n if (!isRetry && this.isTokenError(error)) {\n this.directAccessClient.invalidateToken();\n return this.doGenerateWithChatApi(options, true);\n }\n\n if (error instanceof OpenAI.APIError) {\n throw new GitLabError({\n message: `OpenAI API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n });\n }\n throw error;\n }\n }\n\n private async doGenerateWithResponsesApi(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n const client = await this.getOpenAIClient(isRetry);\n const input = this.convertPromptForResponses(options.prompt);\n const tools = this.convertToolsForResponses(options.tools);\n const instructions = this.extractSystemInstructions(options.prompt);\n\n const openaiModel = this.config.openaiModel || 'gpt-5-codex';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n try {\n const response = await client.responses.create({\n model: openaiModel,\n input,\n instructions,\n tools,\n max_output_tokens: maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n store: false,\n });\n\n const content: LanguageModelV2Content[] = [];\n let hasToolCalls = false;\n\n // Process output items\n for (const item of response.output || []) {\n if (item.type === 'message' && item.role === 'assistant') {\n for (const contentItem of item.content || []) {\n if (contentItem.type === 'output_text') {\n content.push({ type: 'text', text: contentItem.text });\n }\n }\n } else if (item.type === 'function_call') {\n hasToolCalls = true;\n content.push({\n type: 'tool-call',\n toolCallId: item.call_id,\n toolName: item.name,\n input: item.arguments,\n });\n }\n }\n\n const usage: LanguageModelV2Usage = {\n inputTokens: response.usage?.input_tokens || 0,\n outputTokens: response.usage?.output_tokens || 0,\n totalTokens: response.usage?.total_tokens || 0,\n };\n\n return {\n content,\n finishReason: this.convertResponsesStatus(response.status, hasToolCalls),\n usage,\n warnings: [],\n };\n } catch (error) {\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (this.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof OpenAI.APIError>;\n throw new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n });\n }\n\n if (!isRetry && this.isTokenError(error)) {\n this.directAccessClient.invalidateToken();\n return this.doGenerateWithResponsesApi(options, true);\n }\n\n if (error instanceof OpenAI.APIError) {\n throw new GitLabError({\n message: `OpenAI API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n });\n }\n throw error;\n }\n }\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n if (this.useResponsesApi) {\n return this.doStreamWithResponsesApi(options, false);\n }\n return this.doStreamWithChatApi(options, false);\n }\n\n private async doStreamWithChatApi(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n const client = await this.getOpenAIClient(isRetry);\n const messages = this.convertPrompt(options.prompt);\n const tools = this.convertTools(options.tools);\n const toolChoice =\n options.toolChoice?.type !== 'none' ? this.convertToolChoice(options.toolChoice) : undefined;\n\n const openaiModel = this.config.openaiModel || 'gpt-4o';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n const requestBody = {\n model: openaiModel,\n max_completion_tokens: maxTokens,\n messages: messages,\n tools: tools,\n tool_choice: tools ? toolChoice : undefined,\n temperature: options.temperature,\n top_p: options.topP,\n stop: options.stopSequences,\n stream: true as const,\n stream_options: { include_usage: true },\n };\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n const toolCalls: Record<number, { id: string; name: string; arguments: string }> = {};\n\n const usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n let textStarted = false;\n const textId = 'text-0';\n\n try {\n const openaiStream = await client.chat.completions.create({\n ...requestBody,\n stream: true,\n });\n\n controller.enqueue({ type: 'stream-start', warnings: [] });\n\n for await (const chunk of openaiStream) {\n const choice = chunk.choices?.[0];\n\n if (chunk.id && !textStarted) {\n controller.enqueue({\n type: 'response-metadata',\n id: chunk.id,\n modelId: chunk.model,\n });\n }\n\n if (choice?.delta?.content) {\n if (!textStarted) {\n controller.enqueue({ type: 'text-start', id: textId });\n textStarted = true;\n }\n controller.enqueue({\n type: 'text-delta',\n id: textId,\n delta: choice.delta.content,\n });\n }\n\n if (choice?.delta?.tool_calls) {\n for (const tc of choice.delta.tool_calls) {\n const idx = tc.index;\n if (!toolCalls[idx]) {\n toolCalls[idx] = {\n id: tc.id || '',\n name: tc.function?.name || '',\n arguments: '',\n };\n controller.enqueue({\n type: 'tool-input-start',\n id: toolCalls[idx].id,\n toolName: toolCalls[idx].name,\n });\n }\n if (tc.function?.arguments) {\n toolCalls[idx].arguments += tc.function.arguments;\n controller.enqueue({\n type: 'tool-input-delta',\n id: toolCalls[idx].id,\n delta: tc.function.arguments,\n });\n }\n }\n }\n\n if (choice?.finish_reason) {\n finishReason = self.convertFinishReason(choice.finish_reason);\n }\n\n if (chunk.usage) {\n usage.inputTokens = chunk.usage.prompt_tokens || 0;\n usage.outputTokens = chunk.usage.completion_tokens || 0;\n usage.totalTokens = chunk.usage.total_tokens || 0;\n }\n }\n\n if (textStarted) {\n controller.enqueue({ type: 'text-end', id: textId });\n }\n\n for (const [, tc] of Object.entries(toolCalls)) {\n controller.enqueue({ type: 'tool-input-end', id: tc.id });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: tc.id,\n toolName: tc.name,\n input: tc.arguments || '{}',\n });\n }\n\n controller.enqueue({ type: 'finish', finishReason, usage });\n controller.close();\n } catch (error) {\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (self.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof OpenAI.APIError>;\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n if (!isRetry && self.isTokenError(error)) {\n self.directAccessClient.invalidateToken();\n controller.enqueue({\n type: 'error',\n error: new GitLabError({ message: 'TOKEN_REFRESH_NEEDED', cause: error }),\n });\n controller.close();\n return;\n }\n\n if (error instanceof OpenAI.APIError) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `OpenAI API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n }),\n });\n } else {\n controller.enqueue({ type: 'error', error });\n }\n controller.close();\n }\n },\n });\n\n return { stream, request: { body: requestBody } };\n }\n\n private async doStreamWithResponsesApi(\n options: LanguageModelV2CallOptions,\n isRetry: boolean\n ): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n response?: { headers?: Record<string, string> };\n }> {\n const client = await this.getOpenAIClient(isRetry);\n const input = this.convertPromptForResponses(options.prompt);\n const tools = this.convertToolsForResponses(options.tools);\n const instructions = this.extractSystemInstructions(options.prompt);\n\n const openaiModel = this.config.openaiModel || 'gpt-5-codex';\n const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n\n const requestBody = {\n model: openaiModel,\n input,\n instructions,\n tools,\n max_output_tokens: maxTokens,\n temperature: options.temperature,\n top_p: options.topP,\n store: false,\n stream: true as const,\n };\n\n // eslint-disable-next-line @typescript-eslint/no-this-alias\n const self = this;\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n // Use output_index as key (like OpenCode does) to track tool calls across events\n const toolCalls: Record<number, { callId: string; name: string; arguments: string }> = {};\n const usage: LanguageModelV2Usage = {\n inputTokens: 0,\n outputTokens: 0,\n totalTokens: 0,\n };\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n let textStarted = false;\n const textId = 'text-0';\n\n try {\n const openaiStream = await client.responses.create({\n ...requestBody,\n stream: true,\n });\n\n controller.enqueue({ type: 'stream-start', warnings: [] });\n\n for await (const event of openaiStream) {\n // Handle different event types from Responses API streaming\n if (event.type === 'response.created') {\n controller.enqueue({\n type: 'response-metadata',\n id: event.response.id,\n modelId: event.response.model,\n });\n } else if (event.type === 'response.output_item.added') {\n // Track function calls when they start, keyed by output_index\n if (event.item.type === 'function_call') {\n const outputIndex = event.output_index;\n const callId = event.item.call_id;\n toolCalls[outputIndex] = {\n callId,\n name: event.item.name,\n arguments: '',\n };\n controller.enqueue({\n type: 'tool-input-start',\n id: callId,\n toolName: event.item.name,\n });\n }\n } else if (event.type === 'response.output_text.delta') {\n if (!textStarted) {\n controller.enqueue({ type: 'text-start', id: textId });\n textStarted = true;\n }\n controller.enqueue({\n type: 'text-delta',\n id: textId,\n delta: event.delta,\n });\n } else if (event.type === 'response.function_call_arguments.delta') {\n // Use output_index to find the tool call (like OpenCode)\n const outputIndex = event.output_index;\n const tc = toolCalls[outputIndex];\n if (tc) {\n tc.arguments += event.delta;\n controller.enqueue({\n type: 'tool-input-delta',\n id: tc.callId,\n delta: event.delta,\n });\n }\n } else if (event.type === 'response.function_call_arguments.done') {\n const outputIndex = event.output_index;\n const tc = toolCalls[outputIndex];\n if (tc) {\n tc.arguments = event.arguments;\n }\n } else if (event.type === 'response.completed') {\n // Check if there are tool calls to determine finish reason\n const hasToolCalls = Object.keys(toolCalls).length > 0;\n finishReason = self.convertResponsesStatus(event.response.status, hasToolCalls);\n if (event.response.usage) {\n usage.inputTokens = event.response.usage.input_tokens || 0;\n usage.outputTokens = event.response.usage.output_tokens || 0;\n usage.totalTokens = event.response.usage.total_tokens || 0;\n }\n }\n }\n\n if (textStarted) {\n controller.enqueue({ type: 'text-end', id: textId });\n }\n\n // Check if we have tool calls to set the correct finish reason\n const hasToolCalls = Object.keys(toolCalls).length > 0;\n if (hasToolCalls && finishReason === 'stop') {\n finishReason = 'tool-calls';\n }\n\n for (const tc of Object.values(toolCalls)) {\n controller.enqueue({ type: 'tool-input-end', id: tc.callId });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: tc.callId,\n toolName: tc.name,\n input: tc.arguments || '{}',\n });\n }\n\n controller.enqueue({ type: 'finish', finishReason, usage });\n controller.close();\n } catch (error) {\n // Check for context overflow FIRST - these should NOT trigger token refresh\n if (self.isContextOverflowError(error)) {\n const apiError = error as InstanceType<typeof OpenAI.APIError>;\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Context overflow: ${apiError.message}. Please start a new session or use /compact to reduce context.`,\n statusCode: 400,\n cause: error,\n }),\n });\n controller.close();\n return;\n }\n\n if (!isRetry && self.isTokenError(error)) {\n self.directAccessClient.invalidateToken();\n controller.enqueue({\n type: 'error',\n error: new GitLabError({ message: 'TOKEN_REFRESH_NEEDED', cause: error }),\n });\n controller.close();\n return;\n }\n\n if (error instanceof OpenAI.APIError) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `OpenAI API error: ${error.message}`,\n statusCode: error.status,\n cause: error,\n }),\n });\n } else {\n controller.enqueue({ type: 'error', error });\n }\n controller.close();\n }\n },\n });\n\n return { stream, request: { body: requestBody } };\n }\n}\n","export type ModelProvider = 'anthropic' | 'openai' | 'workflow';\n\nexport type OpenAIApiType = 'chat' | 'responses';\n\nexport interface ModelMapping {\n provider: ModelProvider;\n model: string;\n /** For OpenAI models, which API to use: 'chat' for /v1/chat/completions, 'responses' for /v1/responses */\n openaiApiType?: OpenAIApiType;\n}\n\nexport const MODEL_MAPPINGS: Record<string, ModelMapping> = {\n // Anthropic models\n 'duo-chat-opus-4-6': { provider: 'anthropic', model: 'claude-opus-4-6' },\n 'duo-chat-sonnet-4-6': { provider: 'anthropic', model: 'claude-sonnet-4-6' },\n 'duo-chat-opus-4-5': { provider: 'anthropic', model: 'claude-opus-4-5-20251101' },\n 'duo-chat-sonnet-4-5': { provider: 'anthropic', model: 'claude-sonnet-4-5-20250929' },\n 'duo-chat-haiku-4-5': { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },\n\n // OpenAI models - Chat Completions API\n 'duo-chat-gpt-5-1': { provider: 'openai', model: 'gpt-5.1-2025-11-13', openaiApiType: 'chat' },\n 'duo-chat-gpt-5-2': { provider: 'openai', model: 'gpt-5.2-2025-12-11', openaiApiType: 'chat' },\n 'duo-chat-gpt-5-mini': {\n provider: 'openai',\n model: 'gpt-5-mini-2025-08-07',\n openaiApiType: 'chat',\n },\n\n // OpenAI models - Responses API (Codex models)\n 'duo-chat-gpt-5-codex': { provider: 'openai', model: 'gpt-5-codex', openaiApiType: 'responses' },\n 'duo-chat-gpt-5-2-codex': {\n provider: 'openai',\n model: 'gpt-5.2-codex',\n openaiApiType: 'responses',\n },\n\n // Duo Agent Platform model (server-side agentic via DWS WebSocket).\n // This is the single user-facing model ID. The actual underlying model ref\n // is resolved dynamically at runtime via GitLabModelDiscovery.\n 'duo-workflow': { provider: 'workflow', model: 'default' },\n\n // Internal model refs — kept for backwards compatibility and direct use.\n // Not intended as user-facing model IDs.\n 'duo-workflow-default': { provider: 'workflow', model: 'default' },\n 'duo-workflow-sonnet-4-5': {\n provider: 'workflow',\n model: 'anthropic/claude-sonnet-4-5-20250929',\n },\n 'duo-workflow-sonnet-4-6': { provider: 'workflow', model: 'claude_sonnet_4_6' },\n 'duo-workflow-opus-4-5': {\n provider: 'workflow',\n model: 'anthropic/claude-opus-4-5-20251101',\n },\n 'duo-workflow-haiku-4-5': { provider: 'workflow', model: 'claude_haiku_4_5_20251001' },\n 'duo-workflow-opus-4-6': { provider: 'workflow', model: 'claude_opus_4_6_20260205' },\n};\n\nexport function getModelMapping(modelId: string): ModelMapping | undefined {\n return MODEL_MAPPINGS[modelId];\n}\n\nexport function getProviderForModelId(modelId: string): ModelProvider | undefined {\n return MODEL_MAPPINGS[modelId]?.provider;\n}\n\nexport function getValidModelsForProvider(provider: ModelProvider): string[] {\n return Object.values(MODEL_MAPPINGS)\n .filter((m) => m.provider === provider)\n .map((m) => m.model);\n}\n\nexport function getAnthropicModelForModelId(modelId: string): string | undefined {\n const mapping = MODEL_MAPPINGS[modelId];\n return mapping?.provider === 'anthropic' ? mapping.model : undefined;\n}\n\nexport function getOpenAIModelForModelId(modelId: string): string | undefined {\n const mapping = MODEL_MAPPINGS[modelId];\n return mapping?.provider === 'openai' ? mapping.model : undefined;\n}\n\nexport function getOpenAIApiType(modelId: string): OpenAIApiType {\n const mapping = MODEL_MAPPINGS[modelId];\n return mapping?.openaiApiType ?? 'chat';\n}\n\nexport function isResponsesApiModel(modelId: string): boolean {\n return getOpenAIApiType(modelId) === 'responses';\n}\n\nexport function isWorkflowModel(modelId: string): boolean {\n return MODEL_MAPPINGS[modelId]?.provider === 'workflow';\n}\n\nexport function getWorkflowModelRef(modelId: string): string | undefined {\n const mapping = MODEL_MAPPINGS[modelId];\n return mapping?.provider === 'workflow' ? mapping.model : undefined;\n}\n\nexport const MODEL_ID_TO_ANTHROPIC_MODEL: Record<string, string> = Object.fromEntries(\n Object.entries(MODEL_MAPPINGS)\n .filter(([, v]) => v.provider === 'anthropic')\n .map(([k, v]) => [k, v.model])\n);\n","/**\n * WebSocket client for the GitLab Duo Agent Platform (DWS).\n *\n * Handles:\n * - WebSocket connection to `wss://{instance}/api/v4/ai/duo_workflows/ws`\n * - Sending ClientEvent messages (startRequest, actionResponse, stopWorkflow)\n * - Receiving WorkflowAction messages (newCheckpoint, runMcpTool, built-in tools)\n * - Dual heartbeat: ws.ping(45s) + JSON heartbeat(60s) — matching gitlab-lsp\n * - No reconnection on drop (matches gitlab-lsp behavior)\n */\n\nimport WebSocket from 'isomorphic-ws';\nimport { VERSION } from './version';\nimport type {\n ClientEvent,\n WorkflowAction,\n StartRequest,\n ActionResponsePayload,\n WorkflowClientEvent,\n} from './gitlab-workflow-types';\nimport {\n WS_KEEPALIVE_PING_INTERVAL_MS,\n WS_HEARTBEAT_INTERVAL_MS,\n STOP_REASON_USER,\n} from './gitlab-workflow-types';\n\nexport interface WorkflowWebSocketOptions {\n /** GitLab instance URL */\n instanceUrl: string;\n /** Model reference for DWS (e.g. 'anthropic/claude-sonnet-4-5-20250929' or 'default') */\n modelRef: string;\n /** Auth headers — must include Authorization */\n headers: Record<string, string>;\n /** Optional correlation ID */\n requestId?: string;\n /** Optional project context */\n projectId?: string;\n namespaceId?: string;\n rootNamespaceId?: string;\n}\n\ntype EventCallback = (event: WorkflowClientEvent) => void;\n\nexport class GitLabWorkflowClient {\n private socket: WebSocket | null = null;\n private keepaliveInterval: ReturnType<typeof setInterval> | null = null;\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private eventCallback: EventCallback | null = null;\n private closed = false;\n private lastSendTime = 0;\n\n /**\n * Connect to the DWS WebSocket and start listening for events.\n *\n * @param options - Connection parameters\n * @param onEvent - Callback invoked for each WorkflowClientEvent\n * @returns Promise that resolves when the connection is open\n */\n connect(options: WorkflowWebSocketOptions, onEvent: EventCallback): Promise<void> {\n this.validateOptions(options);\n this.eventCallback = onEvent;\n this.closed = false;\n this.cleanedUp = false;\n\n return new Promise<void>((resolve, reject) => {\n const wsUrl = this.buildWebSocketUrl(options);\n const wsHeaders = this.buildWebSocketHeaders(options);\n\n this.socket = new WebSocket(wsUrl, { headers: wsHeaders });\n let resolved = false;\n\n this.socket.onopen = () => {\n resolved = true;\n this.startKeepalive();\n this.startHeartbeat();\n resolve();\n };\n\n this.socket.onmessage = (event: WebSocket.MessageEvent) => {\n try {\n const data = typeof event.data === 'string' ? event.data : event.data.toString();\n const action = JSON.parse(data) as WorkflowAction;\n\n // Basic validation of message structure\n if (!action || typeof action !== 'object') {\n throw new Error('Invalid message structure: expected object');\n }\n\n this.handleAction(action);\n } catch (error) {\n this.emit({\n type: 'failed',\n error: error instanceof Error ? error : new Error(String(error)),\n });\n }\n };\n\n this.socket.onerror = (event: WebSocket.ErrorEvent) => {\n const error = new Error(`WebSocket error: ${event.message || 'unknown'}`);\n if (!resolved) {\n reject(error);\n } else {\n this.emit({ type: 'failed', error });\n }\n };\n\n this.socket.onclose = (event: WebSocket.CloseEvent) => {\n this.cleanup();\n if (!resolved) {\n reject(\n new Error(\n `WebSocket closed before open: code=${event.code} reason=${event.reason || ''}`\n )\n );\n return;\n }\n if (!this.closed) {\n this.emit({\n type: 'closed',\n code: event.code,\n reason: event.reason || '',\n });\n }\n };\n });\n }\n\n /**\n * Send a startRequest to begin the workflow.\n */\n sendStartRequest(request: StartRequest): void {\n this.send({ startRequest: request });\n }\n\n /**\n * Send an actionResponse (tool result) back to DWS.\n */\n sendActionResponse(requestID: string, response: string, error?: string | null): void {\n this.sendHeartbeatIfNeeded();\n const payload: ActionResponsePayload = {\n requestID,\n plainTextResponse: {\n response,\n error: error ?? null,\n },\n };\n this.send({ actionResponse: payload });\n }\n\n /**\n * Stop the workflow gracefully.\n */\n stop(): void {\n this.send({ stopWorkflow: { reason: STOP_REASON_USER } });\n this.closed = true;\n }\n\n /**\n * Close the WebSocket connection.\n */\n close(): void {\n // Set closed flag first to prevent race conditions\n if (this.closed) return;\n this.closed = true;\n\n this.cleanup();\n const sock = this.socket;\n this.socket = null;\n if (sock) {\n if (sock.readyState === WebSocket.OPEN || sock.readyState === WebSocket.CONNECTING) {\n sock.close(1000, 'Client closing');\n }\n }\n }\n\n /**\n * Check if the WebSocket is currently connected.\n */\n get isConnected(): boolean {\n return this.socket?.readyState === WebSocket.OPEN;\n }\n\n // ---------------------------------------------------------------------------\n // Private\n // ---------------------------------------------------------------------------\n\n private validateOptions(options: WorkflowWebSocketOptions): void {\n if (!options.instanceUrl || typeof options.instanceUrl !== 'string') {\n throw new Error('instanceUrl is required');\n }\n const parsed = new URL(options.instanceUrl);\n if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n throw new Error(`Invalid instanceUrl protocol: ${parsed.protocol}`);\n }\n if (parsed.username || parsed.password) {\n throw new Error(\n 'instanceUrl must not contain authentication credentials (username/password)'\n );\n }\n if (!options.headers || typeof options.headers !== 'object') {\n throw new Error('headers are required');\n }\n if (options.modelRef && typeof options.modelRef !== 'string') {\n throw new Error('modelRef must be a string');\n }\n }\n\n private buildWebSocketUrl(options: WorkflowWebSocketOptions): string {\n // Match gitlab-lsp URL construction exactly:\n // - NO workflow_id in URL (it goes in startRequest.workflowID instead)\n // - Only user_selected_model_identifier as query param\n const baseUrl = new URL(options.instanceUrl.replace(/\\/?$/, '/'));\n const url = new URL('./api/v4/ai/duo_workflows/ws', baseUrl);\n url.protocol = url.protocol === 'https:' ? 'wss:' : 'ws:';\n if (options.modelRef && options.modelRef !== 'default') {\n // URL.searchParams.set() automatically encodes the value\n url.searchParams.set('user_selected_model_identifier', options.modelRef);\n }\n return url.toString();\n }\n\n private buildWebSocketHeaders(options: WorkflowWebSocketOptions): Record<string, string> {\n // Normalize incoming headers to lowercase keys to avoid duplicates\n const headers: Record<string, string> = {};\n for (const [key, value] of Object.entries(options.headers)) {\n headers[key.toLowerCase()] = value;\n }\n\n // Remove Content-Type — WebSocket upgrade (RFC 6455 §4.1) uses no body;\n // sending Content-Type can confuse proxies and fails some server checks.\n delete headers['content-type'];\n\n headers['x-gitlab-client-type'] = 'node-websocket';\n\n // Origin header — required by gitlab-lsp, validates WebSocket security\n // The origin is derived from the validated instanceUrl (already checked in validateOptions)\n const parsedUrl = new URL(options.instanceUrl);\n const origin = parsedUrl.origin;\n headers['origin'] = origin;\n\n if (options.requestId) {\n headers['x-request-id'] = options.requestId;\n }\n if (options.projectId) {\n headers['x-gitlab-project-id'] = options.projectId;\n }\n if (options.namespaceId) {\n headers['x-gitlab-namespace-id'] = options.namespaceId;\n }\n if (options.rootNamespaceId) {\n headers['x-gitlab-root-namespace-id'] = options.rootNamespaceId;\n }\n\n // User-Agent — set only if not already provided\n if (!headers['user-agent']) {\n headers['user-agent'] = `gitlab-ai-provider/${VERSION}`;\n }\n\n return headers;\n }\n\n private handleAction(action: WorkflowAction): void {\n // Checkpoint (text/status from LLM)\n if (action.newCheckpoint) {\n const checkpoint = action.newCheckpoint;\n\n this.emit({ type: 'checkpoint', data: checkpoint });\n\n if (checkpoint.status === 'FINISHED' || checkpoint.status === 'COMPLETED') {\n this.emit({ type: 'completed' });\n } else if (checkpoint.status === 'FAILED') {\n this.emit({\n type: 'failed',\n error: new Error(checkpoint.content || 'Workflow failed'),\n });\n } else if (checkpoint.status === 'STOPPED' || checkpoint.status === 'CANCELLED') {\n this.emit({ type: 'completed' });\n }\n return;\n }\n\n // MCP tool invocation\n if (action.runMCPTool && action.requestID) {\n this.emit({\n type: 'tool-request',\n requestID: action.requestID,\n data: action.runMCPTool,\n });\n return;\n }\n\n // Built-in tool invocations — field names match DWS protobuf wire format\n const builtinTools: Array<[string, unknown]> = [\n ['runReadFile', action.runReadFile],\n ['runReadFiles', action.runReadFiles],\n ['runWriteFile', action.runWriteFile],\n ['runShellCommand', action.runShellCommand],\n ['runEditFile', action.runEditFile],\n ['listDirectory', action.listDirectory],\n ['findFiles', action.findFiles],\n ['grep', action.grep],\n ['mkdir', action.mkdir],\n ['runCommand', action.runCommand],\n ['runGitCommand', action.runGitCommand],\n ['runHTTPRequest', action.runHTTPRequest],\n ];\n\n for (const [toolName, data] of builtinTools) {\n if (data && action.requestID) {\n this.emit({\n type: 'builtin-tool-request',\n requestID: action.requestID,\n toolName,\n data: data as Record<string, unknown>,\n });\n return;\n }\n }\n }\n\n private send(event: ClientEvent): void {\n if (this.socket?.readyState === WebSocket.OPEN) {\n const json = JSON.stringify(event);\n this.socket.send(json);\n this.lastSendTime = Date.now();\n }\n }\n\n private sendHeartbeatIfNeeded(): void {\n const elapsed = Date.now() - this.lastSendTime;\n if (elapsed >= WS_HEARTBEAT_INTERVAL_MS / 2) {\n this.send({ heartbeat: { timestamp: Date.now() } });\n }\n }\n\n private emit(event: WorkflowClientEvent): void {\n this.eventCallback?.(event);\n }\n\n /**\n * Start ws.ping() keepalive (45s interval).\n * Keeps TCP connection alive through proxies/load balancers.\n */\n private startKeepalive(): void {\n this.keepaliveInterval = setInterval(() => {\n if (this.socket?.readyState === WebSocket.OPEN) {\n // ws-specific ping (not available in browser WebSocket, but\n // isomorphic-ws in Node.js delegates to the ws library)\n try {\n (this.socket as unknown as { ping: () => void }).ping();\n } catch {\n // Browser WebSocket doesn't have ping — silently skip\n }\n }\n }, WS_KEEPALIVE_PING_INTERVAL_MS);\n }\n\n /**\n * Start application-level heartbeat (60s interval).\n * Prevents DWS from timing out the workflow.\n */\n private startHeartbeat(): void {\n this.heartbeatInterval = setInterval(() => {\n this.send({ heartbeat: { timestamp: Date.now() } });\n }, WS_HEARTBEAT_INTERVAL_MS);\n }\n\n private cleanedUp = false;\n\n /**\n * Clean up intervals. Idempotent — safe to call multiple times.\n */\n private cleanup(): void {\n if (this.cleanedUp) return;\n this.cleanedUp = true;\n\n if (this.keepaliveInterval) {\n clearInterval(this.keepaliveInterval);\n this.keepaliveInterval = null;\n }\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n }\n }\n}\n","// Version string of this package injected at build time.\ndeclare const __PACKAGE_VERSION__: string | undefined;\nexport const VERSION: string =\n typeof __PACKAGE_VERSION__ !== 'undefined' ? __PACKAGE_VERSION__ : '0.0.0-dev';\n","/**\n * Types for the GitLab Duo Agent Platform (DWS) protocol.\n *\n * DWS uses a WebSocket-based bidirectional protocol where:\n * - Client sends `ClientEvent` messages (startRequest, actionResponse, stopWorkflow, heartbeat)\n * - Server sends `WorkflowAction` messages (newCheckpoint, runMcpTool, built-in tools)\n *\n * Message format is JSON-serialized protobuf with camelCase field names.\n */\n\n// ---------------------------------------------------------------------------\n// Token / workflow creation responses\n// ---------------------------------------------------------------------------\n\nexport interface GenerateTokenResponse {\n gitlab_rails: {\n base_url: string;\n token: string;\n token_expires_at: string;\n };\n duo_workflow_service: {\n base_url: string;\n token: string;\n secure: boolean;\n token_expires_at: number;\n headers: Record<string, string>;\n };\n duo_workflow_executor: {\n executor_binary_url: string;\n version: string;\n };\n}\n\nexport interface CreateWorkflowResponse {\n id: string;\n}\n\n// ---------------------------------------------------------------------------\n// MCP tool definitions (sent in startRequest)\n// ---------------------------------------------------------------------------\n\nexport interface McpToolDefinition {\n name: string;\n description: string;\n inputSchema: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client → Server messages (ClientEvent)\n// ---------------------------------------------------------------------------\n\nexport interface AdditionalContext {\n category: string;\n id?: string;\n content?: string;\n metadata?: string;\n}\n\nexport interface StartRequest {\n workflowID: string;\n clientVersion: string;\n workflowDefinition: string;\n goal: string;\n workflowMetadata?: string;\n additional_context?: AdditionalContext[];\n clientCapabilities?: string[];\n mcpTools?: McpToolDefinition[];\n preapproved_tools?: string[];\n flowConfig?: unknown;\n flowConfigSchemaVersion?: string;\n}\n\nexport interface ActionResponsePayload {\n requestID: string;\n plainTextResponse: {\n response: string;\n error: string | null;\n };\n}\n\nexport interface StopWorkflow {\n reason: string;\n}\n\nexport interface Heartbeat {\n timestamp: number;\n}\n\n/**\n * Client → Server event union.\n * Exactly one of the fields should be set per message.\n */\nexport type ClientEvent =\n | { startRequest: StartRequest }\n | { actionResponse: ActionResponsePayload }\n | { stopWorkflow: StopWorkflow }\n | { heartbeat: Heartbeat };\n\n// ---------------------------------------------------------------------------\n// Server → Client messages (WorkflowAction)\n// ---------------------------------------------------------------------------\n\nexport type WorkflowStatus =\n | 'CREATED'\n | 'RUNNING'\n | 'FINISHED'\n | 'COMPLETED'\n | 'FAILED'\n | 'STOPPED'\n | 'CANCELLED'\n | 'PAUSED'\n | 'INPUT_REQUIRED'\n | 'PLAN_APPROVAL_REQUIRED'\n | 'TOOL_CALL_APPROVAL_REQUIRED'\n | 'UNKNOWN';\n\nexport interface NewCheckpoint {\n status: WorkflowStatus;\n goal?: string;\n /** Raw checkpoint JSON string from DWS (contains channel_values.ui_chat_log) */\n checkpoint?: string;\n /** Legacy content field (may be empty — text is in checkpoint.ui_chat_log) */\n content?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Checkpoint parsing types (based on gitlab-lsp ui_chat_log.ts)\n// ---------------------------------------------------------------------------\n\nexport interface UiChatLogEntry {\n message_type: 'user' | 'agent' | 'tool' | 'request';\n message_sub_type: string | null;\n content: string;\n message_id?: string;\n timestamp: string;\n status: string | null;\n correlation_id: string | null;\n tool_info: UiChatLogToolInfo | null;\n additional_context: unknown;\n}\n\nexport interface UiChatLogToolInfo {\n name: string;\n args: Record<string, unknown>;\n tool_response?: UiChatLogToolResponse | string;\n}\n\nexport interface UiChatLogToolResponse {\n content: string;\n type: string;\n name: string;\n id: string | null;\n tool_call_id: string;\n status: string;\n}\n\nexport interface CheckpointData {\n channel_values: {\n ui_chat_log?: UiChatLogEntry[];\n plan?: { steps: unknown[] };\n status?: string;\n [key: string]: unknown;\n };\n}\n\nexport interface RunMcpTool {\n name: string;\n args: string;\n}\n\nexport interface ReadFileAction {\n filepath: string;\n}\n\nexport interface ReadFilesAction {\n filepaths: string[];\n}\n\nexport interface WriteFileAction {\n filepath: string;\n contents: string;\n}\n\nexport interface ShellCommandAction {\n command: string;\n}\n\nexport interface EditFileAction {\n filepath: string;\n oldString: string;\n newString: string;\n}\n\nexport interface ListDirectoryAction {\n directory: string;\n}\n\nexport interface FindFilesAction {\n name_pattern: string;\n}\n\nexport interface GrepAction {\n pattern: string;\n search_directory?: string;\n case_insensitive?: boolean;\n}\n\nexport interface MkdirAction {\n directory_path: string;\n}\n\nexport interface RunCommandAction {\n program: string;\n flags?: string[];\n arguments?: string[];\n}\n\nexport interface RunGitCommandAction {\n command: string;\n arguments?: string[];\n repository_url?: string;\n}\n\nexport interface GitLabApiRequestAction {\n method: string;\n path: string;\n body?: string;\n}\n\n/**\n * Server → Client action union.\n * Field names match the DWS protobuf camelCase wire format exactly.\n * Each message has an optional `requestID` (required for tool invocations\n * that need an `actionResponse` back).\n */\nexport interface WorkflowAction {\n requestID?: string;\n\n newCheckpoint?: NewCheckpoint;\n\n runMCPTool?: RunMcpTool;\n\n runReadFile?: ReadFileAction;\n runReadFiles?: ReadFilesAction;\n runWriteFile?: WriteFileAction;\n runShellCommand?: ShellCommandAction;\n runEditFile?: EditFileAction;\n listDirectory?: ListDirectoryAction;\n findFiles?: FindFilesAction;\n grep?: GrepAction;\n mkdir?: MkdirAction;\n runCommand?: RunCommandAction;\n runGitCommand?: RunGitCommandAction;\n runHTTPRequest?: GitLabApiRequestAction;\n}\n\n// ---------------------------------------------------------------------------\n// Provider options\n// ---------------------------------------------------------------------------\n\n/**\n * Options for creating a workflow chat model via `provider.workflowChat()`.\n */\nexport interface GitLabWorkflowOptions {\n /**\n * Workflow definition type.\n * @default 'chat'\n */\n workflowDefinition?: string;\n\n /**\n * Root namespace ID for the GitLab group/project.\n * Used for token scoping and model discovery.\n */\n rootNamespaceId?: string;\n\n /**\n * GitLab project ID (numeric or path).\n * Sent as `x-gitlab-project-id` header on WebSocket.\n */\n projectId?: string;\n\n /**\n * GitLab namespace ID.\n * Sent as `x-gitlab-namespace-id` header on WebSocket.\n */\n namespaceId?: string;\n\n /**\n * MCP tool definitions to expose to the workflow.\n * These are sent in `startRequest.mcpTools`.\n */\n mcpTools?: McpToolDefinition[];\n\n /**\n * Client capabilities to advertise.\n * @default ['shell_command']\n */\n clientCapabilities?: string[];\n\n /**\n * Tool names that are pre-approved for execution without user confirmation.\n * Sent in `startRequest.preapproved_tools`.\n */\n preapprovedTools?: string[];\n\n /**\n * Additional context items to send with the first request.\n * Used for conversation history continuity.\n */\n additionalContext?: AdditionalContext[];\n\n /**\n * Feature flags to pass to the GitLab API.\n */\n featureFlags?: Record<string, boolean>;\n\n /**\n * Working directory for auto-detecting GitLab project from git remote.\n * Used to resolve `projectId` when not explicitly set.\n * Defaults to `process.cwd()`.\n */\n workingDirectory?: string;\n\n /**\n * Flow configuration (parsed YAML object) to send to DWS.\n * Controls agent behavior, intermediate text generation, etc.\n * Sent as `startRequest.flowConfig`.\n */\n flowConfig?: unknown;\n\n /**\n * Schema version for the flow configuration.\n * Sent as `startRequest.flowConfigSchemaVersion`.\n */\n flowConfigSchemaVersion?: string;\n\n /**\n * Callback invoked when multiple workflow models are available for the\n * workspace and model switching is enabled by the instance admin.\n *\n * The provider calls this before starting the workflow so the host can\n * present a model picker to the user. Return the `ref` of the chosen\n * model, or `null`/`undefined` to fall back to the workspace default.\n *\n * If the returned ref is not in the list of selectable models it is\n * ignored and the workspace default is used instead.\n *\n * Not called when the admin has pinned a model — in that case the\n * pinned model is always used regardless of user preference.\n *\n * @param models - List of models the user can select from\n * @returns The selected model ref, or null/undefined for default\n */\n onSelectModel?: (\n models: import('./gitlab-model-discovery').AiModel[]\n ) => Promise<string | null | undefined>;\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket client configuration\n// ---------------------------------------------------------------------------\n\nexport interface GitLabWorkflowClientConfig {\n /** GitLab instance URL (e.g., 'https://gitlab.com') */\n instanceUrl: string;\n\n /** Function to get current auth headers */\n getHeaders: () => Record<string, string>;\n\n /**\n * Optional callback to refresh the API key when a 401 error occurs.\n */\n refreshApiKey?: () => Promise<void>;\n\n /** Custom fetch implementation */\n fetch?: typeof fetch;\n\n /** Feature flags for the token request */\n featureFlags?: Record<string, boolean>;\n\n /**\n * AI Gateway URL.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// WebSocket event types (emitted by GitLabWorkflowClient)\n// ---------------------------------------------------------------------------\n\nexport type WorkflowClientEvent =\n | { type: 'checkpoint'; data: NewCheckpoint }\n | { type: 'tool-request'; requestID: string; data: RunMcpTool }\n | {\n type: 'builtin-tool-request';\n requestID: string;\n toolName: string;\n data: Record<string, unknown>;\n }\n | { type: 'completed' }\n | { type: 'failed'; error: Error }\n | { type: 'closed'; code: number; reason: string };\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * Workflow type enum — matches gitlab-lsp WorkflowType.\n *\n * - CHAT: Shared token across sessions, tokens NOT revoked on completion\n * - SOFTWARE_DEVELOPMENT: Per-workflow token, tokens revoked on completion\n */\nexport enum WorkflowType {\n CHAT = 'chat',\n SOFTWARE_DEVELOPMENT = 'software_development',\n}\n\n/** WebSocket ping interval (TCP keepalive) — 45s matching gitlab-lsp */\nexport const WS_KEEPALIVE_PING_INTERVAL_MS = 45_000;\n\n/** Application heartbeat interval — 60s matching gitlab-lsp */\nexport const WS_HEARTBEAT_INTERVAL_MS = 60_000;\n\n/** Default workflow definition — uses CHAT for agentic chat (matches gitlab-lsp) */\nexport const DEFAULT_WORKFLOW_DEFINITION = WorkflowType.CHAT;\n\n/** Default client capabilities */\nexport const DEFAULT_CLIENT_CAPABILITIES = ['shell_command'];\n\n/** Client version sent in startRequest */\nexport const CLIENT_VERSION = '1.0';\n\n/** Stop reason for user-initiated stop */\nexport const STOP_REASON_USER = 'USER_ACTION_TRIGGERED_STOP';\n\n/**\n * Agent privileges for workflow creation.\n * Matches gitlab-lsp AGENT_PRIVILEGES enum.\n */\nexport const AGENT_PRIVILEGES = {\n READ_WRITE_FILES: 1,\n READ_ONLY_GITLAB: 2,\n READ_WRITE_GITLAB: 3,\n RUN_COMMANDS: 4,\n USE_GIT: 5,\n RUN_MCP_TOOLS: 6,\n} as const;\n\n/** Default agent privileges — matches gitlab-lsp defaults */\nexport const DEFAULT_AGENT_PRIVILEGES = [\n AGENT_PRIVILEGES.READ_WRITE_FILES,\n AGENT_PRIVILEGES.READ_ONLY_GITLAB,\n AGENT_PRIVILEGES.READ_WRITE_GITLAB,\n AGENT_PRIVILEGES.RUN_COMMANDS,\n AGENT_PRIVILEGES.RUN_MCP_TOOLS,\n AGENT_PRIVILEGES.USE_GIT,\n];\n\n/** Workflow execution environment */\nexport const WORKFLOW_ENVIRONMENT = 'ide' as const;\n","/**\n * DWS built-in tool mapping and shared security utilities.\n *\n * Extracted into a standalone module so both production code\n * (gitlab-workflow-language-model.ts) and tests can reference the\n * same implementation — preventing drift between a test shim and\n * the real logic.\n *\n * @internal — not part of the public API surface.\n */\n\n/**\n * Reject strings containing shell metacharacters.\n * Used as a defence-in-depth check before shellEscape.\n */\nexport function validateNoShellMetachars(value: string, fieldName: string): void {\n const dangerousChars = /[;&|`$()<>]/;\n if (dangerousChars.test(value)) {\n throw new Error(\n `Invalid ${fieldName}: contains shell metacharacters. Use structured arguments instead.`\n );\n }\n}\n\n/**\n * Wrap a value in single quotes for safe use as a single shell argument.\n * Embedded single quotes are escaped with the '\\'' idiom.\n */\nexport function shellEscape(arg: string): string {\n return \"'\" + String(arg).replace(/'/g, \"'\\\\''\") + \"'\";\n}\n\nconst ALLOWED_URL_SCHEMES = ['http:', 'https:'];\n\n/**\n * Redact credential-like patterns from error messages before they are\n * forwarded to the stream or surfaced in UI.\n *\n * Patterns covered:\n * - Bearer / token header values\n * - GitLab PAT / CI tokens (glpat-*, glcbt-*, etc.)\n * - URL query parameters: private_token, access_token, token\n * - Basic auth in URLs: http://user:PASSWORD@host\n * - Additional GitLab token prefixes (gldt, gloas, glrt, glsoat, glffct, glsapat)\n */\nexport function sanitizeErrorMessage(message: string): string {\n if (!message) return '';\n\n return message\n .replace(/\\bBearer\\s+[A-Za-z0-9\\-_.~+/]+=*/gi, 'Bearer [REDACTED]')\n .replace(/\\bgl(?:pat|oat|cbt|dt|oas|rt|soat|ffct|sapat)-[A-Za-z0-9_-]+/g, '[REDACTED]')\n .replace(/([?&](?:private_token|access_token|token)=)[^&\\s\"']*/gi, '$1[REDACTED]')\n .replace(/:\\/\\/([^:@/\\s]+):([^@/\\s]+)@/g, '://$1:[REDACTED]@');\n}\n\n/**\n * Map DWS built-in tool names and arguments to the corresponding\n * consumer tool names and argument formats.\n *\n * DWS uses protobuf-style tool names (runReadFile, runShellCommand, etc.)\n * while consumers like OpenCode use different names (read, bash, write, etc.)\n *\n * IMPORTANT: The returned `args` are structured objects passed to the host's\n * `toolExecutor` callback — they are NOT executed as raw shell commands by\n * this library. The host (e.g., OpenCode) is responsible for safely executing\n * the mapped tool through its own permission-gated tool system.\n */\nexport function mapBuiltinTool(\n dwsToolName: string,\n data: Record<string, unknown>\n): { toolName: string; args: Record<string, unknown> } {\n switch (dwsToolName) {\n case 'runReadFile':\n return { toolName: 'read', args: { filePath: data.filepath } };\n case 'runReadFiles': {\n const paths = (data.filepaths as string[]) ?? [];\n if (paths.length <= 1) {\n return { toolName: 'read', args: { filePath: paths[0] ?? '' } };\n }\n return {\n toolName: 'read',\n args: { filePaths: paths },\n };\n }\n case 'runWriteFile':\n return {\n toolName: 'write',\n args: { filePath: data.filepath, content: data.contents },\n };\n case 'runEditFile':\n return {\n toolName: 'edit',\n args: {\n filePath: data.filepath,\n oldString: data.oldString ?? data.old_string,\n newString: data.newString ?? data.new_string,\n },\n };\n case 'runShellCommand': {\n const command = data.command as string;\n if (!command || typeof command !== 'string') {\n throw new Error('runShellCommand: command is required and must be a string');\n }\n if (command.length > 10000) {\n throw new Error('runShellCommand: command exceeds maximum length of 10000 characters');\n }\n return {\n toolName: 'bash',\n args: { command, description: 'DWS shell command' },\n };\n }\n case 'runCommand': {\n const program = data.program as string;\n if (!program || typeof program !== 'string') {\n throw new Error('runCommand: program is required and must be a string');\n }\n validateNoShellMetachars(program, 'program');\n\n const flags = (data.flags as string[]) ?? [];\n const cmdArgs = (data.arguments as string[]) ?? [];\n\n for (const flag of flags) {\n if (typeof flag === 'string') {\n validateNoShellMetachars(flag, 'flag');\n }\n }\n for (const arg of cmdArgs) {\n if (typeof arg === 'string') {\n validateNoShellMetachars(arg, 'argument');\n }\n }\n\n return {\n toolName: 'bash',\n args: {\n command: [program, ...flags, ...cmdArgs].map((a) => shellEscape(String(a))).join(' '),\n description: `DWS run: ${program}`,\n },\n };\n }\n case 'runGitCommand': {\n const gitCmd = data.command as string;\n if (!gitCmd || typeof gitCmd !== 'string') {\n throw new Error('runGitCommand: command is required and must be a string');\n }\n validateNoShellMetachars(gitCmd, 'git command');\n\n const gitArgs = (data.arguments as string[]) ?? [];\n for (const arg of gitArgs) {\n if (typeof arg === 'string') {\n validateNoShellMetachars(arg, 'git argument');\n }\n }\n return {\n toolName: 'bash',\n args: {\n command: ['git', gitCmd, ...gitArgs].map((a) => shellEscape(String(a))).join(' '),\n description: `DWS git: ${gitCmd}`,\n },\n };\n }\n case 'listDirectory':\n return { toolName: 'read', args: { filePath: data.directory ?? '.' } };\n case 'findFiles':\n return { toolName: 'glob', args: { pattern: data.name_pattern ?? data.namePattern } };\n case 'grep':\n return {\n toolName: 'grep',\n args: {\n pattern: data.pattern,\n path: data.search_directory ?? data.searchDirectory,\n },\n };\n case 'mkdir': {\n const dirPath = String(data.directory_path ?? data.directoryPath ?? '');\n if (!dirPath) {\n throw new Error('mkdir: directory_path is required');\n }\n if (dirPath.includes('\\0')) {\n throw new Error('mkdir: directory_path contains null bytes');\n }\n return {\n toolName: 'bash',\n args: {\n command: `mkdir -p ${shellEscape(dirPath)}`,\n description: 'DWS mkdir',\n },\n };\n }\n case 'runHTTPRequest': {\n const methodRaw = String(data.method ?? 'GET').toUpperCase();\n const allowedMethods = ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'];\n if (!allowedMethods.includes(methodRaw)) {\n throw new Error(`runHTTPRequest: invalid HTTP method '${methodRaw}'`);\n }\n\n const urlPath = String(data.path ?? '');\n if (!urlPath) {\n throw new Error('runHTTPRequest: path is required');\n }\n\n try {\n const parsedUrl = new URL(urlPath);\n if (!ALLOWED_URL_SCHEMES.includes(parsedUrl.protocol)) {\n throw new Error(\n `runHTTPRequest: only http:// and https:// schemes are allowed, got '${parsedUrl.protocol}'`\n );\n }\n } catch (e) {\n if (e instanceof Error && e.message.startsWith('runHTTPRequest:')) throw e;\n // Relative path or non-URL string — allow through (curl handles these)\n }\n\n const method = shellEscape(methodRaw);\n const escapedPath = shellEscape(urlPath);\n const bodyArg = data.body ? ` -d ${shellEscape(String(data.body))}` : '';\n return {\n toolName: 'bash',\n args: {\n command: `curl -s -X ${method} -- ${escapedPath}${bodyArg}`,\n description: `DWS HTTP ${methodRaw}`,\n },\n };\n }\n default:\n return { toolName: dwsToolName, args: data };\n }\n}\n","/**\n * Token management for the GitLab Duo Agent Platform (DWS).\n *\n * Handles two API calls:\n * 1. POST /api/v4/ai/duo_workflows/direct_access → GenerateTokenResponse (workflow token)\n * 2. POST /api/v4/ai/duo_workflows/workflows → CreateWorkflowResponse (workflow ID)\n *\n * Tokens are cached for 25 minutes (they expire after ~30 minutes).\n * On 401, optionally triggers an API key refresh callback and retries once.\n * On 403, throws a clear error explaining GitLab Duo Enterprise requirements.\n */\n\nimport { GitLabError } from './gitlab-error';\nimport { sanitizeErrorMessage } from './gitlab-workflow-builtins';\nimport type {\n GenerateTokenResponse,\n CreateWorkflowResponse,\n GitLabWorkflowClientConfig,\n} from './gitlab-workflow-types';\n\nimport {\n DEFAULT_WORKFLOW_DEFINITION,\n DEFAULT_AGENT_PRIVILEGES,\n WORKFLOW_ENVIRONMENT,\n WorkflowType,\n} from './gitlab-workflow-types';\n\n/** Cache duration: 25 minutes (tokens expire at ~30 minutes) */\nconst TOKEN_CACHE_DURATION_MS = 25 * 60 * 1000;\n\nconst MAX_ERROR_TEXT_LENGTH = 500;\n\nfunction sanitizeErrorText(text: string): string {\n const truncated =\n text.length > MAX_ERROR_TEXT_LENGTH ? text.slice(0, MAX_ERROR_TEXT_LENGTH) + '...' : text;\n return sanitizeErrorMessage(truncated);\n}\n\n/**\n * Shared token cache key for CHAT workflows.\n * CHAT tokens are shared across all sessions (matching gitlab-lsp behavior).\n */\nconst CHAT_SHARED_TOKEN_KEY = '__chat_shared__';\n\ninterface CachedToken {\n token: GenerateTokenResponse;\n expiresAt: number;\n}\n\nexport class GitLabWorkflowTokenClient {\n private readonly config: GitLabWorkflowClientConfig;\n private readonly fetchFn: typeof fetch;\n\n /**\n * Token cache keyed by workflow definition type.\n *\n * - CHAT workflows use a shared key (CHAT_SHARED_TOKEN_KEY) so tokens\n * are reused across ALL chat sessions (matching gitlab-lsp behavior).\n * - SOFTWARE_DEVELOPMENT workflows would use per-workflow-id keys,\n * but since we fetch tokens before creating workflows, we key by type.\n */\n private tokenCache = new Map<string, CachedToken>();\n\n constructor(config: GitLabWorkflowClientConfig) {\n this.config = config;\n this.fetchFn = config.fetch ?? fetch;\n }\n\n /**\n * Resolve the cache key for a given workflow definition.\n * CHAT workflows share a single token per namespace; other types get per-type keys.\n */\n private getCacheKey(workflowDefinition: string, rootNamespaceId?: string): string {\n const base =\n workflowDefinition === WorkflowType.CHAT ? CHAT_SHARED_TOKEN_KEY : workflowDefinition;\n return rootNamespaceId ? `${base}:${rootNamespaceId}` : base;\n }\n\n /**\n * Get a DWS token, using cached value if still valid.\n *\n * Token caching strategy (matches gitlab-lsp):\n * - CHAT workflows: shared token across all sessions\n * - Other workflows: per-type token\n *\n * @param workflowDefinition - Workflow type (default: 'chat')\n * @param rootNamespaceId - Optional root namespace for scoping\n * @param forceRefresh - Bypass cache\n */\n async getToken(\n workflowDefinition: string = DEFAULT_WORKFLOW_DEFINITION,\n rootNamespaceId?: string,\n forceRefresh: boolean = false\n ): Promise<GenerateTokenResponse> {\n const now = Date.now();\n const cacheKey = this.getCacheKey(workflowDefinition, rootNamespaceId);\n\n const cached = this.tokenCache.get(cacheKey);\n if (!forceRefresh && cached && cached.expiresAt > now) {\n return cached.token;\n }\n\n if (forceRefresh) {\n this.tokenCache.delete(cacheKey);\n }\n\n const url = `${this.config.instanceUrl}/api/v4/ai/duo_workflows/direct_access`;\n\n const body: Record<string, unknown> = {\n workflow_definition: workflowDefinition,\n };\n if (rootNamespaceId) {\n body.root_namespace_id = rootNamespaceId;\n }\n if (this.config.featureFlags && Object.keys(this.config.featureFlags).length > 0) {\n body.feature_flags = this.config.featureFlags;\n }\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n const safeError = sanitizeErrorText(errorText);\n\n // 401 — try refreshing the API key once\n if (response.status === 401 && this.config.refreshApiKey && !forceRefresh) {\n try {\n await this.config.refreshApiKey();\n return await this.getToken(workflowDefinition, rootNamespaceId, true);\n } catch {\n throw new GitLabError({\n message: `Failed to get workflow token: ${response.status} ${response.statusText} - ${safeError}`,\n statusCode: response.status,\n responseBody: safeError,\n });\n }\n }\n\n // 403 — fail fast with clear message about requirements\n if (response.status === 403) {\n throw new GitLabError({\n message:\n `GitLab Duo Agent Platform access denied. ` +\n `GitLab Duo Agent Platform requires GitLab Ultimate with Duo Enterprise add-on. ` +\n `Ensure: (1) Your instance has GitLab Ultimate, ` +\n `(2) Duo Enterprise add-on is enabled, ` +\n `(3) Your account has access to AI features.`,\n statusCode: response.status,\n responseBody: safeError,\n });\n }\n\n throw new GitLabError({\n message: `Failed to get workflow token: ${response.status} ${response.statusText} - ${safeError}`,\n statusCode: response.status,\n responseBody: safeError,\n });\n }\n\n const data = (await response.json()) as GenerateTokenResponse;\n\n // Cache for 25 minutes\n this.tokenCache.set(cacheKey, {\n token: data,\n expiresAt: now + TOKEN_CACHE_DURATION_MS,\n });\n\n return data;\n } catch (error) {\n if (error instanceof GitLabError) throw error;\n throw new GitLabError({\n message: `Failed to get workflow token: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Create a new workflow on the GitLab instance.\n *\n * @param goal - The user's message / goal for this workflow\n * @param options - Additional workflow creation options\n * @returns The created workflow's ID\n */\n async createWorkflow(\n goal: string,\n options?: {\n projectId?: string;\n namespaceId?: string;\n workflowDefinition?: string;\n agentPrivileges?: number[];\n environment?: string;\n allowAgentToRequestUser?: boolean;\n }\n ): Promise<string> {\n // Validate goal parameter\n if (!goal || typeof goal !== 'string') {\n throw new GitLabError({ message: 'goal is required and must be a non-empty string' });\n }\n if (goal.length > 10000) {\n throw new GitLabError({ message: 'goal exceeds maximum length of 10000 characters' });\n }\n\n const url = `${this.config.instanceUrl}/api/v4/ai/duo_workflows/workflows`;\n\n const body: Record<string, unknown> = {\n goal,\n project_id: options?.projectId,\n namespace_id: options?.namespaceId,\n workflow_definition: options?.workflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION,\n agent_privileges: options?.agentPrivileges ?? DEFAULT_AGENT_PRIVILEGES,\n environment: options?.environment ?? WORKFLOW_ENVIRONMENT,\n allow_agent_to_request_user: options?.allowAgentToRequestUser ?? true,\n };\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n const safeError = sanitizeErrorText(errorText);\n throw new GitLabError({\n message: `Failed to create workflow: ${response.status} ${response.statusText} - ${safeError}`,\n statusCode: response.status,\n responseBody: safeError,\n });\n }\n\n const data = (await response.json()) as CreateWorkflowResponse;\n return data.id.toString();\n } catch (error) {\n if (error instanceof GitLabError) throw error;\n throw new GitLabError({\n message: `Failed to create workflow: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Invalidate cached tokens.\n *\n * @param workflowDefinition - If provided, only invalidate for this type.\n * If omitted, clears ALL cached tokens.\n */\n invalidateToken(workflowDefinition?: string, rootNamespaceId?: string): void {\n if (workflowDefinition) {\n this.tokenCache.delete(this.getCacheKey(workflowDefinition, rootNamespaceId));\n } else {\n this.tokenCache.clear();\n }\n }\n}\n","import { spawn } from 'child_process';\nimport * as path from 'path';\nimport { GitLabProjectCache, type GitLabProject } from './gitlab-project-cache';\nimport { GitLabError } from './gitlab-error';\n\nexport interface GitLabProjectDetectorConfig {\n instanceUrl: string;\n getHeaders: () => Record<string, string>;\n fetch?: typeof fetch;\n cache?: GitLabProjectCache;\n gitTimeout?: number;\n}\n\n/**\n * Detects GitLab project information from git remote URLs\n *\n * This class provides functionality to:\n * - Parse git remote URLs (SSH, HTTPS, custom domains)\n * - Execute git commands to get remote URLs\n * - Fetch project details from GitLab API\n * - Cache project information to avoid repeated API calls\n */\nexport class GitLabProjectDetector {\n private readonly config: GitLabProjectDetectorConfig;\n private readonly fetchFn: typeof fetch;\n private readonly cache: GitLabProjectCache;\n\n constructor(config: GitLabProjectDetectorConfig) {\n this.config = {\n gitTimeout: 5000, // 5 seconds default\n ...config,\n };\n this.fetchFn = config.fetch ?? fetch;\n this.cache = config.cache ?? new GitLabProjectCache();\n }\n\n /**\n * Auto-detect GitLab project from git remote in the working directory\n *\n * @param workingDirectory - The directory to check for git remote\n * @param remoteName - The git remote name to use (default: 'origin')\n * @returns The detected project or null if not a git repo / no matching remote\n * @throws GitLabError if the API call or an unexpected error occurs\n */\n async detectProject(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<GitLabProject | null> {\n // 1. Check cache first\n const cacheKey = path.resolve(workingDirectory);\n const cached = this.cache.get(cacheKey);\n if (cached) {\n return cached;\n }\n\n try {\n // 2. Get git remote URL\n const remoteUrl = await this.getGitRemoteUrl(workingDirectory, remoteName);\n if (!remoteUrl) {\n return null; // Not a git repo or no remote\n }\n\n // 3. Parse project path from URL\n const projectPath = this.parseGitRemoteUrl(remoteUrl, this.config.instanceUrl);\n if (!projectPath) {\n return null; // Remote doesn't match instance\n }\n\n // 4. Fetch project from GitLab API\n const project = await this.getProjectByPath(projectPath);\n\n // 5. Cache the result\n this.cache.set(cacheKey, project);\n\n return project;\n } catch (error) {\n throw error instanceof GitLabError\n ? error\n : new GitLabError({\n message: `Project detection failed: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Parse a git remote URL to extract the project path\n *\n * Supports:\n * - SSH: git@gitlab.com:namespace/project.git\n * - HTTPS: https://gitlab.com/namespace/project.git\n * - HTTP: http://gitlab.local/namespace/project.git\n * - Custom domains and ports\n *\n * @param remoteUrl - The git remote URL\n * @param instanceUrl - The GitLab instance URL to match against\n * @returns The project path (e.g., \"namespace/project\") or null if parsing fails\n */\n parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null {\n try {\n // Extract hostname from instanceUrl\n const instanceHost = new URL(instanceUrl).hostname;\n\n // SSH format: git@host:path.git or git@host:port/path.git\n const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\\.git)?$/);\n if (sshMatch) {\n const [, host, pathPart] = sshMatch;\n // Handle port in SSH URLs (git@host:port/path)\n const hostWithoutPort = host.split(':')[0];\n if (hostWithoutPort === instanceHost) {\n // Remove port from path if present\n const cleanPath = pathPart.replace(/^\\d+\\//, '');\n return cleanPath.endsWith('.git') ? cleanPath.slice(0, -4) : cleanPath;\n }\n }\n\n // HTTPS/HTTP format: https://host/path.git or https://host:port/path.git\n const httpsMatch = remoteUrl.match(/^(https?):\\/\\/([^/]+)\\/(.+?)(?:\\.git)?$/);\n if (httpsMatch) {\n const [, , hostWithPort, pathPart] = httpsMatch;\n const host = hostWithPort.split(':')[0];\n if (host === instanceHost) {\n return pathPart.endsWith('.git') ? pathPart.slice(0, -4) : pathPart;\n }\n }\n\n return null;\n } catch (error) {\n // URL parsing failed\n return null;\n }\n }\n\n /**\n * Get the git remote URL from a working directory\n *\n * @param workingDirectory - The directory to check\n * @param remoteName - The git remote name (default: 'origin')\n * @returns The remote URL or null if not found\n */\n async getGitRemoteUrl(\n workingDirectory: string,\n remoteName: string = 'origin'\n ): Promise<string | null> {\n return new Promise((resolve) => {\n const child = spawn('git', ['config', '--get', `remote.${remoteName}.url`], {\n cwd: workingDirectory,\n timeout: this.config.gitTimeout,\n });\n\n let stdout = '';\n let _stderr = '';\n\n child.stdout?.on('data', (data) => {\n stdout += data.toString();\n });\n\n child.stderr?.on('data', (data) => {\n _stderr += data.toString();\n });\n\n child.on('close', (exitCode) => {\n if (exitCode === 0 && stdout.trim()) {\n resolve(stdout.trim());\n } else {\n resolve(null);\n }\n });\n\n child.on('error', () => {\n // Git not available or command failed\n resolve(null);\n });\n });\n }\n\n /**\n * Fetch project details from GitLab API by project path\n *\n * @param projectPath - The project path (e.g., \"namespace/project\")\n * @returns The project details\n * @throws GitLabError if the API call fails\n */\n async getProjectByPath(projectPath: string): Promise<GitLabProject> {\n // URL-encode the project path\n const encodedPath = encodeURIComponent(projectPath);\n const url = `${this.config.instanceUrl}/api/v4/projects/${encodedPath}`;\n\n try {\n const response = await this.fetchFn(url, {\n method: 'GET',\n headers: this.config.getHeaders(),\n });\n\n if (!response.ok) {\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${response.status} ${response.statusText}`,\n });\n }\n\n const data = (await response.json()) as {\n id: number;\n path: string;\n path_with_namespace: string;\n name: string;\n namespace?: { id: number };\n };\n\n return {\n id: data.id,\n path: data.path,\n pathWithNamespace: data.path_with_namespace,\n name: data.name,\n namespaceId: data.namespace?.id,\n };\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to fetch project '${projectPath}': ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Clear the project cache\n */\n clearCache(): void {\n this.cache.clear();\n }\n\n /**\n * Get the cache instance (useful for testing)\n */\n getCache(): GitLabProjectCache {\n return this.cache;\n }\n}\n","/**\n * Simple in-memory cache for GitLab project information\n * Used to avoid repeated API calls when detecting projects from git remotes\n */\n\nexport interface GitLabProject {\n id: number;\n path: string;\n pathWithNamespace: string;\n name: string;\n namespaceId?: number;\n}\n\ninterface CacheEntry {\n project: GitLabProject;\n expiresAt: number;\n}\n\n/**\n * In-memory cache for GitLab project information with TTL support\n */\nexport class GitLabProjectCache {\n private cache = new Map<string, CacheEntry>();\n private defaultTTL: number;\n\n /**\n * Create a new project cache\n * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)\n */\n constructor(defaultTTL: number = 5 * 60 * 1000) {\n this.defaultTTL = defaultTTL;\n }\n\n /**\n * Get a cached project by key\n * @param key - Cache key (typically the working directory path)\n * @returns The cached project or null if not found or expired\n */\n get(key: string): GitLabProject | null {\n const entry = this.cache.get(key);\n if (!entry) {\n return null;\n }\n\n // Check if entry has expired\n if (Date.now() > entry.expiresAt) {\n this.cache.delete(key);\n return null;\n }\n\n return entry.project;\n }\n\n /**\n * Store a project in the cache\n * @param key - Cache key (typically the working directory path)\n * @param project - The project to cache\n * @param ttl - Optional custom TTL in milliseconds\n */\n set(key: string, project: GitLabProject, ttl?: number): void {\n this.cache.set(key, {\n project,\n expiresAt: Date.now() + (ttl ?? this.defaultTTL),\n });\n }\n\n /**\n * Check if a key exists in the cache (and is not expired)\n * @param key - Cache key to check\n * @returns true if the key exists and is not expired\n */\n has(key: string): boolean {\n return this.get(key) !== null;\n }\n\n /**\n * Remove a specific entry from the cache\n * @param key - Cache key to remove\n */\n delete(key: string): void {\n this.cache.delete(key);\n }\n\n /**\n * Clear all entries from the cache\n */\n clear(): void {\n this.cache.clear();\n }\n\n /**\n * Get the number of entries in the cache (including expired ones)\n */\n get size(): number {\n return this.cache.size;\n }\n\n /**\n * Clean up expired entries from the cache\n * This is useful for long-running processes to prevent memory leaks\n */\n cleanup(): void {\n const now = Date.now();\n for (const [key, entry] of this.cache.entries()) {\n if (now > entry.expiresAt) {\n this.cache.delete(key);\n }\n }\n }\n}\n","/**\n * Dynamic model discovery via GitLab GraphQL API.\n *\n * Queries `aiChatAvailableModels` to discover which models are available\n * for a given GitLab namespace. Used to dynamically populate `duo-workflow-*`\n * model IDs at runtime.\n *\n * Requires GitLab 18.4+ (18.5+ for pinned model support).\n */\n\nimport { GitLabError } from './gitlab-error';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface AiModel {\n /** Display name (e.g., 'Claude Sonnet 4.6') */\n name: string;\n /** Model reference for API use (e.g., 'claude_sonnet_4_6' or 'anthropic/claude-sonnet-4-5-20250929') */\n ref: string;\n}\n\nexport interface AiChatAvailableModels {\n defaultModel: AiModel | null;\n selectableModels: AiModel[];\n pinnedModel: AiModel | null;\n}\n\nexport interface DiscoveredModels {\n /** The effective model (pinned > user-selected > default) */\n defaultModel: AiModel | null;\n /** All models the user can select from */\n selectableModels: AiModel[];\n /** Admin-pinned model (overrides everything) */\n pinnedModel: AiModel | null;\n /** Whether the ai_user_model_switching feature flag is enabled */\n modelSwitchingEnabled: boolean;\n /** GitLab instance version */\n instanceVersion: string | null;\n}\n\nexport interface ModelDiscoveryConfig {\n /** GitLab instance URL */\n instanceUrl: string;\n /** Function returning auth headers */\n getHeaders: () => Record<string, string>;\n /** Custom fetch */\n fetch?: typeof fetch;\n}\n\n// ---------------------------------------------------------------------------\n// GraphQL query (inlined — no need for graphql-request gql tag)\n// ---------------------------------------------------------------------------\n\nconst AI_CHAT_AVAILABLE_MODELS_QUERY = `\n query aiChatAvailableModels($rootNamespaceId: GroupID!) {\n metadata {\n featureFlags(names: [\"ai_user_model_switching\"]) {\n enabled\n name\n }\n version\n }\n\n aiChatAvailableModels(rootNamespaceId: $rootNamespaceId) {\n defaultModel {\n name\n ref\n }\n selectableModels {\n name\n ref\n }\n pinnedModel {\n name\n ref\n }\n }\n }\n`;\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\nconst DISCOVERY_CACHE_TTL_MS = 10 * 60 * 1000;\n\ninterface CachedDiscovery {\n data: DiscoveredModels;\n expiresAt: number;\n}\n\nexport class GitLabModelDiscovery {\n private readonly config: ModelDiscoveryConfig;\n private readonly fetchFn: typeof fetch;\n private cache = new Map<string, CachedDiscovery>();\n\n constructor(config: ModelDiscoveryConfig) {\n this.config = config;\n this.fetchFn = config.fetch ?? fetch;\n }\n\n /**\n * Discover available models for a given root namespace.\n *\n * Results are cached per `rootNamespaceId` with a 10-minute TTL.\n * Use `invalidateCache()` to force an immediate refresh.\n *\n * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')\n */\n async discover(rootNamespaceId: string): Promise<DiscoveredModels> {\n const cached = this.cache.get(rootNamespaceId);\n if (cached && cached.expiresAt > Date.now()) {\n return cached.data;\n }\n\n const url = `${this.config.instanceUrl}/api/graphql`;\n\n try {\n const response = await this.fetchFn(url, {\n method: 'POST',\n headers: {\n ...this.config.getHeaders(),\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify({\n query: AI_CHAT_AVAILABLE_MODELS_QUERY,\n variables: { rootNamespaceId },\n }),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new GitLabError({\n message: `Model discovery GraphQL request failed: ${response.status} ${response.statusText} - ${errorText}`,\n statusCode: response.status,\n responseBody: errorText,\n });\n }\n\n const json = (await response.json()) as {\n data?: {\n aiChatAvailableModels?: AiChatAvailableModels | null;\n metadata?: {\n featureFlags?: Array<{ name: string; enabled: boolean }>;\n version?: string;\n } | null;\n };\n errors?: Array<{ message: string }>;\n };\n\n if (json.errors && json.errors.length > 0) {\n throw new GitLabError({\n message: `Model discovery GraphQL errors: ${json.errors.map((e) => e.message).join(', ')}`,\n });\n }\n\n const models = json.data?.aiChatAvailableModels;\n const metadata = json.data?.metadata;\n\n const modelSwitchingEnabled =\n metadata?.featureFlags?.find((f) => f.name === 'ai_user_model_switching')?.enabled ?? false;\n\n const result: DiscoveredModels = {\n defaultModel: models?.defaultModel ?? null,\n selectableModels: models?.selectableModels ?? [],\n pinnedModel: models?.pinnedModel ?? null,\n modelSwitchingEnabled,\n instanceVersion: metadata?.version ?? null,\n };\n\n this.cache.set(rootNamespaceId, {\n data: result,\n expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS,\n });\n return result;\n } catch (error) {\n if (error instanceof GitLabError) throw error;\n throw new GitLabError({\n message: `Model discovery failed: ${error}`,\n cause: error,\n });\n }\n }\n\n /**\n * Get the effective model ref to use for a workflow.\n *\n * Priority: pinned > user-selected > default.\n *\n * @param rootNamespaceId - GitLab group ID\n * @param userSelectedRef - Optional user preference\n */\n async getEffectiveModelRef(\n rootNamespaceId: string,\n userSelectedRef?: string\n ): Promise<string | null> {\n const discovered = await this.discover(rootNamespaceId);\n\n // Pinned model always wins\n if (discovered.pinnedModel) {\n return discovered.pinnedModel.ref;\n }\n\n // User selection (if model switching is enabled)\n if (userSelectedRef && discovered.modelSwitchingEnabled) {\n const isValid = discovered.selectableModels.some((m) => m.ref === userSelectedRef);\n if (isValid) {\n return userSelectedRef;\n }\n }\n\n // Default\n return discovered.defaultModel?.ref ?? null;\n }\n\n /**\n * Invalidate the cached discovery results.\n */\n invalidateCache(): void {\n this.cache.clear();\n }\n}\n","/**\n * File-based cache for workflow model discovery results and user selection.\n *\n * A single cache file is stored at\n * `~/.cache/opencode/gitlab-workflow-model-cache.json`\n * (or `$XDG_CACHE_HOME/opencode/...` when set).\n *\n * The file contains a JSON object keyed by a truncated SHA-256 hash of the\n * workspace directory path combined with the GitLab instance URL. This ensures\n * that switching instances for the same workspace invalidates the cache.\n * Each value holds:\n * - `discovery`: The full DiscoveredModels JSON from the last successful discovery\n * - `selectedModelRef`: The model ref the user last selected\n * - `selectedModelName`: Human-readable name of the selected model\n * - `updatedAt`: ISO timestamp of the last write\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport * as crypto from 'crypto';\nimport type { DiscoveredModels } from './gitlab-model-discovery';\n\nexport interface ModelCacheEntry {\n discovery: DiscoveredModels | null;\n selectedModelRef: string | null;\n selectedModelName: string | null;\n updatedAt: string;\n}\n\ntype CacheFile = Record<string, ModelCacheEntry>;\n\nfunction getCacheFilePath(): string {\n const cacheHome = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');\n return path.join(cacheHome, 'opencode', 'gitlab-workflow-model-cache.json');\n}\n\nfunction computeCacheKey(workDir: string, instanceUrl?: string): string {\n const normalizedUrl = (instanceUrl || 'https://gitlab.com').replace(/\\/$/, '');\n return crypto\n .createHash('sha256')\n .update(`${workDir}\\0${normalizedUrl}`)\n .digest('hex')\n .slice(0, 12);\n}\n\nexport class GitLabModelCache {\n private readonly filePath: string;\n private readonly key: string;\n\n constructor(workDir: string, instanceUrl?: string) {\n this.filePath = getCacheFilePath();\n this.key = computeCacheKey(workDir, instanceUrl);\n }\n\n private readAll(): CacheFile {\n try {\n if (!fs.existsSync(this.filePath)) {\n return {};\n }\n const raw = fs.readFileSync(this.filePath, 'utf-8');\n return JSON.parse(raw) as CacheFile;\n } catch {\n return {};\n }\n }\n\n private writeAll(data: CacheFile): void {\n try {\n const dir = path.dirname(this.filePath);\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n fs.writeFileSync(this.filePath, JSON.stringify(data, null, 2), { mode: 0o600 });\n } catch {\n // Best-effort — cache write failures are non-fatal\n }\n }\n\n /**\n * Load the cached entry for this workspace.\n * Returns null if no cache exists or is unreadable.\n */\n load(): ModelCacheEntry | null {\n return this.readAll()[this.key] ?? null;\n }\n\n /**\n * Persist the full cache entry to disk.\n */\n save(entry: ModelCacheEntry): void {\n const data = this.readAll();\n data[this.key] = entry;\n this.writeAll(data);\n }\n\n /**\n * Update only the discovery portion of the cache, preserving selection.\n */\n saveDiscovery(discovery: DiscoveredModels): void {\n const existing = this.load();\n this.save({\n discovery,\n selectedModelRef: existing?.selectedModelRef ?? null,\n selectedModelName: existing?.selectedModelName ?? null,\n updatedAt: new Date().toISOString(),\n });\n }\n\n /**\n * Update only the selected model, preserving the discovery data.\n */\n saveSelection(ref: string | null, name: string | null): void {\n const existing = this.load();\n this.save({\n discovery: existing?.discovery ?? null,\n selectedModelRef: ref,\n selectedModelName: name,\n updatedAt: new Date().toISOString(),\n });\n }\n\n /**\n * Remove the entry for this workspace from the cache file.\n */\n clear(): void {\n const data = this.readAll();\n delete data[this.key];\n if (Object.keys(data).length === 0) {\n try {\n if (fs.existsSync(this.filePath)) {\n fs.unlinkSync(this.filePath);\n }\n } catch {\n // Best-effort\n }\n } else {\n this.writeAll(data);\n }\n }\n\n /**\n * Convenience: get the cached selected model ref (or null).\n */\n getSelectedModelRef(): string | null {\n return this.load()?.selectedModelRef ?? null;\n }\n\n /**\n * Convenience: get the cached selected model name (or null).\n */\n getSelectedModelName(): string | null {\n return this.load()?.selectedModelName ?? null;\n }\n\n /**\n * Convenience: get the cached discovery result (or null).\n */\n getDiscovery(): DiscoveredModels | null {\n return this.load()?.discovery ?? null;\n }\n}\n","/**\n * LanguageModelV2 adapter for GitLab Duo Agent Platform (DWS).\n *\n * Maps DWS WebSocket events to the Vercel AI SDK streaming protocol:\n * newCheckpoint (text) → text-delta\n * runMcpTool → tool-call (emitted for UI visibility)\n * workflow COMPLETED → finish(stop)\n * workflow FAILED → error\n *\n * IMPORTANT: Tool execution architecture\n * =======================================\n * DWS drives the agentic loop server-side. When DWS requests a tool via\n * `runMcpTool`, we execute it ourselves using the AI SDK tools passed in\n * `options.tools`, send the result back to DWS via WebSocket `actionResponse`,\n * and keep streaming. The stream stays open until DWS sends COMPLETED/FAILED.\n *\n * This means the AI SDK's outer tool loop (which would call doStream() again\n * with tool results in messages) is NOT used for workflow models. The entire\n * agentic conversation happens within a single doStream() call.\n *\n * We still emit `tool-call` stream parts so the UI can show tool usage,\n * but finishReason is always 'stop' (never 'tool-calls').\n *\n * Lifecycle per doStream() call:\n * 1. Get workflow token (POST /duo_workflows/direct_access)\n * 2. Create workflow (POST /duo_workflows/workflows)\n * 3. Connect WebSocket (wss://.../duo_workflows/ws)\n * 4. Send startRequest (with goal, tools, context)\n * 5. Stream events (checkpoint → text, tool request → execute → respond)\n * 6. Close on finish (COMPLETED/FAILED/CANCELLED)\n *\n * SECURITY MODEL — Tool Execution\n * =================================\n * This library acts as a **bridge** between DWS (server) and the host's tool\n * system (e.g., OpenCode). It does NOT execute host-OS commands itself except\n * for the read-only `git` calls inside `getGitInfo()` (fixed argument lists,\n * no user-controlled data, via `execFile`).\n *\n * Built-in tool mapping (`mapBuiltinTool`)\n * -----------------------------------------\n * DWS built-in tools are mapped to structured host-tool invocations that the\n * host's `toolExecutor` callback then executes through its own permission\n * system. For tools that ultimately produce shell commands the following\n * defences are applied:\n *\n * • `shellEscape()` — wraps every argument in single quotes and escapes\n * embedded single quotes, preventing metacharacter injection for all\n * argument-based tools (runCommand, runGitCommand, mkdir, runHTTPRequest).\n *\n * • `validateNoShellMetachars()` — rejects program names and git sub-commands\n * containing `;`, `&`, `|`, `` ` ``, `$`, `(`, `)`, `<`, `>` before they\n * reach shellEscape, providing a defence-in-depth check.\n *\n * • `runShellCommand` — intentionally passes the command string through\n * **without sanitization** because it is a deliberately raw shell tool.\n * The host's `toolExecutor` / permission system is the final gate and must\n * decide whether to allow it. A length cap (10 000 chars) limits DoS via\n * oversized payloads.\n *\n * • `runHTTPRequest` — only `http://` and `https://` URL schemes are allowed\n * (allowlist); all others (file://, gopher://, ftp://, etc.) are rejected.\n * A `--` separator before the URL prevents flag injection via paths like\n * `--output /tmp/evil`.\n *\n * • `mkdir` — rejects null bytes in the directory path.\n *\n * Error sanitization\n * -------------------\n * All error messages forwarded into the stream (tool catch blocks, failed\n * events, WebSocket close reasons) are passed through `sanitizeErrorMessage()`\n * which redacts Bearer tokens, GitLab PAT/CI tokens, and URL credential query\n * parameters before they are surfaced to callers or logged.\n *\n * Trust boundary\n * ---------------\n * DWS is treated as a **trusted server** for the purpose of tool invocation —\n * it controls which tools are called and with what arguments. Consumers MUST\n * implement their own authorization layer in the `toolExecutor` callback\n * (e.g., user confirmation prompts, allow-lists) for any tool that can cause\n * side effects on the user's machine.\n */\n\nimport { GitLabWorkflowClient } from './gitlab-workflow-client';\nimport { GitLabWorkflowTokenClient } from './gitlab-workflow-token-client';\nimport { GitLabProjectDetector } from './gitlab-project-detector';\nimport { GitLabError } from './gitlab-error';\nimport { getWorkflowModelRef } from './model-mappings';\nimport { GitLabModelDiscovery } from './gitlab-model-discovery';\nimport { GitLabModelCache } from './gitlab-model-cache';\nimport { mapBuiltinTool, sanitizeErrorMessage } from './gitlab-workflow-builtins';\n\nimport type {\n LanguageModelV2,\n LanguageModelV2CallOptions,\n LanguageModelV2StreamPart,\n LanguageModelV2FinishReason,\n LanguageModelV2CallWarning,\n LanguageModelV2Content,\n LanguageModelV2Usage,\n LanguageModelV2Message,\n LanguageModelV2FunctionTool,\n} from '@ai-sdk/provider';\n\nimport type {\n GitLabWorkflowOptions,\n GitLabWorkflowClientConfig,\n McpToolDefinition,\n AdditionalContext,\n StartRequest,\n WorkflowClientEvent,\n CheckpointData,\n UiChatLogEntry,\n NewCheckpoint,\n} from './gitlab-workflow-types';\n\ninterface StreamState {\n streamClosed: boolean;\n streamedInputChars: number;\n streamedOutputChars: number;\n pendingToolCount: number;\n deferredClose: (() => void) | null;\n activeTextBlockId: string | null;\n agentMessageEmitted: Map<string, number>;\n currentAgentMessageId: string;\n activeClient: GitLabWorkflowClient | null;\n}\n\nimport {\n DEFAULT_WORKFLOW_DEFINITION,\n DEFAULT_CLIENT_CAPABILITIES,\n CLIENT_VERSION,\n} from './gitlab-workflow-types';\n\nexport interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {\n /** Provider name (e.g., 'gitlab.workflow') */\n provider: string;\n}\n\n// ---------------------------------------------------------------------------\n// Payload size utilities\n// ---------------------------------------------------------------------------\n\nfunction simplifySchemaObj(schema: Record<string, unknown>): Record<string, unknown> {\n if (!schema || typeof schema !== 'object') return schema;\n\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(schema)) {\n if (key === 'description' || key === 'examples' || key === 'default') {\n continue;\n }\n if (key === 'properties' && typeof value === 'object' && value !== null) {\n const props: Record<string, unknown> = {};\n for (const [propName, propValue] of Object.entries(value as Record<string, unknown>)) {\n if (typeof propValue === 'object' && propValue !== null) {\n props[propName] = simplifySchemaObj(propValue as Record<string, unknown>);\n } else {\n props[propName] = propValue;\n }\n }\n result[key] = props;\n } else if (key === 'items' && typeof value === 'object' && value !== null) {\n result[key] = simplifySchemaObj(value as Record<string, unknown>);\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nfunction simplifySchema(schemaStr: string): string {\n try {\n return JSON.stringify(simplifySchemaObj(JSON.parse(schemaStr)));\n } catch {\n return schemaStr;\n }\n}\n\nfunction minimalSchemaObj(schema: Record<string, unknown>): Record<string, unknown> {\n if (!schema || typeof schema !== 'object') return schema;\n\n const result: Record<string, unknown> = { type: schema.type || 'object' };\n if (schema.required) {\n result.required = schema.required;\n }\n if (schema.properties && typeof schema.properties === 'object') {\n const props: Record<string, unknown> = {};\n for (const [propName, propValue] of Object.entries(\n schema.properties as Record<string, unknown>\n )) {\n if (typeof propValue === 'object' && propValue !== null) {\n const pv = propValue as Record<string, unknown>;\n props[propName] = { type: pv.type || 'string' };\n } else {\n props[propName] = { type: 'string' };\n }\n }\n result.properties = props;\n }\n return result;\n}\n\nfunction minimalSchema(schemaStr: string): string {\n try {\n return JSON.stringify(minimalSchemaObj(JSON.parse(schemaStr)));\n } catch {\n return schemaStr;\n }\n}\n\n/**\n * Callback for executing a tool requested by DWS.\n * Provided by the consumer (e.g., OpenCode) to bridge DWS tool requests\n * to the host's tool execution system.\n *\n * @param toolName - Name of the tool DWS wants to execute\n * @param args - JSON-encoded arguments\n * @returns Tool execution result as a string, or throws on error\n */\nexport type WorkflowToolExecutor = (\n toolName: string,\n args: string,\n requestID: string\n) => Promise<{ result: string; error?: string | null }>;\n\n// mapBuiltinTool, sanitizeErrorMessage, shellEscape, validateNoShellMetachars\n// are imported from './gitlab-workflow-builtins' (shared module).\n\n/**\n * GitLab Duo Agent Platform Language Model.\n *\n * Implements LanguageModelV2 by bridging the DWS WebSocket protocol\n * to the Vercel AI SDK stream part format.\n */\nexport class GitLabWorkflowLanguageModel implements LanguageModelV2 {\n readonly specificationVersion = 'v2' as const;\n readonly modelId: string;\n readonly supportedUrls: Record<string, RegExp[]> = {};\n\n private readonly config: GitLabWorkflowLanguageModelConfig;\n private readonly workflowOptions: GitLabWorkflowOptions;\n private readonly tokenClient: GitLabWorkflowTokenClient;\n private readonly projectDetector: GitLabProjectDetector;\n private readonly modelDiscovery: GitLabModelDiscovery;\n private readonly modelCache: GitLabModelCache;\n\n // Cached detected project path\n private detectedProjectPath: string | null = null;\n\n // Workflow ID persisted across turns for multi-turn conversations.\n // When DWS sends INPUT_REQUIRED, the workflow stays alive server-side.\n // On the next doStream() call we reuse this ID (skip createWorkflow).\n private currentWorkflowId: string | null = null;\n\n // Persisted across turns so that cumulative DWS chat logs don't re-emit\n // messages that were already streamed in a previous doStream() call.\n private persistedAgentEmitted = new Map<string, number>();\n\n // Track all active stream clients so stopWorkflow() can stop them all.\n private readonly activeClients = new Set<GitLabWorkflowClient>();\n\n // Cache resolved values to avoid redundant GraphQL calls\n private _selectedModelRef?: string;\n private _selectedModelName?: string;\n private _rootNamespaceId?: string;\n private _discoveryPromise?: Promise<string>;\n\n /**\n * Get the cached selected model ref.\n */\n get selectedModelRef(): string | null {\n return this._selectedModelRef ?? null;\n }\n\n /**\n * Set the selected model ref (e.g., from an eager discover call).\n * This will be used by resolveModelRef() to skip the picker.\n * Also persists to the file-based workspace cache.\n */\n set selectedModelRef(ref: string | null) {\n this._selectedModelRef = ref ?? undefined;\n this.modelCache.saveSelection(ref, this._selectedModelName ?? null);\n }\n\n /**\n * Get the cached selected model display name.\n */\n get selectedModelName(): string | null {\n return this._selectedModelName ?? null;\n }\n\n /**\n * Set the selected model display name.\n * Also persists to the file-based workspace cache.\n */\n set selectedModelName(name: string | null) {\n this._selectedModelName = name ?? undefined;\n this.modelCache.saveSelection(this._selectedModelRef ?? null, name);\n }\n\n /**\n * Optional external tool executor. When set, this is called for tool\n * requests instead of looking up tools from `options.tools`.\n * This allows the consumer (OpenCode) to wire in its permission system.\n *\n * The executor is automatically bound to the async context at the time\n * it is set, so that AsyncLocalStorage-based contexts (like Instance)\n * remain available when the executor is invoked from WebSocket callbacks.\n */\n private _toolExecutor: WorkflowToolExecutor | null = null;\n\n /**\n * Optional callback invoked with intermediate token usage estimates\n * after each tool execution completes. This allows the consumer to\n * display live token counts during long-running DWS workflows, since\n * the AI SDK only surfaces usage via finish-step at stream end.\n */\n onUsageUpdate: ((usage: { inputTokens: number; outputTokens: number }) => void) | null = null;\n\n /**\n * Optional callback invoked when multiple workflow models are available\n * and the user should pick one. Set per-stream by the host (e.g., OpenCode)\n * alongside `toolExecutor`. Takes precedence over `workflowOptions.onSelectModel`.\n */\n onSelectModel:\n | ((models: import('./gitlab-model-discovery').AiModel[]) => Promise<string | null | undefined>)\n | null = null;\n\n get toolExecutor(): WorkflowToolExecutor | null {\n return this._toolExecutor;\n }\n\n set toolExecutor(executor: WorkflowToolExecutor | null) {\n if (executor) {\n try {\n // eslint-disable-next-line @typescript-eslint/no-var-requires\n const { AsyncResource } = require('node:async_hooks');\n this._toolExecutor = AsyncResource.bind(executor);\n } catch {\n this._toolExecutor = executor;\n }\n } else {\n this._toolExecutor = null;\n }\n }\n\n constructor(\n modelId: string,\n config: GitLabWorkflowLanguageModelConfig,\n workflowOptions: GitLabWorkflowOptions = {}\n ) {\n this.modelId = modelId;\n this.config = config;\n this.workflowOptions = workflowOptions;\n\n const workDir = workflowOptions.workingDirectory ?? process.cwd();\n this.modelCache = new GitLabModelCache(workDir, config.instanceUrl);\n\n const cached = this.modelCache.load();\n if (cached?.selectedModelRef) {\n this._selectedModelRef = cached.selectedModelRef;\n }\n if (cached?.selectedModelName) {\n this._selectedModelName = cached.selectedModelName;\n }\n\n this.tokenClient = new GitLabWorkflowTokenClient({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n refreshApiKey: config.refreshApiKey,\n fetch: config.fetch,\n featureFlags: config.featureFlags,\n });\n\n this.projectDetector = new GitLabProjectDetector({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n fetch: config.fetch,\n });\n\n this.modelDiscovery = new GitLabModelDiscovery({\n instanceUrl: config.instanceUrl,\n getHeaders: config.getHeaders,\n fetch: config.fetch,\n });\n }\n\n get provider(): string {\n return this.config.provider;\n }\n\n /**\n * Resolve the project ID (path) to use for workflow creation.\n * Priority: explicit option > auto-detected from git remote > undefined.\n */\n private async resolveProjectId(): Promise<string | undefined> {\n if (this.workflowOptions.projectId) {\n return this.workflowOptions.projectId;\n }\n\n if (this.detectedProjectPath) {\n return this.detectedProjectPath;\n }\n\n const workDir = this.workflowOptions.workingDirectory ?? process.cwd();\n const project = await this.projectDetector.detectProject(workDir);\n if (project) {\n this.detectedProjectPath = project.pathWithNamespace;\n return project.pathWithNamespace;\n }\n\n return undefined;\n }\n\n /**\n * Resolve the root namespace GID to use for model discovery.\n *\n * Priority:\n * 1. Explicit `rootNamespaceId` in workflowOptions (caller-provided GID)\n * 2. Auto-detected from git remote via project detector (namespace.id → GID)\n * 3. Cached from previous call\n */\n private async resolveRootNamespaceId(): Promise<string | null> {\n if (this.workflowOptions.rootNamespaceId) {\n return this.workflowOptions.rootNamespaceId;\n }\n\n // Return cached value if available\n if (this._rootNamespaceId !== undefined) {\n return this._rootNamespaceId;\n }\n\n const workDir = this.workflowOptions.workingDirectory ?? process.cwd();\n const project = await this.projectDetector.detectProject(workDir);\n if (project?.namespaceId) {\n const gid = `gid://gitlab/Group/${project.namespaceId}`;\n this._rootNamespaceId = gid;\n return gid;\n }\n\n this._rootNamespaceId = null;\n return null;\n }\n\n /**\n * Resolve the effective DWS model ref to use for this stream.\n * Deduplicates concurrent calls via a shared promise.\n *\n * Priority for the canonical `duo-workflow` model ID:\n * 1. Admin-pinned model (from GitLabModelDiscovery) — always wins\n * 2. User selection via onSelectModel callback (if model switching enabled)\n * 3. Workspace default model\n * 4. File-cached discovery/selection — used when live discovery fails\n * 5. Hard-coded 'default' (DWS decides) — fallback when discovery fails\n *\n * For all other `duo-workflow-*` model IDs the static mapping is used as-is.\n */\n private async resolveModelRef(): Promise<string> {\n const staticRef = getWorkflowModelRef(this.modelId);\n\n if (this.modelId !== 'duo-workflow') {\n return staticRef ?? 'default';\n }\n\n if (this._selectedModelRef) {\n return this._selectedModelRef;\n }\n\n if (!this._discoveryPromise) {\n this._discoveryPromise = this.doResolveModelRef();\n this._discoveryPromise.finally(() => {\n this._discoveryPromise = undefined;\n });\n }\n return this._discoveryPromise;\n }\n\n private async doResolveModelRef(): Promise<string> {\n const rootNamespaceId = await this.resolveRootNamespaceId();\n\n if (!rootNamespaceId) {\n this._selectedModelRef = 'default';\n return 'default';\n }\n\n try {\n const discovered = await this.modelDiscovery.discover(rootNamespaceId);\n this.modelCache.saveDiscovery(discovered);\n\n if (discovered.pinnedModel) {\n this._selectedModelRef = discovered.pinnedModel.ref;\n this._selectedModelName = discovered.pinnedModel.name;\n this.modelCache.saveSelection(discovered.pinnedModel.ref, discovered.pinnedModel.name);\n return discovered.pinnedModel.ref;\n }\n\n const selectFn = this.onSelectModel ?? this.workflowOptions.onSelectModel;\n if (discovered.selectableModels.length > 0 && selectFn) {\n const selected = await selectFn(discovered.selectableModels);\n if (selected) {\n const match = discovered.selectableModels.find((m) => m.ref === selected);\n if (match) {\n this._selectedModelRef = match.ref;\n this._selectedModelName = match.name;\n this.modelCache.saveSelection(match.ref, match.name);\n return match.ref;\n }\n }\n }\n\n if (discovered.defaultModel) {\n this._selectedModelRef = discovered.defaultModel.ref;\n this._selectedModelName = discovered.defaultModel.name;\n this.modelCache.saveSelection(discovered.defaultModel.ref, discovered.defaultModel.name);\n return discovered.defaultModel.ref;\n }\n } catch {\n const cachedEntry = this.modelCache.load();\n if (cachedEntry?.selectedModelRef) {\n this._selectedModelRef = cachedEntry.selectedModelRef;\n this._selectedModelName = cachedEntry.selectedModelName ?? undefined;\n return cachedEntry.selectedModelRef;\n }\n }\n\n this._selectedModelRef = 'default';\n return 'default';\n }\n\n /**\n * Pre-fetch available models for the workspace.\n * Call this early (e.g., on IDE startup) to avoid blocking the first stream.\n * Results are persisted to the workspace model cache.\n *\n * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')\n * @returns Discovered models with default, selectable, and pinned models\n */\n async discoverModels(\n rootNamespaceId: string\n ): Promise<import('./gitlab-model-discovery').DiscoveredModels> {\n const result = await this.modelDiscovery.discover(rootNamespaceId);\n this.modelCache.saveDiscovery(result);\n return result;\n }\n\n /**\n * Get the file-based model cache instance for this workspace.\n * Useful for consumers that need direct cache access (e.g., the discover route).\n */\n getModelCache(): GitLabModelCache {\n return this.modelCache;\n }\n\n /**\n * Stop the active workflow.\n */\n stopWorkflow(): void {\n for (const client of this.activeClients) {\n if (client.isConnected) {\n client.stop();\n }\n }\n }\n\n /**\n * Reset the workflow state, forcing a new workflow to be created on the\n * next doStream() call. Call this when starting a new conversation.\n */\n resetWorkflow(): void {\n this.currentWorkflowId = null;\n this.persistedAgentEmitted.clear();\n }\n\n /**\n * Get the current workflow ID (if any).\n * Useful for consumers that need to track workflow state.\n */\n get workflowId(): string | null {\n return this.currentWorkflowId;\n }\n\n // ---------------------------------------------------------------------------\n // LanguageModelV2 — doGenerate (non-streaming)\n // ---------------------------------------------------------------------------\n\n async doGenerate(options: LanguageModelV2CallOptions): Promise<{\n content: LanguageModelV2Content[];\n finishReason: LanguageModelV2FinishReason;\n usage: LanguageModelV2Usage;\n warnings: LanguageModelV2CallWarning[];\n }> {\n // DWS is inherently streaming. Collect the full stream into a single result.\n const { stream } = await this.doStream(options);\n const reader = stream.getReader();\n\n const textParts: string[] = [];\n const toolCalls: LanguageModelV2Content[] = [];\n let finishReason: LanguageModelV2FinishReason = 'unknown';\n const usage: LanguageModelV2Usage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };\n\n try {\n // eslint-disable-next-line no-constant-condition\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n switch (value.type) {\n case 'text-delta':\n textParts.push(value.delta);\n break;\n case 'tool-call':\n toolCalls.push({\n type: 'tool-call',\n toolCallId: value.toolCallId,\n toolName: value.toolName,\n input: value.input,\n });\n break;\n case 'finish':\n finishReason = value.finishReason;\n if (value.usage) {\n usage.inputTokens = value.usage.inputTokens ?? 0;\n usage.outputTokens = value.usage.outputTokens ?? 0;\n usage.totalTokens = value.usage.totalTokens ?? 0;\n }\n break;\n case 'error':\n throw value.error;\n }\n }\n } finally {\n reader.releaseLock();\n }\n\n const content: LanguageModelV2Content[] = [];\n const fullText = textParts.join('');\n if (fullText) {\n content.push({ type: 'text', text: fullText });\n }\n content.push(...toolCalls);\n\n return { content, finishReason, usage, warnings: [] };\n }\n\n // ---------------------------------------------------------------------------\n // LanguageModelV2 — doStream (streaming)\n // ---------------------------------------------------------------------------\n\n async doStream(options: LanguageModelV2CallOptions): Promise<{\n stream: ReadableStream<LanguageModelV2StreamPart>;\n request?: { body?: unknown };\n }> {\n // Extract the user's goal from the prompt\n const goal = this.extractGoalFromPrompt(options.prompt);\n\n // Get the model ref for WebSocket URL — resolved dynamically for 'duo-workflow'.\n const modelRef = await this.resolveModelRef();\n\n // Extract MCP tools from options.tools (AI SDK tools → DWS mcpTools)\n const mcpTools = this.extractMcpTools(options);\n\n // Merge preapproved tools — all tool names if options provided\n const preapprovedTools = this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name);\n\n // Build additional context from conversation history.\n const additionalContext = this.buildAdditionalContext(options.prompt);\n\n const toolExecutor = this.toolExecutor ?? null;\n\n // Step 1: Warm the token cache — createWorkflow() below requires a valid\n // session, and getToken() caches the result for subsequent API calls.\n // The DWS token itself is used server-side; the WebSocket authenticates\n // via the GitLab PAT/OAuth token in headers.\n await this.tokenClient.getToken(\n this.workflowOptions.workflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION,\n this.workflowOptions.rootNamespaceId\n );\n\n // Step 1b: Resolve project ID (auto-detect from git remote if needed)\n const projectId = await this.resolveProjectId();\n\n let workflowId: string;\n if (this.currentWorkflowId) {\n workflowId = this.currentWorkflowId;\n } else {\n workflowId = await this.tokenClient.createWorkflow(goal, {\n projectId,\n namespaceId: this.workflowOptions.namespaceId,\n workflowDefinition: this.workflowOptions.workflowDefinition,\n });\n this.currentWorkflowId = workflowId;\n }\n\n // Step 3: Create WebSocket client\n const wsClient = new GitLabWorkflowClient();\n this.activeClients.add(wsClient);\n\n let textBlockCounter = 0;\n\n // Per-stream state — isolated so parallel streams don't corrupt each other.\n // Seed agentMessageEmitted from the persisted map so that cumulative DWS\n // chat logs don't re-emit messages already streamed in a prior turn.\n const ss: StreamState = {\n streamClosed: false,\n streamedInputChars: 0,\n streamedOutputChars: 0,\n pendingToolCount: 0,\n deferredClose: null,\n activeTextBlockId: null,\n agentMessageEmitted: new Map(this.persistedAgentEmitted),\n currentAgentMessageId: '',\n activeClient: wsClient,\n };\n\n for (const msg of options.prompt) {\n if (msg.role === 'system') {\n ss.streamedInputChars += msg.content.length;\n } else if (msg.role === 'user') {\n for (const part of msg.content) {\n if (part.type === 'text') {\n ss.streamedInputChars += (part as { text: string }).text.length;\n }\n }\n }\n }\n\n const stream = new ReadableStream<LanguageModelV2StreamPart>({\n start: async (controller) => {\n try {\n // Connect WebSocket\n await wsClient.connect(\n {\n instanceUrl: this.config.instanceUrl,\n modelRef,\n headers: this.config.getHeaders(),\n projectId: this.workflowOptions.projectId,\n namespaceId: this.workflowOptions.namespaceId,\n rootNamespaceId: this.workflowOptions.rootNamespaceId,\n },\n (event: WorkflowClientEvent) => {\n this.handleWorkflowEvent(\n ss,\n event,\n controller,\n wsClient,\n toolExecutor,\n () => `text-${textBlockCounter++}`\n );\n }\n );\n\n const workflowDef =\n this.workflowOptions.workflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION;\n const capabilities =\n this.workflowOptions.clientCapabilities ?? DEFAULT_CLIENT_CAPABILITIES;\n const workflowMetadata = await this.buildWorkflowMetadata();\n const metadataStr = JSON.stringify(workflowMetadata);\n\n const basePayload = {\n workflowID: workflowId,\n clientVersion: CLIENT_VERSION,\n workflowDefinition: workflowDef,\n goal,\n workflowMetadata: metadataStr,\n clientCapabilities: capabilities,\n preapproved_tools: preapprovedTools,\n };\n const baseSize = JSON.stringify(basePayload).length + 100;\n\n const trimmed = this.trimPayload(mcpTools, additionalContext, baseSize);\n\n const trimmedPreapproved = preapprovedTools.filter((name) =>\n trimmed.mcpTools.some((t) => t.name === name)\n );\n\n const startReq: StartRequest = {\n workflowID: workflowId,\n clientVersion: CLIENT_VERSION,\n workflowDefinition: workflowDef,\n goal,\n workflowMetadata: metadataStr,\n additional_context: trimmed.additionalContext,\n clientCapabilities: capabilities,\n mcpTools: trimmed.mcpTools,\n preapproved_tools: trimmedPreapproved,\n };\n\n if (this.workflowOptions.flowConfig) {\n startReq.flowConfig = this.workflowOptions.flowConfig;\n }\n if (this.workflowOptions.flowConfigSchemaVersion) {\n startReq.flowConfigSchemaVersion = this.workflowOptions.flowConfigSchemaVersion;\n }\n\n wsClient.sendStartRequest(startReq);\n\n // Emit stream-start\n controller.enqueue({\n type: 'stream-start',\n warnings: [],\n });\n\n // Emit response metadata\n controller.enqueue({\n type: 'response-metadata',\n id: workflowId,\n modelId: modelRef,\n });\n } catch (error) {\n if (!ss.streamClosed) {\n controller.enqueue({\n type: 'error',\n error:\n error instanceof GitLabError\n ? error\n : new GitLabError({\n message: `Workflow connection failed: ${error}`,\n cause: error,\n }),\n });\n ss.streamClosed = true;\n controller.close();\n }\n }\n },\n cancel: (_reason) => {\n wsClient.stop();\n wsClient.close();\n this.activeClients.delete(wsClient);\n ss.activeClient = null;\n this.currentWorkflowId = null;\n },\n });\n\n return {\n stream,\n request: {\n body: { workflowId, modelRef, goal },\n },\n };\n }\n\n // ---------------------------------------------------------------------------\n // Event handling\n // ---------------------------------------------------------------------------\n\n private handleWorkflowEvent(\n ss: StreamState,\n event: WorkflowClientEvent,\n controller: ReadableStreamDefaultController<LanguageModelV2StreamPart>,\n wsClient: GitLabWorkflowClient,\n toolExecutor: WorkflowToolExecutor | null,\n nextTextId: () => string\n ): void {\n if (ss.streamClosed) {\n return;\n }\n\n switch (event.type) {\n case 'checkpoint': {\n this.processCheckpoint(ss, event.data, controller, nextTextId);\n break;\n }\n\n case 'tool-request': {\n const { requestID, data } = event;\n let parsedArgs: string;\n try {\n JSON.parse(data.args);\n parsedArgs = data.args;\n } catch {\n parsedArgs = data.args || '{}';\n }\n\n if (ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n\n controller.enqueue({\n type: 'tool-input-start',\n id: requestID,\n toolName: data.name,\n providerExecuted: true,\n });\n controller.enqueue({\n type: 'tool-input-delta',\n id: requestID,\n delta: parsedArgs,\n });\n controller.enqueue({\n type: 'tool-input-end',\n id: requestID,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: requestID,\n toolName: data.name,\n input: parsedArgs,\n providerExecuted: true,\n });\n\n this.executeToolAndRespond(\n ss,\n wsClient,\n controller,\n requestID,\n data.name,\n parsedArgs,\n toolExecutor\n ).catch(() => {});\n break;\n }\n\n case 'builtin-tool-request': {\n const mapped = mapBuiltinTool(event.toolName, event.data);\n const mappedArgs = JSON.stringify(mapped.args);\n\n if (ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n\n controller.enqueue({\n type: 'tool-input-start',\n id: event.requestID,\n toolName: mapped.toolName,\n providerExecuted: true,\n });\n controller.enqueue({\n type: 'tool-input-delta',\n id: event.requestID,\n delta: mappedArgs,\n });\n controller.enqueue({\n type: 'tool-input-end',\n id: event.requestID,\n });\n controller.enqueue({\n type: 'tool-call',\n toolCallId: event.requestID,\n toolName: mapped.toolName,\n input: mappedArgs,\n providerExecuted: true,\n });\n\n this.executeToolAndRespond(\n ss,\n wsClient,\n controller,\n event.requestID,\n mapped.toolName,\n mappedArgs,\n toolExecutor\n ).catch(() => {});\n break;\n }\n\n case 'completed': {\n if (ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n\n const doCompleteClose = () => {\n if (ss.streamClosed) return;\n // Approximate token counts (1 token ≈ 4 chars). DWS does not expose\n // actual token usage; these are estimates for AI SDK compatibility only.\n const inputTokens = Math.ceil(ss.streamedInputChars / 4);\n const outputTokens = Math.ceil(ss.streamedOutputChars / 4);\n controller.enqueue({\n type: 'finish',\n finishReason: 'stop',\n usage: { inputTokens, outputTokens, totalTokens: inputTokens + outputTokens },\n });\n ss.streamClosed = true;\n controller.close();\n this.cleanupClient(ss);\n };\n\n if (ss.pendingToolCount > 0) {\n ss.deferredClose = doCompleteClose;\n } else {\n ss.deferredClose = null;\n doCompleteClose();\n }\n break;\n }\n\n case 'failed': {\n if (ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `Workflow failed: ${sanitizeErrorMessage(event.error.message)}`,\n cause: event.error,\n }),\n });\n ss.streamClosed = true;\n controller.close();\n this.cleanupClient(ss, true);\n break;\n }\n\n case 'closed': {\n if (ss.streamClosed) {\n break;\n }\n if (ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n\n const doClose = () => {\n if (ss.streamClosed) return;\n if (event.code !== 1000) {\n controller.enqueue({\n type: 'error',\n error: new GitLabError({\n message: `WebSocket closed unexpectedly: code=${event.code} reason=${sanitizeErrorMessage(event.reason)}`,\n statusCode: event.code,\n }),\n });\n ss.streamClosed = true;\n controller.close();\n this.cleanupClient(ss, true);\n } else {\n const inTok = Math.ceil(ss.streamedInputChars / 4);\n const outTok = Math.ceil(ss.streamedOutputChars / 4);\n controller.enqueue({\n type: 'finish',\n finishReason: 'stop',\n usage: { inputTokens: inTok, outputTokens: outTok, totalTokens: inTok + outTok },\n });\n ss.streamClosed = true;\n controller.close();\n this.cleanupClient(ss);\n }\n };\n\n if (ss.pendingToolCount > 0) {\n ss.deferredClose = doClose;\n } else {\n ss.deferredClose = null;\n doClose();\n }\n break;\n }\n }\n }\n\n // ---------------------------------------------------------------------------\n // Checkpoint content extraction\n // ---------------------------------------------------------------------------\n\n private processCheckpoint(\n ss: StreamState,\n checkpoint: NewCheckpoint,\n controller: ReadableStreamDefaultController<LanguageModelV2StreamPart>,\n nextTextId: () => string\n ): void {\n if (!checkpoint.checkpoint) {\n if (checkpoint.content) {\n if (!ss.activeTextBlockId) {\n ss.activeTextBlockId = nextTextId();\n controller.enqueue({ type: 'text-start', id: ss.activeTextBlockId });\n }\n controller.enqueue({\n type: 'text-delta',\n id: ss.activeTextBlockId,\n delta: checkpoint.content,\n });\n ss.streamedOutputChars += checkpoint.content.length;\n }\n return;\n }\n\n let parsed: CheckpointData;\n try {\n parsed = JSON.parse(checkpoint.checkpoint);\n } catch (e) {\n return;\n }\n\n const chatLog = parsed.channel_values?.ui_chat_log;\n if (!chatLog || !Array.isArray(chatLog) || chatLog.length === 0) {\n return;\n }\n\n if (\n checkpoint.status !== 'RUNNING' &&\n checkpoint.status !== 'INPUT_REQUIRED' &&\n checkpoint.status !== 'FINISHED' &&\n checkpoint.status !== 'COMPLETED'\n ) {\n return;\n }\n\n for (let i = 0; i < chatLog.length; i++) {\n const entry = chatLog[i] as UiChatLogEntry;\n if (entry.message_type !== 'agent') continue;\n\n const content = entry.content || '';\n const msgId = entry.message_id || `idx-${i}`;\n const emittedLen = ss.agentMessageEmitted.get(msgId) ?? 0;\n\n if (content.length <= emittedLen) continue;\n\n const delta = content.slice(emittedLen);\n const isSameMsg = msgId === ss.currentAgentMessageId;\n\n if (!isSameMsg && ss.activeTextBlockId) {\n controller.enqueue({ type: 'text-end', id: ss.activeTextBlockId });\n ss.activeTextBlockId = null;\n }\n\n if (!ss.activeTextBlockId) {\n ss.activeTextBlockId = nextTextId();\n controller.enqueue({ type: 'text-start', id: ss.activeTextBlockId });\n }\n controller.enqueue({\n type: 'text-delta',\n id: ss.activeTextBlockId,\n delta,\n });\n ss.streamedOutputChars += delta.length;\n\n ss.agentMessageEmitted.set(msgId, content.length);\n this.persistedAgentEmitted.set(msgId, content.length);\n ss.currentAgentMessageId = msgId;\n }\n }\n\n private async executeToolAndRespond(\n ss: StreamState,\n wsClient: GitLabWorkflowClient,\n controller: ReadableStreamDefaultController<LanguageModelV2StreamPart>,\n requestID: string,\n toolName: string,\n argsJson: string,\n toolExecutor: WorkflowToolExecutor | null\n ): Promise<void> {\n ss.pendingToolCount++;\n\n const safeEnqueue = (part: LanguageModelV2StreamPart): void => {\n if (ss.streamClosed) {\n return;\n }\n try {\n controller.enqueue(part);\n } catch {\n // Stream may have been closed between the check and enqueue\n }\n };\n\n try {\n if (toolExecutor) {\n const result = await toolExecutor(toolName, argsJson, requestID);\n wsClient.sendActionResponse(requestID, result.result, result.error);\n\n // Track tool call tokens (args as input, result as output)\n ss.streamedInputChars += argsJson.length;\n ss.streamedOutputChars += result.result.length;\n\n let toolOutput = result.result;\n let toolTitle = `${toolName} result`;\n let toolMetadata: Record<string, unknown> = { output: result.result };\n try {\n const parsed = JSON.parse(result.result);\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n if (typeof parsed.output === 'string') {\n toolOutput = parsed.output;\n } else if (parsed.output != null) {\n toolOutput = JSON.stringify(parsed.output);\n }\n if (typeof parsed.title === 'string') toolTitle = parsed.title;\n if (parsed.metadata && typeof parsed.metadata === 'object') {\n toolMetadata = {} as Record<string, unknown>;\n for (const [k, v] of Object.entries(parsed.metadata as Record<string, unknown>)) {\n toolMetadata[k] = typeof v === 'string' ? v : JSON.stringify(v);\n }\n if (!('output' in toolMetadata)) {\n toolMetadata.output = toolOutput;\n }\n }\n } else if (Array.isArray(parsed)) {\n toolOutput = JSON.stringify(parsed);\n toolMetadata = { output: toolOutput };\n }\n } catch {\n // result is plain text, use as-is\n }\n\n if (result.error) {\n let errorText: string;\n if (typeof result.error === 'string') {\n errorText = result.error;\n } else if (result.error && typeof result.error === 'object') {\n errorText = JSON.stringify(result.error);\n } else {\n errorText = String(result.error);\n }\n const errorOutput = toolOutput || errorText;\n safeEnqueue({\n type: 'tool-result',\n toolCallId: requestID,\n toolName,\n result: {\n output: errorOutput,\n title: toolTitle,\n metadata: { ...toolMetadata, error: errorText },\n },\n isError: true,\n providerExecuted: true,\n });\n } else {\n safeEnqueue({\n type: 'tool-result',\n toolCallId: requestID,\n toolName,\n result: {\n output: toolOutput,\n title: toolTitle,\n metadata: toolMetadata,\n },\n isError: false,\n providerExecuted: true,\n });\n }\n } else {\n const errorMsg = `Tool executor not configured for tool: ${toolName}`;\n wsClient.sendActionResponse(requestID, '', errorMsg);\n\n safeEnqueue({\n type: 'tool-result',\n toolCallId: requestID,\n toolName,\n result: {\n output: errorMsg,\n title: `${toolName} error`,\n metadata: { output: errorMsg },\n },\n isError: true,\n providerExecuted: true,\n });\n }\n } catch (error) {\n const rawMsg = error instanceof Error ? error.message : String(error);\n const errorMsg = sanitizeErrorMessage(rawMsg);\n wsClient.sendActionResponse(requestID, '', errorMsg);\n\n safeEnqueue({\n type: 'tool-result',\n toolCallId: requestID,\n toolName,\n result: {\n output: errorMsg,\n title: `${toolName} error`,\n metadata: { output: errorMsg },\n },\n isError: true,\n providerExecuted: true,\n });\n } finally {\n ss.pendingToolCount--;\n\n if (this.onUsageUpdate) {\n try {\n this.onUsageUpdate({\n inputTokens: Math.ceil(ss.streamedInputChars / 4),\n outputTokens: Math.ceil(ss.streamedOutputChars / 4),\n });\n } catch {\n // ignore callback errors\n }\n }\n\n if (ss.pendingToolCount <= 0 && ss.deferredClose) {\n const close = ss.deferredClose;\n ss.deferredClose = null;\n close();\n }\n }\n }\n\n private cleanupClient(ss: StreamState, clearWorkflow = false): void {\n if (ss.activeClient) {\n ss.activeClient.close();\n this.activeClients.delete(ss.activeClient);\n ss.activeClient = null;\n }\n if (clearWorkflow) {\n this.currentWorkflowId = null;\n this.persistedAgentEmitted.clear();\n }\n }\n\n // ---------------------------------------------------------------------------\n // Workflow metadata\n // ---------------------------------------------------------------------------\n\n private async buildWorkflowMetadata(): Promise<Record<string, unknown>> {\n const metadata: Record<string, unknown> = {\n extended_logging: false,\n };\n\n try {\n const workDir = this.workflowOptions.workingDirectory ?? process.cwd();\n const gitInfo = await this.getGitInfo(workDir);\n if (gitInfo.url) metadata.git_url = gitInfo.url;\n if (gitInfo.sha) metadata.git_sha = gitInfo.sha;\n if (gitInfo.branch) metadata.git_branch = gitInfo.branch;\n } catch {\n // Git info is best-effort\n }\n\n return metadata;\n }\n\n private async getGitInfo(\n workDir: string\n ): Promise<{ url?: string; sha?: string; branch?: string }> {\n const { execFile } = await import('child_process');\n const { promisify } = await import('util');\n const execFileAsync = promisify(execFile);\n const opts = { cwd: workDir, timeout: 3000 };\n\n const run = async (cmd: string, args: string[]): Promise<string | undefined> => {\n try {\n const { stdout } = await execFileAsync(cmd, args, opts);\n return stdout.trim() || undefined;\n } catch {\n return undefined;\n }\n };\n\n const [url, sha, branch] = await Promise.all([\n run('git', ['remote', 'get-url', 'origin']),\n run('git', ['rev-parse', 'HEAD']),\n run('git', ['rev-parse', '--abbrev-ref', 'HEAD']),\n ]);\n\n return { url, sha, branch };\n }\n\n // ---------------------------------------------------------------------------\n // Prompt / tool extraction helpers\n // ---------------------------------------------------------------------------\n\n /**\n * Extract the user's goal (last user message) from the AI SDK prompt.\n */\n private extractGoalFromPrompt(prompt: LanguageModelV2Message[]): string {\n for (let i = prompt.length - 1; i >= 0; i--) {\n const message = prompt[i];\n if (message.role === 'user') {\n const textParts = message.content\n .filter((part) => part.type === 'text')\n .map((part) => (part as { type: 'text'; text: string }).text);\n if (textParts.length > 0) {\n return textParts.join('\\n');\n }\n }\n }\n return '';\n }\n\n /**\n * Convert AI SDK tools to DWS McpToolDefinition format.\n */\n private extractMcpTools(options: LanguageModelV2CallOptions): McpToolDefinition[] {\n if (this.workflowOptions.mcpTools && this.workflowOptions.mcpTools.length > 0) {\n return this.workflowOptions.mcpTools;\n }\n\n if (!options.tools || options.tools.length === 0) {\n return [];\n }\n\n return options.tools\n .filter((tool): tool is LanguageModelV2FunctionTool => tool.type === 'function')\n .map((tool) => ({\n name: tool.name,\n description: tool.description || '',\n inputSchema: JSON.stringify(tool.inputSchema || { type: 'object', properties: {} }),\n }));\n }\n\n // ---------------------------------------------------------------------------\n // Payload size management\n // ---------------------------------------------------------------------------\n\n private static readonly MAX_START_REQUEST_BYTES = 4 * 1024 * 1024;\n\n /**\n * Trim mcpTools and additionalContext to fit within the DWS 4MB gRPC\n * message size limit (`MAX_MESSAGE_SIZE` in duo_workflow_service/server.py).\n *\n * DWS has no per-field limits on tool descriptions, schemas, or context items.\n * The only hard constraint is the total serialized message size.\n *\n * Strategy (progressive, only if over budget):\n * 1. Send everything as-is\n * 2. Simplify tool input schemas (strip descriptions from properties)\n * 3. Strip schemas to minimal form (type + property names only)\n * 4. Drop tools from the end until it fits\n */\n private trimPayload(\n mcpTools: McpToolDefinition[],\n additionalContext: AdditionalContext[],\n basePayloadSize: number\n ): { mcpTools: McpToolDefinition[]; additionalContext: AdditionalContext[] } {\n const budget = GitLabWorkflowLanguageModel.MAX_START_REQUEST_BYTES - basePayloadSize;\n const contextJson = JSON.stringify(additionalContext);\n\n const toolsJson = JSON.stringify(mcpTools);\n const totalSize = toolsJson.length + contextJson.length;\n\n if (totalSize <= budget) {\n return { mcpTools, additionalContext };\n }\n\n const simplifiedTools = mcpTools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: simplifySchema(tool.inputSchema),\n }));\n\n const simpSize = JSON.stringify(simplifiedTools).length + contextJson.length;\n if (simpSize <= budget) {\n return { mcpTools: simplifiedTools, additionalContext };\n }\n\n const minTools = simplifiedTools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n inputSchema: minimalSchema(tool.inputSchema),\n }));\n\n const minSize = JSON.stringify(minTools).length + contextJson.length;\n if (minSize <= budget) {\n return { mcpTools: minTools, additionalContext };\n }\n\n const keptTools = [...minTools];\n while (keptTools.length > 0) {\n const currentSize = JSON.stringify(keptTools).length + contextJson.length;\n if (currentSize <= budget) break;\n keptTools.pop();\n }\n\n return { mcpTools: keptTools, additionalContext };\n }\n\n private buildAdditionalContext(prompt: LanguageModelV2Message[]): AdditionalContext[] {\n const context: AdditionalContext[] = [];\n\n if (this.workflowOptions.additionalContext) {\n context.push(...this.workflowOptions.additionalContext);\n }\n\n for (const message of prompt) {\n if (message.role === 'system') {\n context.push({\n category: 'system_prompt',\n content: message.content,\n metadata: JSON.stringify({ role: 'system' }),\n });\n } else if (message.role === 'assistant') {\n const textContent = message.content\n .filter((part) => part.type === 'text')\n .map((part) => (part as { type: 'text'; text: string }).text)\n .join('\\n');\n if (textContent) {\n context.push({\n category: 'conversation',\n content: textContent,\n metadata: JSON.stringify({ role: 'assistant' }),\n });\n }\n }\n }\n\n return context;\n }\n}\n","/**\n * OAuth types and constants for GitLab authentication\n * Based on gitlab-vscode-extension and gitlab-lsp patterns\n */\n\nexport interface GitLabOAuthTokens {\n accessToken: string;\n refreshToken: string;\n expiresAt: number; // Unix timestamp in milliseconds\n instanceUrl: string;\n}\n\nexport interface OpenCodeAuthOAuth {\n type: 'oauth';\n refresh: string;\n access: string;\n expires: number; // Unix timestamp in milliseconds\n /** @deprecated Use enterpriseUrl instead. Kept for backwards compatibility with older auth.json files. */\n instanceUrl?: string;\n /** Instance URL as written by opencode-gitlab-auth plugin (e.g. 'https://gitlab.com') */\n enterpriseUrl?: string;\n}\n\nexport interface OpenCodeAuthApi {\n type: 'api';\n key: string;\n}\n\nexport type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;\n\n/**\n * Default OAuth client ID for GitLab.com\n * This is the same client ID used by opencode-gitlab-auth plugin.\n * The GITLAB_OAUTH_CLIENT_ID env var takes precedence if set.\n * Note: VS Code extension uses a different client ID ('36f2a70c...') but we use the opencode plugin's ID\n * to ensure token refresh works correctly with tokens created by the auth plugin.\n */\nexport const OPENCODE_GITLAB_AUTH_CLIENT_ID =\n '1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e';\n\n/**\n * @deprecated Use OPENCODE_GITLAB_AUTH_CLIENT_ID instead. This is the VS Code extension's client ID\n * and will cause refresh failures if used with tokens created by opencode-gitlab-auth.\n */\nexport const BUNDLED_CLIENT_ID = '36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5';\n\n/**\n * GitLab.com URL constant\n */\nexport const GITLAB_COM_URL = 'https://gitlab.com';\n\n/**\n * Token expiry skew in milliseconds (5 minutes)\n * Refresh tokens this many milliseconds before they expire\n */\nexport const TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000;\n\n/**\n * OAuth scopes to request\n */\nexport const OAUTH_SCOPES = ['api'];\n","/**\n * GitLab OAuth Manager\n * Handles OAuth token management, refresh, and exchange\n * Based on gitlab-vscode-extension TokenExchangeService and gitlab-lsp OAuthClientProvider\n */\n\nimport { GitLabError } from './gitlab-error';\nimport type { GitLabOAuthTokenResponse } from './gitlab-api-types';\nimport {\n type GitLabOAuthTokens,\n TOKEN_EXPIRY_SKEW_MS,\n OPENCODE_GITLAB_AUTH_CLIENT_ID,\n GITLAB_COM_URL,\n} from './gitlab-oauth-types';\n\nexport interface TokenExchangeParams {\n instanceUrl: string;\n clientId?: string;\n redirectUri?: string;\n}\n\nexport interface AuthorizationCodeParams extends TokenExchangeParams {\n code: string;\n codeVerifier: string;\n}\n\nexport interface RefreshTokenParams extends TokenExchangeParams {\n refreshToken: string;\n}\n\nexport class GitLabOAuthManager {\n private fetch: typeof fetch;\n\n constructor(fetchImpl: typeof fetch = fetch) {\n this.fetch = fetchImpl;\n }\n\n /**\n * Check if a token is expired\n */\n isTokenExpired(expiresAt: number): boolean {\n return Date.now() >= expiresAt;\n }\n\n /**\n * Check if a token needs refresh (within skew window)\n */\n needsRefresh(expiresAt: number): boolean {\n return Date.now() >= expiresAt - TOKEN_EXPIRY_SKEW_MS;\n }\n\n /**\n * Refresh tokens if needed\n * Returns the same tokens if refresh is not needed, or new tokens if refreshed\n */\n async refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens> {\n if (!this.needsRefresh(tokens.expiresAt)) {\n return tokens;\n }\n\n if (this.isTokenExpired(tokens.expiresAt)) {\n throw new GitLabError({\n message: 'OAuth token has expired and cannot be used',\n });\n }\n\n return this.exchangeRefreshToken({\n instanceUrl: tokens.instanceUrl,\n refreshToken: tokens.refreshToken,\n clientId,\n });\n }\n\n /**\n * Exchange authorization code for tokens\n * Based on gitlab-vscode-extension createOAuthAccountFromCode\n */\n async exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, code, codeVerifier, clientId, redirectUri } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'authorization_code',\n code,\n codeVerifier,\n clientId: clientId || this.getClientId(instanceUrl),\n redirectUri,\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Exchange refresh token for new tokens\n * Based on gitlab-vscode-extension TokenExchangeService\n */\n async exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens> {\n const { instanceUrl, refreshToken, clientId } = params;\n\n const tokenResponse = await this.exchangeToken({\n instanceUrl,\n grantType: 'refresh_token',\n refreshToken,\n clientId: clientId || this.getClientId(instanceUrl),\n });\n\n return this.createTokensFromResponse(tokenResponse, instanceUrl);\n }\n\n /**\n * Get the OAuth client ID for an instance.\n * Priority: env var > opencode-gitlab-auth default (for GitLab.com).\n * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId\n * that bypasses this method entirely.\n */\n private getClientId(instanceUrl: string): string {\n // Priority 1: Environment variable (allows overriding at runtime)\n const envClientId = process.env['GITLAB_OAUTH_CLIENT_ID'];\n if (envClientId) {\n return envClientId;\n }\n\n // Priority 2: Use opencode-gitlab-auth's client ID for GitLab.com\n // This ensures refresh works with tokens created by the auth plugin\n if (instanceUrl === GITLAB_COM_URL) {\n return OPENCODE_GITLAB_AUTH_CLIENT_ID;\n }\n\n throw new GitLabError({\n message: `No OAuth client ID configured for instance ${instanceUrl}. Please provide a clientId parameter or set GITLAB_OAUTH_CLIENT_ID environment variable.`,\n });\n }\n\n /**\n * Exchange token with GitLab OAuth endpoint\n * Based on gitlab-vscode-extension GitLabService.exchangeToken\n */\n private async exchangeToken(params: {\n instanceUrl: string;\n grantType: 'authorization_code' | 'refresh_token';\n code?: string;\n codeVerifier?: string;\n refreshToken?: string;\n clientId: string;\n redirectUri?: string;\n }): Promise<GitLabOAuthTokenResponse> {\n const { instanceUrl, grantType, code, codeVerifier, refreshToken, clientId, redirectUri } =\n params;\n\n const body: Record<string, string> = {\n client_id: clientId,\n grant_type: grantType,\n };\n\n if (grantType === 'authorization_code') {\n if (!code || !codeVerifier || !redirectUri) {\n throw new GitLabError({\n message:\n 'Authorization code, code verifier, and redirect URI are required for authorization_code grant',\n });\n }\n body.code = code;\n body.code_verifier = codeVerifier;\n body.redirect_uri = redirectUri;\n } else if (grantType === 'refresh_token') {\n if (!refreshToken) {\n throw new GitLabError({\n message: 'Refresh token is required for refresh_token grant',\n });\n }\n body.refresh_token = refreshToken;\n }\n\n const url = `${instanceUrl}/oauth/token`;\n\n try {\n const response = await this.fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/x-www-form-urlencoded',\n },\n body: new URLSearchParams(body).toString(),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n throw new GitLabError({\n message: `OAuth token exchange failed: ${response.status} ${response.statusText}`,\n cause: new Error(errorText),\n });\n }\n\n const data = await response.json();\n return data as GitLabOAuthTokenResponse;\n } catch (error) {\n if (error instanceof GitLabError) {\n throw error;\n }\n throw new GitLabError({\n message: `Failed to exchange OAuth token: ${error instanceof Error ? error.message : String(error)}`,\n cause: error instanceof Error ? error : undefined,\n });\n }\n }\n\n /**\n * Create GitLabOAuthTokens from token response\n */\n private createTokensFromResponse(\n response: GitLabOAuthTokenResponse,\n instanceUrl: string\n ): GitLabOAuthTokens {\n const expiresAt = this.createExpiresTimestamp(response);\n\n return {\n accessToken: response.access_token,\n refreshToken: response.refresh_token || '',\n expiresAt,\n instanceUrl,\n };\n }\n\n /**\n * Create expiry timestamp from token response\n * Based on gitlab-vscode-extension createExpiresTimestamp\n */\n private createExpiresTimestamp(response: GitLabOAuthTokenResponse): number {\n // GitLab returns created_at (Unix timestamp in seconds) and expires_in (seconds)\n const createdAt = response.created_at * 1000; // Convert to milliseconds\n const expiresIn = response.expires_in * 1000; // Convert to milliseconds\n return createdAt + expiresIn;\n }\n}\n","import { GitLabAnthropicLanguageModel } from './gitlab-anthropic-language-model';\nimport { GitLabOpenAILanguageModel } from './gitlab-openai-language-model';\nimport { GitLabWorkflowLanguageModel } from './gitlab-workflow-language-model';\nimport { GitLabError } from './gitlab-error';\nimport type { LanguageModelV2 } from '@ai-sdk/provider';\nimport { GitLabOAuthManager } from './gitlab-oauth-manager';\nimport type { OpenCodeAuth } from './gitlab-oauth-types';\nimport { getModelMapping, getValidModelsForProvider, isWorkflowModel } from './model-mappings';\nimport type { GitLabWorkflowOptions } from './gitlab-workflow-types';\nimport { VERSION } from './version';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface GitLabProvider {\n (modelId: string): LanguageModelV2;\n readonly specificationVersion: 'v2';\n languageModel(modelId: string): LanguageModelV2;\n chat(modelId: string): LanguageModelV2;\n /**\n * Create an agentic chat model with tool calling support\n *\n * @param modelId - GitLab model identifier. Some IDs automatically map to specific Anthropic models.\n * @param options - Configuration options for the agentic model\n * @returns A language model with native tool calling support via Anthropic\n *\n * @example\n * // Automatic model mapping\n * const model = gitlab.agenticChat('duo-chat-opus-4-5');\n * // Uses claude-opus-4-5-20251101\n *\n * @example\n * // Explicit model override\n * const model = gitlab.agenticChat('duo-chat', {\n * anthropicModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAnthropicLanguageModel;\n /**\n * Create a workflow chat model using GitLab Duo Agent Platform.\n *\n * Workflow models use a server-side agentic loop where GitLab's DWS drives\n * the LLM, requests tool executions from the client via WebSocket, and\n * streams text/status back.\n *\n * Requires GitLab Ultimate with Duo Enterprise add-on.\n *\n * @param modelId - Workflow model identifier (e.g., 'duo-workflow-sonnet-4-6')\n * @param options - Workflow-specific configuration\n * @returns A language model backed by the DWS WebSocket protocol\n *\n * @example\n * const model = gitlab.workflowChat('duo-workflow-sonnet-4-6', {\n * mcpTools: [...],\n * preapprovedTools: ['read_file', 'write_file'],\n * });\n */\n workflowChat(modelId: string, options?: GitLabWorkflowOptions): GitLabWorkflowLanguageModel;\n textEmbeddingModel(modelId: string): never;\n imageModel(modelId: string): never;\n}\n\nexport interface GitLabAgenticOptions {\n /**\n * Override the provider-specific model (optional).\n * Must be a valid model for the detected provider.\n *\n * For Anthropic models:\n * - 'claude-opus-4-6'\n * - 'claude-sonnet-4-6'\n * - 'claude-opus-4-5-20251101'\n * - 'claude-sonnet-4-5-20250929'\n * - 'claude-haiku-4-5-20251001'\n *\n * For OpenAI models:\n * - 'gpt-5.1-2025-11-13'\n * - 'gpt-5-mini-2025-08-07'\n * - 'gpt-5-codex'\n * - 'gpt-5.2-codex'\n *\n * @example\n * // Override with explicit model\n * const model = gitlab.agenticChat('duo-chat-opus-4-5', {\n * providerModel: 'claude-sonnet-4-5-20250929'\n * });\n */\n providerModel?: string;\n\n /**\n * Maximum tokens to generate\n * @default 8192\n */\n maxTokens?: number;\n\n /**\n * Feature flags to pass to the GitLab API\n */\n featureFlags?: Record<string, boolean>;\n\n /**\n * Custom headers for AI Gateway requests (per-model override).\n * These headers are sent to the Anthropic/OpenAI proxy endpoints.\n * Merged with provider-level aiGatewayHeaders (model-level takes precedence).\n */\n aiGatewayHeaders?: Record<string, string>;\n}\n\nexport interface GitLabProviderSettings {\n /**\n * GitLab instance URL (e.g., 'https://gitlab.com')\n * Can also be set via GITLAB_INSTANCE_URL environment variable.\n * @default 'https://gitlab.com'\n */\n instanceUrl?: string;\n\n /**\n * API token (Personal Access Token or OAuth access token)\n * Can also be set via GITLAB_TOKEN environment variable\n */\n apiKey?: string;\n\n /**\n * OAuth refresh token (optional, for OAuth flow)\n */\n refreshToken?: string;\n\n /**\n * OAuth client ID (required for OAuth flow)\n */\n clientId?: string;\n\n /**\n * OAuth redirect URI (required for OAuth flow)\n */\n redirectUri?: string;\n\n /**\n * Custom headers to include in requests\n */\n headers?: Record<string, string>;\n\n /**\n * Custom fetch implementation\n */\n fetch?: typeof fetch;\n\n /**\n * Provider name override\n */\n name?: string;\n\n /**\n * Default feature flags to pass to the GitLab API for all agentic chat models\n */\n featureFlags?: Record<string, boolean>;\n\n /**\n * AI Gateway URL for the Anthropic proxy.\n * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.\n * @default 'https://cloud.gitlab.com'\n */\n aiGatewayUrl?: string;\n\n /**\n * Custom headers to include in AI Gateway requests (Anthropic/OpenAI proxy).\n * These headers are merged with the default headers from direct_access response.\n * Default User-Agent: gitlab-ai-provider/{version}\n */\n aiGatewayHeaders?: Record<string, string>;\n}\n\n/**\n * Get OpenCode auth file path\n * Uses XDG Base Directory specification\n */\nfunction getOpenCodeAuthPath(): string {\n const homeDir = os.homedir();\n\n // Check XDG_DATA_HOME first (Linux/Mac standard)\n const xdgDataHome = process.env.XDG_DATA_HOME;\n if (xdgDataHome) {\n return path.join(xdgDataHome, 'opencode', 'auth.json');\n }\n\n // Fallback to ~/.local/share/opencode/auth.json (XDG default)\n if (process.platform !== 'win32') {\n return path.join(homeDir, '.local', 'share', 'opencode', 'auth.json');\n }\n\n // Windows fallback\n return path.join(homeDir, '.opencode', 'auth.json');\n}\n\n/**\n * Load OpenCode auth.json file\n */\nasync function loadOpenCodeAuth(instanceUrl: string): Promise<OpenCodeAuth | undefined> {\n try {\n const authPath = getOpenCodeAuthPath();\n\n if (!fs.existsSync(authPath)) {\n return undefined;\n }\n\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n\n // Priority 1: Check 'gitlab' key (used by opencode-gitlab-auth plugin)\n if (authData.gitlab?.type === 'oauth') {\n const gitlabAuth = authData.gitlab;\n // Verify it matches the requested instance URL\n if (\n gitlabAuth.enterpriseUrl === instanceUrl ||\n gitlabAuth.enterpriseUrl === instanceUrl.replace(/\\/$/, '')\n ) {\n return gitlabAuth as OpenCodeAuth;\n }\n }\n\n // Priority 2: Try to find auth for this instance by URL\n // Check both with and without trailing slash\n const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n const auth = authData[normalizedUrl] || authData[`${normalizedUrl}/`];\n\n return auth as OpenCodeAuth | undefined;\n } catch (error) {\n throw new Error(`Failed to load auth.json: ${error instanceof Error ? error.message : error}`);\n }\n}\n\n/**\n * Load GitLab API key with OAuth support\n * Priority: explicit apiKey > OAuth token > env var\n */\nasync function loadApiKey(\n options: {\n apiKey?: string;\n environmentVariableName: string;\n description: string;\n },\n instanceUrl: string,\n clientId?: string\n): Promise<string> {\n // Priority 1: Explicit apiKey\n if (options.apiKey) {\n return options.apiKey;\n }\n\n // Priority 2: OAuth token from OpenCode auth.json\n const auth = await loadOpenCodeAuth(instanceUrl);\n if (auth?.type === 'oauth') {\n const oauthManager = new GitLabOAuthManager();\n\n // Check if token needs refresh\n if (oauthManager.needsRefresh(auth.expires)) {\n try {\n const refreshed = await oauthManager.exchangeRefreshToken({\n instanceUrl,\n refreshToken: auth.refresh,\n clientId,\n });\n\n // Update stored token under 'gitlab' key (same format as opencode-gitlab-auth plugin)\n const authPath = getOpenCodeAuthPath();\n const authData = JSON.parse(fs.readFileSync(authPath, 'utf-8'));\n\n authData.gitlab = {\n type: 'oauth',\n refresh: refreshed.refreshToken,\n access: refreshed.accessToken,\n expires: refreshed.expiresAt,\n enterpriseUrl: instanceUrl, // Use enterpriseUrl to match auth plugin format\n };\n\n fs.writeFileSync(authPath, JSON.stringify(authData, null, 2), { mode: 0o600 });\n\n return refreshed.accessToken;\n } catch (error) {\n // If refresh fails, fall through to env var but remember the error\n const refreshErrorMsg = error instanceof Error ? error.message : String(error);\n // Silently handle refresh failure — avoid stdout output that interferes with TUI\n\n // Priority 3: Environment variable (fallback when refresh fails)\n const envApiKey = process.env[options.environmentVariableName];\n if (envApiKey) {\n return envApiKey;\n }\n\n // No env var fallback — throw with the refresh failure context\n throw new GitLabError({\n message:\n `OAuth token refresh failed and no fallback ${options.environmentVariableName} environment variable is set. ` +\n `Refresh error: ${refreshErrorMsg}. ` +\n `Re-authenticate with 'opencode auth login gitlab' or set ${options.environmentVariableName}.`,\n });\n }\n } else {\n return auth.access;\n }\n }\n\n // Priority 3: Environment variable\n const apiKey = process.env[options.environmentVariableName];\n\n if (!apiKey) {\n throw new GitLabError({\n message: `${options.description} API key is missing. Pass it as the 'apiKey' parameter, set the ${options.environmentVariableName} environment variable, or authenticate with 'opencode auth login gitlab'.`,\n });\n }\n\n return apiKey;\n}\n\nfunction withUserAgentSuffix(\n headers: Record<string, string>,\n suffix: string\n): Record<string, string> {\n const userAgent = headers['User-Agent'];\n return {\n ...headers,\n 'User-Agent': userAgent ? `${userAgent} ${suffix}` : suffix,\n };\n}\n\nexport function createGitLab(options: GitLabProviderSettings = {}): GitLabProvider {\n const instanceUrl =\n options.instanceUrl ?? process.env['GITLAB_INSTANCE_URL'] ?? 'https://gitlab.com';\n const providerName = options.name ?? 'gitlab';\n\n // Cache for the API key - loaded lazily on first use\n let cachedApiKey: string | undefined;\n let apiKeyPromise: Promise<string> | undefined;\n\n const getApiKey = async (): Promise<string> => {\n if (cachedApiKey) {\n return cachedApiKey;\n }\n\n if (apiKeyPromise) {\n return apiKeyPromise;\n }\n\n apiKeyPromise = loadApiKey(\n {\n apiKey: options.apiKey,\n environmentVariableName: 'GITLAB_TOKEN',\n description: 'GitLab',\n },\n instanceUrl,\n options.clientId\n );\n\n cachedApiKey = await apiKeyPromise;\n apiKeyPromise = undefined;\n return cachedApiKey;\n };\n\n /**\n * Refresh the API key by clearing the cache and re-fetching from auth provider.\n * This is called when a 401 error occurs to trigger OAuth token refresh.\n */\n const refreshApiKey = async (): Promise<void> => {\n // Clear the cached API key to force a refresh\n cachedApiKey = undefined;\n apiKeyPromise = undefined;\n\n // Re-fetch the API key, but don't pass the stale options.apiKey\n // This forces loadApiKey to read from auth.json and potentially refresh the OAuth token\n cachedApiKey = await loadApiKey(\n {\n apiKey: undefined, // Bypass stale options.apiKey to force auth.json read\n environmentVariableName: 'GITLAB_TOKEN',\n description: 'GitLab',\n },\n instanceUrl,\n options.clientId\n );\n };\n\n const getHeaders = () => {\n // For synchronous access, we need to have the key already loaded\n // or fall back to env var/explicit key\n const apiKey = cachedApiKey || options.apiKey || process.env['GITLAB_TOKEN'] || '';\n\n if (!apiKey) {\n throw new GitLabError({\n message:\n \"GitLab API key is missing. Pass it as the 'apiKey' parameter, set the GITLAB_TOKEN environment variable, or authenticate with 'opencode auth login gitlab'.\",\n });\n }\n\n return withUserAgentSuffix(\n {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n `ai-sdk-gitlab/${VERSION}`\n );\n };\n\n // Pre-load the API key asynchronously\n getApiKey().catch(() => {\n // Silently fail - will be caught when getHeaders is called\n });\n\n const createAgenticChatModel = (modelId: string, agenticOptions?: GitLabAgenticOptions) => {\n const mapping = getModelMapping(modelId);\n\n if (!mapping) {\n throw new GitLabError({\n message: `Unknown model ID: ${modelId}. Model must be registered in MODEL_MAPPINGS.`,\n });\n }\n\n if (agenticOptions?.providerModel) {\n const validModels = getValidModelsForProvider(mapping.provider);\n if (!validModels.includes(agenticOptions.providerModel)) {\n throw new GitLabError({\n message: `Invalid providerModel '${agenticOptions.providerModel}' for provider '${mapping.provider}'. Valid models: ${validModels.join(', ')}`,\n });\n }\n }\n\n const featureFlags = {\n DuoAgentPlatformNext: true as const,\n ...options.featureFlags,\n ...agenticOptions?.featureFlags,\n };\n\n const defaultAiGatewayHeaders = {\n 'User-Agent': `gitlab-ai-provider/${VERSION}`,\n };\n\n const aiGatewayHeaders = {\n ...defaultAiGatewayHeaders,\n ...options.aiGatewayHeaders,\n ...agenticOptions?.aiGatewayHeaders,\n };\n\n const baseConfig = {\n provider: `${providerName}.agentic`,\n instanceUrl,\n getHeaders,\n refreshApiKey,\n fetch: options.fetch,\n maxTokens: agenticOptions?.maxTokens,\n featureFlags,\n aiGatewayUrl: options.aiGatewayUrl,\n aiGatewayHeaders,\n };\n\n if (mapping.provider === 'openai') {\n return new GitLabOpenAILanguageModel(modelId, {\n ...baseConfig,\n openaiModel: agenticOptions?.providerModel ?? mapping.model,\n });\n }\n\n return new GitLabAnthropicLanguageModel(modelId, {\n ...baseConfig,\n anthropicModel: agenticOptions?.providerModel ?? mapping.model,\n });\n };\n\n const createWorkflowChatModel = (\n modelId: string,\n workflowOptions?: GitLabWorkflowOptions\n ): GitLabWorkflowLanguageModel => {\n const mapping = getModelMapping(modelId);\n\n if (!mapping || mapping.provider !== 'workflow') {\n throw new GitLabError({\n message: `Unknown workflow model ID: ${modelId}. Use 'duo-workflow' or a 'duo-workflow-*' model ID.`,\n });\n }\n\n return new GitLabWorkflowLanguageModel(\n modelId,\n {\n provider: `${providerName}.workflow`,\n instanceUrl,\n getHeaders,\n refreshApiKey,\n fetch: options.fetch,\n featureFlags: {\n ...options.featureFlags,\n ...workflowOptions?.featureFlags,\n },\n aiGatewayUrl: options.aiGatewayUrl,\n },\n workflowOptions\n );\n };\n\n // Default model factory - uses Anthropic backend for tool support\n const createDefaultModel = (modelId: string): LanguageModelV2 => {\n // Route workflow models to the workflow backend\n if (isWorkflowModel(modelId)) {\n return createWorkflowChatModel(modelId);\n }\n // Use Anthropic-based model by default for all models to get tool support\n return createAgenticChatModel(modelId);\n };\n\n const provider = Object.assign((modelId: string) => createDefaultModel(modelId), {\n specificationVersion: 'v2' as const,\n languageModel: createDefaultModel,\n chat: createDefaultModel,\n agenticChat: createAgenticChatModel,\n workflowChat: createWorkflowChatModel,\n }) as GitLabProvider;\n\n // Unsupported model types\n provider.textEmbeddingModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support text embedding models. Model ID: ${modelId}`,\n });\n };\n\n provider.imageModel = (modelId: string) => {\n throw new GitLabError({\n message: `GitLab provider does not support image models. Model ID: ${modelId}`,\n });\n };\n\n return provider;\n}\n\n/**\n * Default GitLab Duo provider instance\n *\n * @example\n * ```typescript\n * import { gitlab } from '@ai-sdk/gitlab';\n *\n * const model = gitlab('duo-chat');\n * ```\n */\nexport const gitlab = createGitLab();\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,iBAAsB;;;ACAtB,iBAAkB;;;ACOX,IAAM,cAAN,MAAM,qBAAoB,MAAM;AAAA,EAC5B;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,SAA6B;AACvC,UAAM,QAAQ,OAAO;AACrB,SAAK,OAAO;AACZ,SAAK,aAAa,QAAQ;AAC1B,SAAK,eAAe,QAAQ;AAC5B,SAAK,QAAQ,QAAQ;AAGrB,QAAI,MAAM,mBAAmB;AAC3B,YAAM,kBAAkB,MAAM,YAAW;AAAA,IAC3C;AAAA,EACF;AAAA,EAEA,OAAO,aAAa,UAAoB,MAA2B;AACjE,WAAO,IAAI,aAAY;AAAA,MACrB,SAAS,qBAAqB,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,MACpE,YAAY,SAAS;AAAA,MACrB,cAAc;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,cAAuB;AACrB,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,mBAA4B;AAC1B,WAAO,KAAK,eAAe;AAAA,EAC7B;AAAA,EAEA,gBAAyB;AACvB,WAAO,KAAK,eAAe,UAAa,KAAK,cAAc;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,yBAAkC;AAChC,QAAI,KAAK,eAAe,KAAK;AAC3B,aAAO;AAAA,IACT;AACA,UAAM,UAAU,KAAK,SAAS,YAAY,KAAK;AAC/C,WACE,QAAQ,SAAS,kBAAkB,KACnC,QAAQ,SAAS,oBAAoB,KACrC,QAAQ,SAAS,iBAAiB,KACjC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,SAAS;AAAA,EAE7D;AACF;;;AD3DO,IAAM,0BAA0B,aAAE,OAAO;AAAA,EAC9C,SAAS,aAAE,OAAO,aAAE,OAAO,CAAC;AAAA,EAC5B,OAAO,aAAE,OAAO;AAClB,CAAC;AAIM,IAAM,yBAAyB;AA2B/B,IAAM,2BAAN,MAA+B;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AAAA,EACT,cAAwC;AAAA,EACxC,iBAAyB;AAAA,EAEjC,YAAY,QAAkC;AAC5C,SAAK,SAAS;AACd,SAAK,UAAU,OAAO,SAAS;AAC/B,SAAK,eACH,OAAO,gBAAgB,QAAQ,IAAI,uBAAuB,KAAK;AAAA,EACnE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,eAAwB,OAAmC;AAEpF,UAAM,MAAM,KAAK,IAAI;AACrB,QAAI,CAAC,gBAAgB,KAAK,eAAe,KAAK,iBAAiB,KAAK;AAClE,aAAO,KAAK;AAAA,IACd;AAGA,QAAI,cAAc;AAChB,WAAK,gBAAgB;AAAA,IACvB;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAGtC,UAAM,cAAuC,CAAC;AAC9C,QAAI,KAAK,OAAO,gBAAgB,OAAO,KAAK,KAAK,OAAO,YAAY,EAAE,SAAS,GAAG;AAChF,kBAAY,gBAAgB,KAAK,OAAO;AAAA,IAC1C;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,GAAG,KAAK,OAAO,WAAW;AAAA,UAC1B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,WAAW;AAAA,MAClC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AAGtC,YAAI,SAAS,WAAW,OAAO,KAAK,OAAO,iBAAiB,CAAC,cAAc;AACzE,cAAI;AAEF,kBAAM,KAAK,OAAO,cAAc;AAGhC,mBAAO,MAAM,KAAK,qBAAqB,IAAI;AAAA,UAC7C,SAAS,cAAc;AAErB,kBAAM,IAAI,YAAY;AAAA,cACpB,SAAS,sCAAsC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,cACpG,YAAY,SAAS;AAAA,cACrB,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,IAAI,YAAY;AAAA,YACpB,SACE,wCAAwC,KAAK,OAAO,WAAW,4MAI5C,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,YAC1E,YAAY,SAAS;AAAA,YACrB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,sCAAsC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,UACpG,YAAY,SAAS;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,YAAM,QAAQ,wBAAwB,MAAM,IAAI;AAGhD,WAAK,cAAc;AACnB,WAAK,iBAAiB,MAAM,KAAK,KAAK;AAEtC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,sCAAsC,KAAK;AAAA,QACpD,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,uBAA+B;AAC7B,UAAM,UAAU,KAAK,aAAa,QAAQ,OAAO,EAAE;AACnD,WAAO,GAAG,OAAO;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,oBAA4B;AAC1B,UAAM,UAAU,KAAK,aAAa,QAAQ,OAAO,EAAE;AACnD,WAAO,GAAG,OAAO;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAwB;AACtB,SAAK,cAAc;AACnB,SAAK,iBAAiB;AAAA,EACxB;AACF;;;ADxGO,IAAM,+BAAN,MAA8D;AAAA,EAC1D,uBAAuB;AAAA,EACvB;AAAA,EACA,gBAA0C,CAAC;AAAA,EAEnC;AAAA,EACA;AAAA,EACT,kBAAoC;AAAA,EAE5C,YAAY,SAAiB,QAA+B;AAC1D,SAAK,UAAU;AACf,SAAK,SAAS;AAEd,SAAK,qBAAqB,IAAI,yBAAyB;AAAA,MACrD,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAmB,eAAwB,OAA2B;AAElF,UAAM,YAAY,MAAM,KAAK,mBAAmB,qBAAqB,YAAY;AAOjF,UAAM,EAAE,aAAa,UAAU,GAAG,gBAAgB,IAAI,UAAU;AAGhE,UAAM,gBAAgB;AAAA,MACpB,GAAG;AAAA,MACH,GAAG,KAAK,OAAO;AAAA,IACjB;AAEA,SAAK,kBAAkB,IAAI,WAAAA,QAAU;AAAA,MACnC,QAAQ;AAAA,MACR,WAAW,UAAU;AAAA,MACrB,SAAS,KAAK,mBAAmB,qBAAqB;AAAA,MACtD,gBAAgB;AAAA,IAClB,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAyB;AAC5C,QAAI,iBAAiB,WAAAA,QAAU,UAAU;AAEvC,UAAI,MAAM,WAAW,KAAK;AACxB,eAAO;AAAA,MACT;AAEA,YAAM,UAAU,MAAM,SAAS,YAAY,KAAK;AAChD,UACE,QAAQ,SAAS,OAAO,MACvB,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,IACzF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuB,OAAyB;AACtD,QAAI,iBAAiB,WAAAA,QAAU,UAAU;AAEvC,UAAI,MAAM,WAAW,KAAK;AACxB,cAAM,UAAU,MAAM,SAAS,YAAY,KAAK;AAChD,YACE,QAAQ,SAAS,oBAAoB,KACrC,QAAQ,SAAS,iBAAiB,KACjC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,SAAS,GACzD;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,aAAa,OAAiE;AACpF,QAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,WAAO,MACJ,OAAO,CAAC,SAA8C,KAAK,SAAS,UAAU,EAC9E,IAAI,CAAC,SAAS;AACb,YAAM,SAAS,KAAK;AACpB,aAAO;AAAA,QACL,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,eAAe;AAAA,QACjC,cAAc;AAAA,UACZ,MAAM;AAAA,UACN,YAAY,QAAQ,cAAc,CAAC;AAAA,UACnC,UAAU,QAAQ,YAAY,CAAC;AAAA,QACjC;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKQ,kBACN,YAC8C;AAC9C,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,YAAQ,WAAW,MAAM;AAAA,MACvB,KAAK;AACH,eAAO,EAAE,MAAM,OAAO;AAAA,MACxB,KAAK;AAEH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,EAAE,MAAM,MAAM;AAAA,MACvB,KAAK;AACH,eAAO,EAAE,MAAM,QAAQ,MAAM,WAAW,SAAS;AAAA,MACnD;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,cAAc,QAGpB;AACA,QAAI;AACJ,UAAM,WAAqC,CAAC;AAE5C,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,UAAU;AAC7B,wBAAgB,QAAQ;AACxB;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,QAAQ;AAC3B,cAAM,UAAyC,CAAC;AAEhD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UAChD,WAAW,KAAK,SAAS,QAAQ;AAAA,UAGjC;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAAA,QACzC;AAAA,MACF,WAAW,QAAQ,SAAS,aAAa;AACvC,cAAM,UAAyC,CAAC;AAEhD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,oBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,KAAK,KAAK,CAAC;AAAA,UAChD,WAAW,KAAK,SAAS,aAAa;AACpC,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,IAAI,KAAK;AAAA,cACT,MAAM,KAAK;AAAA,cACX,OAAO,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK;AAAA,YACxE,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,aAAa,QAAQ,CAAC;AAAA,QAC9C;AAAA,MACF,WAAW,QAAQ,SAAS,QAAQ;AAElC,cAAM,UAA4C,CAAC;AAEnD,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,eAAe;AAC/B,gBAAI;AAGJ,gBAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,QAAQ;AACtC,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,OAAO;AACL,8BAAgB,KAAK,UAAU,KAAK,MAAM;AAAA,YAC5C;AAEA,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,aAAa,KAAK;AAAA,cAClB,SAAS;AAAA,cACT,UAAU,KAAK,OAAO,KAAK,WAAW,OAAO;AAAA,YAC/C,CAAC;AAAA,UACH;AAAA,QACF;AAEA,YAAI,QAAQ,SAAS,GAAG;AACtB,mBAAS,KAAK,EAAE,MAAM,QAAQ,QAAQ,CAAC;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,WAAO,EAAE,QAAQ,eAAe,SAAS;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKQ,oBAAoB,YAAwD;AAClF,YAAQ,YAAY;AAAA,MAClB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAKd;AACD,WAAO,KAAK,oBAAoB,SAAS,KAAK;AAAA,EAChD;AAAA,EAEA,MAAc,oBACZ,SACA,SAMC;AACD,UAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAM,EAAE,QAAQ,SAAS,IAAI,KAAK,cAAc,QAAQ,MAAM;AAC9D,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,iBAAiB,KAAK,OAAO,kBAAkB;AACrD,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,SAAS,OAAO;AAAA,QAC5C,OAAO;AAAA,QACP,YAAY;AAAA,QACZ;AAAA,QACA;AAAA,QACA;AAAA,QACA,aAAa,QAAQ,aAAa;AAAA,QAClC,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,gBAAgB,QAAQ;AAAA,MAC1B,CAAC;AAED,YAAM,UAAoC,CAAC;AAE3C,iBAAW,SAAS,SAAS,SAAS;AACpC,YAAI,MAAM,SAAS,QAAQ;AACzB,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH,WAAW,MAAM,SAAS,YAAY;AACpC,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,YAAY,MAAM;AAAA,YAClB,UAAU,MAAM;AAAA,YAChB,OAAO,KAAK,UAAU,MAAM,KAAK;AAAA,UACnC,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,QAA8B;AAAA,QAClC,aAAa,SAAS,MAAM;AAAA,QAC5B,cAAc,SAAS,MAAM;AAAA,QAC7B,aAAa,SAAS,MAAM,eAAe,SAAS,MAAM;AAAA,MAC5D;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc,KAAK,oBAAoB,SAAS,WAAW;AAAA,QAC3D;AAAA,QACA,UAAU,CAAC;AAAA,MACb;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,cAAM,WAAW;AACjB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,qBAAqB,SAAS,OAAO;AAAA,UAC9C,YAAY;AAAA,UACZ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAGA,UAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,aAAK,mBAAmB,gBAAgB;AACxC,eAAO,KAAK,oBAAoB,SAAS,IAAI;AAAA,MAC/C;AAEA,UAAI,iBAAiB,WAAAA,QAAU,UAAU;AACvC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,wBAAwB,MAAM,OAAO;AAAA,UAC9C,YAAY,MAAM;AAAA,UAClB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAIZ;AACD,WAAO,KAAK,kBAAkB,SAAS,KAAK;AAAA,EAC9C;AAAA,EAEA,MAAc,kBACZ,SACA,SAKC;AACD,UAAM,SAAS,MAAM,KAAK,mBAAmB,OAAO;AACpD,UAAM,EAAE,QAAQ,SAAS,IAAI,KAAK,cAAc,QAAQ,MAAM;AAC9D,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,iBAAiB,KAAK,OAAO,kBAAkB;AACrD,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,UAAM,cAAc;AAAA,MAClB,OAAO;AAAA,MACP,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,aAAa;AAAA,MAClC,aAAa,QAAQ;AAAA,MACrB,OAAO,QAAQ;AAAA,MACf,gBAAgB,QAAQ;AAAA,MACxB,QAAQ;AAAA,IACV;AAIA,UAAM,OAAO;AAEb,UAAM,SAAS,IAAI,eAA0C;AAAA,MAC3D,OAAO,OAAO,eAAe;AAC3B,cAAM,gBAIF,CAAC;AAEL,cAAM,QAA8B;AAAA,UAClC,aAAa;AAAA,UACb,cAAc;AAAA,UACd,aAAa;AAAA,QACf;AACA,YAAI,eAA4C;AAEhD,YAAI;AACF,gBAAM,kBAAkB,OAAO,SAAS,OAAO,aAAa;AAAA,YAC1D,QAAQ,QAAQ;AAAA,UAClB,CAAC;AAGD,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,UAAU,CAAC;AAAA,UACb,CAAC;AAGD,gBAAM,IAAI,QAAc,CAACC,UAAS,WAAW;AAC3C,4BAAgB,GAAG,eAAe,CAAC,UAAU;AAC3C,kBAAI;AACF,wBAAQ,MAAM,MAAM;AAAA,kBAClB,KAAK;AACH,wBAAI,MAAM,QAAQ,OAAO;AACvB,4BAAM,cAAc,MAAM,QAAQ,MAAM;AAAA,oBAC1C;AACA,+BAAW,QAAQ;AAAA,sBACjB,MAAM;AAAA,sBACN,IAAI,MAAM,QAAQ;AAAA,sBAClB,SAAS,MAAM,QAAQ;AAAA,oBACzB,CAAC;AACD;AAAA,kBAEF,KAAK;AACH,wBAAI,MAAM,cAAc,SAAS,QAAQ;AACvC,4BAAM,SAAS,QAAQ,MAAM,KAAK;AAClC,oCAAc,MAAM,KAAK,IAAI,EAAE,MAAM,QAAQ,IAAI,OAAO;AACxD,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI;AAAA,sBACN,CAAC;AAAA,oBACH,WAAW,MAAM,cAAc,SAAS,YAAY;AAClD,oCAAc,MAAM,KAAK,IAAI;AAAA,wBAC3B,MAAM;AAAA,wBACN,YAAY,MAAM,cAAc;AAAA,wBAChC,UAAU,MAAM,cAAc;AAAA,wBAC9B,OAAO;AAAA,sBACT;AACA,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM,cAAc;AAAA,wBACxB,UAAU,MAAM,cAAc;AAAA,sBAChC,CAAC;AAAA,oBACH;AACA;AAAA,kBAEF,KAAK,uBAAuB;AAC1B,0BAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,wBAAI,MAAM,MAAM,SAAS,gBAAgB,OAAO,SAAS,QAAQ;AAC/D,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,wBACV,OAAO,MAAM,MAAM;AAAA,sBACrB,CAAC;AAAA,oBACH,WACE,MAAM,MAAM,SAAS,sBACrB,OAAO,SAAS,aAChB;AACA,4BAAM,SAAS,MAAM,MAAM;AAC3B,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,wBACV,OAAO,MAAM,MAAM;AAAA,sBACrB,CAAC;AAAA,oBACH;AACA;AAAA,kBACF;AAAA,kBAEA,KAAK,sBAAsB;AACzB,0BAAM,QAAQ,cAAc,MAAM,KAAK;AACvC,wBAAI,OAAO,SAAS,QAAQ;AAC1B,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,sBACZ,CAAC;AAAA,oBACH,WAAW,OAAO,SAAS,aAAa;AACtC,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,IAAI,MAAM;AAAA,sBACZ,CAAC;AAED,iCAAW,QAAQ;AAAA,wBACjB,MAAM;AAAA,wBACN,YAAY,MAAM;AAAA,wBAClB,UAAU,MAAM;AAAA,wBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,sBAC3C,CAAC;AAAA,oBACH;AACA,2BAAO,cAAc,MAAM,KAAK;AAChC;AAAA,kBACF;AAAA,kBAEA,KAAK;AACH,wBAAI,MAAM,OAAO;AACf,4BAAM,eAAe,MAAM,MAAM;AACjC,4BAAM,eAAe,MAAM,eAAe,KAAK,MAAM,MAAM;AAAA,oBAC7D;AACA,wBAAI,MAAM,MAAM,aAAa;AAC3B,qCAAe,KAAK,oBAAoB,MAAM,MAAM,WAAW;AAAA,oBACjE;AACA;AAAA,kBAEF,KAAK,gBAAgB;AACnB,+BAAW,QAAQ;AAAA,sBACjB,MAAM;AAAA,sBACN;AAAA,sBACA;AAAA,oBACF,CAAC;AACD;AAAA,kBACF;AAAA,gBACF;AAAA,cACF,SAAS,OAAO;AACd,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,gBACjE,CAAC;AAAA,cACH;AAAA,YACF,CAAC;AAED,4BAAgB,GAAG,OAAO,MAAM;AAC9B,cAAAA,SAAQ;AAAA,YACV,CAAC;AAED,4BAAgB,GAAG,SAAS,CAAC,UAAU;AACrC,qBAAO,KAAK;AAAA,YACd,CAAC;AAAA,UACH,CAAC;AAGD,qBAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,aAAa,GAAG;AACrD,gBAAI,MAAM,SAAS,aAAa;AAC9B,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,cACZ,CAAC;AACD,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,cAC3C,CAAC;AAAA,YACH;AAAA,UACF;AAEA,qBAAW,MAAM;AAAA,QACnB,SAAS,OAAO;AAEd,qBAAW,CAAC,EAAE,KAAK,KAAK,OAAO,QAAQ,aAAa,GAAG;AACrD,gBAAI,MAAM,SAAS,aAAa;AAC9B,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,cACZ,CAAC;AACD,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,YAAY,MAAM;AAAA,gBAClB,UAAU,MAAM;AAAA,gBAChB,OAAO,MAAM,UAAU,KAAK,OAAO,MAAM;AAAA,cAC3C,CAAC;AAAA,YACH;AAAA,UACF;AAGA,cAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,kBAAM,WAAW;AACjB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,qBAAqB,SAAS,OAAO;AAAA,gBAC9C,YAAY;AAAA,gBACZ,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAIA,cAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,iBAAK,mBAAmB,gBAAgB;AAExC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS;AAAA,gBACT,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,iBAAiB,WAAAD,QAAU,UAAU;AACvC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,wBAAwB,MAAM,OAAO;AAAA,gBAC9C,YAAY,MAAM;AAAA,gBAClB,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AAAA,UACH,OAAO;AACL,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN;AAAA,YACF,CAAC;AAAA,UACH;AACA,qBAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,SAAS,EAAE,MAAM,YAAY;AAAA,IAC/B;AAAA,EACF;AACF;;;AGhsBA,oBAAmB;;;ACWZ,IAAM,iBAA+C;AAAA;AAAA,EAE1D,qBAAqB,EAAE,UAAU,aAAa,OAAO,kBAAkB;AAAA,EACvE,uBAAuB,EAAE,UAAU,aAAa,OAAO,oBAAoB;AAAA,EAC3E,qBAAqB,EAAE,UAAU,aAAa,OAAO,2BAA2B;AAAA,EAChF,uBAAuB,EAAE,UAAU,aAAa,OAAO,6BAA6B;AAAA,EACpF,sBAAsB,EAAE,UAAU,aAAa,OAAO,4BAA4B;AAAA;AAAA,EAGlF,oBAAoB,EAAE,UAAU,UAAU,OAAO,sBAAsB,eAAe,OAAO;AAAA,EAC7F,oBAAoB,EAAE,UAAU,UAAU,OAAO,sBAAsB,eAAe,OAAO;AAAA,EAC7F,uBAAuB;AAAA,IACrB,UAAU;AAAA,IACV,OAAO;AAAA,IACP,eAAe;AAAA,EACjB;AAAA;AAAA,EAGA,wBAAwB,EAAE,UAAU,UAAU,OAAO,eAAe,eAAe,YAAY;AAAA,EAC/F,0BAA0B;AAAA,IACxB,UAAU;AAAA,IACV,OAAO;AAAA,IACP,eAAe;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKA,gBAAgB,EAAE,UAAU,YAAY,OAAO,UAAU;AAAA;AAAA;AAAA,EAIzD,wBAAwB,EAAE,UAAU,YAAY,OAAO,UAAU;AAAA,EACjE,2BAA2B;AAAA,IACzB,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,2BAA2B,EAAE,UAAU,YAAY,OAAO,oBAAoB;AAAA,EAC9E,yBAAyB;AAAA,IACvB,UAAU;AAAA,IACV,OAAO;AAAA,EACT;AAAA,EACA,0BAA0B,EAAE,UAAU,YAAY,OAAO,4BAA4B;AAAA,EACrF,yBAAyB,EAAE,UAAU,YAAY,OAAO,2BAA2B;AACrF;AAEO,SAAS,gBAAgB,SAA2C;AACzE,SAAO,eAAe,OAAO;AAC/B;AAEO,SAAS,sBAAsB,SAA4C;AAChF,SAAO,eAAe,OAAO,GAAG;AAClC;AAEO,SAAS,0BAA0B,UAAmC;AAC3E,SAAO,OAAO,OAAO,cAAc,EAChC,OAAO,CAAC,MAAM,EAAE,aAAa,QAAQ,EACrC,IAAI,CAAC,MAAM,EAAE,KAAK;AACvB;AAEO,SAAS,4BAA4B,SAAqC;AAC/E,QAAM,UAAU,eAAe,OAAO;AACtC,SAAO,SAAS,aAAa,cAAc,QAAQ,QAAQ;AAC7D;AAEO,SAAS,yBAAyB,SAAqC;AAC5E,QAAM,UAAU,eAAe,OAAO;AACtC,SAAO,SAAS,aAAa,WAAW,QAAQ,QAAQ;AAC1D;AAEO,SAAS,iBAAiB,SAAgC;AAC/D,QAAM,UAAU,eAAe,OAAO;AACtC,SAAO,SAAS,iBAAiB;AACnC;AAEO,SAAS,oBAAoB,SAA0B;AAC5D,SAAO,iBAAiB,OAAO,MAAM;AACvC;AAEO,SAAS,gBAAgB,SAA0B;AACxD,SAAO,eAAe,OAAO,GAAG,aAAa;AAC/C;AAEO,SAAS,oBAAoB,SAAqC;AACvE,QAAM,UAAU,eAAe,OAAO;AACtC,SAAO,SAAS,aAAa,aAAa,QAAQ,QAAQ;AAC5D;AAEO,IAAM,8BAAsD,OAAO;AAAA,EACxE,OAAO,QAAQ,cAAc,EAC1B,OAAO,CAAC,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,WAAW,EAC5C,IAAI,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC;AACjC;;;ADhEO,IAAM,4BAAN,MAA2D;AAAA,EACvD,uBAAuB;AAAA,EACvB;AAAA,EACA,gBAA0C,CAAC;AAAA,EAEnC;AAAA,EACA;AAAA,EACA;AAAA,EACT,eAA8B;AAAA,EAEtC,YAAY,SAAiB,QAA4B;AACvD,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,kBAAkB,OAAO,mBAAmB,oBAAoB,OAAO;AAE5E,SAAK,qBAAqB,IAAI,yBAAyB;AAAA,MACrD,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,cAAc,OAAO;AAAA,MACrB,cAAc,OAAO;AAAA,IACvB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA,EAEA,MAAc,gBAAgB,eAAwB,OAAwB;AAC5E,UAAM,YAAY,MAAM,KAAK,mBAAmB,qBAAqB,YAAY;AACjF,UAAM,EAAE,aAAa,UAAU,GAAG,gBAAgB,IAAI,UAAU;AAGhE,UAAM,gBAAgB;AAAA,MACpB,GAAG;AAAA,MACH,GAAG,KAAK,OAAO;AAAA,IACjB;AAEA,SAAK,eAAe,IAAI,cAAAE,QAAO;AAAA,MAC7B,QAAQ,UAAU;AAAA,MAClB,SAAS,KAAK,mBAAmB,kBAAkB;AAAA,MACnD,gBAAgB;AAAA,IAClB,CAAC;AAED,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,aAAa,OAAyB;AAC5C,QAAI,iBAAiB,cAAAA,QAAO,UAAU;AACpC,UAAI,MAAM,WAAW,KAAK;AACxB,eAAO;AAAA,MACT;AACA,YAAM,UAAU,MAAM,SAAS,YAAY,KAAK;AAChD,UACE,QAAQ,SAAS,OAAO,MACvB,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,KAAK,QAAQ,SAAS,SAAS,IACzF;AACA,eAAO;AAAA,MACT;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuB,OAAyB;AACtD,QAAI,iBAAiB,cAAAA,QAAO,UAAU;AAEpC,UAAI,MAAM,WAAW,KAAK;AACxB,cAAM,UAAU,MAAM,SAAS,YAAY,KAAK;AAChD,YACE,QAAQ,SAAS,oBAAoB,KACrC,QAAQ,SAAS,iBAAiB,KACjC,QAAQ,SAAS,QAAQ,KAAK,QAAQ,SAAS,SAAS,GACzD;AACA,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,aACN,OACyC;AACzC,QAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,WAAO,MACJ,OAAO,CAAC,SAA8C,KAAK,SAAS,UAAU,EAC9E,IAAI,CAAC,SAAS;AACb,YAAM,SAAS,KAAK;AACpB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,UAAU;AAAA,UACR,MAAM,KAAK;AAAA,UACX,aAAa,KAAK,eAAe;AAAA;AAAA,UAEjC,YAAY;AAAA,YACV,MAAM;AAAA,YACN,GAAG;AAAA,UACL;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACL;AAAA,EAEQ,kBACN,YACmD;AACnD,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,IACT;AAEA,YAAQ,WAAW,MAAM;AAAA,MACvB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO,EAAE,MAAM,YAAY,UAAU,EAAE,MAAM,WAAW,SAAS,EAAE;AAAA,MACrE;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEQ,cAAc,QAAuE;AAC3F,UAAM,WAAgD,CAAC;AAEvD,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,UAAU;AAC7B,iBAAS,KAAK,EAAE,MAAM,UAAU,SAAS,QAAQ,QAAQ,CAAC;AAC1D;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,QAAQ;AAC3B,cAAM,YAAY,QAAQ,QACvB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI;AAC1B,YAAI,UAAU,SAAS,GAAG;AACxB,mBAAS,KAAK,EAAE,MAAM,QAAQ,SAAS,UAAU,KAAK,IAAI,EAAE,CAAC;AAAA,QAC/D;AAAA,MACF,WAAW,QAAQ,SAAS,aAAa;AACvC,cAAM,YAAsB,CAAC;AAC7B,cAAM,YAAoD,CAAC;AAE3D,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,sBAAU,KAAK,KAAK,IAAI;AAAA,UAC1B,WAAW,KAAK,SAAS,aAAa;AACpC,sBAAU,KAAK;AAAA,cACb,IAAI,KAAK;AAAA,cACT,MAAM;AAAA,cACN,UAAU;AAAA,gBACR,MAAM,KAAK;AAAA,gBACX,WAAW,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK,UAAU,KAAK,KAAK;AAAA,cACpF;AAAA,YACF,CAAC;AAAA,UACH;AAAA,QACF;AAEA,cAAM,mBAA+D;AAAA,UACnE,MAAM;AAAA,UACN,SAAS,UAAU,SAAS,IAAI,UAAU,KAAK,IAAI,IAAI;AAAA,QACzD;AACA,YAAI,UAAU,SAAS,GAAG;AACxB,2BAAiB,aAAa;AAAA,QAChC;AACA,iBAAS,KAAK,gBAAgB;AAAA,MAChC,WAAW,QAAQ,SAAS,QAAQ;AAClC,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,eAAe;AAC/B,gBAAI;AACJ,gBAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,QAAQ;AACtC,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,OAAO;AACL,8BAAgB,KAAK,UAAU,KAAK,MAAM;AAAA,YAC5C;AACA,qBAAS,KAAK;AAAA,cACZ,MAAM;AAAA,cACN,cAAc,KAAK;AAAA,cACnB,SAAS;AAAA,YACX,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,oBACN,cAC6B;AAC7B,YAAQ,cAAc;AAAA,MACpB,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACN,OAC6C;AAC7C,QAAI,CAAC,SAAS,MAAM,WAAW,GAAG;AAChC,aAAO;AAAA,IACT;AAEA,WAAO,MACJ,OAAO,CAAC,SAA8C,KAAK,SAAS,UAAU,EAC9E,IAAI,CAAC,SAAS;AAGb,YAAM,SAAS,EAAE,GAAI,KAAK,YAAwC;AAClE,aAAO,OAAO,SAAS;AAEvB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,eAAe;AAAA,QACjC,YAAY;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,IACF,CAAC;AAAA,EACL;AAAA;AAAA;AAAA;AAAA,EAKQ,0BACN,QACgC;AAChC,UAAM,QAA8C,CAAC;AAErD,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,UAAU;AAE7B;AAAA,MACF;AAEA,UAAI,QAAQ,SAAS,QAAQ;AAC3B,cAAM,YAAY,QAAQ,QACvB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAS,KAAK,IAAI;AAC1B,YAAI,UAAU,SAAS,GAAG;AACxB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS,UAAU,IAAI,CAAC,UAAU,EAAE,MAAM,cAAuB,KAAK,EAAE;AAAA,UAC1E,CAAuC;AAAA,QACzC;AAAA,MACF,WAAW,QAAQ,SAAS,aAAa;AAEvC,cAAM,YAAsB,CAAC;AAC7B,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,QAAQ;AACxB,sBAAU,KAAK,KAAK,IAAI;AAAA,UAC1B,WAAW,KAAK,SAAS,aAAa;AAEpC,kBAAM,KAAK;AAAA,cACT,MAAM;AAAA,cACN,SAAS,KAAK;AAAA,cACd,MAAM,KAAK;AAAA,cACX,WAAW,OAAO,KAAK,UAAU,WAAW,KAAK,QAAQ,KAAK,UAAU,KAAK,KAAK;AAAA,YACpF,CAAuC;AAAA,UACzC;AAAA,QACF;AAEA,YAAI,UAAU,SAAS,GAAG;AACxB,gBAAM,KAAK;AAAA,YACT,MAAM;AAAA,YACN,MAAM;AAAA,YACN,SAAS,CAAC,EAAE,MAAM,eAAe,MAAM,UAAU,KAAK,IAAI,GAAG,aAAa,CAAC,EAAE,CAAC;AAAA,UAChF,CAAuC;AAAA,QACzC;AAAA,MACF,WAAW,QAAQ,SAAS,QAAQ;AAClC,mBAAW,QAAQ,QAAQ,SAAS;AAClC,cAAI,KAAK,SAAS,eAAe;AAC/B,gBAAI;AACJ,gBAAI,KAAK,OAAO,SAAS,QAAQ;AAC/B,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,QAAQ;AACtC,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,OAAO;AAAA,YAC9B,WAAW,KAAK,OAAO,SAAS,cAAc;AAC5C,8BAAgB,KAAK,UAAU,KAAK,OAAO,KAAK;AAAA,YAClD,OAAO;AACL,8BAAgB,KAAK,UAAU,KAAK,MAAM;AAAA,YAC5C;AACA,kBAAM,KAAK;AAAA,cACT,MAAM;AAAA,cACN,SAAS,KAAK;AAAA,cACd,QAAQ;AAAA,YACV,CAAuC;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,0BAA0B,QAAsD;AACtF,UAAM,iBAAiB,OACpB,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,EACjC,IAAI,CAAC,MAAM,EAAE,OAAO,EACpB,KAAK,IAAI;AACZ,WAAO,kBAAkB;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,uBACN,QACA,eAAwB,OACK;AAE7B,QAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAEA,YAAQ,QAAQ;AAAA,MACd,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT,KAAK;AACH,eAAO;AAAA,MACT;AACE,eAAO;AAAA,IACX;AAAA,EACF;AAAA,EAEA,MAAM,WAAW,SAKd;AACD,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,2BAA2B,SAAS,KAAK;AAAA,IACvD;AACA,WAAO,KAAK,sBAAsB,SAAS,KAAK;AAAA,EAClD;AAAA,EAEA,MAAc,sBACZ,SACA,SAMC;AACD,UAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO;AACjD,UAAM,WAAW,KAAK,cAAc,QAAQ,MAAM;AAClD,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,QACpD,OAAO;AAAA,QACP,uBAAuB;AAAA,QACvB;AAAA,QACA;AAAA,QACA,aAAa,QAAQ,aAAa;AAAA,QAClC,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,MAAM,QAAQ;AAAA,MAChB,CAAC;AAED,YAAM,SAAS,SAAS,QAAQ,CAAC;AACjC,YAAM,UAAoC,CAAC;AAE3C,UAAI,QAAQ,QAAQ,SAAS;AAC3B,gBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,OAAO,QAAQ,QAAQ,CAAC;AAAA,MAC7D;AAEA,UAAI,QAAQ,QAAQ,YAAY;AAC9B,mBAAW,YAAY,OAAO,QAAQ,YAAY;AAChD,cAAI,SAAS,SAAS,YAAY;AAChC,oBAAQ,KAAK;AAAA,cACX,MAAM;AAAA,cACN,YAAY,SAAS;AAAA,cACrB,UAAU,SAAS,SAAS;AAAA,cAC5B,OAAO,SAAS,SAAS;AAAA,YAC3B,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAEA,YAAM,QAA8B;AAAA,QAClC,aAAa,SAAS,OAAO,iBAAiB;AAAA,QAC9C,cAAc,SAAS,OAAO,qBAAqB;AAAA,QACnD,aAAa,SAAS,OAAO,gBAAgB;AAAA,MAC/C;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc,KAAK,oBAAoB,QAAQ,aAAa;AAAA,QAC5D;AAAA,QACA,UAAU,CAAC;AAAA,MACb;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,cAAM,WAAW;AACjB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,qBAAqB,SAAS,OAAO;AAAA,UAC9C,YAAY;AAAA,UACZ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,aAAK,mBAAmB,gBAAgB;AACxC,eAAO,KAAK,sBAAsB,SAAS,IAAI;AAAA,MACjD;AAEA,UAAI,iBAAiB,cAAAA,QAAO,UAAU;AACpC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,qBAAqB,MAAM,OAAO;AAAA,UAC3C,YAAY,MAAM;AAAA,UAClB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAc,2BACZ,SACA,SAMC;AACD,UAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO;AACjD,UAAM,QAAQ,KAAK,0BAA0B,QAAQ,MAAM;AAC3D,UAAM,QAAQ,KAAK,yBAAyB,QAAQ,KAAK;AACzD,UAAM,eAAe,KAAK,0BAA0B,QAAQ,MAAM;AAElE,UAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,QAAI;AACF,YAAM,WAAW,MAAM,OAAO,UAAU,OAAO;AAAA,QAC7C,OAAO;AAAA,QACP;AAAA,QACA;AAAA,QACA;AAAA,QACA,mBAAmB;AAAA,QACnB,aAAa,QAAQ;AAAA,QACrB,OAAO,QAAQ;AAAA,QACf,OAAO;AAAA,MACT,CAAC;AAED,YAAM,UAAoC,CAAC;AAC3C,UAAI,eAAe;AAGnB,iBAAW,QAAQ,SAAS,UAAU,CAAC,GAAG;AACxC,YAAI,KAAK,SAAS,aAAa,KAAK,SAAS,aAAa;AACxD,qBAAW,eAAe,KAAK,WAAW,CAAC,GAAG;AAC5C,gBAAI,YAAY,SAAS,eAAe;AACtC,sBAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,YAAY,KAAK,CAAC;AAAA,YACvD;AAAA,UACF;AAAA,QACF,WAAW,KAAK,SAAS,iBAAiB;AACxC,yBAAe;AACf,kBAAQ,KAAK;AAAA,YACX,MAAM;AAAA,YACN,YAAY,KAAK;AAAA,YACjB,UAAU,KAAK;AAAA,YACf,OAAO,KAAK;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF;AAEA,YAAM,QAA8B;AAAA,QAClC,aAAa,SAAS,OAAO,gBAAgB;AAAA,QAC7C,cAAc,SAAS,OAAO,iBAAiB;AAAA,QAC/C,aAAa,SAAS,OAAO,gBAAgB;AAAA,MAC/C;AAEA,aAAO;AAAA,QACL;AAAA,QACA,cAAc,KAAK,uBAAuB,SAAS,QAAQ,YAAY;AAAA,QACvE;AAAA,QACA,UAAU,CAAC;AAAA,MACb;AAAA,IACF,SAAS,OAAO;AAEd,UAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,cAAM,WAAW;AACjB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,qBAAqB,SAAS,OAAO;AAAA,UAC9C,YAAY;AAAA,UACZ,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAEA,UAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,aAAK,mBAAmB,gBAAgB;AACxC,eAAO,KAAK,2BAA2B,SAAS,IAAI;AAAA,MACtD;AAEA,UAAI,iBAAiB,cAAAA,QAAO,UAAU;AACpC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,qBAAqB,MAAM,OAAO;AAAA,UAC3C,YAAY,MAAM;AAAA,UAClB,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,SAAS,SAIZ;AACD,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK,yBAAyB,SAAS,KAAK;AAAA,IACrD;AACA,WAAO,KAAK,oBAAoB,SAAS,KAAK;AAAA,EAChD;AAAA,EAEA,MAAc,oBACZ,SACA,SAKC;AACD,UAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO;AACjD,UAAM,WAAW,KAAK,cAAc,QAAQ,MAAM;AAClD,UAAM,QAAQ,KAAK,aAAa,QAAQ,KAAK;AAC7C,UAAM,aACJ,QAAQ,YAAY,SAAS,SAAS,KAAK,kBAAkB,QAAQ,UAAU,IAAI;AAErF,UAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,UAAM,cAAc;AAAA,MAClB,OAAO;AAAA,MACP,uBAAuB;AAAA,MACvB;AAAA,MACA;AAAA,MACA,aAAa,QAAQ,aAAa;AAAA,MAClC,aAAa,QAAQ;AAAA,MACrB,OAAO,QAAQ;AAAA,MACf,MAAM,QAAQ;AAAA,MACd,QAAQ;AAAA,MACR,gBAAgB,EAAE,eAAe,KAAK;AAAA,IACxC;AAGA,UAAM,OAAO;AAEb,UAAM,SAAS,IAAI,eAA0C;AAAA,MAC3D,OAAO,OAAO,eAAe;AAC3B,cAAM,YAA6E,CAAC;AAEpF,cAAM,QAA8B;AAAA,UAClC,aAAa;AAAA,UACb,cAAc;AAAA,UACd,aAAa;AAAA,QACf;AACA,YAAI,eAA4C;AAChD,YAAI,cAAc;AAClB,cAAM,SAAS;AAEf,YAAI;AACF,gBAAM,eAAe,MAAM,OAAO,KAAK,YAAY,OAAO;AAAA,YACxD,GAAG;AAAA,YACH,QAAQ;AAAA,UACV,CAAC;AAED,qBAAW,QAAQ,EAAE,MAAM,gBAAgB,UAAU,CAAC,EAAE,CAAC;AAEzD,2BAAiB,SAAS,cAAc;AACtC,kBAAM,SAAS,MAAM,UAAU,CAAC;AAEhC,gBAAI,MAAM,MAAM,CAAC,aAAa;AAC5B,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM;AAAA,gBACV,SAAS,MAAM;AAAA,cACjB,CAAC;AAAA,YACH;AAEA,gBAAI,QAAQ,OAAO,SAAS;AAC1B,kBAAI,CAAC,aAAa;AAChB,2BAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,OAAO,CAAC;AACrD,8BAAc;AAAA,cAChB;AACA,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI;AAAA,gBACJ,OAAO,OAAO,MAAM;AAAA,cACtB,CAAC;AAAA,YACH;AAEA,gBAAI,QAAQ,OAAO,YAAY;AAC7B,yBAAW,MAAM,OAAO,MAAM,YAAY;AACxC,sBAAM,MAAM,GAAG;AACf,oBAAI,CAAC,UAAU,GAAG,GAAG;AACnB,4BAAU,GAAG,IAAI;AAAA,oBACf,IAAI,GAAG,MAAM;AAAA,oBACb,MAAM,GAAG,UAAU,QAAQ;AAAA,oBAC3B,WAAW;AAAA,kBACb;AACA,6BAAW,QAAQ;AAAA,oBACjB,MAAM;AAAA,oBACN,IAAI,UAAU,GAAG,EAAE;AAAA,oBACnB,UAAU,UAAU,GAAG,EAAE;AAAA,kBAC3B,CAAC;AAAA,gBACH;AACA,oBAAI,GAAG,UAAU,WAAW;AAC1B,4BAAU,GAAG,EAAE,aAAa,GAAG,SAAS;AACxC,6BAAW,QAAQ;AAAA,oBACjB,MAAM;AAAA,oBACN,IAAI,UAAU,GAAG,EAAE;AAAA,oBACnB,OAAO,GAAG,SAAS;AAAA,kBACrB,CAAC;AAAA,gBACH;AAAA,cACF;AAAA,YACF;AAEA,gBAAI,QAAQ,eAAe;AACzB,6BAAe,KAAK,oBAAoB,OAAO,aAAa;AAAA,YAC9D;AAEA,gBAAI,MAAM,OAAO;AACf,oBAAM,cAAc,MAAM,MAAM,iBAAiB;AACjD,oBAAM,eAAe,MAAM,MAAM,qBAAqB;AACtD,oBAAM,cAAc,MAAM,MAAM,gBAAgB;AAAA,YAClD;AAAA,UACF;AAEA,cAAI,aAAa;AACf,uBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,OAAO,CAAC;AAAA,UACrD;AAEA,qBAAW,CAAC,EAAE,EAAE,KAAK,OAAO,QAAQ,SAAS,GAAG;AAC9C,uBAAW,QAAQ,EAAE,MAAM,kBAAkB,IAAI,GAAG,GAAG,CAAC;AACxD,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,YAAY,GAAG;AAAA,cACf,UAAU,GAAG;AAAA,cACb,OAAO,GAAG,aAAa;AAAA,YACzB,CAAC;AAAA,UACH;AAEA,qBAAW,QAAQ,EAAE,MAAM,UAAU,cAAc,MAAM,CAAC;AAC1D,qBAAW,MAAM;AAAA,QACnB,SAAS,OAAO;AAEd,cAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,kBAAM,WAAW;AACjB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,qBAAqB,SAAS,OAAO;AAAA,gBAC9C,YAAY;AAAA,gBACZ,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,iBAAK,mBAAmB,gBAAgB;AACxC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY,EAAE,SAAS,wBAAwB,OAAO,MAAM,CAAC;AAAA,YAC1E,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,iBAAiB,cAAAA,QAAO,UAAU;AACpC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,qBAAqB,MAAM,OAAO;AAAA,gBAC3C,YAAY,MAAM;AAAA,gBAClB,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AAAA,UACH,OAAO;AACL,uBAAW,QAAQ,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,UAC7C;AACA,qBAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,EAAE,QAAQ,SAAS,EAAE,MAAM,YAAY,EAAE;AAAA,EAClD;AAAA,EAEA,MAAc,yBACZ,SACA,SAKC;AACD,UAAM,SAAS,MAAM,KAAK,gBAAgB,OAAO;AACjD,UAAM,QAAQ,KAAK,0BAA0B,QAAQ,MAAM;AAC3D,UAAM,QAAQ,KAAK,yBAAyB,QAAQ,KAAK;AACzD,UAAM,eAAe,KAAK,0BAA0B,QAAQ,MAAM;AAElE,UAAM,cAAc,KAAK,OAAO,eAAe;AAC/C,UAAM,YAAY,QAAQ,mBAAmB,KAAK,OAAO,aAAa;AAEtE,UAAM,cAAc;AAAA,MAClB,OAAO;AAAA,MACP;AAAA,MACA;AAAA,MACA;AAAA,MACA,mBAAmB;AAAA,MACnB,aAAa,QAAQ;AAAA,MACrB,OAAO,QAAQ;AAAA,MACf,OAAO;AAAA,MACP,QAAQ;AAAA,IACV;AAGA,UAAM,OAAO;AAEb,UAAM,SAAS,IAAI,eAA0C;AAAA,MAC3D,OAAO,OAAO,eAAe;AAE3B,cAAM,YAAiF,CAAC;AACxF,cAAM,QAA8B;AAAA,UAClC,aAAa;AAAA,UACb,cAAc;AAAA,UACd,aAAa;AAAA,QACf;AACA,YAAI,eAA4C;AAChD,YAAI,cAAc;AAClB,cAAM,SAAS;AAEf,YAAI;AACF,gBAAM,eAAe,MAAM,OAAO,UAAU,OAAO;AAAA,YACjD,GAAG;AAAA,YACH,QAAQ;AAAA,UACV,CAAC;AAED,qBAAW,QAAQ,EAAE,MAAM,gBAAgB,UAAU,CAAC,EAAE,CAAC;AAEzD,2BAAiB,SAAS,cAAc;AAEtC,gBAAI,MAAM,SAAS,oBAAoB;AACrC,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI,MAAM,SAAS;AAAA,gBACnB,SAAS,MAAM,SAAS;AAAA,cAC1B,CAAC;AAAA,YACH,WAAW,MAAM,SAAS,8BAA8B;AAEtD,kBAAI,MAAM,KAAK,SAAS,iBAAiB;AACvC,sBAAM,cAAc,MAAM;AAC1B,sBAAM,SAAS,MAAM,KAAK;AAC1B,0BAAU,WAAW,IAAI;AAAA,kBACvB;AAAA,kBACA,MAAM,MAAM,KAAK;AAAA,kBACjB,WAAW;AAAA,gBACb;AACA,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,IAAI;AAAA,kBACJ,UAAU,MAAM,KAAK;AAAA,gBACvB,CAAC;AAAA,cACH;AAAA,YACF,WAAW,MAAM,SAAS,8BAA8B;AACtD,kBAAI,CAAC,aAAa;AAChB,2BAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,OAAO,CAAC;AACrD,8BAAc;AAAA,cAChB;AACA,yBAAW,QAAQ;AAAA,gBACjB,MAAM;AAAA,gBACN,IAAI;AAAA,gBACJ,OAAO,MAAM;AAAA,cACf,CAAC;AAAA,YACH,WAAW,MAAM,SAAS,0CAA0C;AAElE,oBAAM,cAAc,MAAM;AAC1B,oBAAM,KAAK,UAAU,WAAW;AAChC,kBAAI,IAAI;AACN,mBAAG,aAAa,MAAM;AACtB,2BAAW,QAAQ;AAAA,kBACjB,MAAM;AAAA,kBACN,IAAI,GAAG;AAAA,kBACP,OAAO,MAAM;AAAA,gBACf,CAAC;AAAA,cACH;AAAA,YACF,WAAW,MAAM,SAAS,yCAAyC;AACjE,oBAAM,cAAc,MAAM;AAC1B,oBAAM,KAAK,UAAU,WAAW;AAChC,kBAAI,IAAI;AACN,mBAAG,YAAY,MAAM;AAAA,cACvB;AAAA,YACF,WAAW,MAAM,SAAS,sBAAsB;AAE9C,oBAAMC,gBAAe,OAAO,KAAK,SAAS,EAAE,SAAS;AACrD,6BAAe,KAAK,uBAAuB,MAAM,SAAS,QAAQA,aAAY;AAC9E,kBAAI,MAAM,SAAS,OAAO;AACxB,sBAAM,cAAc,MAAM,SAAS,MAAM,gBAAgB;AACzD,sBAAM,eAAe,MAAM,SAAS,MAAM,iBAAiB;AAC3D,sBAAM,cAAc,MAAM,SAAS,MAAM,gBAAgB;AAAA,cAC3D;AAAA,YACF;AAAA,UACF;AAEA,cAAI,aAAa;AACf,uBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,OAAO,CAAC;AAAA,UACrD;AAGA,gBAAM,eAAe,OAAO,KAAK,SAAS,EAAE,SAAS;AACrD,cAAI,gBAAgB,iBAAiB,QAAQ;AAC3C,2BAAe;AAAA,UACjB;AAEA,qBAAW,MAAM,OAAO,OAAO,SAAS,GAAG;AACzC,uBAAW,QAAQ,EAAE,MAAM,kBAAkB,IAAI,GAAG,OAAO,CAAC;AAC5D,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,YAAY,GAAG;AAAA,cACf,UAAU,GAAG;AAAA,cACb,OAAO,GAAG,aAAa;AAAA,YACzB,CAAC;AAAA,UACH;AAEA,qBAAW,QAAQ,EAAE,MAAM,UAAU,cAAc,MAAM,CAAC;AAC1D,qBAAW,MAAM;AAAA,QACnB,SAAS,OAAO;AAEd,cAAI,KAAK,uBAAuB,KAAK,GAAG;AACtC,kBAAM,WAAW;AACjB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,qBAAqB,SAAS,OAAO;AAAA,gBAC9C,YAAY;AAAA,gBACZ,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,CAAC,WAAW,KAAK,aAAa,KAAK,GAAG;AACxC,iBAAK,mBAAmB,gBAAgB;AACxC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY,EAAE,SAAS,wBAAwB,OAAO,MAAM,CAAC;AAAA,YAC1E,CAAC;AACD,uBAAW,MAAM;AACjB;AAAA,UACF;AAEA,cAAI,iBAAiB,cAAAD,QAAO,UAAU;AACpC,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,qBAAqB,MAAM,OAAO;AAAA,gBAC3C,YAAY,MAAM;AAAA,gBAClB,OAAO;AAAA,cACT,CAAC;AAAA,YACH,CAAC;AAAA,UACH,OAAO;AACL,uBAAW,QAAQ,EAAE,MAAM,SAAS,MAAM,CAAC;AAAA,UAC7C;AACA,qBAAW,MAAM;AAAA,QACnB;AAAA,MACF;AAAA,IACF,CAAC;AAED,WAAO,EAAE,QAAQ,SAAS,EAAE,MAAM,YAAY,EAAE;AAAA,EAClD;AACF;;;AEz7BA,2BAAsB;;;ACTf,IAAM,UACX,OAA6C,UAAsB;;;AC6Z9D,IAAK,eAAL,kBAAKE,kBAAL;AACL,EAAAA,cAAA,UAAO;AACP,EAAAA,cAAA,0BAAuB;AAFb,SAAAA;AAAA,GAAA;AAML,IAAM,gCAAgC;AAGtC,IAAM,2BAA2B;AAGjC,IAAM,8BAA8B;AAGpC,IAAM,8BAA8B,CAAC,eAAe;AAGpD,IAAM,iBAAiB;AAGvB,IAAM,mBAAmB;AAMzB,IAAM,mBAAmB;AAAA,EAC9B,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,cAAc;AAAA,EACd,SAAS;AAAA,EACT,eAAe;AACjB;AAGO,IAAM,2BAA2B;AAAA,EACtC,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,iBAAiB;AAAA,EACjB,iBAAiB;AACnB;AAGO,IAAM,uBAAuB;;;AFpa7B,IAAM,uBAAN,MAA2B;AAAA,EACxB,SAA2B;AAAA,EAC3B,oBAA2D;AAAA,EAC3D,oBAA2D;AAAA,EAC3D,gBAAsC;AAAA,EACtC,SAAS;AAAA,EACT,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASvB,QAAQ,SAAmC,SAAuC;AAChF,SAAK,gBAAgB,OAAO;AAC5B,SAAK,gBAAgB;AACrB,SAAK,SAAS;AACd,SAAK,YAAY;AAEjB,WAAO,IAAI,QAAc,CAACC,UAAS,WAAW;AAC5C,YAAM,QAAQ,KAAK,kBAAkB,OAAO;AAC5C,YAAM,YAAY,KAAK,sBAAsB,OAAO;AAEpD,WAAK,SAAS,IAAI,qBAAAC,QAAU,OAAO,EAAE,SAAS,UAAU,CAAC;AACzD,UAAI,WAAW;AAEf,WAAK,OAAO,SAAS,MAAM;AACzB,mBAAW;AACX,aAAK,eAAe;AACpB,aAAK,eAAe;AACpB,QAAAD,SAAQ;AAAA,MACV;AAEA,WAAK,OAAO,YAAY,CAAC,UAAkC;AACzD,YAAI;AACF,gBAAM,OAAO,OAAO,MAAM,SAAS,WAAW,MAAM,OAAO,MAAM,KAAK,SAAS;AAC/E,gBAAM,SAAS,KAAK,MAAM,IAAI;AAG9B,cAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,kBAAM,IAAI,MAAM,4CAA4C;AAAA,UAC9D;AAEA,eAAK,aAAa,MAAM;AAAA,QAC1B,SAAS,OAAO;AACd,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN,OAAO,iBAAiB,QAAQ,QAAQ,IAAI,MAAM,OAAO,KAAK,CAAC;AAAA,UACjE,CAAC;AAAA,QACH;AAAA,MACF;AAEA,WAAK,OAAO,UAAU,CAAC,UAAgC;AACrD,cAAM,QAAQ,IAAI,MAAM,oBAAoB,MAAM,WAAW,SAAS,EAAE;AACxE,YAAI,CAAC,UAAU;AACb,iBAAO,KAAK;AAAA,QACd,OAAO;AACL,eAAK,KAAK,EAAE,MAAM,UAAU,MAAM,CAAC;AAAA,QACrC;AAAA,MACF;AAEA,WAAK,OAAO,UAAU,CAAC,UAAgC;AACrD,aAAK,QAAQ;AACb,YAAI,CAAC,UAAU;AACb;AAAA,YACE,IAAI;AAAA,cACF,sCAAsC,MAAM,IAAI,WAAW,MAAM,UAAU,EAAE;AAAA,YAC/E;AAAA,UACF;AACA;AAAA,QACF;AACA,YAAI,CAAC,KAAK,QAAQ;AAChB,eAAK,KAAK;AAAA,YACR,MAAM;AAAA,YACN,MAAM,MAAM;AAAA,YACZ,QAAQ,MAAM,UAAU;AAAA,UAC1B,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,SAA6B;AAC5C,SAAK,KAAK,EAAE,cAAc,QAAQ,CAAC;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,mBAAmB,WAAmB,UAAkB,OAA6B;AACnF,SAAK,sBAAsB;AAC3B,UAAM,UAAiC;AAAA,MACrC;AAAA,MACA,mBAAmB;AAAA,QACjB;AAAA,QACA,OAAO,SAAS;AAAA,MAClB;AAAA,IACF;AACA,SAAK,KAAK,EAAE,gBAAgB,QAAQ,CAAC;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA,EAKA,OAAa;AACX,SAAK,KAAK,EAAE,cAAc,EAAE,QAAQ,iBAAiB,EAAE,CAAC;AACxD,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AAEZ,QAAI,KAAK,OAAQ;AACjB,SAAK,SAAS;AAEd,SAAK,QAAQ;AACb,UAAM,OAAO,KAAK;AAClB,SAAK,SAAS;AACd,QAAI,MAAM;AACR,UAAI,KAAK,eAAe,qBAAAC,QAAU,QAAQ,KAAK,eAAe,qBAAAA,QAAU,YAAY;AAClF,aAAK,MAAM,KAAM,gBAAgB;AAAA,MACnC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,cAAuB;AACzB,WAAO,KAAK,QAAQ,eAAe,qBAAAA,QAAU;AAAA,EAC/C;AAAA;AAAA;AAAA;AAAA,EAMQ,gBAAgB,SAAyC;AAC/D,QAAI,CAAC,QAAQ,eAAe,OAAO,QAAQ,gBAAgB,UAAU;AACnE,YAAM,IAAI,MAAM,yBAAyB;AAAA,IAC3C;AACA,UAAM,SAAS,IAAI,IAAI,QAAQ,WAAW;AAC1C,QAAI,OAAO,aAAa,YAAY,OAAO,aAAa,SAAS;AAC/D,YAAM,IAAI,MAAM,iCAAiC,OAAO,QAAQ,EAAE;AAAA,IACpE;AACA,QAAI,OAAO,YAAY,OAAO,UAAU;AACtC,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,QAAI,CAAC,QAAQ,WAAW,OAAO,QAAQ,YAAY,UAAU;AAC3D,YAAM,IAAI,MAAM,sBAAsB;AAAA,IACxC;AACA,QAAI,QAAQ,YAAY,OAAO,QAAQ,aAAa,UAAU;AAC5D,YAAM,IAAI,MAAM,2BAA2B;AAAA,IAC7C;AAAA,EACF;AAAA,EAEQ,kBAAkB,SAA2C;AAInE,UAAM,UAAU,IAAI,IAAI,QAAQ,YAAY,QAAQ,QAAQ,GAAG,CAAC;AAChE,UAAM,MAAM,IAAI,IAAI,gCAAgC,OAAO;AAC3D,QAAI,WAAW,IAAI,aAAa,WAAW,SAAS;AACpD,QAAI,QAAQ,YAAY,QAAQ,aAAa,WAAW;AAEtD,UAAI,aAAa,IAAI,kCAAkC,QAAQ,QAAQ;AAAA,IACzE;AACA,WAAO,IAAI,SAAS;AAAA,EACtB;AAAA,EAEQ,sBAAsB,SAA2D;AAEvF,UAAM,UAAkC,CAAC;AACzC,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,OAAO,GAAG;AAC1D,cAAQ,IAAI,YAAY,CAAC,IAAI;AAAA,IAC/B;AAIA,WAAO,QAAQ,cAAc;AAE7B,YAAQ,sBAAsB,IAAI;AAIlC,UAAM,YAAY,IAAI,IAAI,QAAQ,WAAW;AAC7C,UAAM,SAAS,UAAU;AACzB,YAAQ,QAAQ,IAAI;AAEpB,QAAI,QAAQ,WAAW;AACrB,cAAQ,cAAc,IAAI,QAAQ;AAAA,IACpC;AACA,QAAI,QAAQ,WAAW;AACrB,cAAQ,qBAAqB,IAAI,QAAQ;AAAA,IAC3C;AACA,QAAI,QAAQ,aAAa;AACvB,cAAQ,uBAAuB,IAAI,QAAQ;AAAA,IAC7C;AACA,QAAI,QAAQ,iBAAiB;AAC3B,cAAQ,4BAA4B,IAAI,QAAQ;AAAA,IAClD;AAGA,QAAI,CAAC,QAAQ,YAAY,GAAG;AAC1B,cAAQ,YAAY,IAAI,sBAAsB,OAAO;AAAA,IACvD;AAEA,WAAO;AAAA,EACT;AAAA,EAEQ,aAAa,QAA8B;AAEjD,QAAI,OAAO,eAAe;AACxB,YAAM,aAAa,OAAO;AAE1B,WAAK,KAAK,EAAE,MAAM,cAAc,MAAM,WAAW,CAAC;AAElD,UAAI,WAAW,WAAW,cAAc,WAAW,WAAW,aAAa;AACzE,aAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAAA,MACjC,WAAW,WAAW,WAAW,UAAU;AACzC,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,OAAO,IAAI,MAAM,WAAW,WAAW,iBAAiB;AAAA,QAC1D,CAAC;AAAA,MACH,WAAW,WAAW,WAAW,aAAa,WAAW,WAAW,aAAa;AAC/E,aAAK,KAAK,EAAE,MAAM,YAAY,CAAC;AAAA,MACjC;AACA;AAAA,IACF;AAGA,QAAI,OAAO,cAAc,OAAO,WAAW;AACzC,WAAK,KAAK;AAAA,QACR,MAAM;AAAA,QACN,WAAW,OAAO;AAAA,QAClB,MAAM,OAAO;AAAA,MACf,CAAC;AACD;AAAA,IACF;AAGA,UAAM,eAAyC;AAAA,MAC7C,CAAC,eAAe,OAAO,WAAW;AAAA,MAClC,CAAC,gBAAgB,OAAO,YAAY;AAAA,MACpC,CAAC,gBAAgB,OAAO,YAAY;AAAA,MACpC,CAAC,mBAAmB,OAAO,eAAe;AAAA,MAC1C,CAAC,eAAe,OAAO,WAAW;AAAA,MAClC,CAAC,iBAAiB,OAAO,aAAa;AAAA,MACtC,CAAC,aAAa,OAAO,SAAS;AAAA,MAC9B,CAAC,QAAQ,OAAO,IAAI;AAAA,MACpB,CAAC,SAAS,OAAO,KAAK;AAAA,MACtB,CAAC,cAAc,OAAO,UAAU;AAAA,MAChC,CAAC,iBAAiB,OAAO,aAAa;AAAA,MACtC,CAAC,kBAAkB,OAAO,cAAc;AAAA,IAC1C;AAEA,eAAW,CAAC,UAAU,IAAI,KAAK,cAAc;AAC3C,UAAI,QAAQ,OAAO,WAAW;AAC5B,aAAK,KAAK;AAAA,UACR,MAAM;AAAA,UACN,WAAW,OAAO;AAAA,UAClB;AAAA,UACA;AAAA,QACF,CAAC;AACD;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,KAAK,OAA0B;AACrC,QAAI,KAAK,QAAQ,eAAe,qBAAAA,QAAU,MAAM;AAC9C,YAAM,OAAO,KAAK,UAAU,KAAK;AACjC,WAAK,OAAO,KAAK,IAAI;AACrB,WAAK,eAAe,KAAK,IAAI;AAAA,IAC/B;AAAA,EACF;AAAA,EAEQ,wBAA8B;AACpC,UAAM,UAAU,KAAK,IAAI,IAAI,KAAK;AAClC,QAAI,WAAW,2BAA2B,GAAG;AAC3C,WAAK,KAAK,EAAE,WAAW,EAAE,WAAW,KAAK,IAAI,EAAE,EAAE,CAAC;AAAA,IACpD;AAAA,EACF;AAAA,EAEQ,KAAK,OAAkC;AAC7C,SAAK,gBAAgB,KAAK;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAuB;AAC7B,SAAK,oBAAoB,YAAY,MAAM;AACzC,UAAI,KAAK,QAAQ,eAAe,qBAAAA,QAAU,MAAM;AAG9C,YAAI;AACF,UAAC,KAAK,OAA2C,KAAK;AAAA,QACxD,QAAQ;AAAA,QAER;AAAA,MACF;AAAA,IACF,GAAG,6BAA6B;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,iBAAuB;AAC7B,SAAK,oBAAoB,YAAY,MAAM;AACzC,WAAK,KAAK,EAAE,WAAW,EAAE,WAAW,KAAK,IAAI,EAAE,EAAE,CAAC;AAAA,IACpD,GAAG,wBAAwB;AAAA,EAC7B;AAAA,EAEQ,YAAY;AAAA;AAAA;AAAA;AAAA,EAKZ,UAAgB;AACtB,QAAI,KAAK,UAAW;AACpB,SAAK,YAAY;AAEjB,QAAI,KAAK,mBAAmB;AAC1B,oBAAc,KAAK,iBAAiB;AACpC,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,KAAK,mBAAmB;AAC1B,oBAAc,KAAK,iBAAiB;AACpC,WAAK,oBAAoB;AAAA,IAC3B;AAAA,EACF;AACF;;;AGlXO,SAAS,yBAAyB,OAAe,WAAyB;AAC/E,QAAM,iBAAiB;AACvB,MAAI,eAAe,KAAK,KAAK,GAAG;AAC9B,UAAM,IAAI;AAAA,MACR,WAAW,SAAS;AAAA,IACtB;AAAA,EACF;AACF;AAMO,SAAS,YAAY,KAAqB;AAC/C,SAAO,MAAM,OAAO,GAAG,EAAE,QAAQ,MAAM,OAAO,IAAI;AACpD;AAEA,IAAM,sBAAsB,CAAC,SAAS,QAAQ;AAavC,SAAS,qBAAqB,SAAyB;AAC5D,MAAI,CAAC,QAAS,QAAO;AAErB,SAAO,QACJ,QAAQ,sCAAsC,mBAAmB,EACjE,QAAQ,iEAAiE,YAAY,EACrF,QAAQ,0DAA0D,cAAc,EAChF,QAAQ,iCAAiC,mBAAmB;AACjE;AAcO,SAAS,eACd,aACA,MACqD;AACrD,UAAQ,aAAa;AAAA,IACnB,KAAK;AACH,aAAO,EAAE,UAAU,QAAQ,MAAM,EAAE,UAAU,KAAK,SAAS,EAAE;AAAA,IAC/D,KAAK,gBAAgB;AACnB,YAAM,QAAS,KAAK,aAA0B,CAAC;AAC/C,UAAI,MAAM,UAAU,GAAG;AACrB,eAAO,EAAE,UAAU,QAAQ,MAAM,EAAE,UAAU,MAAM,CAAC,KAAK,GAAG,EAAE;AAAA,MAChE;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM,EAAE,WAAW,MAAM;AAAA,MAC3B;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM,EAAE,UAAU,KAAK,UAAU,SAAS,KAAK,SAAS;AAAA,MAC1D;AAAA,IACF,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,UAAU,KAAK;AAAA,UACf,WAAW,KAAK,aAAa,KAAK;AAAA,UAClC,WAAW,KAAK,aAAa,KAAK;AAAA,QACpC;AAAA,MACF;AAAA,IACF,KAAK,mBAAmB;AACtB,YAAM,UAAU,KAAK;AACrB,UAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,cAAM,IAAI,MAAM,2DAA2D;AAAA,MAC7E;AACA,UAAI,QAAQ,SAAS,KAAO;AAC1B,cAAM,IAAI,MAAM,qEAAqE;AAAA,MACvF;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM,EAAE,SAAS,aAAa,oBAAoB;AAAA,MACpD;AAAA,IACF;AAAA,IACA,KAAK,cAAc;AACjB,YAAM,UAAU,KAAK;AACrB,UAAI,CAAC,WAAW,OAAO,YAAY,UAAU;AAC3C,cAAM,IAAI,MAAM,sDAAsD;AAAA,MACxE;AACA,+BAAyB,SAAS,SAAS;AAE3C,YAAM,QAAS,KAAK,SAAsB,CAAC;AAC3C,YAAM,UAAW,KAAK,aAA0B,CAAC;AAEjD,iBAAW,QAAQ,OAAO;AACxB,YAAI,OAAO,SAAS,UAAU;AAC5B,mCAAyB,MAAM,MAAM;AAAA,QACvC;AAAA,MACF;AACA,iBAAW,OAAO,SAAS;AACzB,YAAI,OAAO,QAAQ,UAAU;AAC3B,mCAAyB,KAAK,UAAU;AAAA,QAC1C;AAAA,MACF;AAEA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,SAAS,CAAC,SAAS,GAAG,OAAO,GAAG,OAAO,EAAE,IAAI,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG;AAAA,UACpF,aAAa,YAAY,OAAO;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK,iBAAiB;AACpB,YAAM,SAAS,KAAK;AACpB,UAAI,CAAC,UAAU,OAAO,WAAW,UAAU;AACzC,cAAM,IAAI,MAAM,yDAAyD;AAAA,MAC3E;AACA,+BAAyB,QAAQ,aAAa;AAE9C,YAAM,UAAW,KAAK,aAA0B,CAAC;AACjD,iBAAW,OAAO,SAAS;AACzB,YAAI,OAAO,QAAQ,UAAU;AAC3B,mCAAyB,KAAK,cAAc;AAAA,QAC9C;AAAA,MACF;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,SAAS,CAAC,OAAO,QAAQ,GAAG,OAAO,EAAE,IAAI,CAAC,MAAM,YAAY,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,GAAG;AAAA,UAChF,aAAa,YAAY,MAAM;AAAA,QACjC;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK;AACH,aAAO,EAAE,UAAU,QAAQ,MAAM,EAAE,UAAU,KAAK,aAAa,IAAI,EAAE;AAAA,IACvE,KAAK;AACH,aAAO,EAAE,UAAU,QAAQ,MAAM,EAAE,SAAS,KAAK,gBAAgB,KAAK,YAAY,EAAE;AAAA,IACtF,KAAK;AACH,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,SAAS,KAAK;AAAA,UACd,MAAM,KAAK,oBAAoB,KAAK;AAAA,QACtC;AAAA,MACF;AAAA,IACF,KAAK,SAAS;AACZ,YAAM,UAAU,OAAO,KAAK,kBAAkB,KAAK,iBAAiB,EAAE;AACtE,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,mCAAmC;AAAA,MACrD;AACA,UAAI,QAAQ,SAAS,IAAI,GAAG;AAC1B,cAAM,IAAI,MAAM,2CAA2C;AAAA,MAC7D;AACA,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,SAAS,YAAY,YAAY,OAAO,CAAC;AAAA,UACzC,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,IACA,KAAK,kBAAkB;AACrB,YAAM,YAAY,OAAO,KAAK,UAAU,KAAK,EAAE,YAAY;AAC3D,YAAM,iBAAiB,CAAC,OAAO,QAAQ,OAAO,SAAS,UAAU,QAAQ,SAAS;AAClF,UAAI,CAAC,eAAe,SAAS,SAAS,GAAG;AACvC,cAAM,IAAI,MAAM,wCAAwC,SAAS,GAAG;AAAA,MACtE;AAEA,YAAM,UAAU,OAAO,KAAK,QAAQ,EAAE;AACtC,UAAI,CAAC,SAAS;AACZ,cAAM,IAAI,MAAM,kCAAkC;AAAA,MACpD;AAEA,UAAI;AACF,cAAM,YAAY,IAAI,IAAI,OAAO;AACjC,YAAI,CAAC,oBAAoB,SAAS,UAAU,QAAQ,GAAG;AACrD,gBAAM,IAAI;AAAA,YACR,uEAAuE,UAAU,QAAQ;AAAA,UAC3F;AAAA,QACF;AAAA,MACF,SAAS,GAAG;AACV,YAAI,aAAa,SAAS,EAAE,QAAQ,WAAW,iBAAiB,EAAG,OAAM;AAAA,MAE3E;AAEA,YAAM,SAAS,YAAY,SAAS;AACpC,YAAM,cAAc,YAAY,OAAO;AACvC,YAAM,UAAU,KAAK,OAAO,OAAO,YAAY,OAAO,KAAK,IAAI,CAAC,CAAC,KAAK;AACtE,aAAO;AAAA,QACL,UAAU;AAAA,QACV,MAAM;AAAA,UACJ,SAAS,cAAc,MAAM,OAAO,WAAW,GAAG,OAAO;AAAA,UACzD,aAAa,YAAY,SAAS;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,IACA;AACE,aAAO,EAAE,UAAU,aAAa,MAAM,KAAK;AAAA,EAC/C;AACF;;;ACvMA,IAAM,0BAA0B,KAAK,KAAK;AAE1C,IAAM,wBAAwB;AAE9B,SAAS,kBAAkB,MAAsB;AAC/C,QAAM,YACJ,KAAK,SAAS,wBAAwB,KAAK,MAAM,GAAG,qBAAqB,IAAI,QAAQ;AACvF,SAAO,qBAAqB,SAAS;AACvC;AAMA,IAAM,wBAAwB;AAOvB,IAAM,4BAAN,MAAgC;AAAA,EACpB;AAAA,EACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUT,aAAa,oBAAI,IAAyB;AAAA,EAElD,YAAY,QAAoC;AAC9C,SAAK,SAAS;AACd,SAAK,UAAU,OAAO,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,YAAY,oBAA4B,iBAAkC;AAChF,UAAM,OACJ,2CAA2C,wBAAwB;AACrE,WAAO,kBAAkB,GAAG,IAAI,IAAI,eAAe,KAAK;AAAA,EAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,SACJ,qBAA6B,6BAC7B,iBACA,eAAwB,OACQ;AAChC,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,WAAW,KAAK,YAAY,oBAAoB,eAAe;AAErE,UAAM,SAAS,KAAK,WAAW,IAAI,QAAQ;AAC3C,QAAI,CAAC,gBAAgB,UAAU,OAAO,YAAY,KAAK;AACrD,aAAO,OAAO;AAAA,IAChB;AAEA,QAAI,cAAc;AAChB,WAAK,WAAW,OAAO,QAAQ;AAAA,IACjC;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAEtC,UAAM,OAAgC;AAAA,MACpC,qBAAqB;AAAA,IACvB;AACA,QAAI,iBAAiB;AACnB,WAAK,oBAAoB;AAAA,IAC3B;AACA,QAAI,KAAK,OAAO,gBAAgB,OAAO,KAAK,KAAK,OAAO,YAAY,EAAE,SAAS,GAAG;AAChF,WAAK,gBAAgB,KAAK,OAAO;AAAA,IACnC;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,GAAG,KAAK,OAAO,WAAW;AAAA,UAC1B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,YAAY,kBAAkB,SAAS;AAG7C,YAAI,SAAS,WAAW,OAAO,KAAK,OAAO,iBAAiB,CAAC,cAAc;AACzE,cAAI;AACF,kBAAM,KAAK,OAAO,cAAc;AAChC,mBAAO,MAAM,KAAK,SAAS,oBAAoB,iBAAiB,IAAI;AAAA,UACtE,QAAQ;AACN,kBAAM,IAAI,YAAY;AAAA,cACpB,SAAS,iCAAiC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,cAC/F,YAAY,SAAS;AAAA,cACrB,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AAGA,YAAI,SAAS,WAAW,KAAK;AAC3B,gBAAM,IAAI,YAAY;AAAA,YACpB,SACE;AAAA,YAKF,YAAY,SAAS;AAAA,YACrB,cAAc;AAAA,UAChB,CAAC;AAAA,QACH;AAEA,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,iCAAiC,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,UAC/F,YAAY,SAAS;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAGlC,WAAK,WAAW,IAAI,UAAU;AAAA,QAC5B,OAAO;AAAA,QACP,WAAW,MAAM;AAAA,MACnB,CAAC;AAED,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,YAAa,OAAM;AACxC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,iCAAiC,KAAK;AAAA,QAC/C,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,eACJ,MACA,SAQiB;AAEjB,QAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,YAAM,IAAI,YAAY,EAAE,SAAS,kDAAkD,CAAC;AAAA,IACtF;AACA,QAAI,KAAK,SAAS,KAAO;AACvB,YAAM,IAAI,YAAY,EAAE,SAAS,kDAAkD,CAAC;AAAA,IACtF;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAEtC,UAAM,OAAgC;AAAA,MACpC;AAAA,MACA,YAAY,SAAS;AAAA,MACrB,cAAc,SAAS;AAAA,MACvB,qBAAqB,SAAS,sBAAsB;AAAA,MACpD,kBAAkB,SAAS,mBAAmB;AAAA,MAC9C,aAAa,SAAS,eAAe;AAAA,MACrC,6BAA6B,SAAS,2BAA2B;AAAA,IACnE;AAEA,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,GAAG,KAAK,OAAO,WAAW;AAAA,UAC1B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU,IAAI;AAAA,MAC3B,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,YAAY,kBAAkB,SAAS;AAC7C,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,8BAA8B,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,UAC5F,YAAY,SAAS;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAClC,aAAO,KAAK,GAAG,SAAS;AAAA,IAC1B,SAAS,OAAO;AACd,UAAI,iBAAiB,YAAa,OAAM;AACxC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,8BAA8B,KAAK;AAAA,QAC5C,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,gBAAgB,oBAA6B,iBAAgC;AAC3E,QAAI,oBAAoB;AACtB,WAAK,WAAW,OAAO,KAAK,YAAY,oBAAoB,eAAe,CAAC;AAAA,IAC9E,OAAO;AACL,WAAK,WAAW,MAAM;AAAA,IACxB;AAAA,EACF;AACF;;;AC3QA,2BAAsB;AACtB,WAAsB;;;ACoBf,IAAM,qBAAN,MAAyB;AAAA,EACtB,QAAQ,oBAAI,IAAwB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,YAAY,aAAqB,IAAI,KAAK,KAAM;AAC9C,SAAK,aAAa;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,KAAmC;AACrC,UAAM,QAAQ,KAAK,MAAM,IAAI,GAAG;AAChC,QAAI,CAAC,OAAO;AACV,aAAO;AAAA,IACT;AAGA,QAAI,KAAK,IAAI,IAAI,MAAM,WAAW;AAChC,WAAK,MAAM,OAAO,GAAG;AACrB,aAAO;AAAA,IACT;AAEA,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,IAAI,KAAa,SAAwB,KAAoB;AAC3D,SAAK,MAAM,IAAI,KAAK;AAAA,MAClB;AAAA,MACA,WAAW,KAAK,IAAI,KAAK,OAAO,KAAK;AAAA,IACvC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,KAAsB;AACxB,WAAO,KAAK,IAAI,GAAG,MAAM;AAAA,EAC3B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,KAAmB;AACxB,SAAK,MAAM,OAAO,GAAG;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,OAAe;AACjB,WAAO,KAAK,MAAM;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAgB;AACd,UAAM,MAAM,KAAK,IAAI;AACrB,eAAW,CAAC,KAAK,KAAK,KAAK,KAAK,MAAM,QAAQ,GAAG;AAC/C,UAAI,MAAM,MAAM,WAAW;AACzB,aAAK,MAAM,OAAO,GAAG;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AACF;;;ADvFO,IAAM,wBAAN,MAA4B;AAAA,EAChB;AAAA,EACA;AAAA,EACA;AAAA,EAEjB,YAAY,QAAqC;AAC/C,SAAK,SAAS;AAAA,MACZ,YAAY;AAAA;AAAA,MACZ,GAAG;AAAA,IACL;AACA,SAAK,UAAU,OAAO,SAAS;AAC/B,SAAK,QAAQ,OAAO,SAAS,IAAI,mBAAmB;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,cACJ,kBACA,aAAqB,UACU;AAE/B,UAAM,WAAgB,aAAQ,gBAAgB;AAC9C,UAAM,SAAS,KAAK,MAAM,IAAI,QAAQ;AACtC,QAAI,QAAQ;AACV,aAAO;AAAA,IACT;AAEA,QAAI;AAEF,YAAM,YAAY,MAAM,KAAK,gBAAgB,kBAAkB,UAAU;AACzE,UAAI,CAAC,WAAW;AACd,eAAO;AAAA,MACT;AAGA,YAAM,cAAc,KAAK,kBAAkB,WAAW,KAAK,OAAO,WAAW;AAC7E,UAAI,CAAC,aAAa;AAChB,eAAO;AAAA,MACT;AAGA,YAAM,UAAU,MAAM,KAAK,iBAAiB,WAAW;AAGvD,WAAK,MAAM,IAAI,UAAU,OAAO;AAEhC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,iBAAiB,cACnB,QACA,IAAI,YAAY;AAAA,QACd,SAAS,6BAA6B,KAAK;AAAA,QAC3C,OAAO;AAAA,MACT,CAAC;AAAA,IACP;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,kBAAkB,WAAmB,aAAoC;AACvE,QAAI;AAEF,YAAM,eAAe,IAAI,IAAI,WAAW,EAAE;AAG1C,YAAM,WAAW,UAAU,MAAM,+BAA+B;AAChE,UAAI,UAAU;AACZ,cAAM,CAAC,EAAE,MAAM,QAAQ,IAAI;AAE3B,cAAM,kBAAkB,KAAK,MAAM,GAAG,EAAE,CAAC;AACzC,YAAI,oBAAoB,cAAc;AAEpC,gBAAM,YAAY,SAAS,QAAQ,UAAU,EAAE;AAC/C,iBAAO,UAAU,SAAS,MAAM,IAAI,UAAU,MAAM,GAAG,EAAE,IAAI;AAAA,QAC/D;AAAA,MACF;AAGA,YAAM,aAAa,UAAU,MAAM,yCAAyC;AAC5E,UAAI,YAAY;AACd,cAAM,CAAC,EAAE,EAAE,cAAc,QAAQ,IAAI;AACrC,cAAM,OAAO,aAAa,MAAM,GAAG,EAAE,CAAC;AACtC,YAAI,SAAS,cAAc;AACzB,iBAAO,SAAS,SAAS,MAAM,IAAI,SAAS,MAAM,GAAG,EAAE,IAAI;AAAA,QAC7D;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AAEd,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,gBACJ,kBACA,aAAqB,UACG;AACxB,WAAO,IAAI,QAAQ,CAACC,aAAY;AAC9B,YAAM,YAAQ,4BAAM,OAAO,CAAC,UAAU,SAAS,UAAU,UAAU,MAAM,GAAG;AAAA,QAC1E,KAAK;AAAA,QACL,SAAS,KAAK,OAAO;AAAA,MACvB,CAAC;AAED,UAAI,SAAS;AACb,UAAI,UAAU;AAEd,YAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS;AACjC,kBAAU,KAAK,SAAS;AAAA,MAC1B,CAAC;AAED,YAAM,QAAQ,GAAG,QAAQ,CAAC,SAAS;AACjC,mBAAW,KAAK,SAAS;AAAA,MAC3B,CAAC;AAED,YAAM,GAAG,SAAS,CAAC,aAAa;AAC9B,YAAI,aAAa,KAAK,OAAO,KAAK,GAAG;AACnC,UAAAA,SAAQ,OAAO,KAAK,CAAC;AAAA,QACvB,OAAO;AACL,UAAAA,SAAQ,IAAI;AAAA,QACd;AAAA,MACF,CAAC;AAED,YAAM,GAAG,SAAS,MAAM;AAEtB,QAAAA,SAAQ,IAAI;AAAA,MACd,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,iBAAiB,aAA6C;AAElE,UAAM,cAAc,mBAAmB,WAAW;AAClD,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW,oBAAoB,WAAW;AAErE,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS,KAAK,OAAO,WAAW;AAAA,MAClC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,4BAA4B,WAAW,MAAM,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,QAC9F,CAAC;AAAA,MACH;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAQlC,aAAO;AAAA,QACL,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX,mBAAmB,KAAK;AAAA,QACxB,MAAM,KAAK;AAAA,QACX,aAAa,KAAK,WAAW;AAAA,MAC/B;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,4BAA4B,WAAW,MAAM,KAAK;AAAA,QAC3D,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,aAAmB;AACjB,SAAK,MAAM,MAAM;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA,EAKA,WAA+B;AAC7B,WAAO,KAAK;AAAA,EACd;AACF;;;AExLA,IAAM,iCAAiC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BvC,IAAM,yBAAyB,KAAK,KAAK;AAOlC,IAAM,uBAAN,MAA2B;AAAA,EACf;AAAA,EACA;AAAA,EACT,QAAQ,oBAAI,IAA6B;AAAA,EAEjD,YAAY,QAA8B;AACxC,SAAK,SAAS;AACd,SAAK,UAAU,OAAO,SAAS;AAAA,EACjC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,SAAS,iBAAoD;AACjE,UAAM,SAAS,KAAK,MAAM,IAAI,eAAe;AAC7C,QAAI,UAAU,OAAO,YAAY,KAAK,IAAI,GAAG;AAC3C,aAAO,OAAO;AAAA,IAChB;AAEA,UAAM,MAAM,GAAG,KAAK,OAAO,WAAW;AAEtC,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,QAAQ,KAAK;AAAA,QACvC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,GAAG,KAAK,OAAO,WAAW;AAAA,UAC1B,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,KAAK,UAAU;AAAA,UACnB,OAAO;AAAA,UACP,WAAW,EAAE,gBAAgB;AAAA,QAC/B,CAAC;AAAA,MACH,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,2CAA2C,SAAS,MAAM,IAAI,SAAS,UAAU,MAAM,SAAS;AAAA,UACzG,YAAY,SAAS;AAAA,UACrB,cAAc;AAAA,QAChB,CAAC;AAAA,MACH;AAEA,YAAM,OAAQ,MAAM,SAAS,KAAK;AAWlC,UAAI,KAAK,UAAU,KAAK,OAAO,SAAS,GAAG;AACzC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,mCAAmC,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,QAC1F,CAAC;AAAA,MACH;AAEA,YAAM,SAAS,KAAK,MAAM;AAC1B,YAAM,WAAW,KAAK,MAAM;AAE5B,YAAM,wBACJ,UAAU,cAAc,KAAK,CAAC,MAAM,EAAE,SAAS,yBAAyB,GAAG,WAAW;AAExF,YAAM,SAA2B;AAAA,QAC/B,cAAc,QAAQ,gBAAgB;AAAA,QACtC,kBAAkB,QAAQ,oBAAoB,CAAC;AAAA,QAC/C,aAAa,QAAQ,eAAe;AAAA,QACpC;AAAA,QACA,iBAAiB,UAAU,WAAW;AAAA,MACxC;AAEA,WAAK,MAAM,IAAI,iBAAiB;AAAA,QAC9B,MAAM;AAAA,QACN,WAAW,KAAK,IAAI,IAAI;AAAA,MAC1B,CAAC;AACD,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,YAAa,OAAM;AACxC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,2BAA2B,KAAK;AAAA,QACzC,OAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,qBACJ,iBACA,iBACwB;AACxB,UAAM,aAAa,MAAM,KAAK,SAAS,eAAe;AAGtD,QAAI,WAAW,aAAa;AAC1B,aAAO,WAAW,YAAY;AAAA,IAChC;AAGA,QAAI,mBAAmB,WAAW,uBAAuB;AACvD,YAAM,UAAU,WAAW,iBAAiB,KAAK,CAAC,MAAM,EAAE,QAAQ,eAAe;AACjF,UAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,IACF;AAGA,WAAO,WAAW,cAAc,OAAO;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA,EAKA,kBAAwB;AACtB,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;;;AC9MA,SAAoB;AACpB,IAAAC,QAAsB;AACtB,SAAoB;AACpB,aAAwB;AAYxB,SAAS,mBAA2B;AAClC,QAAM,YAAY,QAAQ,IAAI,kBAAuB,WAAQ,WAAQ,GAAG,QAAQ;AAChF,SAAY,WAAK,WAAW,YAAY,kCAAkC;AAC5E;AAEA,SAAS,gBAAgB,SAAiB,aAA8B;AACtE,QAAM,iBAAiB,eAAe,sBAAsB,QAAQ,OAAO,EAAE;AAC7E,SACG,kBAAW,QAAQ,EACnB,OAAO,GAAG,OAAO,KAAK,aAAa,EAAE,EACrC,OAAO,KAAK,EACZ,MAAM,GAAG,EAAE;AAChB;AAEO,IAAM,mBAAN,MAAuB;AAAA,EACX;AAAA,EACA;AAAA,EAEjB,YAAY,SAAiB,aAAsB;AACjD,SAAK,WAAW,iBAAiB;AACjC,SAAK,MAAM,gBAAgB,SAAS,WAAW;AAAA,EACjD;AAAA,EAEQ,UAAqB;AAC3B,QAAI;AACF,UAAI,CAAI,cAAW,KAAK,QAAQ,GAAG;AACjC,eAAO,CAAC;AAAA,MACV;AACA,YAAM,MAAS,gBAAa,KAAK,UAAU,OAAO;AAClD,aAAO,KAAK,MAAM,GAAG;AAAA,IACvB,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AAAA,EAEQ,SAAS,MAAuB;AACtC,QAAI;AACF,YAAM,MAAW,cAAQ,KAAK,QAAQ;AACtC,MAAG,aAAU,KAAK,EAAE,WAAW,MAAM,MAAM,IAAM,CAAC;AAClD,MAAG,iBAAc,KAAK,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAAA,IAChF,QAAQ;AAAA,IAER;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAA+B;AAC7B,WAAO,KAAK,QAAQ,EAAE,KAAK,GAAG,KAAK;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK,OAA8B;AACjC,UAAM,OAAO,KAAK,QAAQ;AAC1B,SAAK,KAAK,GAAG,IAAI;AACjB,SAAK,SAAS,IAAI;AAAA,EACpB;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,WAAmC;AAC/C,UAAM,WAAW,KAAK,KAAK;AAC3B,SAAK,KAAK;AAAA,MACR;AAAA,MACA,kBAAkB,UAAU,oBAAoB;AAAA,MAChD,mBAAmB,UAAU,qBAAqB;AAAA,MAClD,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,cAAc,KAAoB,MAA2B;AAC3D,UAAM,WAAW,KAAK,KAAK;AAC3B,SAAK,KAAK;AAAA,MACR,WAAW,UAAU,aAAa;AAAA,MAClC,kBAAkB;AAAA,MAClB,mBAAmB;AAAA,MACnB,YAAW,oBAAI,KAAK,GAAE,YAAY;AAAA,IACpC,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,QAAc;AACZ,UAAM,OAAO,KAAK,QAAQ;AAC1B,WAAO,KAAK,KAAK,GAAG;AACpB,QAAI,OAAO,KAAK,IAAI,EAAE,WAAW,GAAG;AAClC,UAAI;AACF,YAAO,cAAW,KAAK,QAAQ,GAAG;AAChC,UAAG,cAAW,KAAK,QAAQ;AAAA,QAC7B;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,OAAO;AACL,WAAK,SAAS,IAAI;AAAA,IACpB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,sBAAqC;AACnC,WAAO,KAAK,KAAK,GAAG,oBAAoB;AAAA,EAC1C;AAAA;AAAA;AAAA;AAAA,EAKA,uBAAsC;AACpC,WAAO,KAAK,KAAK,GAAG,qBAAqB;AAAA,EAC3C;AAAA;AAAA;AAAA;AAAA,EAKA,eAAwC;AACtC,WAAO,KAAK,KAAK,GAAG,aAAa;AAAA,EACnC;AACF;;;ACjBA,SAAS,kBAAkB,QAA0D;AACnF,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,QAAM,SAAkC,CAAC;AACzC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,QAAI,QAAQ,iBAAiB,QAAQ,cAAc,QAAQ,WAAW;AACpE;AAAA,IACF;AACA,QAAI,QAAQ,gBAAgB,OAAO,UAAU,YAAY,UAAU,MAAM;AACvE,YAAM,QAAiC,CAAC;AACxC,iBAAW,CAAC,UAAU,SAAS,KAAK,OAAO,QAAQ,KAAgC,GAAG;AACpF,YAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,gBAAM,QAAQ,IAAI,kBAAkB,SAAoC;AAAA,QAC1E,OAAO;AACL,gBAAM,QAAQ,IAAI;AAAA,QACpB;AAAA,MACF;AACA,aAAO,GAAG,IAAI;AAAA,IAChB,WAAW,QAAQ,WAAW,OAAO,UAAU,YAAY,UAAU,MAAM;AACzE,aAAO,GAAG,IAAI,kBAAkB,KAAgC;AAAA,IAClE,OAAO;AACL,aAAO,GAAG,IAAI;AAAA,IAChB;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,eAAe,WAA2B;AACjD,MAAI;AACF,WAAO,KAAK,UAAU,kBAAkB,KAAK,MAAM,SAAS,CAAC,CAAC;AAAA,EAChE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,iBAAiB,QAA0D;AAClF,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAElD,QAAM,SAAkC,EAAE,MAAM,OAAO,QAAQ,SAAS;AACxE,MAAI,OAAO,UAAU;AACnB,WAAO,WAAW,OAAO;AAAA,EAC3B;AACA,MAAI,OAAO,cAAc,OAAO,OAAO,eAAe,UAAU;AAC9D,UAAM,QAAiC,CAAC;AACxC,eAAW,CAAC,UAAU,SAAS,KAAK,OAAO;AAAA,MACzC,OAAO;AAAA,IACT,GAAG;AACD,UAAI,OAAO,cAAc,YAAY,cAAc,MAAM;AACvD,cAAM,KAAK;AACX,cAAM,QAAQ,IAAI,EAAE,MAAM,GAAG,QAAQ,SAAS;AAAA,MAChD,OAAO;AACL,cAAM,QAAQ,IAAI,EAAE,MAAM,SAAS;AAAA,MACrC;AAAA,IACF;AACA,WAAO,aAAa;AAAA,EACtB;AACA,SAAO;AACT;AAEA,SAAS,cAAc,WAA2B;AAChD,MAAI;AACF,WAAO,KAAK,UAAU,iBAAiB,KAAK,MAAM,SAAS,CAAC,CAAC;AAAA,EAC/D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AA0BO,IAAM,8BAAN,MAAM,6BAAuD;AAAA,EACzD,uBAAuB;AAAA,EACvB;AAAA,EACA,gBAA0C,CAAC;AAAA,EAEnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAGT,sBAAqC;AAAA;AAAA;AAAA;AAAA,EAKrC,oBAAmC;AAAA;AAAA;AAAA,EAInC,wBAAwB,oBAAI,IAAoB;AAAA;AAAA,EAGvC,gBAAgB,oBAAI,IAA0B;AAAA;AAAA,EAGvD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKR,IAAI,mBAAkC;AACpC,WAAO,KAAK,qBAAqB;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,iBAAiB,KAAoB;AACvC,SAAK,oBAAoB,OAAO;AAChC,SAAK,WAAW,cAAc,KAAK,KAAK,sBAAsB,IAAI;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,oBAAmC;AACrC,WAAO,KAAK,sBAAsB;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,kBAAkB,MAAqB;AACzC,SAAK,qBAAqB,QAAQ;AAClC,SAAK,WAAW,cAAc,KAAK,qBAAqB,MAAM,IAAI;AAAA,EACpE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,gBAA6C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQrD,gBAAyF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOzF,gBAEW;AAAA,EAEX,IAAI,eAA4C;AAC9C,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,aAAa,UAAuC;AACtD,QAAI,UAAU;AACZ,UAAI;AAEF,cAAM,EAAE,cAAc,IAAI,QAAQ,aAAkB;AACpD,aAAK,gBAAgB,cAAc,KAAK,QAAQ;AAAA,MAClD,QAAQ;AACN,aAAK,gBAAgB;AAAA,MACvB;AAAA,IACF,OAAO;AACL,WAAK,gBAAgB;AAAA,IACvB;AAAA,EACF;AAAA,EAEA,YACE,SACA,QACA,kBAAyC,CAAC,GAC1C;AACA,SAAK,UAAU;AACf,SAAK,SAAS;AACd,SAAK,kBAAkB;AAEvB,UAAM,UAAU,gBAAgB,oBAAoB,QAAQ,IAAI;AAChE,SAAK,aAAa,IAAI,iBAAiB,SAAS,OAAO,WAAW;AAElE,UAAM,SAAS,KAAK,WAAW,KAAK;AACpC,QAAI,QAAQ,kBAAkB;AAC5B,WAAK,oBAAoB,OAAO;AAAA,IAClC;AACA,QAAI,QAAQ,mBAAmB;AAC7B,WAAK,qBAAqB,OAAO;AAAA,IACnC;AAEA,SAAK,cAAc,IAAI,0BAA0B;AAAA,MAC/C,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,eAAe,OAAO;AAAA,MACtB,OAAO,OAAO;AAAA,MACd,cAAc,OAAO;AAAA,IACvB,CAAC;AAED,SAAK,kBAAkB,IAAI,sBAAsB;AAAA,MAC/C,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,OAAO,OAAO;AAAA,IAChB,CAAC;AAED,SAAK,iBAAiB,IAAI,qBAAqB;AAAA,MAC7C,aAAa,OAAO;AAAA,MACpB,YAAY,OAAO;AAAA,MACnB,OAAO,OAAO;AAAA,IAChB,CAAC;AAAA,EACH;AAAA,EAEA,IAAI,WAAmB;AACrB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,mBAAgD;AAC5D,QAAI,KAAK,gBAAgB,WAAW;AAClC,aAAO,KAAK,gBAAgB;AAAA,IAC9B;AAEA,QAAI,KAAK,qBAAqB;AAC5B,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,UAAU,KAAK,gBAAgB,oBAAoB,QAAQ,IAAI;AACrE,UAAM,UAAU,MAAM,KAAK,gBAAgB,cAAc,OAAO;AAChE,QAAI,SAAS;AACX,WAAK,sBAAsB,QAAQ;AACnC,aAAO,QAAQ;AAAA,IACjB;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAc,yBAAiD;AAC7D,QAAI,KAAK,gBAAgB,iBAAiB;AACxC,aAAO,KAAK,gBAAgB;AAAA,IAC9B;AAGA,QAAI,KAAK,qBAAqB,QAAW;AACvC,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,UAAU,KAAK,gBAAgB,oBAAoB,QAAQ,IAAI;AACrE,UAAM,UAAU,MAAM,KAAK,gBAAgB,cAAc,OAAO;AAChE,QAAI,SAAS,aAAa;AACxB,YAAM,MAAM,sBAAsB,QAAQ,WAAW;AACrD,WAAK,mBAAmB;AACxB,aAAO;AAAA,IACT;AAEA,SAAK,mBAAmB;AACxB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeA,MAAc,kBAAmC;AAC/C,UAAM,YAAY,oBAAoB,KAAK,OAAO;AAElD,QAAI,KAAK,YAAY,gBAAgB;AACnC,aAAO,aAAa;AAAA,IACtB;AAEA,QAAI,KAAK,mBAAmB;AAC1B,aAAO,KAAK;AAAA,IACd;AAEA,QAAI,CAAC,KAAK,mBAAmB;AAC3B,WAAK,oBAAoB,KAAK,kBAAkB;AAChD,WAAK,kBAAkB,QAAQ,MAAM;AACnC,aAAK,oBAAoB;AAAA,MAC3B,CAAC;AAAA,IACH;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,MAAc,oBAAqC;AACjD,UAAM,kBAAkB,MAAM,KAAK,uBAAuB;AAE1D,QAAI,CAAC,iBAAiB;AACpB,WAAK,oBAAoB;AACzB,aAAO;AAAA,IACT;AAEA,QAAI;AACF,YAAM,aAAa,MAAM,KAAK,eAAe,SAAS,eAAe;AACrE,WAAK,WAAW,cAAc,UAAU;AAExC,UAAI,WAAW,aAAa;AAC1B,aAAK,oBAAoB,WAAW,YAAY;AAChD,aAAK,qBAAqB,WAAW,YAAY;AACjD,aAAK,WAAW,cAAc,WAAW,YAAY,KAAK,WAAW,YAAY,IAAI;AACrF,eAAO,WAAW,YAAY;AAAA,MAChC;AAEA,YAAM,WAAW,KAAK,iBAAiB,KAAK,gBAAgB;AAC5D,UAAI,WAAW,iBAAiB,SAAS,KAAK,UAAU;AACtD,cAAM,WAAW,MAAM,SAAS,WAAW,gBAAgB;AAC3D,YAAI,UAAU;AACZ,gBAAM,QAAQ,WAAW,iBAAiB,KAAK,CAAC,MAAM,EAAE,QAAQ,QAAQ;AACxE,cAAI,OAAO;AACT,iBAAK,oBAAoB,MAAM;AAC/B,iBAAK,qBAAqB,MAAM;AAChC,iBAAK,WAAW,cAAc,MAAM,KAAK,MAAM,IAAI;AACnD,mBAAO,MAAM;AAAA,UACf;AAAA,QACF;AAAA,MACF;AAEA,UAAI,WAAW,cAAc;AAC3B,aAAK,oBAAoB,WAAW,aAAa;AACjD,aAAK,qBAAqB,WAAW,aAAa;AAClD,aAAK,WAAW,cAAc,WAAW,aAAa,KAAK,WAAW,aAAa,IAAI;AACvF,eAAO,WAAW,aAAa;AAAA,MACjC;AAAA,IACF,QAAQ;AACN,YAAM,cAAc,KAAK,WAAW,KAAK;AACzC,UAAI,aAAa,kBAAkB;AACjC,aAAK,oBAAoB,YAAY;AACrC,aAAK,qBAAqB,YAAY,qBAAqB;AAC3D,eAAO,YAAY;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,oBAAoB;AACzB,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,MAAM,eACJ,iBAC8D;AAC9D,UAAM,SAAS,MAAM,KAAK,eAAe,SAAS,eAAe;AACjE,SAAK,WAAW,cAAc,MAAM;AACpC,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAkC;AAChC,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,eAAqB;AACnB,eAAW,UAAU,KAAK,eAAe;AACvC,UAAI,OAAO,aAAa;AACtB,eAAO,KAAK;AAAA,MACd;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,gBAAsB;AACpB,SAAK,oBAAoB;AACzB,SAAK,sBAAsB,MAAM;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,aAA4B;AAC9B,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,WAAW,SAKd;AAED,UAAM,EAAE,OAAO,IAAI,MAAM,KAAK,SAAS,OAAO;AAC9C,UAAM,SAAS,OAAO,UAAU;AAEhC,UAAM,YAAsB,CAAC;AAC7B,UAAM,YAAsC,CAAC;AAC7C,QAAI,eAA4C;AAChD,UAAM,QAA8B,EAAE,aAAa,GAAG,cAAc,GAAG,aAAa,EAAE;AAEtF,QAAI;AAEF,aAAO,MAAM;AACX,cAAM,EAAE,MAAM,MAAM,IAAI,MAAM,OAAO,KAAK;AAC1C,YAAI,KAAM;AAEV,gBAAQ,MAAM,MAAM;AAAA,UAClB,KAAK;AACH,sBAAU,KAAK,MAAM,KAAK;AAC1B;AAAA,UACF,KAAK;AACH,sBAAU,KAAK;AAAA,cACb,MAAM;AAAA,cACN,YAAY,MAAM;AAAA,cAClB,UAAU,MAAM;AAAA,cAChB,OAAO,MAAM;AAAA,YACf,CAAC;AACD;AAAA,UACF,KAAK;AACH,2BAAe,MAAM;AACrB,gBAAI,MAAM,OAAO;AACf,oBAAM,cAAc,MAAM,MAAM,eAAe;AAC/C,oBAAM,eAAe,MAAM,MAAM,gBAAgB;AACjD,oBAAM,cAAc,MAAM,MAAM,eAAe;AAAA,YACjD;AACA;AAAA,UACF,KAAK;AACH,kBAAM,MAAM;AAAA,QAChB;AAAA,MACF;AAAA,IACF,UAAE;AACA,aAAO,YAAY;AAAA,IACrB;AAEA,UAAM,UAAoC,CAAC;AAC3C,UAAM,WAAW,UAAU,KAAK,EAAE;AAClC,QAAI,UAAU;AACZ,cAAQ,KAAK,EAAE,MAAM,QAAQ,MAAM,SAAS,CAAC;AAAA,IAC/C;AACA,YAAQ,KAAK,GAAG,SAAS;AAEzB,WAAO,EAAE,SAAS,cAAc,OAAO,UAAU,CAAC,EAAE;AAAA,EACtD;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,SAAS,SAGZ;AAED,UAAM,OAAO,KAAK,sBAAsB,QAAQ,MAAM;AAGtD,UAAM,WAAW,MAAM,KAAK,gBAAgB;AAG5C,UAAM,WAAW,KAAK,gBAAgB,OAAO;AAG7C,UAAM,mBAAmB,KAAK,gBAAgB,oBAAoB,SAAS,IAAI,CAAC,MAAM,EAAE,IAAI;AAG5F,UAAM,oBAAoB,KAAK,uBAAuB,QAAQ,MAAM;AAEpE,UAAM,eAAe,KAAK,gBAAgB;AAM1C,UAAM,KAAK,YAAY;AAAA,MACrB,KAAK,gBAAgB,sBAAsB;AAAA,MAC3C,KAAK,gBAAgB;AAAA,IACvB;AAGA,UAAM,YAAY,MAAM,KAAK,iBAAiB;AAE9C,QAAI;AACJ,QAAI,KAAK,mBAAmB;AAC1B,mBAAa,KAAK;AAAA,IACpB,OAAO;AACL,mBAAa,MAAM,KAAK,YAAY,eAAe,MAAM;AAAA,QACvD;AAAA,QACA,aAAa,KAAK,gBAAgB;AAAA,QAClC,oBAAoB,KAAK,gBAAgB;AAAA,MAC3C,CAAC;AACD,WAAK,oBAAoB;AAAA,IAC3B;AAGA,UAAM,WAAW,IAAI,qBAAqB;AAC1C,SAAK,cAAc,IAAI,QAAQ;AAE/B,QAAI,mBAAmB;AAKvB,UAAM,KAAkB;AAAA,MACtB,cAAc;AAAA,MACd,oBAAoB;AAAA,MACpB,qBAAqB;AAAA,MACrB,kBAAkB;AAAA,MAClB,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,qBAAqB,IAAI,IAAI,KAAK,qBAAqB;AAAA,MACvD,uBAAuB;AAAA,MACvB,cAAc;AAAA,IAChB;AAEA,eAAW,OAAO,QAAQ,QAAQ;AAChC,UAAI,IAAI,SAAS,UAAU;AACzB,WAAG,sBAAsB,IAAI,QAAQ;AAAA,MACvC,WAAW,IAAI,SAAS,QAAQ;AAC9B,mBAAW,QAAQ,IAAI,SAAS;AAC9B,cAAI,KAAK,SAAS,QAAQ;AACxB,eAAG,sBAAuB,KAA0B,KAAK;AAAA,UAC3D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,UAAM,SAAS,IAAI,eAA0C;AAAA,MAC3D,OAAO,OAAO,eAAe;AAC3B,YAAI;AAEF,gBAAM,SAAS;AAAA,YACb;AAAA,cACE,aAAa,KAAK,OAAO;AAAA,cACzB;AAAA,cACA,SAAS,KAAK,OAAO,WAAW;AAAA,cAChC,WAAW,KAAK,gBAAgB;AAAA,cAChC,aAAa,KAAK,gBAAgB;AAAA,cAClC,iBAAiB,KAAK,gBAAgB;AAAA,YACxC;AAAA,YACA,CAAC,UAA+B;AAC9B,mBAAK;AAAA,gBACH;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA,MAAM,QAAQ,kBAAkB;AAAA,cAClC;AAAA,YACF;AAAA,UACF;AAEA,gBAAM,cACJ,KAAK,gBAAgB,sBAAsB;AAC7C,gBAAM,eACJ,KAAK,gBAAgB,sBAAsB;AAC7C,gBAAM,mBAAmB,MAAM,KAAK,sBAAsB;AAC1D,gBAAM,cAAc,KAAK,UAAU,gBAAgB;AAEnD,gBAAM,cAAc;AAAA,YAClB,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,oBAAoB;AAAA,YACpB;AAAA,YACA,kBAAkB;AAAA,YAClB,oBAAoB;AAAA,YACpB,mBAAmB;AAAA,UACrB;AACA,gBAAM,WAAW,KAAK,UAAU,WAAW,EAAE,SAAS;AAEtD,gBAAM,UAAU,KAAK,YAAY,UAAU,mBAAmB,QAAQ;AAEtE,gBAAM,qBAAqB,iBAAiB;AAAA,YAAO,CAAC,SAClD,QAAQ,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,IAAI;AAAA,UAC9C;AAEA,gBAAM,WAAyB;AAAA,YAC7B,YAAY;AAAA,YACZ,eAAe;AAAA,YACf,oBAAoB;AAAA,YACpB;AAAA,YACA,kBAAkB;AAAA,YAClB,oBAAoB,QAAQ;AAAA,YAC5B,oBAAoB;AAAA,YACpB,UAAU,QAAQ;AAAA,YAClB,mBAAmB;AAAA,UACrB;AAEA,cAAI,KAAK,gBAAgB,YAAY;AACnC,qBAAS,aAAa,KAAK,gBAAgB;AAAA,UAC7C;AACA,cAAI,KAAK,gBAAgB,yBAAyB;AAChD,qBAAS,0BAA0B,KAAK,gBAAgB;AAAA,UAC1D;AAEA,mBAAS,iBAAiB,QAAQ;AAGlC,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,UAAU,CAAC;AAAA,UACb,CAAC;AAGD,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,IAAI;AAAA,YACJ,SAAS;AAAA,UACX,CAAC;AAAA,QACH,SAAS,OAAO;AACd,cAAI,CAAC,GAAG,cAAc;AACpB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OACE,iBAAiB,cACb,QACA,IAAI,YAAY;AAAA,gBACd,SAAS,+BAA+B,KAAK;AAAA,gBAC7C,OAAO;AAAA,cACT,CAAC;AAAA,YACT,CAAC;AACD,eAAG,eAAe;AAClB,uBAAW,MAAM;AAAA,UACnB;AAAA,QACF;AAAA,MACF;AAAA,MACA,QAAQ,CAAC,YAAY;AACnB,iBAAS,KAAK;AACd,iBAAS,MAAM;AACf,aAAK,cAAc,OAAO,QAAQ;AAClC,WAAG,eAAe;AAClB,aAAK,oBAAoB;AAAA,MAC3B;AAAA,IACF,CAAC;AAED,WAAO;AAAA,MACL;AAAA,MACA,SAAS;AAAA,QACP,MAAM,EAAE,YAAY,UAAU,KAAK;AAAA,MACrC;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,oBACN,IACA,OACA,YACA,UACA,cACA,YACM;AACN,QAAI,GAAG,cAAc;AACnB;AAAA,IACF;AAEA,YAAQ,MAAM,MAAM;AAAA,MAClB,KAAK,cAAc;AACjB,aAAK,kBAAkB,IAAI,MAAM,MAAM,YAAY,UAAU;AAC7D;AAAA,MACF;AAAA,MAEA,KAAK,gBAAgB;AACnB,cAAM,EAAE,WAAW,KAAK,IAAI;AAC5B,YAAI;AACJ,YAAI;AACF,eAAK,MAAM,KAAK,IAAI;AACpB,uBAAa,KAAK;AAAA,QACpB,QAAQ;AACN,uBAAa,KAAK,QAAQ;AAAA,QAC5B;AAEA,YAAI,GAAG,mBAAmB;AACxB,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,aAAG,oBAAoB;AAAA,QACzB;AAEA,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,UAAU,KAAK;AAAA,UACf,kBAAkB;AAAA,QACpB,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,QACT,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI;AAAA,QACN,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,YAAY;AAAA,UACZ,UAAU,KAAK;AAAA,UACf,OAAO;AAAA,UACP,kBAAkB;AAAA,QACpB,CAAC;AAED,aAAK;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA,KAAK;AAAA,UACL;AAAA,UACA;AAAA,QACF,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAChB;AAAA,MACF;AAAA,MAEA,KAAK,wBAAwB;AAC3B,cAAM,SAAS,eAAe,MAAM,UAAU,MAAM,IAAI;AACxD,cAAM,aAAa,KAAK,UAAU,OAAO,IAAI;AAE7C,YAAI,GAAG,mBAAmB;AACxB,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,aAAG,oBAAoB;AAAA,QACzB;AAEA,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,UAAU,OAAO;AAAA,UACjB,kBAAkB;AAAA,QACpB,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,UACV,OAAO;AAAA,QACT,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI,MAAM;AAAA,QACZ,CAAC;AACD,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,YAAY,MAAM;AAAA,UAClB,UAAU,OAAO;AAAA,UACjB,OAAO;AAAA,UACP,kBAAkB;AAAA,QACpB,CAAC;AAED,aAAK;AAAA,UACH;AAAA,UACA;AAAA,UACA;AAAA,UACA,MAAM;AAAA,UACN,OAAO;AAAA,UACP;AAAA,UACA;AAAA,QACF,EAAE,MAAM,MAAM;AAAA,QAAC,CAAC;AAChB;AAAA,MACF;AAAA,MAEA,KAAK,aAAa;AAChB,YAAI,GAAG,mBAAmB;AACxB,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,aAAG,oBAAoB;AAAA,QACzB;AAEA,cAAM,kBAAkB,MAAM;AAC5B,cAAI,GAAG,aAAc;AAGrB,gBAAM,cAAc,KAAK,KAAK,GAAG,qBAAqB,CAAC;AACvD,gBAAM,eAAe,KAAK,KAAK,GAAG,sBAAsB,CAAC;AACzD,qBAAW,QAAQ;AAAA,YACjB,MAAM;AAAA,YACN,cAAc;AAAA,YACd,OAAO,EAAE,aAAa,cAAc,aAAa,cAAc,aAAa;AAAA,UAC9E,CAAC;AACD,aAAG,eAAe;AAClB,qBAAW,MAAM;AACjB,eAAK,cAAc,EAAE;AAAA,QACvB;AAEA,YAAI,GAAG,mBAAmB,GAAG;AAC3B,aAAG,gBAAgB;AAAA,QACrB,OAAO;AACL,aAAG,gBAAgB;AACnB,0BAAgB;AAAA,QAClB;AACA;AAAA,MACF;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,GAAG,mBAAmB;AACxB,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,aAAG,oBAAoB;AAAA,QACzB;AACA,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,OAAO,IAAI,YAAY;AAAA,YACrB,SAAS,oBAAoB,qBAAqB,MAAM,MAAM,OAAO,CAAC;AAAA,YACtE,OAAO,MAAM;AAAA,UACf,CAAC;AAAA,QACH,CAAC;AACD,WAAG,eAAe;AAClB,mBAAW,MAAM;AACjB,aAAK,cAAc,IAAI,IAAI;AAC3B;AAAA,MACF;AAAA,MAEA,KAAK,UAAU;AACb,YAAI,GAAG,cAAc;AACnB;AAAA,QACF;AACA,YAAI,GAAG,mBAAmB;AACxB,qBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,aAAG,oBAAoB;AAAA,QACzB;AAEA,cAAM,UAAU,MAAM;AACpB,cAAI,GAAG,aAAc;AACrB,cAAI,MAAM,SAAS,KAAM;AACvB,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,OAAO,IAAI,YAAY;AAAA,gBACrB,SAAS,uCAAuC,MAAM,IAAI,WAAW,qBAAqB,MAAM,MAAM,CAAC;AAAA,gBACvG,YAAY,MAAM;AAAA,cACpB,CAAC;AAAA,YACH,CAAC;AACD,eAAG,eAAe;AAClB,uBAAW,MAAM;AACjB,iBAAK,cAAc,IAAI,IAAI;AAAA,UAC7B,OAAO;AACL,kBAAM,QAAQ,KAAK,KAAK,GAAG,qBAAqB,CAAC;AACjD,kBAAM,SAAS,KAAK,KAAK,GAAG,sBAAsB,CAAC;AACnD,uBAAW,QAAQ;AAAA,cACjB,MAAM;AAAA,cACN,cAAc;AAAA,cACd,OAAO,EAAE,aAAa,OAAO,cAAc,QAAQ,aAAa,QAAQ,OAAO;AAAA,YACjF,CAAC;AACD,eAAG,eAAe;AAClB,uBAAW,MAAM;AACjB,iBAAK,cAAc,EAAE;AAAA,UACvB;AAAA,QACF;AAEA,YAAI,GAAG,mBAAmB,GAAG;AAC3B,aAAG,gBAAgB;AAAA,QACrB,OAAO;AACL,aAAG,gBAAgB;AACnB,kBAAQ;AAAA,QACV;AACA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMQ,kBACN,IACA,YACA,YACA,YACM;AACN,QAAI,CAAC,WAAW,YAAY;AAC1B,UAAI,WAAW,SAAS;AACtB,YAAI,CAAC,GAAG,mBAAmB;AACzB,aAAG,oBAAoB,WAAW;AAClC,qBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,GAAG,kBAAkB,CAAC;AAAA,QACrE;AACA,mBAAW,QAAQ;AAAA,UACjB,MAAM;AAAA,UACN,IAAI,GAAG;AAAA,UACP,OAAO,WAAW;AAAA,QACpB,CAAC;AACD,WAAG,uBAAuB,WAAW,QAAQ;AAAA,MAC/C;AACA;AAAA,IACF;AAEA,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,WAAW,UAAU;AAAA,IAC3C,SAAS,GAAG;AACV;AAAA,IACF;AAEA,UAAM,UAAU,OAAO,gBAAgB;AACvC,QAAI,CAAC,WAAW,CAAC,MAAM,QAAQ,OAAO,KAAK,QAAQ,WAAW,GAAG;AAC/D;AAAA,IACF;AAEA,QACE,WAAW,WAAW,aACtB,WAAW,WAAW,oBACtB,WAAW,WAAW,cACtB,WAAW,WAAW,aACtB;AACA;AAAA,IACF;AAEA,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,YAAM,QAAQ,QAAQ,CAAC;AACvB,UAAI,MAAM,iBAAiB,QAAS;AAEpC,YAAM,UAAU,MAAM,WAAW;AACjC,YAAM,QAAQ,MAAM,cAAc,OAAO,CAAC;AAC1C,YAAM,aAAa,GAAG,oBAAoB,IAAI,KAAK,KAAK;AAExD,UAAI,QAAQ,UAAU,WAAY;AAElC,YAAM,QAAQ,QAAQ,MAAM,UAAU;AACtC,YAAM,YAAY,UAAU,GAAG;AAE/B,UAAI,CAAC,aAAa,GAAG,mBAAmB;AACtC,mBAAW,QAAQ,EAAE,MAAM,YAAY,IAAI,GAAG,kBAAkB,CAAC;AACjE,WAAG,oBAAoB;AAAA,MACzB;AAEA,UAAI,CAAC,GAAG,mBAAmB;AACzB,WAAG,oBAAoB,WAAW;AAClC,mBAAW,QAAQ,EAAE,MAAM,cAAc,IAAI,GAAG,kBAAkB,CAAC;AAAA,MACrE;AACA,iBAAW,QAAQ;AAAA,QACjB,MAAM;AAAA,QACN,IAAI,GAAG;AAAA,QACP;AAAA,MACF,CAAC;AACD,SAAG,uBAAuB,MAAM;AAEhC,SAAG,oBAAoB,IAAI,OAAO,QAAQ,MAAM;AAChD,WAAK,sBAAsB,IAAI,OAAO,QAAQ,MAAM;AACpD,SAAG,wBAAwB;AAAA,IAC7B;AAAA,EACF;AAAA,EAEA,MAAc,sBACZ,IACA,UACA,YACA,WACA,UACA,UACA,cACe;AACf,OAAG;AAEH,UAAM,cAAc,CAAC,SAA0C;AAC7D,UAAI,GAAG,cAAc;AACnB;AAAA,MACF;AACA,UAAI;AACF,mBAAW,QAAQ,IAAI;AAAA,MACzB,QAAQ;AAAA,MAER;AAAA,IACF;AAEA,QAAI;AACF,UAAI,cAAc;AAChB,cAAM,SAAS,MAAM,aAAa,UAAU,UAAU,SAAS;AAC/D,iBAAS,mBAAmB,WAAW,OAAO,QAAQ,OAAO,KAAK;AAGlE,WAAG,sBAAsB,SAAS;AAClC,WAAG,uBAAuB,OAAO,OAAO;AAExC,YAAI,aAAa,OAAO;AACxB,YAAI,YAAY,GAAG,QAAQ;AAC3B,YAAI,eAAwC,EAAE,QAAQ,OAAO,OAAO;AACpE,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,OAAO,MAAM;AACvC,cAAI,UAAU,OAAO,WAAW,YAAY,CAAC,MAAM,QAAQ,MAAM,GAAG;AAClE,gBAAI,OAAO,OAAO,WAAW,UAAU;AACrC,2BAAa,OAAO;AAAA,YACtB,WAAW,OAAO,UAAU,MAAM;AAChC,2BAAa,KAAK,UAAU,OAAO,MAAM;AAAA,YAC3C;AACA,gBAAI,OAAO,OAAO,UAAU,SAAU,aAAY,OAAO;AACzD,gBAAI,OAAO,YAAY,OAAO,OAAO,aAAa,UAAU;AAC1D,6BAAe,CAAC;AAChB,yBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,OAAO,QAAmC,GAAG;AAC/E,6BAAa,CAAC,IAAI,OAAO,MAAM,WAAW,IAAI,KAAK,UAAU,CAAC;AAAA,cAChE;AACA,kBAAI,EAAE,YAAY,eAAe;AAC/B,6BAAa,SAAS;AAAA,cACxB;AAAA,YACF;AAAA,UACF,WAAW,MAAM,QAAQ,MAAM,GAAG;AAChC,yBAAa,KAAK,UAAU,MAAM;AAClC,2BAAe,EAAE,QAAQ,WAAW;AAAA,UACtC;AAAA,QACF,QAAQ;AAAA,QAER;AAEA,YAAI,OAAO,OAAO;AAChB,cAAI;AACJ,cAAI,OAAO,OAAO,UAAU,UAAU;AACpC,wBAAY,OAAO;AAAA,UACrB,WAAW,OAAO,SAAS,OAAO,OAAO,UAAU,UAAU;AAC3D,wBAAY,KAAK,UAAU,OAAO,KAAK;AAAA,UACzC,OAAO;AACL,wBAAY,OAAO,OAAO,KAAK;AAAA,UACjC;AACA,gBAAM,cAAc,cAAc;AAClC,sBAAY;AAAA,YACV,MAAM;AAAA,YACN,YAAY;AAAA,YACZ;AAAA,YACA,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,UAAU,EAAE,GAAG,cAAc,OAAO,UAAU;AAAA,YAChD;AAAA,YACA,SAAS;AAAA,YACT,kBAAkB;AAAA,UACpB,CAAC;AAAA,QACH,OAAO;AACL,sBAAY;AAAA,YACV,MAAM;AAAA,YACN,YAAY;AAAA,YACZ;AAAA,YACA,QAAQ;AAAA,cACN,QAAQ;AAAA,cACR,OAAO;AAAA,cACP,UAAU;AAAA,YACZ;AAAA,YACA,SAAS;AAAA,YACT,kBAAkB;AAAA,UACpB,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,cAAM,WAAW,0CAA0C,QAAQ;AACnE,iBAAS,mBAAmB,WAAW,IAAI,QAAQ;AAEnD,oBAAY;AAAA,UACV,MAAM;AAAA,UACN,YAAY;AAAA,UACZ;AAAA,UACA,QAAQ;AAAA,YACN,QAAQ;AAAA,YACR,OAAO,GAAG,QAAQ;AAAA,YAClB,UAAU,EAAE,QAAQ,SAAS;AAAA,UAC/B;AAAA,UACA,SAAS;AAAA,UACT,kBAAkB;AAAA,QACpB,CAAC;AAAA,MACH;AAAA,IACF,SAAS,OAAO;AACd,YAAM,SAAS,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACpE,YAAM,WAAW,qBAAqB,MAAM;AAC5C,eAAS,mBAAmB,WAAW,IAAI,QAAQ;AAEnD,kBAAY;AAAA,QACV,MAAM;AAAA,QACN,YAAY;AAAA,QACZ;AAAA,QACA,QAAQ;AAAA,UACN,QAAQ;AAAA,UACR,OAAO,GAAG,QAAQ;AAAA,UAClB,UAAU,EAAE,QAAQ,SAAS;AAAA,QAC/B;AAAA,QACA,SAAS;AAAA,QACT,kBAAkB;AAAA,MACpB,CAAC;AAAA,IACH,UAAE;AACA,SAAG;AAEH,UAAI,KAAK,eAAe;AACtB,YAAI;AACF,eAAK,cAAc;AAAA,YACjB,aAAa,KAAK,KAAK,GAAG,qBAAqB,CAAC;AAAA,YAChD,cAAc,KAAK,KAAK,GAAG,sBAAsB,CAAC;AAAA,UACpD,CAAC;AAAA,QACH,QAAQ;AAAA,QAER;AAAA,MACF;AAEA,UAAI,GAAG,oBAAoB,KAAK,GAAG,eAAe;AAChD,cAAM,QAAQ,GAAG;AACjB,WAAG,gBAAgB;AACnB,cAAM;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,cAAc,IAAiB,gBAAgB,OAAa;AAClE,QAAI,GAAG,cAAc;AACnB,SAAG,aAAa,MAAM;AACtB,WAAK,cAAc,OAAO,GAAG,YAAY;AACzC,SAAG,eAAe;AAAA,IACpB;AACA,QAAI,eAAe;AACjB,WAAK,oBAAoB;AACzB,WAAK,sBAAsB,MAAM;AAAA,IACnC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,wBAA0D;AACtE,UAAM,WAAoC;AAAA,MACxC,kBAAkB;AAAA,IACpB;AAEA,QAAI;AACF,YAAM,UAAU,KAAK,gBAAgB,oBAAoB,QAAQ,IAAI;AACrE,YAAM,UAAU,MAAM,KAAK,WAAW,OAAO;AAC7C,UAAI,QAAQ,IAAK,UAAS,UAAU,QAAQ;AAC5C,UAAI,QAAQ,IAAK,UAAS,UAAU,QAAQ;AAC5C,UAAI,QAAQ,OAAQ,UAAS,aAAa,QAAQ;AAAA,IACpD,QAAQ;AAAA,IAER;AAEA,WAAO;AAAA,EACT;AAAA,EAEA,MAAc,WACZ,SAC0D;AAC1D,UAAM,EAAE,SAAS,IAAI,MAAM,OAAO,eAAe;AACjD,UAAM,EAAE,UAAU,IAAI,MAAM,OAAO,MAAM;AACzC,UAAM,gBAAgB,UAAU,QAAQ;AACxC,UAAM,OAAO,EAAE,KAAK,SAAS,SAAS,IAAK;AAE3C,UAAM,MAAM,OAAO,KAAa,SAAgD;AAC9E,UAAI;AACF,cAAM,EAAE,OAAO,IAAI,MAAM,cAAc,KAAK,MAAM,IAAI;AACtD,eAAO,OAAO,KAAK,KAAK;AAAA,MAC1B,QAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAEA,UAAM,CAAC,KAAK,KAAK,MAAM,IAAI,MAAM,QAAQ,IAAI;AAAA,MAC3C,IAAI,OAAO,CAAC,UAAU,WAAW,QAAQ,CAAC;AAAA,MAC1C,IAAI,OAAO,CAAC,aAAa,MAAM,CAAC;AAAA,MAChC,IAAI,OAAO,CAAC,aAAa,gBAAgB,MAAM,CAAC;AAAA,IAClD,CAAC;AAED,WAAO,EAAE,KAAK,KAAK,OAAO;AAAA,EAC5B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASQ,sBAAsB,QAA0C;AACtE,aAAS,IAAI,OAAO,SAAS,GAAG,KAAK,GAAG,KAAK;AAC3C,YAAM,UAAU,OAAO,CAAC;AACxB,UAAI,QAAQ,SAAS,QAAQ;AAC3B,cAAM,YAAY,QAAQ,QACvB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAU,KAAwC,IAAI;AAC9D,YAAI,UAAU,SAAS,GAAG;AACxB,iBAAO,UAAU,KAAK,IAAI;AAAA,QAC5B;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,gBAAgB,SAA0D;AAChF,QAAI,KAAK,gBAAgB,YAAY,KAAK,gBAAgB,SAAS,SAAS,GAAG;AAC7E,aAAO,KAAK,gBAAgB;AAAA,IAC9B;AAEA,QAAI,CAAC,QAAQ,SAAS,QAAQ,MAAM,WAAW,GAAG;AAChD,aAAO,CAAC;AAAA,IACV;AAEA,WAAO,QAAQ,MACZ,OAAO,CAAC,SAA8C,KAAK,SAAS,UAAU,EAC9E,IAAI,CAAC,UAAU;AAAA,MACd,MAAM,KAAK;AAAA,MACX,aAAa,KAAK,eAAe;AAAA,MACjC,aAAa,KAAK,UAAU,KAAK,eAAe,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE,CAAC;AAAA,IACpF,EAAE;AAAA,EACN;AAAA;AAAA;AAAA;AAAA,EAMA,OAAwB,0BAA0B,IAAI,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAerD,YACN,UACA,mBACA,iBAC2E;AAC3E,UAAM,SAAS,6BAA4B,0BAA0B;AACrE,UAAM,cAAc,KAAK,UAAU,iBAAiB;AAEpD,UAAM,YAAY,KAAK,UAAU,QAAQ;AACzC,UAAM,YAAY,UAAU,SAAS,YAAY;AAEjD,QAAI,aAAa,QAAQ;AACvB,aAAO,EAAE,UAAU,kBAAkB;AAAA,IACvC;AAEA,UAAM,kBAAkB,SAAS,IAAI,CAAC,UAAU;AAAA,MAC9C,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,aAAa,eAAe,KAAK,WAAW;AAAA,IAC9C,EAAE;AAEF,UAAM,WAAW,KAAK,UAAU,eAAe,EAAE,SAAS,YAAY;AACtE,QAAI,YAAY,QAAQ;AACtB,aAAO,EAAE,UAAU,iBAAiB,kBAAkB;AAAA,IACxD;AAEA,UAAM,WAAW,gBAAgB,IAAI,CAAC,UAAU;AAAA,MAC9C,MAAM,KAAK;AAAA,MACX,aAAa,KAAK;AAAA,MAClB,aAAa,cAAc,KAAK,WAAW;AAAA,IAC7C,EAAE;AAEF,UAAM,UAAU,KAAK,UAAU,QAAQ,EAAE,SAAS,YAAY;AAC9D,QAAI,WAAW,QAAQ;AACrB,aAAO,EAAE,UAAU,UAAU,kBAAkB;AAAA,IACjD;AAEA,UAAM,YAAY,CAAC,GAAG,QAAQ;AAC9B,WAAO,UAAU,SAAS,GAAG;AAC3B,YAAM,cAAc,KAAK,UAAU,SAAS,EAAE,SAAS,YAAY;AACnE,UAAI,eAAe,OAAQ;AAC3B,gBAAU,IAAI;AAAA,IAChB;AAEA,WAAO,EAAE,UAAU,WAAW,kBAAkB;AAAA,EAClD;AAAA,EAEQ,uBAAuB,QAAuD;AACpF,UAAM,UAA+B,CAAC;AAEtC,QAAI,KAAK,gBAAgB,mBAAmB;AAC1C,cAAQ,KAAK,GAAG,KAAK,gBAAgB,iBAAiB;AAAA,IACxD;AAEA,eAAW,WAAW,QAAQ;AAC5B,UAAI,QAAQ,SAAS,UAAU;AAC7B,gBAAQ,KAAK;AAAA,UACX,UAAU;AAAA,UACV,SAAS,QAAQ;AAAA,UACjB,UAAU,KAAK,UAAU,EAAE,MAAM,SAAS,CAAC;AAAA,QAC7C,CAAC;AAAA,MACH,WAAW,QAAQ,SAAS,aAAa;AACvC,cAAM,cAAc,QAAQ,QACzB,OAAO,CAAC,SAAS,KAAK,SAAS,MAAM,EACrC,IAAI,CAAC,SAAU,KAAwC,IAAI,EAC3D,KAAK,IAAI;AACZ,YAAI,aAAa;AACf,kBAAQ,KAAK;AAAA,YACX,UAAU;AAAA,YACV,SAAS;AAAA,YACT,UAAU,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAAA,UAChD,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AACF;;;AC16CO,IAAM,iCACX;AAMK,IAAM,oBAAoB;AAK1B,IAAM,iBAAiB;AAMvB,IAAM,uBAAuB,IAAI,KAAK;AAKtC,IAAM,eAAe,CAAC,KAAK;;;AC9B3B,IAAM,qBAAN,MAAyB;AAAA,EACtB;AAAA,EAER,YAAY,YAA0B,OAAO;AAC3C,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,eAAe,WAA4B;AACzC,WAAO,KAAK,IAAI,KAAK;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,WAA4B;AACvC,WAAO,KAAK,IAAI,KAAK,YAAY;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBAAgB,QAA2B,UAA+C;AAC9F,QAAI,CAAC,KAAK,aAAa,OAAO,SAAS,GAAG;AACxC,aAAO;AAAA,IACT;AAEA,QAAI,KAAK,eAAe,OAAO,SAAS,GAAG;AACzC,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS;AAAA,MACX,CAAC;AAAA,IACH;AAEA,WAAO,KAAK,qBAAqB;AAAA,MAC/B,aAAa,OAAO;AAAA,MACpB,cAAc,OAAO;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,0BAA0B,QAA6D;AAC3F,UAAM,EAAE,aAAa,MAAM,cAAc,UAAU,YAAY,IAAI;AAEnE,UAAM,gBAAgB,MAAM,KAAK,cAAc;AAAA,MAC7C;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA,UAAU,YAAY,KAAK,YAAY,WAAW;AAAA,MAClD;AAAA,IACF,CAAC;AAED,WAAO,KAAK,yBAAyB,eAAe,WAAW;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,qBAAqB,QAAwD;AACjF,UAAM,EAAE,aAAa,cAAc,SAAS,IAAI;AAEhD,UAAM,gBAAgB,MAAM,KAAK,cAAc;AAAA,MAC7C;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,UAAU,YAAY,KAAK,YAAY,WAAW;AAAA,IACpD,CAAC;AAED,WAAO,KAAK,yBAAyB,eAAe,WAAW;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,YAAY,aAA6B;AAE/C,UAAM,cAAc,QAAQ,IAAI,wBAAwB;AACxD,QAAI,aAAa;AACf,aAAO;AAAA,IACT;AAIA,QAAI,gBAAgB,gBAAgB;AAClC,aAAO;AAAA,IACT;AAEA,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,8CAA8C,WAAW;AAAA,IACpE,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,cAAc,QAQU;AACpC,UAAM,EAAE,aAAa,WAAW,MAAM,cAAc,cAAc,UAAU,YAAY,IACtF;AAEF,UAAM,OAA+B;AAAA,MACnC,WAAW;AAAA,MACX,YAAY;AAAA,IACd;AAEA,QAAI,cAAc,sBAAsB;AACtC,UAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,aAAa;AAC1C,cAAM,IAAI,YAAY;AAAA,UACpB,SACE;AAAA,QACJ,CAAC;AAAA,MACH;AACA,WAAK,OAAO;AACZ,WAAK,gBAAgB;AACrB,WAAK,eAAe;AAAA,IACtB,WAAW,cAAc,iBAAiB;AACxC,UAAI,CAAC,cAAc;AACjB,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS;AAAA,QACX,CAAC;AAAA,MACH;AACA,WAAK,gBAAgB;AAAA,IACvB;AAEA,UAAM,MAAM,GAAG,WAAW;AAE1B,QAAI;AACF,YAAM,WAAW,MAAM,KAAK,MAAM,KAAK;AAAA,QACrC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,QAClB;AAAA,QACA,MAAM,IAAI,gBAAgB,IAAI,EAAE,SAAS;AAAA,MAC3C,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,YAAY,MAAM,SAAS,KAAK;AACtC,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,gCAAgC,SAAS,MAAM,IAAI,SAAS,UAAU;AAAA,UAC/E,OAAO,IAAI,MAAM,SAAS;AAAA,QAC5B,CAAC;AAAA,MACH;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,UAAI,iBAAiB,aAAa;AAChC,cAAM;AAAA,MACR;AACA,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAClG,OAAO,iBAAiB,QAAQ,QAAQ;AAAA,MAC1C,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKQ,yBACN,UACA,aACmB;AACnB,UAAM,YAAY,KAAK,uBAAuB,QAAQ;AAEtD,WAAO;AAAA,MACL,aAAa,SAAS;AAAA,MACtB,cAAc,SAAS,iBAAiB;AAAA,MACxC;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMQ,uBAAuB,UAA4C;AAEzE,UAAM,YAAY,SAAS,aAAa;AACxC,UAAM,YAAY,SAAS,aAAa;AACxC,WAAO,YAAY;AAAA,EACrB;AACF;;;AC9NA,IAAAC,MAAoB;AACpB,IAAAC,QAAsB;AACtB,IAAAC,MAAoB;AAmKpB,SAAS,sBAA8B;AACrC,QAAM,UAAa,YAAQ;AAG3B,QAAM,cAAc,QAAQ,IAAI;AAChC,MAAI,aAAa;AACf,WAAY,WAAK,aAAa,YAAY,WAAW;AAAA,EACvD;AAGA,MAAI,QAAQ,aAAa,SAAS;AAChC,WAAY,WAAK,SAAS,UAAU,SAAS,YAAY,WAAW;AAAA,EACtE;AAGA,SAAY,WAAK,SAAS,aAAa,WAAW;AACpD;AAKA,eAAe,iBAAiB,aAAwD;AACtF,MAAI;AACF,UAAM,WAAW,oBAAoB;AAErC,QAAI,CAAI,eAAW,QAAQ,GAAG;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,KAAK,MAAS,iBAAa,UAAU,OAAO,CAAC;AAG9D,QAAI,SAAS,QAAQ,SAAS,SAAS;AACrC,YAAM,aAAa,SAAS;AAE5B,UACE,WAAW,kBAAkB,eAC7B,WAAW,kBAAkB,YAAY,QAAQ,OAAO,EAAE,GAC1D;AACA,eAAO;AAAA,MACT;AAAA,IACF;AAIA,UAAM,gBAAgB,YAAY,QAAQ,OAAO,EAAE;AACnD,UAAM,OAAO,SAAS,aAAa,KAAK,SAAS,GAAG,aAAa,GAAG;AAEpE,WAAO;AAAA,EACT,SAAS,OAAO;AACd,UAAM,IAAI,MAAM,6BAA6B,iBAAiB,QAAQ,MAAM,UAAU,KAAK,EAAE;AAAA,EAC/F;AACF;AAMA,eAAe,WACb,SAKA,aACA,UACiB;AAEjB,MAAI,QAAQ,QAAQ;AAClB,WAAO,QAAQ;AAAA,EACjB;AAGA,QAAM,OAAO,MAAM,iBAAiB,WAAW;AAC/C,MAAI,MAAM,SAAS,SAAS;AAC1B,UAAM,eAAe,IAAI,mBAAmB;AAG5C,QAAI,aAAa,aAAa,KAAK,OAAO,GAAG;AAC3C,UAAI;AACF,cAAM,YAAY,MAAM,aAAa,qBAAqB;AAAA,UACxD;AAAA,UACA,cAAc,KAAK;AAAA,UACnB;AAAA,QACF,CAAC;AAGD,cAAM,WAAW,oBAAoB;AACrC,cAAM,WAAW,KAAK,MAAS,iBAAa,UAAU,OAAO,CAAC;AAE9D,iBAAS,SAAS;AAAA,UAChB,MAAM;AAAA,UACN,SAAS,UAAU;AAAA,UACnB,QAAQ,UAAU;AAAA,UAClB,SAAS,UAAU;AAAA,UACnB,eAAe;AAAA;AAAA,QACjB;AAEA,QAAG,kBAAc,UAAU,KAAK,UAAU,UAAU,MAAM,CAAC,GAAG,EAAE,MAAM,IAAM,CAAC;AAE7E,eAAO,UAAU;AAAA,MACnB,SAAS,OAAO;AAEd,cAAM,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAI7E,cAAM,YAAY,QAAQ,IAAI,QAAQ,uBAAuB;AAC7D,YAAI,WAAW;AACb,iBAAO;AAAA,QACT;AAGA,cAAM,IAAI,YAAY;AAAA,UACpB,SACE,8CAA8C,QAAQ,uBAAuB,gDAC3D,eAAe,8DAC2B,QAAQ,uBAAuB;AAAA,QAC/F,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,aAAO,KAAK;AAAA,IACd;AAAA,EACF;AAGA,QAAM,SAAS,QAAQ,IAAI,QAAQ,uBAAuB;AAE1D,MAAI,CAAC,QAAQ;AACX,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,GAAG,QAAQ,WAAW,mEAAmE,QAAQ,uBAAuB;AAAA,IACnI,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAEA,SAAS,oBACP,SACA,QACwB;AACxB,QAAM,YAAY,QAAQ,YAAY;AACtC,SAAO;AAAA,IACL,GAAG;AAAA,IACH,cAAc,YAAY,GAAG,SAAS,IAAI,MAAM,KAAK;AAAA,EACvD;AACF;AAEO,SAAS,aAAa,UAAkC,CAAC,GAAmB;AACjF,QAAM,cACJ,QAAQ,eAAe,QAAQ,IAAI,qBAAqB,KAAK;AAC/D,QAAM,eAAe,QAAQ,QAAQ;AAGrC,MAAI;AACJ,MAAI;AAEJ,QAAM,YAAY,YAA6B;AAC7C,QAAI,cAAc;AAChB,aAAO;AAAA,IACT;AAEA,QAAI,eAAe;AACjB,aAAO;AAAA,IACT;AAEA,oBAAgB;AAAA,MACd;AAAA,QACE,QAAQ,QAAQ;AAAA,QAChB,yBAAyB;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAEA,mBAAe,MAAM;AACrB,oBAAgB;AAChB,WAAO;AAAA,EACT;AAMA,QAAM,gBAAgB,YAA2B;AAE/C,mBAAe;AACf,oBAAgB;AAIhB,mBAAe,MAAM;AAAA,MACnB;AAAA,QACE,QAAQ;AAAA;AAAA,QACR,yBAAyB;AAAA,QACzB,aAAa;AAAA,MACf;AAAA,MACA;AAAA,MACA,QAAQ;AAAA,IACV;AAAA,EACF;AAEA,QAAM,aAAa,MAAM;AAGvB,UAAM,SAAS,gBAAgB,QAAQ,UAAU,QAAQ,IAAI,cAAc,KAAK;AAEhF,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,YAAY;AAAA,QACpB,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL;AAAA,QACE,eAAe,UAAU,MAAM;AAAA,QAC/B,gBAAgB;AAAA,QAChB,GAAG,QAAQ;AAAA,MACb;AAAA,MACA,iBAAiB,OAAO;AAAA,IAC1B;AAAA,EACF;AAGA,YAAU,EAAE,MAAM,MAAM;AAAA,EAExB,CAAC;AAED,QAAM,yBAAyB,CAAC,SAAiB,mBAA0C;AACzF,UAAM,UAAU,gBAAgB,OAAO;AAEvC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,qBAAqB,OAAO;AAAA,MACvC,CAAC;AAAA,IACH;AAEA,QAAI,gBAAgB,eAAe;AACjC,YAAM,cAAc,0BAA0B,QAAQ,QAAQ;AAC9D,UAAI,CAAC,YAAY,SAAS,eAAe,aAAa,GAAG;AACvD,cAAM,IAAI,YAAY;AAAA,UACpB,SAAS,0BAA0B,eAAe,aAAa,mBAAmB,QAAQ,QAAQ,oBAAoB,YAAY,KAAK,IAAI,CAAC;AAAA,QAC9I,CAAC;AAAA,MACH;AAAA,IACF;AAEA,UAAM,eAAe;AAAA,MACnB,sBAAsB;AAAA,MACtB,GAAG,QAAQ;AAAA,MACX,GAAG,gBAAgB;AAAA,IACrB;AAEA,UAAM,0BAA0B;AAAA,MAC9B,cAAc,sBAAsB,OAAO;AAAA,IAC7C;AAEA,UAAM,mBAAmB;AAAA,MACvB,GAAG;AAAA,MACH,GAAG,QAAQ;AAAA,MACX,GAAG,gBAAgB;AAAA,IACrB;AAEA,UAAM,aAAa;AAAA,MACjB,UAAU,GAAG,YAAY;AAAA,MACzB;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,WAAW,gBAAgB;AAAA,MAC3B;AAAA,MACA,cAAc,QAAQ;AAAA,MACtB;AAAA,IACF;AAEA,QAAI,QAAQ,aAAa,UAAU;AACjC,aAAO,IAAI,0BAA0B,SAAS;AAAA,QAC5C,GAAG;AAAA,QACH,aAAa,gBAAgB,iBAAiB,QAAQ;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,WAAO,IAAI,6BAA6B,SAAS;AAAA,MAC/C,GAAG;AAAA,MACH,gBAAgB,gBAAgB,iBAAiB,QAAQ;AAAA,IAC3D,CAAC;AAAA,EACH;AAEA,QAAM,0BAA0B,CAC9B,SACA,oBACgC;AAChC,UAAM,UAAU,gBAAgB,OAAO;AAEvC,QAAI,CAAC,WAAW,QAAQ,aAAa,YAAY;AAC/C,YAAM,IAAI,YAAY;AAAA,QACpB,SAAS,8BAA8B,OAAO;AAAA,MAChD,CAAC;AAAA,IACH;AAEA,WAAO,IAAI;AAAA,MACT;AAAA,MACA;AAAA,QACE,UAAU,GAAG,YAAY;AAAA,QACzB;AAAA,QACA;AAAA,QACA;AAAA,QACA,OAAO,QAAQ;AAAA,QACf,cAAc;AAAA,UACZ,GAAG,QAAQ;AAAA,UACX,GAAG,iBAAiB;AAAA,QACtB;AAAA,QACA,cAAc,QAAQ;AAAA,MACxB;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAGA,QAAM,qBAAqB,CAAC,YAAqC;AAE/D,QAAI,gBAAgB,OAAO,GAAG;AAC5B,aAAO,wBAAwB,OAAO;AAAA,IACxC;AAEA,WAAO,uBAAuB,OAAO;AAAA,EACvC;AAEA,QAAM,WAAW,OAAO,OAAO,CAAC,YAAoB,mBAAmB,OAAO,GAAG;AAAA,IAC/E,sBAAsB;AAAA,IACtB,eAAe;AAAA,IACf,MAAM;AAAA,IACN,aAAa;AAAA,IACb,cAAc;AAAA,EAChB,CAAC;AAGD,WAAS,qBAAqB,CAAC,YAAoB;AACjD,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,qEAAqE,OAAO;AAAA,IACvF,CAAC;AAAA,EACH;AAEA,WAAS,aAAa,CAAC,YAAoB;AACzC,UAAM,IAAI,YAAY;AAAA,MACpB,SAAS,4DAA4D,OAAO;AAAA,IAC9E,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAYO,IAAM,SAAS,aAAa;","names":["Anthropic","resolve","OpenAI","hasToolCalls","WorkflowType","resolve","WebSocket","resolve","path","fs","path","os"]}