{"version":3,"sources":["../src/gitlab-direct-access-cache-prune.ts","../src/gitlab-direct-access-cache.ts","../src/gitlab-anthropic-language-model.ts","../src/gitlab-direct-access.ts","../src/gitlab-error.ts","../src/gitlab-workflow-builtins.ts","../src/gitlab-workflow-types.ts","../src/gitlab-workflow-token-client.ts","../src/gitlab-openai-language-model.ts","../src/model-mappings.ts","../src/gitlab-workflow-language-model.ts","../src/gitlab-workflow-client.ts","../src/version.ts","../src/gitlab-project-detector.ts","../src/gitlab-project-cache.ts","../src/gitlab-model-discovery.ts","../src/gitlab-model-cache.ts","../src/gitlab-oauth-types.ts","../src/gitlab-api-types.ts","../src/gitlab-oauth-manager.ts","../src/gitlab-provider.ts","../src/gitlab-model-config.ts","../src/gitlab-workflow-discovery.ts"],"sourcesContent":["import { constants } from 'node:fs';\nimport { lstat, open, opendir, unlink } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { lock } from 'proper-lockfile';\nimport type { LockOptions } from 'proper-lockfile';\n\nconst lifetime = 25 * 60 * 1000;\nconst candidateName = /^([a-f0-9]{64})(?:\\.json|\\.[a-f0-9-]{36}\\.tmp)$/;\n// Bound process-local cursor state; directory order may change between sweeps.\nconst cursors = new Map<string, number>();\n\n/** Best-effort bounded cleanup; another scope's writer must never be disturbed. */\nexport async function pruneDirectAccessCache(\n  directory: string,\n  currentKey: string,\n  sameDirectory: () => boolean,\n  filesystem: LockOptions['fs'],\n  currentLeaseOwned: () => boolean = () => true\n): Promise<void> {\n  let scanned = 0;\n  let candidates = 0;\n  const offset = cursors.get(directory) ?? 0;\n  let position = 0;\n  let exhausted = true;\n  try {\n    const entries = await opendir(directory);\n    for await (const entry of entries) {\n      if (position++ < offset) continue;\n      if (++scanned > 128 || candidates >= 32 || !sameDirectory() || !currentLeaseOwned()) {\n        position--;\n        exhausted = false;\n        break;\n      }\n      const match = candidateName.exec(entry.name);\n      if (!match || !entry.isFile()) continue;\n      candidates++;\n      const key = match[1];\n      let release: (() => Promise<void>) | undefined;\n      let compromised = false;\n      let acquiredAt = performance.now();\n      const owned = () =>\n        currentLeaseOwned() && !compromised && performance.now() - acquiredAt < 30_000;\n      try {\n        if (key !== currentKey) {\n          release = await lock(join(directory, `${key}.json`), {\n            fs: filesystem,\n            realpath: false,\n            lockfilePath: join(directory, `${key}.refresh-v1.lock`),\n            stale: 45_000,\n            update: 5_000,\n            retries: 0,\n            onCompromised: () => {\n              compromised = true;\n            },\n          });\n          acquiredAt = performance.now();\n        }\n        if (!sameDirectory()) continue;\n        const path = join(directory, entry.name);\n        const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);\n        try {\n          const info = await file.stat();\n          if (!info.isFile() || info.uid !== process.getuid?.() || (info.mode & 0o077) !== 0)\n            continue;\n          let expired: boolean;\n          if (entry.name.endsWith('.tmp')) {\n            expired = info.mtimeMs < Date.now() - lifetime;\n          } else {\n            const value: unknown = JSON.parse(await file.readFile('utf8'));\n            const expiresAt = (value as { expiresAt?: unknown } | null)?.expiresAt;\n            expired =\n              typeof expiresAt === 'number' &&\n              Number.isFinite(expiresAt) &&\n              expiresAt <= Date.now();\n          }\n          const current = await lstat(path);\n          if (\n            expired &&\n            owned() &&\n            sameDirectory() &&\n            current.dev === info.dev &&\n            current.ino === info.ino\n          ) {\n            await unlink(path);\n          }\n        } finally {\n          await file.close();\n        }\n      } catch {\n        // Busy scopes, malformed entries and filesystem failures are not token failures.\n      } finally {\n        if (!compromised) await release?.().catch(() => {});\n      }\n    }\n  } catch {\n    // Pruning is opportunistic and must not turn a successful refresh into a failure.\n  } finally {\n    cursors.delete(directory);\n    cursors.set(directory, exhausted ? 0 : position);\n    if (cursors.size > 16) cursors.delete(cursors.keys().next().value!);\n  }\n}\n","import { createHash, randomUUID } from 'node:crypto';\nimport * as filesystem from 'node:fs';\nimport { constants } from 'node:fs';\nimport { lstat, mkdir, open, rename, unlink } from 'node:fs/promises';\nimport { isAbsolute, join } from 'node:path';\nimport { lock } from 'proper-lockfile';\nimport { z } from 'zod';\nimport { pruneDirectAccessCache } from './gitlab-direct-access-cache-prune';\n\nconst tokenSchema = z.object({ token: z.string().min(1), headers: z.record(z.string()) });\nconst entrySchema = z.object({ expiresAt: z.number(), value: tokenSchema });\nconst lifetime = 25 * 60 * 1000;\n\n/** Share only credentials with identical authorization, endpoint and feature settings. */\nexport async function cachedDirectAccess(\n  directory: string,\n  scope: string,\n  bypass: boolean,\n  fetchToken: (signal: AbortSignal) => Promise<Response>\n): Promise<{ response: Response; expiresAt: number }> {\n  if (typeof process.getuid !== 'function') {\n    throw new Error('Shared direct-access caching requires POSIX ownership and permissions');\n  }\n  if (!isAbsolute(directory)) throw new Error('Direct-access cache directory must be absolute');\n  await mkdir(directory, { recursive: true, mode: 0o700 });\n  const stat = await lstat(directory);\n  if (!stat.isDirectory() || stat.uid !== process.getuid?.() || (stat.mode & 0o077) !== 0) {\n    throw new Error('Direct-access cache directory must be owner-only (0700), not a symlink');\n  }\n  const key = createHash('sha256').update(scope).digest('hex');\n  const path = join(directory, `${key}.json`);\n  // Version the suffix to leave room for future lock-format changes.\n  const lockPath = join(directory, `${key}.refresh-v1.lock`);\n  const read = async (): Promise<{ response: Response; expiresAt: number } | undefined> => {\n    let file;\n    try {\n      file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW);\n      const info = await file.stat();\n      if (!info.isFile() || info.uid !== stat.uid || (info.mode & 0o077) !== 0) {\n        throw new Error('Direct-access cache entry must be an owner-only regular file');\n      }\n      const entry = entrySchema.parse(JSON.parse(await file.readFile('utf8')));\n      if (entry.expiresAt > Date.now() && entry.expiresAt <= Date.now() + lifetime) {\n        return {\n          response: new Response(JSON.stringify(entry.value), {\n            headers: { 'Content-Type': 'application/json' },\n          }),\n          expiresAt: entry.expiresAt,\n        };\n      }\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n    } finally {\n      await file?.close();\n    }\n    return undefined;\n  };\n  // Atomic rename makes published entries safe to read without the refresh lock.\n  // Still re-read after locking: another process may have populated a cold miss.\n  if (!bypass) {\n    const hit = await read();\n    if (hit) return hit;\n  }\n  const controller = new AbortController();\n  let compromised: Error | undefined;\n  // The library retires its timer/bookkeeping before calling rmdir. Guard only\n  // that pathname removal, not release itself, if the parent has been replaced.\n  const sameDirectory = () => {\n    try {\n      const current = filesystem.lstatSync(directory);\n      return current.isDirectory() && current.dev === stat.dev && current.ino === stat.ino;\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;\n      return false;\n    }\n  };\n  const lockFilesystem = {\n    ...filesystem,\n    rmdir: (target: string, callback: (error: NodeJS.ErrnoException | null) => void) => {\n      try {\n        if (sameDirectory()) filesystem.rmdir(target, callback);\n        else callback(null);\n      } catch (error) {\n        callback(error as NodeJS.ErrnoException);\n      }\n    },\n    rmdirSync: (target: string) => {\n      if (sameDirectory()) filesystem.rmdirSync(target);\n    },\n  };\n  const release = await lock(path, {\n    fs: lockFilesystem,\n    realpath: false,\n    lockfilePath: lockPath,\n    stale: 45_000,\n    update: 5_000,\n    retries: { retries: 120, factor: 1, minTimeout: 500, maxTimeout: 500, randomize: false },\n    onCompromised: (error) => {\n      compromised = error;\n      controller.abort();\n    },\n  }).catch((error: NodeJS.ErrnoException) => {\n    if (error.code === 'ELOCKED') {\n      throw new Error(\n        'Direct-access cache refresh remained locked after approximately 60 seconds. ' +\n          'Check the private directory configured by directAccessCacheDir or ' +\n          'GITLAB_DIRECT_ACCESS_CACHE_DIR; do not remove an active lock.'\n      );\n    }\n    throw error;\n  });\n  const acquiredAt = performance.now();\n  const assertOwned = () => {\n    if (compromised) throw compromised;\n    // A suspended process must not publish after another process could reclaim\n    // its lease. The monotonic deadline is shorter than the stale threshold.\n    if (performance.now() - acquiredAt >= 30_000) {\n      throw new Error('Direct-access refresh timed out after 30 seconds');\n    }\n  };\n  try {\n    if (!bypass) {\n      const hit = await read();\n      if (hit) {\n        return hit;\n      }\n    } else {\n      await unlink(path).catch((error: NodeJS.ErrnoException) => {\n        if (error.code !== 'ENOENT') throw error;\n      });\n    }\n    const started = Date.now();\n    let timer: ReturnType<typeof setTimeout> | undefined;\n    // Only fetch/body consumption races the deadline. Publication stays outside\n    // the losing task, so even a custom fetch ignoring abort cannot write late.\n    const consume = async () => {\n      const response = await fetchToken(controller.signal);\n      const body = await response.text();\n      return { response, body };\n    };\n    let result: Awaited<ReturnType<typeof consume>>;\n    try {\n      result = await Promise.race([\n        consume(),\n        new Promise<never>((_resolve, reject) => {\n          timer = setTimeout(() => {\n            reject(new Error('Direct-access refresh timed out after 30 seconds'));\n            controller.abort();\n          }, 30_000);\n        }),\n      ]);\n    } finally {\n      clearTimeout(timer);\n    }\n    const current = await lstat(directory);\n    if (!current.isDirectory() || current.dev !== stat.dev || current.ino !== stat.ino) {\n      throw new Error('Direct-access cache directory changed during refresh');\n    }\n    assertOwned();\n    const { response, body } = result;\n    const restored = new Response(body, {\n      status: response.status,\n      statusText: response.statusText,\n    });\n    if (!response.ok) return { response: restored, expiresAt: 0 };\n    const value = tokenSchema.parse(JSON.parse(body));\n    const temporary = join(directory, `${key}.${randomUUID()}.tmp`);\n    try {\n      const file = await open(temporary, 'wx', 0o600);\n      try {\n        await file.writeFile(JSON.stringify({ expiresAt: started + lifetime, value }));\n      } finally {\n        await file.close();\n      }\n      assertOwned();\n      await rename(temporary, path);\n    } finally {\n      await unlink(temporary).catch((error: NodeJS.ErrnoException) => {\n        if (error.code !== 'ENOENT') throw error;\n      });\n    }\n    await pruneDirectAccessCache(directory, key, sameDirectory, lockFilesystem, () => {\n      try {\n        assertOwned();\n        return true;\n      } catch {\n        return false;\n      }\n    });\n    return { response: restored, expiresAt: started + lifetime };\n  } finally {\n    if (!compromised) await release();\n  }\n}\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  LanguageModelV3,\n  LanguageModelV3CallOptions,\n  LanguageModelV3StreamPart,\n  LanguageModelV3FinishReason,\n  LanguageModelV3Content,\n  LanguageModelV3Usage,\n  LanguageModelV3FunctionTool,\n  LanguageModelV3Message,\n  LanguageModelV3ToolChoice,\n  LanguageModelV3GenerateResult,\n  LanguageModelV3StreamResult,\n} from '@ai-sdk/provider';\n\n/**\n * Extended thinking configuration for Anthropic Messages API models.\n *\n * - `enabled`/`disabled` map to the Anthropic `thinking` field directly. `enabled`\n *   requires a `budgetTokens` value that is less than the request's max tokens.\n * - `adaptive` is required by effort-based models (e.g. Claude Opus 4.8), which\n *   reject `thinking.type.enabled`. It is serialized as `thinking: { type: 'adaptive' }`\n *   plus a sibling `output_config: { effort }`.\n */\nexport type GitLabThinkingConfig =\n  | { type: 'disabled' }\n  | { type: 'enabled'; budgetTokens: number }\n  | { type: 'adaptive'; effort: 'low' | 'medium' | 'high' | 'xhigh' | 'max' };\n\n/**\n * Per-request options for Anthropic models, read from `providerOptions.gitlab`\n * or from the provider's configured name (e.g. `providerOptions['gitlab.agentic']`).\n */\nexport interface GitLabAnthropicProviderOptions {\n  /**\n   * Extended thinking configuration for this request. Takes precedence over the\n   * model-level `thinking` default.\n   */\n  thinking?: GitLabThinkingConfig;\n\n  /**\n   * Omit the message-level prompt-cache breakpoints for this request, so a\n   * one-shot or background call whose context is never reused does not pay the\n   * cache-write premium. The system prompt stays cached either way, since it is\n   * static and cheap to keep cached.\n   * @default false\n   */\n  skipCache?: boolean;\n}\n\nexport interface GitLabAnthropicConfig {\n  provider: string;\n  instanceUrl: string;\n  getHeaders: () => Record<string, string>;\n  fetch?: typeof fetch;\n\n  /**\n   * Optional async hook that resolves once credentials are loaded, awaited\n   * before the synchronous getHeaders() is used for the direct-access request.\n   */\n  ensureApiKey?: () => Promise<void>;\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  thinking?: GitLabThinkingConfig;\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  directAccessCacheDir?: 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 LanguageModelV3 {\n  readonly specificationVersion = 'v3' 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      ensureApiKey: config.ensureApiKey,\n      refreshApiKey: config.refreshApiKey,\n      fetch: config.fetch,\n      featureFlags: config.featureFlags,\n      aiGatewayUrl: config.aiGatewayUrl,\n      directAccessCacheDir: config.directAccessCacheDir,\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?: LanguageModelV3CallOptions['tools']): Tool[] | undefined {\n    if (!tools || tools.length === 0) {\n      return undefined;\n    }\n\n    return tools\n      .filter((tool): tool is LanguageModelV3FunctionTool => 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?: LanguageModelV3ToolChoice\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   * Cache breakpoints (`cache_control: { type: \"ephemeral\" }`) are placed on:\n   * 1. The system prompt content block — static across all turns.\n   * 2. The last content block of each of the final two messages.\n   *\n   * Two trailing breakpoints (rather than a single one on the penultimate\n   * message) keep a cache write within Anthropic's 20-block lookback window\n   * as an agentic conversation grows several messages per turn (assistant\n   * tool-call → tool-result → …). With a single breakpoint the most recent\n   * write can drift more than 20 blocks behind the current position, so the\n   * next request fails to prefix-match and pays for a fresh cache write\n   * instead of a cheap read. The extra breakpoint costs nothing (breakpoints\n   * themselves are free; you only pay for tokens actually written/read) and\n   * materially raises the cache hit rate in multi-turn tool-using sessions.\n   *\n   * When `skipCache` is true (for example one-shot or background runs whose\n   * context is never reused) the message-level breakpoints are omitted, so no\n   * cache-write premium is paid for a cache that will never be read. The\n   * system-prompt breakpoint is left in place because the system prompt is\n   * static and cheap to keep cached.\n   *\n   * @see https://docs.anthropic.com/en/docs/build-with-claude/prompt-caching\n   */\n  private convertPrompt(\n    prompt: LanguageModelV3Message[],\n    options: { skipCache?: boolean } = {}\n  ): {\n    system?: Anthropic.MessageCreateParams['system'];\n    messages: Anthropic.MessageParam[];\n  } {\n    const { skipCache = false } = options;\n    let systemMessage: string | undefined;\n    const messages: Anthropic.MessageParam[] = [];\n\n    for (const message of prompt) {\n      if (message.role === 'system') {\n        systemMessage = systemMessage ? `${systemMessage}\\n${message.content}` : 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 === 'reasoning') {\n            const thinkingBlock = this.convertReasoningPart(part);\n            if (thinkingBlock) {\n              content.push(thinkingBlock);\n            }\n          } else if (part.type === 'text') {\n            content.push({ type: 'text', text: part.text });\n          } else if (part.type === 'tool-call') {\n            let toolInput: unknown = part.input;\n            if (typeof part.input === 'string') {\n              try {\n                toolInput = JSON.parse(part.input);\n              } catch {\n                toolInput = {};\n              }\n            }\n            content.push({\n              type: 'tool_use',\n              id: part.toolCallId,\n              name: part.toolName,\n              input: toolInput,\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 === 'content') {\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 if (part.output.type === 'execution-denied') {\n              resultContent = part.output.reason ?? 'Tool execution denied.';\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    const system: Anthropic.MessageCreateParams['system'] = systemMessage\n      ? [\n          {\n            type: 'text' as const,\n            text: systemMessage,\n            cache_control: { type: 'ephemeral' as const },\n          },\n        ]\n      : undefined;\n\n    if (!skipCache) {\n      // Mark the last content block of each of the final two messages. Two\n      // trailing breakpoints keep a prior cache write inside Anthropic's\n      // 20-block lookback window as the conversation grows several blocks per\n      // turn, so the next request prefix-matches and reads instead of rewriting.\n      const breakpointCount = Math.min(2, messages.length);\n      for (let i = messages.length - breakpointCount; i < messages.length; i++) {\n        const message = messages[i];\n        if (Array.isArray(message.content) && message.content.length > 0) {\n          const lastBlock = message.content[message.content.length - 1];\n          (lastBlock as unknown as Record<string, unknown>).cache_control = {\n            type: 'ephemeral' as const,\n          };\n        }\n      }\n    }\n\n    return { system, messages };\n  }\n\n  /**\n   * Convert Anthropic finish reason to AI SDK format\n   */\n  private convertFinishReason(stopReason: string | null): LanguageModelV3FinishReason {\n    const unified: LanguageModelV3FinishReason['unified'] = (() => {\n      switch (stopReason) {\n        case 'end_turn':\n          return 'stop';\n        case 'stop_sequence':\n          return 'stop';\n        case 'pause_turn':\n          return 'stop';\n        case 'max_tokens':\n          return 'length';\n        case 'model_context_window_exceeded':\n          return 'length';\n        case 'tool_use':\n          return 'tool-calls';\n        case 'refusal':\n          return 'content-filter';\n        default:\n          return 'other';\n      }\n    })();\n\n    return { unified, raw: stopReason ?? undefined };\n  }\n\n  private createUsage(params?: {\n    inputTotal?: number;\n    outputTotal?: number;\n    outputReasoning?: number;\n    cacheRead?: number;\n    cacheWrite?: number;\n    raw?: LanguageModelV3Usage['raw'];\n  }): LanguageModelV3Usage {\n    const inputNoCache = params?.inputTotal;\n    const outputTotal = params?.outputTotal;\n    const cacheRead = params?.cacheRead;\n    const cacheWrite = params?.cacheWrite;\n    const inputTotal =\n      inputNoCache != null ? inputNoCache + (cacheRead ?? 0) + (cacheWrite ?? 0) : undefined;\n\n    return {\n      inputTokens: {\n        total: inputTotal,\n        noCache: inputNoCache,\n        cacheRead,\n        cacheWrite,\n      },\n      outputTokens: {\n        total: outputTotal,\n        text: outputTotal != null ? outputTotal - (params?.outputReasoning ?? 0) : undefined,\n        reasoning: params?.outputReasoning,\n      },\n      raw: params?.raw,\n    };\n  }\n\n  /**\n   * Translates the camelCase GitLab thinking config into the Anthropic Messages\n   * request fields. `adaptive` is required by effort-based models such as Claude\n   * Opus 4.8 and pairs `thinking: { type: 'adaptive' }` with a sibling\n   * `output_config: { effort }`; `enabled`/`disabled` map through directly.\n   */\n  private buildThinkingParams(config: GitLabThinkingConfig | undefined): Record<string, unknown> {\n    if (!config) return {};\n    if (config.type === 'adaptive') {\n      return {\n        // Newer adaptive-only models (Claude Sonnet 5+, Opus 4.7+) default\n        // `thinking.display` to `'omitted'`, which returns *empty* thinking\n        // blocks — the model still reasons and effort still affects\n        // behavior/token usage, but no visible chain-of-thought text comes\n        // back. Older models already default to `'summarized'`, so it's\n        // safe to always request it explicitly rather than gating on model\n        // version.\n        thinking: { type: 'adaptive', display: 'summarized' },\n        output_config: { effort: config.effort },\n      };\n    }\n    if (config.type === 'enabled') {\n      return { thinking: { type: 'enabled', budget_tokens: config.budgetTokens } };\n    }\n    return { thinking: { type: 'disabled' } };\n  }\n\n  /** Per-call thinking configuration takes precedence over the model-level default. */\n  private resolveThinkingConfig(\n    options: LanguageModelV3CallOptions\n  ): GitLabThinkingConfig | undefined {\n    return this.getProviderOption(options, 'thinking') ?? this.config.thinking;\n  }\n\n  /**\n   * Look up a per-request option under `providerOptions.gitlab` first, then under\n   * the provider's configured name (e.g. `gitlab.agentic`). The Set dedupes the\n   * case where the configured name is itself `gitlab`.\n   */\n  private getProviderOption<K extends keyof GitLabAnthropicProviderOptions>(\n    options: LanguageModelV3CallOptions,\n    name: K\n  ): GitLabAnthropicProviderOptions[K] | undefined {\n    const providerOptions = options.providerOptions;\n    if (!providerOptions) return undefined;\n    for (const key of new Set(['gitlab', this.config.provider])) {\n      const scoped: unknown = providerOptions[key];\n      if (typeof scoped !== 'object' || scoped === null) continue;\n      const value = (scoped as Record<string, unknown>)[name];\n      if (value !== undefined) return value as GitLabAnthropicProviderOptions[K];\n    }\n    return undefined;\n  }\n\n  private validateThinkingConfig(\n    config: GitLabThinkingConfig | undefined,\n    maxTokens: number\n  ): void {\n    if (config?.type === 'enabled' && config.budgetTokens >= maxTokens) {\n      throw new GitLabError({\n        message:\n          `Anthropic thinking budgetTokens (${config.budgetTokens}) must be less than ` +\n          `maxTokens (${maxTokens}).`,\n        statusCode: 400,\n      });\n    }\n  }\n\n  /**\n   * Rebuild an Anthropic thinking block from a prior-turn reasoning part.\n   * Anthropic requires thinking blocks to be replayed unmodified (with their\n   * signature) during tool-use loops; the signature / redacted payload are\n   * carried in the reasoning part's provider metadata under `gitlab`.\n   */\n  private convertReasoningPart(part: {\n    text: string;\n    providerOptions?: Record<string, Record<string, unknown>>;\n  }): Anthropic.ContentBlockParam | undefined {\n    const meta = part.providerOptions?.['gitlab'];\n    const redactedData = meta?.['redactedData'];\n    if (typeof redactedData === 'string') {\n      return { type: 'redacted_thinking', data: redactedData };\n    }\n\n    const signature = meta?.['signature'];\n    // A thinking block without its signature cannot be replayed — Anthropic\n    // rejects unsigned thinking blocks — so drop it rather than send a 400.\n    if (typeof signature !== 'string') {\n      return undefined;\n    }\n    return { type: 'thinking', thinking: part.text, signature };\n  }\n\n  private isThinkingActive(config: GitLabThinkingConfig | undefined): boolean {\n    return config?.type === 'enabled' || config?.type === 'adaptive';\n  }\n\n  /**\n   * Anthropic rejects `temperature` changes while thinking is active and requires\n   * `top_p` within [0.95, 1]; drop those params when thinking is engaged so the\n   * gateway does not 400. Undefined values are omitted either way.\n   */\n  private buildSamplingParams(\n    options: LanguageModelV3CallOptions,\n    thinkingConfig: GitLabThinkingConfig | undefined\n  ): { temperature?: number; top_p?: number } {\n    const params: { temperature?: number; top_p?: number } = {};\n    const thinkingActive = this.isThinkingActive(thinkingConfig);\n\n    if (options.temperature != null && !thinkingActive) {\n      params.temperature = options.temperature;\n    }\n\n    if (options.topP != null) {\n      if (!thinkingActive || (options.topP >= 0.95 && options.topP <= 1)) {\n        params.top_p = options.topP;\n      }\n    }\n\n    return params;\n  }\n\n  /**\n   * Read the `skipCache` flag from provider options. Callers pass it as\n   * `providerOptions.gitlab.skipCache` (or under the provider's own name) to\n   * omit the message-level prompt-cache breakpoints for one-shot / background\n   * invocations whose context is never reused. The system-prompt breakpoint is\n   * always kept. Defaults to false.\n   */\n  private shouldSkipCache(options: LanguageModelV3CallOptions): boolean {\n    const skipCache = this.getProviderOption(options, 'skipCache');\n    return typeof skipCache === 'boolean' ? skipCache : false;\n  }\n\n  async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {\n    return this.doGenerateWithRetry(options, false);\n  }\n\n  private async doGenerateWithRetry(\n    options: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    content: LanguageModelV3Content[];\n    finishReason: LanguageModelV3FinishReason;\n    usage: LanguageModelV3Usage;\n    warnings: [];\n  }> {\n    const { system, messages } = this.convertPrompt(options.prompt, {\n      skipCache: this.shouldSkipCache(options),\n    });\n    const toolsDisabled = options.toolChoice?.type === 'none';\n    const tools = toolsDisabled ? undefined : this.convertTools(options.tools);\n    const toolChoice = toolsDisabled ? undefined : this.convertToolChoice(options.toolChoice);\n\n    const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n    const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n    const thinkingConfig = this.resolveThinkingConfig(options);\n    this.validateThinkingConfig(thinkingConfig, maxTokens);\n    const client = await this.getAnthropicClient(isRetry);\n\n    const generateParams = {\n      model: anthropicModel,\n      max_tokens: maxTokens,\n      system: system,\n      messages: messages,\n      tools: tools,\n      tool_choice: tools ? toolChoice : undefined,\n      ...this.buildSamplingParams(options, thinkingConfig),\n      stop_sequences: options.stopSequences,\n      ...this.buildThinkingParams(thinkingConfig),\n    };\n\n    try {\n      const response = options.abortSignal\n        ? await client.messages.create(generateParams, { signal: options.abortSignal })\n        : await client.messages.create(generateParams);\n\n      const content: LanguageModelV3Content[] = [];\n\n      for (const block of response.content) {\n        if (block.type === 'thinking') {\n          content.push({\n            type: 'reasoning',\n            text: block.thinking,\n            providerMetadata: { gitlab: { signature: block.signature } },\n          });\n        } else if (block.type === 'redacted_thinking') {\n          content.push({\n            type: 'reasoning',\n            text: '',\n            providerMetadata: { gitlab: { redactedData: block.data } },\n          });\n        } else 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 rawUsage = response.usage as unknown as Record<string, number>;\n      const usage = this.createUsage({\n        inputTotal: response.usage.input_tokens,\n        outputTotal: response.usage.output_tokens,\n        cacheRead: rawUsage.cache_read_input_tokens,\n        cacheWrite: rawUsage.cache_creation_input_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: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {\n    return this.doStreamWithRetry(options, false);\n  }\n\n  private async doStreamWithRetry(\n    options: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    stream: ReadableStream<LanguageModelV3StreamPart>;\n    request?: { body?: unknown };\n    response?: { headers?: Record<string, string> };\n  }> {\n    const { system, messages } = this.convertPrompt(options.prompt, {\n      skipCache: this.shouldSkipCache(options),\n    });\n    const toolsDisabled = options.toolChoice?.type === 'none';\n    const tools = toolsDisabled ? undefined : this.convertTools(options.tools);\n    const toolChoice = toolsDisabled ? undefined : this.convertToolChoice(options.toolChoice);\n\n    const anthropicModel = this.config.anthropicModel || 'claude-sonnet-4-5-20250929';\n    const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n    const thinkingConfig = this.resolveThinkingConfig(options);\n    this.validateThinkingConfig(thinkingConfig, maxTokens);\n    const client = await this.getAnthropicClient(isRetry);\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      ...this.buildSamplingParams(options, thinkingConfig),\n      stop_sequences: options.stopSequences,\n      ...this.buildThinkingParams(thinkingConfig),\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 abortController = new AbortController();\n    if (options.abortSignal) {\n      if (options.abortSignal.aborted) {\n        abortController.abort(options.abortSignal.reason);\n      } else {\n        options.abortSignal.addEventListener('abort', () =>\n          abortController.abort(options.abortSignal?.reason)\n        );\n      }\n    }\n    let streamClosed = false;\n\n    const stream = new ReadableStream<LanguageModelV3StreamPart>({\n      cancel: () => {\n        streamClosed = true;\n        abortController.abort();\n      },\n      start: async (controller) => {\n        const safeEnqueue = (part: LanguageModelV3StreamPart) => {\n          if (streamClosed) return;\n          try {\n            controller.enqueue(part);\n          } catch {\n            streamClosed = true;\n          }\n        };\n        const safeClose = () => {\n          if (streamClosed) return;\n          streamClosed = true;\n          try {\n            controller.close();\n          } catch {\n            // already closed\n          }\n        };\n\n        const contentBlocks: Record<\n          number,\n          | { type: 'text'; id: string }\n          | { type: 'reasoning'; id: string; signature?: string; redactedData?: string }\n          | { type: 'tool-call'; toolCallId: string; toolName: string; input: string }\n        > = {};\n\n        let usage = self.createUsage();\n        let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined };\n        let finishEmitted = false;\n        let contentEmitted = false;\n\n        const flushPendingToolCalls = () => {\n          for (const [index, block] of Object.entries(contentBlocks)) {\n            if (block.type === 'tool-call') {\n              safeEnqueue({\n                type: 'tool-input-end',\n                id: block.toolCallId,\n              });\n              safeEnqueue({\n                type: 'tool-call',\n                toolCallId: block.toolCallId,\n                toolName: block.toolName,\n                input: block.input === '' ? '{}' : block.input,\n              });\n            }\n            delete contentBlocks[Number(index)];\n          }\n        };\n\n        try {\n          const anthropicStream = client.messages.stream(requestBody, {\n            signal: abortController.signal,\n          });\n\n          // Stream start\n          safeEnqueue({\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                      const msgUsage = event.message.usage as {\n                        input_tokens?: number;\n                        cache_read_input_tokens?: number;\n                        cache_creation_input_tokens?: number;\n                      };\n                      usage = self.createUsage({\n                        inputTotal: msgUsage.input_tokens,\n                        outputTotal: usage.outputTokens.total,\n                        outputReasoning: usage.outputTokens.reasoning,\n                        cacheRead: msgUsage.cache_read_input_tokens,\n                        cacheWrite: msgUsage.cache_creation_input_tokens,\n                        raw: usage.raw,\n                      });\n                    }\n                    safeEnqueue({\n                      type: 'response-metadata',\n                      id: event.message.id,\n                      modelId: event.message.model,\n                    });\n                    break;\n\n                  case 'content_block_start':\n                    contentEmitted = true;\n                    if (event.content_block.type === 'text') {\n                      const textId = `text-${event.index}`;\n                      contentBlocks[event.index] = { type: 'text', id: textId };\n                      safeEnqueue({\n                        type: 'text-start',\n                        id: textId,\n                      });\n                    } else if (event.content_block.type === 'thinking') {\n                      const reasoningId = `reasoning-${event.index}`;\n                      contentBlocks[event.index] = { type: 'reasoning', id: reasoningId };\n                      safeEnqueue({\n                        type: 'reasoning-start',\n                        id: reasoningId,\n                      });\n                    } else if (event.content_block.type === 'redacted_thinking') {\n                      const reasoningId = `reasoning-${event.index}`;\n                      contentBlocks[event.index] = {\n                        type: 'reasoning',\n                        id: reasoningId,\n                        redactedData: event.content_block.data,\n                      };\n                      safeEnqueue({\n                        type: 'reasoning-start',\n                        id: reasoningId,\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                      safeEnqueue({\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                      safeEnqueue({\n                        type: 'text-delta',\n                        id: block.id,\n                        delta: event.delta.text,\n                      });\n                    } else if (\n                      event.delta.type === 'thinking_delta' &&\n                      block?.type === 'reasoning'\n                    ) {\n                      safeEnqueue({\n                        type: 'reasoning-delta',\n                        id: block.id,\n                        delta: event.delta.thinking,\n                      });\n                    } else if (\n                      event.delta.type === 'signature_delta' &&\n                      block?.type === 'reasoning'\n                    ) {\n                      block.signature = event.delta.signature;\n                    } else if (\n                      event.delta.type === 'input_json_delta' &&\n                      block?.type === 'tool-call'\n                    ) {\n                      block.input += event.delta.partial_json;\n                      safeEnqueue({\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                      safeEnqueue({\n                        type: 'text-end',\n                        id: block.id,\n                      });\n                    } else if (block?.type === 'reasoning') {\n                      const gitlabMeta =\n                        block.redactedData != null\n                          ? { redactedData: block.redactedData }\n                          : block.signature != null\n                            ? { signature: block.signature }\n                            : undefined;\n                      safeEnqueue({\n                        type: 'reasoning-end',\n                        id: block.id,\n                        ...(gitlabMeta && { providerMetadata: { gitlab: gitlabMeta } }),\n                      });\n                    } else if (block?.type === 'tool-call') {\n                      safeEnqueue({\n                        type: 'tool-input-end',\n                        id: block.toolCallId,\n                      });\n\n                      safeEnqueue({\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                      const deltaUsage = event.usage as {\n                        output_tokens?: number;\n                        cache_read_input_tokens?: number;\n                        cache_creation_input_tokens?: number;\n                      };\n                      usage = self.createUsage({\n                        inputTotal: usage.inputTokens.noCache,\n                        outputTotal: deltaUsage.output_tokens,\n                        outputReasoning: usage.outputTokens.reasoning,\n                        cacheRead:\n                          deltaUsage.cache_read_input_tokens ?? usage.inputTokens.cacheRead,\n                        cacheWrite:\n                          deltaUsage.cache_creation_input_tokens ?? usage.inputTokens.cacheWrite,\n                        raw: usage.raw,\n                      });\n                    }\n                    if (event.delta.stop_reason) {\n                      finishReason = self.convertFinishReason(event.delta.stop_reason);\n                    }\n                    break;\n\n                  case 'message_stop': {\n                    flushPendingToolCalls();\n                    finishEmitted = true;\n                    safeEnqueue({\n                      type: 'finish',\n                      finishReason,\n                      usage,\n                    });\n                    break;\n                  }\n                }\n              } catch (error) {\n                safeEnqueue({\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          // and guarantee a finish part even when message_stop never arrived.\n          flushPendingToolCalls();\n          if (!finishEmitted) {\n            finishEmitted = true;\n            safeEnqueue({\n              type: 'finish',\n              finishReason,\n              usage,\n            });\n          }\n\n          safeClose();\n        } catch (error) {\n          // Emit any pending tool calls before handling the error\n          flushPendingToolCalls();\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            safeEnqueue({\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            safeClose();\n            return;\n          }\n\n          // If this is a token error and we haven't retried yet, refresh the token\n          // and retry the stream once — but only if no content was emitted yet.\n          if (!isRetry && self.isTokenError(error)) {\n            self.directAccessClient.invalidateToken();\n            if (!contentEmitted) {\n              try {\n                const retried = await self.doStreamWithRetry(options, true);\n                const reader = retried.stream.getReader();\n                for (;;) {\n                  const { done, value } = await reader.read();\n                  if (done) break;\n                  if (value.type === 'stream-start') continue;\n                  safeEnqueue(value);\n                }\n                safeClose();\n                return;\n              } catch (retryError) {\n                safeEnqueue({\n                  type: 'error',\n                  error:\n                    retryError instanceof GitLabError\n                      ? retryError\n                      : new GitLabError({\n                          message: 'Token refresh retry failed',\n                          cause: retryError,\n                        }),\n                });\n                safeClose();\n                return;\n              }\n            }\n            safeEnqueue({\n              type: 'error',\n              error: new GitLabError({\n                message: 'TOKEN_REFRESH_NEEDED',\n                cause: error,\n              }),\n            });\n            safeClose();\n            return;\n          }\n\n          if (error instanceof Anthropic.APIError) {\n            safeEnqueue({\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            safeEnqueue({\n              type: 'error',\n              error,\n            });\n          }\n          safeClose();\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';\nimport { sanitizeErrorText } from './gitlab-workflow-token-client';\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  /**\n   * Optional async hook that resolves once credentials are loaded.\n   * `getHeaders` is synchronous, but the API key is loaded asynchronously; the\n   * client awaits this before building request headers so the first request on\n   * a cold provider doesn't race the lazy key load (which would otherwise throw\n   * \"API key is missing\" or send an empty Authorization header).\n   */\n  ensureApiKey?: () => Promise<void>;\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   * Private POSIX directory for cross-process token caching; empty string disables it.\n   * Falls back to GITLAB_DIRECT_ACCESS_CACHE_DIR when omitted.\n   * @default undefined\n   */\n  directAccessCacheDir?: 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  private invalidationVersion = 0;\n  private refreshedVersion = 0;\n  private cachedScope: string | null = null;\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    const directory =\n      this.config.directAccessCacheDir ?? process.env['GITLAB_DIRECT_ACCESS_CACHE_DIR'];\n    if (!directory && !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    // Ensure the (asynchronously loaded) API key is ready before building the\n    // synchronous headers, so a cold first request doesn't race the lazy load.\n    if (this.config.ensureApiKey) {\n      await this.config.ensureApiKey();\n    }\n\n    try {\n      const headers = this.config.getHeaders();\n      const scope = JSON.stringify([\n        url,\n        this.aiGatewayUrl,\n        Object.entries(headers).sort(([a], [b]) => a.localeCompare(b)),\n        Object.entries(this.config.featureFlags ?? {}).sort(([a], [b]) => a.localeCompare(b)),\n      ]);\n      const version = this.invalidationVersion;\n      const bypass = version !== this.refreshedVersion;\n      if (\n        directory &&\n        !bypass &&\n        this.cachedScope === scope &&\n        this.cachedToken &&\n        this.tokenExpiresAt > Date.now()\n      ) {\n        return this.cachedToken;\n      }\n      const request = (signal?: AbortSignal) =>\n        this.fetchFn(url, {\n          method: 'POST',\n          signal,\n          headers: {\n            ...headers,\n            'Content-Type': 'application/json',\n          },\n          body: JSON.stringify(requestBody),\n        });\n      const shared = directory\n        ? await (\n            await import('./gitlab-direct-access-cache')\n          ).cachedDirectAccess(directory, scope, bypass, request)\n        : undefined;\n      const response = shared?.response ?? (await request());\n\n      if (!response.ok) {\n        const errorText = await response.text();\n        const safeError = sanitizeErrorText(errorText);\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 (retryError) {\n            if (retryError instanceof GitLabError) {\n              throw retryError;\n            }\n            throw new GitLabError({\n              message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${safeError}`,\n              statusCode: response.status,\n              responseBody: safeError,\n              cause: retryError,\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} - ${safeError}`,\n            statusCode: response.status,\n            responseBody: safeError,\n          });\n        }\n\n        throw new GitLabError({\n          message: `Failed to get direct access token: ${response.status} ${response.statusText} - ${safeError}`,\n          statusCode: response.status,\n          responseBody: safeError,\n        });\n      }\n\n      const data = await response.json();\n      const token = directAccessTokenSchema.parse(data);\n      this.refreshedVersion = version;\n\n      // Cache the token for 25 minutes (tokens expire after 30 minutes)\n      this.cachedToken = token;\n      this.tokenExpiresAt = shared?.expiresAt ?? now + 25 * 60 * 1000;\n      this.cachedScope = scope;\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    this.invalidationVersion++;\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  declare readonly cause?: unknown;\n\n  constructor(options: GitLabErrorOptions) {\n    super(options.message, { cause: options.cause });\n    this.name = 'GitLabError';\n    this.statusCode = options.statusCode;\n    this.responseBody = options.responseBody;\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","/**\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\nimport * as path from 'node:path';\nimport * as fs from 'node:fs';\nimport { GitLabError } from './gitlab-error';\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 GitLabError({\n      message: `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 * Validate a server-supplied path argument before forwarding it to a host tool.\n *\n * Absolute paths are passed through — the host's permission-gated tool system\n * is responsible for confining them. Relative paths must stay within the\n * current working directory (no `..` escapes), and null bytes are rejected.\n */\nfunction validateMappedPath(value: unknown, fieldName: string): string {\n  const filePath = String(value ?? '');\n  if (filePath.includes('\\0')) {\n    throw new GitLabError({ message: `${fieldName} contains null bytes` });\n  }\n  if (filePath && !path.isAbsolute(filePath)) {\n    const resolved = path.resolve(filePath);\n    const cwd = process.cwd();\n    if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {\n      throw new GitLabError({\n        message: `${fieldName} resolves outside the working directory: ${filePath}`,\n      });\n    }\n  }\n  return filePath;\n}\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  availableTools?: Set<string>\n): { toolName: string; args: Record<string, unknown> } {\n  const has = (name: string) => !availableTools || availableTools.has(name);\n\n  switch (dwsToolName) {\n    case 'runReadFile':\n      return {\n        toolName: 'read',\n        args: { filePath: validateMappedPath(data.filepath, 'filepath') },\n      };\n    case 'runReadFiles': {\n      const paths = ((data.filepaths as string[]) ?? []).map((p) =>\n        validateMappedPath(p, 'filepath')\n      );\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      const writePath = validateMappedPath(data.filepath, 'filepath');\n      if (has('write')) {\n        return {\n          toolName: 'write',\n          args: { filePath: writePath, content: data.contents },\n        };\n      }\n      // Fallback to apply_patch using the *** Begin/End Patch format\n      const filePath = String(data.filepath ?? '');\n      const content = String(data.contents ?? '');\n      const patchLines = [\n        '*** Begin Patch',\n        `*** Add File: ${filePath}`,\n        ...content.split('\\n').map((l) => `+${l}`),\n        '*** End Patch',\n      ].join('\\n');\n      return { toolName: 'apply_patch', args: { patchText: patchLines } };\n    }\n    case 'runEditFile': {\n      // Proto3 omitempty: empty strings are omitted from JSON, so these fields\n      // may be absent (undefined) even when the LLM provided empty strings.\n      // Default to '' so the edit tool's empty-oldString=create path is used.\n      const editOldString = String(data.oldString ?? data.old_string ?? '');\n      const editNewString = String(data.newString ?? data.new_string ?? '');\n      const editFilePath = validateMappedPath(data.filepath, 'filepath');\n      if (has('edit')) {\n        return {\n          toolName: 'edit',\n          args: {\n            filePath: editFilePath,\n            oldString: editOldString,\n            newString: editNewString,\n          },\n        };\n      }\n      // Fallback to apply_patch using the *** Begin/End Patch format\n      const editPath = String(data.filepath ?? '');\n      const oldStr = editOldString;\n      const newStr = editNewString;\n      const oldLines = oldStr.split('\\n');\n      const newLines = newStr.split('\\n');\n      // Empty context (@@ with no text) tells the parser to search from the start\n      // of the file rather than seeking to a specific anchor line first. Using\n      // the first old line as context would advance lineIndex past it, causing\n      // the subsequent old_lines match to fail.\n      const patchContent = [\n        '*** Begin Patch',\n        `*** Update File: ${editPath}`,\n        '@@',\n        ...oldLines.map((l) => `-${l}`),\n        ...newLines.map((l) => `+${l}`),\n        '*** End Patch',\n      ].join('\\n');\n      return { toolName: 'apply_patch', args: { patchText: patchContent } };\n    }\n    case 'runShellCommand': {\n      const command = data.command as string;\n      if (!command || typeof command !== 'string') {\n        throw new GitLabError({\n          message: 'runShellCommand: command is required and must be a string',\n        });\n      }\n      if (command.length > 10000) {\n        throw new GitLabError({\n          message: 'runShellCommand: command exceeds maximum length of 10000 characters',\n        });\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 GitLabError({ message: '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 GitLabError({\n          message: 'runGitCommand: command is required and must be a string',\n        });\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 {\n        toolName: 'read',\n        args: { filePath: validateMappedPath(data.directory ?? '.', 'directory') },\n      };\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 GitLabError({ message: 'mkdir: directory_path is required' });\n      }\n      if (dirPath.includes('\\0')) {\n        throw new GitLabError({ message: '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 GitLabError({ message: `runHTTPRequest: invalid HTTP method '${methodRaw}'` });\n      }\n\n      const urlPath = String(data.path ?? '');\n      if (!urlPath) {\n        throw new GitLabError({ message: 'runHTTPRequest: path is required' });\n      }\n\n      let parsedUrl: URL | null = null;\n      try {\n        parsedUrl = new URL(urlPath);\n      } catch {\n        parsedUrl = null;\n      }\n      if (parsedUrl) {\n        if (!ALLOWED_URL_SCHEMES.includes(parsedUrl.protocol)) {\n          throw new GitLabError({\n            message: `runHTTPRequest: only http:// and https:// schemes are allowed, got '${parsedUrl.protocol}'`,\n          });\n        }\n      } else if (!urlPath.startsWith('/')) {\n        throw new GitLabError({\n          message:\n            'runHTTPRequest: only http:// and https:// schemes are allowed, ' +\n            `got a non-URL value '${urlPath}' (curl would guess the protocol)`,\n        });\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/**\n * Resolve symlinks on the deepest existing ancestor of a path so that\n * symlink-based escapes from the working directory are detected even\n * for paths that do not exist yet.\n */\nfunction realpathDeepestExisting(targetPath: string): string {\n  let current = targetPath;\n  let suffix = '';\n  for (;;) {\n    try {\n      const real = fs.realpathSync(current);\n      return suffix ? path.join(real, suffix) : real;\n    } catch {\n      const parent = path.dirname(current);\n      if (parent === current) {\n        return targetPath;\n      }\n      suffix = suffix ? path.join(path.basename(current), suffix) : path.basename(current);\n      current = parent;\n    }\n  }\n}\n\n/**\n * Validate that a file path resolves to within the current working directory.\n * Prevents path traversal attacks (e.g., `../../etc/passwd`), including\n * escapes through symlinks that point outside the working directory.\n */\nexport function validateSafePath(filePath: string): string {\n  if (!filePath) {\n    throw new GitLabError({ message: 'filePath is required' });\n  }\n  if (filePath.includes('\\0')) {\n    throw new GitLabError({ message: 'filePath contains null bytes' });\n  }\n  const resolved = path.resolve(filePath);\n  const cwd = process.cwd();\n  if (!resolved.startsWith(cwd + path.sep) && resolved !== cwd) {\n    throw new GitLabError({\n      message: `filePath resolves outside the working directory: ${filePath}`,\n    });\n  }\n  const realResolved = realpathDeepestExisting(resolved);\n  const realCwd = realpathDeepestExisting(cwd);\n  if (!realResolved.startsWith(realCwd + path.sep) && realResolved !== realCwd) {\n    throw new GitLabError({\n      message: `filePath resolves outside the working directory: ${filePath}`,\n    });\n  }\n  return resolved;\n}\n\n/**\n * Direct file operation fallback for when the host doesn't have edit/write\n * tools (e.g., GPT models that use apply_patch instead).\n *\n * This performs the same string-replacement logic as the host's `edit` tool\n * but without requiring the tool to be registered. It runs synchronously\n * using Node.js fs so that DWS builtins always succeed regardless of the\n * host's tool configuration.\n *\n * All file paths are validated to be within the current working directory\n * to prevent path traversal attacks.\n *\n * Returns null if the tool is not one we can handle as a fallback.\n */\nexport function executeBuiltinFallback(\n  toolName: string,\n  argsJson: string\n): {\n  result: string;\n  error?: string | null;\n  metadata?: Record<string, unknown>;\n  title?: string;\n} | null {\n  if (toolName !== 'edit' && toolName !== 'write') {\n    return null;\n  }\n\n  let args: Record<string, unknown>;\n  try {\n    args = JSON.parse(argsJson);\n  } catch {\n    return { result: '', error: `${toolName} fallback: invalid JSON arguments` };\n  }\n\n  try {\n    if (toolName === 'write') {\n      const filePath = String(args.filePath ?? '');\n      if (!filePath) {\n        return { result: '', error: 'write fallback: filePath is required' };\n      }\n      const safePath = validateSafePath(filePath);\n      const content = String(args.content ?? '');\n      fs.writeFileSync(safePath, content, 'utf-8');\n      return {\n        result: 'File written successfully.',\n        title: filePath,\n        metadata: { output: 'File written successfully.' },\n      };\n    }\n\n    const filePath = String(args.filePath ?? '');\n    const oldString = String(args.oldString ?? '');\n    const newString = String(args.newString ?? '');\n\n    if (!filePath) {\n      return { result: '', error: 'edit fallback: filePath is required' };\n    }\n    if (!oldString && !newString) {\n      return { result: '', error: 'edit fallback: oldString and newString are both empty' };\n    }\n\n    const safePath = validateSafePath(filePath);\n\n    let content: string;\n    try {\n      content = fs.readFileSync(safePath, 'utf-8');\n    } catch {\n      content = '';\n    }\n\n    if (oldString === '') {\n      fs.writeFileSync(safePath, newString, 'utf-8');\n      return {\n        result: 'Edit applied successfully.',\n        title: filePath,\n        metadata: { output: 'Edit applied successfully.' },\n      };\n    }\n\n    const idx = content.indexOf(oldString);\n    if (idx === -1) {\n      return { result: '', error: `edit fallback: could not find oldString in ${filePath}` };\n    }\n\n    const newContent =\n      content.substring(0, idx) + newString + content.substring(idx + oldString.length);\n    fs.writeFileSync(safePath, newContent, 'utf-8');\n\n    return {\n      result: 'Edit applied successfully.',\n      title: filePath,\n      metadata: { output: 'Edit applied successfully.' },\n    };\n  } catch (e) {\n    const msg = e instanceof Error ? e.message : String(e);\n    return { result: '', error: sanitizeErrorMessage(msg) };\n  }\n}\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  approval?: ApprovalDecision;\n}\n\nexport interface ApprovalDecision {\n  approval?: {\n    remember_approval?: boolean;\n    tool_name?: string;\n    tool_args_json?: string;\n  };\n  rejection?: {\n    message?: string;\n  };\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, as a **plain numeric id** (e.g. `'12'`, not\n   * `'gid://gitlab/Group/12'`).\n   * Sent as `x-gitlab-namespace-id` header on WebSocket and used for workflow\n   * creation. When unset, the WebSocket on self-managed instances falls back to\n   * the namespace of the project detected from the git remote; GitLab.com\n   * relies on the user's default Duo namespace preference.\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   * System prompt to override DWS's default system prompt.\n   * Sent via `flowConfig.prompts[].prompt_template.system`.\n   *\n   * When set and `flowConfig` is not explicitly provided, the SDK\n   * auto-generates the appropriate `flowConfig` and sets\n   * `flowConfigSchemaVersion` to `'v1'`.\n   *\n   * Explicit `flowConfig` takes precedence if both are provided.\n   */\n  systemPrompt?: 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   * Takes precedence over `systemPrompt` if both are provided.\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   * Agent privileges to request when creating the workflow.\n   * Defaults to DEFAULT_AGENT_PRIVILEGES (all privileges).\n   * Pass a subset to restrict which tools DWS pre-approves server-side,\n   * causing TOOL_CALL_APPROVAL_REQUIRED for excluded privileges.\n   */\n  agentPrivileges?: number[];\n\n  /**\n   * Called when DWS requires approval for a tool call.\n   * Return `{ approved: true }` to proceed or `{ approved: false, message? }` to reject.\n   * If not set, the stream ends silently when approval is required (backward compat).\n   */\n  approvalHandler?: (\n    tools: Array<{ name: string; args: string }>\n  ) => Promise<{ approved: boolean; message?: string }>;\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: 'approval-required'; tools: Array<{ name: string; args: string }> }\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/**\n * WebSocket close code Workhorse sends when another session still holds the\n * exclusive lock on the workflow (\"Failed to acquire lock on workflow\").\n */\nexport const WS_CLOSE_WORKFLOW_LOCKED = 1013;\n\n/**\n * How long to wait for the previous socket's close handshake before\n * reconnecting to the same workflow. Workhorse frees the lock only after that\n * handshake, so reconnecting immediately races it.\n */\nexport const WS_CLOSE_WAIT_TIMEOUT_MS = 3_000;\n\n/** Delay before retrying a reconnect that Workhorse rejected with 1013. */\nexport const WS_WORKFLOW_LOCK_RETRY_DELAY_MS = 1_500;\n\n/** How many times to retry a reconnect rejected with 1013. */\nexport const WS_WORKFLOW_LOCK_MAX_RETRIES = 8;\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 = '8.51.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 * 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\n/**\n * Truncate and redact credential-like patterns from raw error response text\n * before embedding it in error messages.\n *\n * @param text - Raw error response body\n * @returns Sanitized text, truncated to 500 characters\n */\nexport function 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 (retryError) {\n            if (retryError instanceof GitLabError) {\n              throw retryError;\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              cause: retryError,\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      aiCatalogItemVersionId?: number;\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      ...(options?.aiCatalogItemVersionId !== undefined && {\n        ai_catalog_item_version_id: options.aiCatalogItemVersionId,\n      }),\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 OpenAI from 'openai';\nimport { GitLabDirectAccessClient } from './gitlab-direct-access';\nimport { GitLabError } from './gitlab-error';\nimport { isResponsesApiModel } from './model-mappings';\n\nimport type {\n  LanguageModelV3,\n  LanguageModelV3CallOptions,\n  LanguageModelV3StreamPart,\n  LanguageModelV3FinishReason,\n  LanguageModelV3Content,\n  LanguageModelV3Usage,\n  LanguageModelV3FunctionTool,\n  LanguageModelV3Message,\n  LanguageModelV3ToolChoice,\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  ensureApiKey?: () => Promise<void>;\n  refreshApiKey?: () => Promise<void>;\n  openaiModel?: string;\n  maxTokens?: number;\n  reasoningEffort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n  featureFlags?: {\n    DuoAgentPlatformNext: true;\n  } & Record<string, boolean>;\n  aiGatewayUrl?: string;\n  directAccessCacheDir?: 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 LanguageModelV3 {\n  readonly specificationVersion = 'v3' 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      ensureApiKey: config.ensureApiKey,\n      refreshApiKey: config.refreshApiKey,\n      fetch: config.fetch,\n      featureFlags: config.featureFlags,\n      aiGatewayUrl: config.aiGatewayUrl,\n      directAccessCacheDir: config.directAccessCacheDir,\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  /**\n   * Build a descriptive error message from an OpenAI APIError.\n   *\n   * The AI Gateway proxy often returns errors with empty bodies, which the\n   * OpenAI SDK renders as \"500 status code (no body)\". This helper surfaces\n   * everything that is actually available: the parsed error body, the\n   * request ID for support, and — for 5xx responses with a large tool set —\n   * a hint that the gateway may be rejecting the request due to tool count.\n   */\n  private formatOpenAIError(\n    error: InstanceType<typeof OpenAI.APIError>,\n    toolCount?: number\n  ): string {\n    const parts: string[] = [`OpenAI API error: ${error.message}`];\n\n    const body = error.error as unknown;\n    if (body) {\n      const detail =\n        typeof body === 'string'\n          ? body\n          : ((body as Record<string, unknown>).message ??\n            (body as Record<string, unknown>).detail ??\n            (body as Record<string, unknown>).error);\n      if (detail && !error.message.includes(String(detail))) {\n        parts.push(`detail: ${typeof detail === 'string' ? detail : JSON.stringify(detail)}`);\n      }\n    }\n\n    const headers = error.headers as { get?: (name: string) => string | null } | undefined;\n    const requestId =\n      typeof headers?.get === 'function'\n        ? (headers.get('x-request-id') ?? headers.get('x-amzn-requestid'))\n        : undefined;\n    if (requestId) {\n      parts.push(`request-id: ${requestId}`);\n    }\n\n    const isOpaque = error.message?.includes('no body');\n    if (\n      error.status != null &&\n      error.status >= 400 &&\n      isOpaque &&\n      toolCount != null &&\n      toolCount > 20\n    ) {\n      parts.push(\n        `Hint: the request included ${toolCount} tools; the GitLab AI Gateway may reject ` +\n          'large tool sets — try reducing the number of enabled tools or MCP servers.'\n      );\n    }\n\n    return parts.join(' | ');\n  }\n\n  /**\n   * Per-call `providerOptions.gitlab.reasoningEffort` takes precedence over the\n   * model-level default.\n   */\n  private resolveReasoningEffort(\n    options: LanguageModelV3CallOptions\n  ): GitLabOpenAIConfig['reasoningEffort'] {\n    const gitlabOptions = (options.providerOptions as Record<string, unknown> | undefined)?.[\n      'gitlab'\n    ] as Record<string, unknown> | undefined;\n    return (\n      (gitlabOptions?.reasoningEffort as GitLabOpenAIConfig['reasoningEffort']) ??\n      this.config.reasoningEffort\n    );\n  }\n\n  private asOpenAIReasoningEffort(\n    effort: NonNullable<GitLabOpenAIConfig['reasoningEffort']>\n  ): OpenAI.ReasoningEffort {\n    // The API supports `max`, but the pinned OpenAI SDK's ReasoningEffort type\n    // predates it. Keep the compatibility cast isolated at serialization.\n    return effort as OpenAI.ReasoningEffort;\n  }\n\n  private convertTools(\n    tools?: LanguageModelV3CallOptions['tools']\n  ): OpenAI.ChatCompletionTool[] | undefined {\n    if (!tools || tools.length === 0) {\n      return undefined;\n    }\n\n    return tools\n      .filter((tool): tool is LanguageModelV3FunctionTool => 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?: LanguageModelV3ToolChoice\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: LanguageModelV3Message[]): 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 === 'content') {\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 if (part.output.type === 'execution-denied') {\n              resultContent = part.output.reason ?? 'Tool execution denied.';\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  ): LanguageModelV3FinishReason {\n    const unified: LanguageModelV3FinishReason['unified'] = (() => {\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 'other';\n      }\n    })();\n\n    return { unified, raw: finishReason ?? undefined };\n  }\n\n  private createUsage(params?: {\n    inputTotal?: number;\n    outputTotal?: number;\n    outputReasoning?: number;\n    cacheRead?: number;\n    raw?: LanguageModelV3Usage['raw'];\n  }): LanguageModelV3Usage {\n    const inputTotal = params?.inputTotal;\n    const outputTotal = params?.outputTotal;\n    const cacheRead = params?.cacheRead;\n\n    return {\n      inputTokens: {\n        total: inputTotal,\n        noCache: inputTotal == null ? undefined : Math.max(0, inputTotal - (cacheRead ?? 0)),\n        cacheRead,\n        cacheWrite: undefined,\n      },\n      outputTokens: {\n        total: outputTotal,\n        text: outputTotal != null ? outputTotal - (params?.outputReasoning ?? 0) : undefined,\n        reasoning: params?.outputReasoning,\n      },\n      raw: params?.raw,\n    };\n  }\n\n  /**\n   * Convert tools to Responses API format\n   */\n  private convertToolsForResponses(\n    tools?: LanguageModelV3CallOptions['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 LanguageModelV3FunctionTool => 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          // Responses may normalize schemas into strict mode when this field is omitted.\n          strict: tool.strict ?? false,\n        };\n      });\n  }\n\n  /**\n   * Convert prompt to Responses API input format\n   */\n  private convertPromptForResponses(\n    prompt: LanguageModelV3Message[]\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 === 'content') {\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 if (part.output.type === 'execution-denied') {\n              resultContent = part.output.reason ?? 'Tool execution denied.';\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: LanguageModelV3Message[]): 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  ): LanguageModelV3FinishReason {\n    // If we have tool calls, return 'tool-calls' regardless of status\n    if (hasToolCalls) {\n      return { unified: 'tool-calls', raw: status };\n    }\n\n    const unified: LanguageModelV3FinishReason['unified'] = (() => {\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 'other';\n      }\n    })();\n\n    return { unified, raw: status };\n  }\n\n  async doGenerate(options: LanguageModelV3CallOptions): Promise<{\n    content: LanguageModelV3Content[];\n    finishReason: LanguageModelV3FinishReason;\n    usage: LanguageModelV3Usage;\n    warnings: [];\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: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    content: LanguageModelV3Content[];\n    finishReason: LanguageModelV3FinishReason;\n    usage: LanguageModelV3Usage;\n    warnings: [];\n  }> {\n    const client = await this.getOpenAIClient(isRetry);\n    const messages = this.convertPrompt(options.prompt);\n    const toolsDisabled = options.toolChoice?.type === 'none';\n    const tools = toolsDisabled ? undefined : this.convertTools(options.tools);\n    const toolChoice = toolsDisabled ? undefined : this.convertToolChoice(options.toolChoice);\n\n    const openaiModel = this.config.openaiModel || 'gpt-4o';\n    const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n    const reasoningEffort = this.resolveReasoningEffort(options);\n\n    const generateParams = {\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      ...(reasoningEffort && {\n        reasoning_effort: this.asOpenAIReasoningEffort(reasoningEffort),\n      }),\n    };\n\n    try {\n      const response = options.abortSignal\n        ? await client.chat.completions.create(generateParams, { signal: options.abortSignal })\n        : await client.chat.completions.create(generateParams);\n\n      const choice = response.choices[0];\n      const content: LanguageModelV3Content[] = [];\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 = this.createUsage({\n        inputTotal: response.usage?.prompt_tokens,\n        outputTotal: response.usage?.completion_tokens,\n        cacheRead: response.usage?.prompt_tokens_details?.cached_tokens,\n        raw: { total_tokens: response.usage?.total_tokens },\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: this.formatOpenAIError(error, tools?.length),\n          statusCode: error.status,\n          cause: error,\n        });\n      }\n      throw error;\n    }\n  }\n\n  private async doGenerateWithResponsesApi(\n    options: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    content: LanguageModelV3Content[];\n    finishReason: LanguageModelV3FinishReason;\n    usage: LanguageModelV3Usage;\n    warnings: [];\n  }> {\n    const client = await this.getOpenAIClient(isRetry);\n    const input = this.convertPromptForResponses(options.prompt);\n    const tools =\n      options.toolChoice?.type === 'none'\n        ? undefined\n        : 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    const reasoningEffort = this.resolveReasoningEffort(options);\n\n    const generateParams = {\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      ...(reasoningEffort && {\n        // `summary: 'auto'` opts into visible reasoning summary text.\n        // Without it, the Responses API never returns summary content —\n        // the model still reasons and effort still affects behavior, but\n        // no chain-of-thought text comes back (mirrors the Anthropic\n        // `thinking.display` gap fixed in buildThinkingParams).\n        reasoning: {\n          effort: this.asOpenAIReasoningEffort(reasoningEffort),\n          summary: 'auto' as const,\n        },\n      }),\n    };\n\n    try {\n      const response = options.abortSignal\n        ? await client.responses.create(generateParams, { signal: options.abortSignal })\n        : await client.responses.create(generateParams);\n\n      const content: LanguageModelV3Content[] = [];\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        } else if (item.type === 'reasoning') {\n          for (const summary of item.summary || []) {\n            if (summary.type === 'summary_text' && summary.text) {\n              content.push({ type: 'reasoning', text: summary.text });\n            }\n          }\n        }\n      }\n\n      const usage = this.createUsage({\n        inputTotal: response.usage?.input_tokens,\n        outputTotal: response.usage?.output_tokens,\n        outputReasoning: response.usage?.output_tokens_details?.reasoning_tokens,\n        cacheRead: response.usage?.input_tokens_details?.cached_tokens,\n        raw: { total_tokens: response.usage?.total_tokens },\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: this.formatOpenAIError(error, tools?.length),\n          statusCode: error.status,\n          cause: error,\n        });\n      }\n      throw error;\n    }\n  }\n\n  async doStream(options: LanguageModelV3CallOptions): Promise<{\n    stream: ReadableStream<LanguageModelV3StreamPart>;\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: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    stream: ReadableStream<LanguageModelV3StreamPart>;\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 toolsDisabled = options.toolChoice?.type === 'none';\n    const tools = toolsDisabled ? undefined : this.convertTools(options.tools);\n    const toolChoice = toolsDisabled ? undefined : this.convertToolChoice(options.toolChoice);\n\n    const openaiModel = this.config.openaiModel || 'gpt-4o';\n    const maxTokens = options.maxOutputTokens || this.config.maxTokens || 8192;\n    const reasoningEffort = this.resolveReasoningEffort(options);\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      ...(reasoningEffort && {\n        reasoning_effort: this.asOpenAIReasoningEffort(reasoningEffort),\n      }),\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 abortController = new AbortController();\n    if (options.abortSignal) {\n      if (options.abortSignal.aborted) {\n        abortController.abort(options.abortSignal.reason);\n      } else {\n        options.abortSignal.addEventListener('abort', () =>\n          abortController.abort(options.abortSignal?.reason)\n        );\n      }\n    }\n    let streamClosed = false;\n\n    const stream = new ReadableStream<LanguageModelV3StreamPart>({\n      cancel: () => {\n        streamClosed = true;\n        abortController.abort();\n      },\n      start: async (controller) => {\n        const safeEnqueue = (part: LanguageModelV3StreamPart) => {\n          if (streamClosed) return;\n          try {\n            controller.enqueue(part);\n          } catch {\n            streamClosed = true;\n          }\n        };\n        const safeClose = () => {\n          if (streamClosed) return;\n          streamClosed = true;\n          try {\n            controller.close();\n          } catch {\n            // already closed\n          }\n        };\n\n        const toolCalls: Record<number, { id: string; name: string; arguments: string }> = {};\n\n        let usage = self.createUsage();\n        let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined };\n        let textStarted = false;\n        let metadataEmitted = false;\n        let contentEmitted = false;\n        const textId = 'text-0';\n\n        try {\n          const openaiStream = await client.chat.completions.create(\n            {\n              ...requestBody,\n              stream: true,\n            },\n            { signal: abortController.signal }\n          );\n\n          safeEnqueue({ type: 'stream-start', warnings: [] });\n\n          for await (const chunk of openaiStream) {\n            const choice = chunk.choices?.[0];\n\n            if (chunk.id && !metadataEmitted) {\n              metadataEmitted = true;\n              safeEnqueue({\n                type: 'response-metadata',\n                id: chunk.id,\n                modelId: chunk.model,\n              });\n            }\n\n            if (choice?.delta?.content) {\n              contentEmitted = true;\n              if (!textStarted) {\n                safeEnqueue({ type: 'text-start', id: textId });\n                textStarted = true;\n              }\n              safeEnqueue({\n                type: 'text-delta',\n                id: textId,\n                delta: choice.delta.content,\n              });\n            }\n\n            if (choice?.delta?.tool_calls) {\n              contentEmitted = true;\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                  safeEnqueue({\n                    type: 'tool-input-start',\n                    id: toolCalls[idx].id,\n                    toolName: toolCalls[idx].name,\n                  });\n                } else {\n                  if (tc.id && !toolCalls[idx].id) {\n                    toolCalls[idx].id = tc.id;\n                  }\n                  if (tc.function?.name && !toolCalls[idx].name) {\n                    toolCalls[idx].name = tc.function.name;\n                  }\n                }\n                if (tc.function?.arguments) {\n                  toolCalls[idx].arguments += tc.function.arguments;\n                  safeEnqueue({\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 = self.createUsage({\n                inputTotal: chunk.usage.prompt_tokens,\n                outputTotal: chunk.usage.completion_tokens,\n                cacheRead: chunk.usage.prompt_tokens_details?.cached_tokens,\n                raw: { total_tokens: chunk.usage.total_tokens },\n              });\n            }\n          }\n\n          if (textStarted) {\n            safeEnqueue({ type: 'text-end', id: textId });\n          }\n\n          for (const [, tc] of Object.entries(toolCalls)) {\n            safeEnqueue({ type: 'tool-input-end', id: tc.id });\n            safeEnqueue({\n              type: 'tool-call',\n              toolCallId: tc.id,\n              toolName: tc.name,\n              input: tc.arguments || '{}',\n            });\n          }\n\n          safeEnqueue({ type: 'finish', finishReason, usage });\n          safeClose();\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            safeEnqueue({\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            safeClose();\n            return;\n          }\n\n          if (!isRetry && self.isTokenError(error)) {\n            self.directAccessClient.invalidateToken();\n            if (!contentEmitted) {\n              try {\n                const retried = await self.doStreamWithChatApi(options, true);\n                const reader = retried.stream.getReader();\n                for (;;) {\n                  const { done, value } = await reader.read();\n                  if (done) break;\n                  if (value.type === 'stream-start') continue;\n                  safeEnqueue(value);\n                }\n                safeClose();\n                return;\n              } catch (retryError) {\n                safeEnqueue({\n                  type: 'error',\n                  error:\n                    retryError instanceof GitLabError\n                      ? retryError\n                      : new GitLabError({\n                          message: 'Token refresh retry failed',\n                          cause: retryError,\n                        }),\n                });\n                safeClose();\n                return;\n              }\n            }\n            safeEnqueue({\n              type: 'error',\n              error: new GitLabError({ message: 'TOKEN_REFRESH_NEEDED', cause: error }),\n            });\n            safeClose();\n            return;\n          }\n\n          if (error instanceof OpenAI.APIError) {\n            safeEnqueue({\n              type: 'error',\n              error: new GitLabError({\n                message: self.formatOpenAIError(error, tools?.length),\n                statusCode: error.status,\n                cause: error,\n              }),\n            });\n          } else {\n            safeEnqueue({ type: 'error', error });\n          }\n          safeClose();\n        }\n      },\n    });\n\n    return { stream, request: { body: requestBody } };\n  }\n\n  private async doStreamWithResponsesApi(\n    options: LanguageModelV3CallOptions,\n    isRetry: boolean\n  ): Promise<{\n    stream: ReadableStream<LanguageModelV3StreamPart>;\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 =\n      options.toolChoice?.type === 'none'\n        ? undefined\n        : 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    const reasoningEffort = this.resolveReasoningEffort(options);\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      ...(reasoningEffort && {\n        // `summary: 'auto'` opts into visible reasoning summary text.\n        // Without it, the Responses API never returns summary content —\n        // the model still reasons and effort still affects behavior, but\n        // no chain-of-thought text comes back (mirrors the Anthropic\n        // `thinking.display` gap fixed in buildThinkingParams).\n        reasoning: {\n          effort: this.asOpenAIReasoningEffort(reasoningEffort),\n          summary: 'auto' as const,\n        },\n      }),\n      stream: true as const,\n    };\n\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    const self = this;\n\n    const abortController = new AbortController();\n    if (options.abortSignal) {\n      if (options.abortSignal.aborted) {\n        abortController.abort(options.abortSignal.reason);\n      } else {\n        options.abortSignal.addEventListener('abort', () =>\n          abortController.abort(options.abortSignal?.reason)\n        );\n      }\n    }\n    let streamClosed = false;\n\n    const stream = new ReadableStream<LanguageModelV3StreamPart>({\n      cancel: () => {\n        streamClosed = true;\n        abortController.abort();\n      },\n      start: async (controller) => {\n        const safeEnqueue = (part: LanguageModelV3StreamPart) => {\n          if (streamClosed) return;\n          try {\n            controller.enqueue(part);\n          } catch {\n            streamClosed = true;\n          }\n        };\n        const safeClose = () => {\n          if (streamClosed) return;\n          streamClosed = true;\n          try {\n            controller.close();\n          } catch {\n            // already closed\n          }\n        };\n\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 activeReasoning = new Set<string>();\n        const knownReasoning = new Set<string>();\n        const reasoningWithText = new Set<string>();\n        let usage = self.createUsage();\n        let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined };\n        let textStarted = false;\n        let contentEmitted = false;\n        const textId = 'text-0';\n\n        const reasoningId = (outputIndex: number, summaryIndex: number) =>\n          `reasoning-${outputIndex}-${summaryIndex}`;\n        const startReasoning = (outputIndex: number, summaryIndex: number) => {\n          const id = reasoningId(outputIndex, summaryIndex);\n          if (!knownReasoning.has(id)) {\n            knownReasoning.add(id);\n            activeReasoning.add(id);\n            contentEmitted = true;\n            safeEnqueue({ type: 'reasoning-start', id });\n          }\n          return id;\n        };\n        const emitReasoningDelta = (outputIndex: number, summaryIndex: number, delta: string) => {\n          const id = startReasoning(outputIndex, summaryIndex);\n          if (activeReasoning.has(id) && delta) {\n            reasoningWithText.add(id);\n            safeEnqueue({ type: 'reasoning-delta', id, delta });\n          }\n        };\n        const endReasoning = (outputIndex: number, summaryIndex: number) => {\n          const id = reasoningId(outputIndex, summaryIndex);\n          if (activeReasoning.delete(id)) {\n            safeEnqueue({ type: 'reasoning-end', id });\n          }\n        };\n\n        try {\n          const openaiStream = await client.responses.create(\n            {\n              ...requestBody,\n              stream: true,\n            },\n            { signal: abortController.signal }\n          );\n\n          safeEnqueue({ 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              safeEnqueue({\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                contentEmitted = true;\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                safeEnqueue({\n                  type: 'tool-input-start',\n                  id: callId,\n                  toolName: event.item.name,\n                });\n              }\n            } else if (event.type === 'response.reasoning_summary_part.added') {\n              startReasoning(event.output_index, event.summary_index);\n            } else if (event.type === 'response.reasoning_summary_text.delta') {\n              emitReasoningDelta(event.output_index, event.summary_index, event.delta);\n            } else if (event.type === 'response.reasoning_summary_text.done') {\n              const id = startReasoning(event.output_index, event.summary_index);\n              if (!reasoningWithText.has(id)) {\n                emitReasoningDelta(event.output_index, event.summary_index, event.text);\n              }\n              endReasoning(event.output_index, event.summary_index);\n            } else if (event.type === 'response.reasoning_summary_part.done') {\n              const id = startReasoning(event.output_index, event.summary_index);\n              if (!reasoningWithText.has(id)) {\n                emitReasoningDelta(event.output_index, event.summary_index, event.part.text);\n              }\n              endReasoning(event.output_index, event.summary_index);\n            } else if (\n              event.type === 'response.output_item.done' &&\n              event.item.type === 'reasoning'\n            ) {\n              const prefix = `reasoning-${event.output_index}-`;\n              for (const id of [...activeReasoning]) {\n                if (id.startsWith(prefix)) {\n                  activeReasoning.delete(id);\n                  safeEnqueue({ type: 'reasoning-end', id });\n                }\n              }\n            } else if (event.type === 'response.output_text.delta') {\n              contentEmitted = true;\n              if (!textStarted) {\n                safeEnqueue({ type: 'text-start', id: textId });\n                textStarted = true;\n              }\n              safeEnqueue({\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                safeEnqueue({\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 = self.createUsage({\n                  inputTotal: event.response.usage.input_tokens,\n                  outputTotal: event.response.usage.output_tokens,\n                  outputReasoning: event.response.usage.output_tokens_details?.reasoning_tokens,\n                  cacheRead: event.response.usage.input_tokens_details?.cached_tokens,\n                  raw: { total_tokens: event.response.usage.total_tokens },\n                });\n              }\n            }\n          }\n\n          for (const id of activeReasoning) {\n            safeEnqueue({ type: 'reasoning-end', id });\n          }\n          activeReasoning.clear();\n\n          if (textStarted) {\n            safeEnqueue({ 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.unified === 'stop') {\n            finishReason = { unified: 'tool-calls', raw: finishReason.raw };\n          }\n\n          for (const tc of Object.values(toolCalls)) {\n            safeEnqueue({ type: 'tool-input-end', id: tc.callId });\n            safeEnqueue({\n              type: 'tool-call',\n              toolCallId: tc.callId,\n              toolName: tc.name,\n              input: tc.arguments || '{}',\n            });\n          }\n\n          safeEnqueue({ type: 'finish', finishReason, usage });\n          safeClose();\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            safeEnqueue({\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            safeClose();\n            return;\n          }\n\n          if (!isRetry && self.isTokenError(error)) {\n            self.directAccessClient.invalidateToken();\n            if (!contentEmitted) {\n              try {\n                const retried = await self.doStreamWithResponsesApi(options, true);\n                const reader = retried.stream.getReader();\n                for (;;) {\n                  const { done, value } = await reader.read();\n                  if (done) break;\n                  if (value.type === 'stream-start') continue;\n                  safeEnqueue(value);\n                }\n                safeClose();\n                return;\n              } catch (retryError) {\n                safeEnqueue({\n                  type: 'error',\n                  error:\n                    retryError instanceof GitLabError\n                      ? retryError\n                      : new GitLabError({\n                          message: 'Token refresh retry failed',\n                          cause: retryError,\n                        }),\n                });\n                safeClose();\n                return;\n              }\n            }\n            safeEnqueue({\n              type: 'error',\n              error: new GitLabError({ message: 'TOKEN_REFRESH_NEEDED', cause: error }),\n            });\n            safeClose();\n            return;\n          }\n\n          if (error instanceof OpenAI.APIError) {\n            safeEnqueue({\n              type: 'error',\n              error: new GitLabError({\n                message: self.formatOpenAIError(error, tools?.length),\n                statusCode: error.status,\n                cause: error,\n              }),\n            });\n          } else {\n            safeEnqueue({ type: 'error', error });\n          }\n          safeClose();\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-fable-5-1': { provider: 'anthropic', model: 'claude-fable-5-1' },\n  'duo-chat-fable-5': { provider: 'anthropic', model: 'claude-fable-5' },\n  'duo-chat-opus-5-5': { provider: 'anthropic', model: 'claude-opus-5-5' },\n  'duo-chat-opus-5': { provider: 'anthropic', model: 'claude-opus-5' },\n  'duo-chat-opus-4-8': { provider: 'anthropic', model: 'claude-opus-4-8' },\n  'duo-chat-opus-4-7': { provider: 'anthropic', model: 'claude-opus-4-7' },\n  'duo-chat-opus-4-6': { provider: 'anthropic', model: 'claude-opus-4-6' },\n  'duo-chat-sonnet-5-5': { provider: 'anthropic', model: 'claude-sonnet-5-5' },\n  'duo-chat-sonnet-5': { provider: 'anthropic', model: 'claude-sonnet-5' },\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-5-5': { provider: 'anthropic', model: 'claude-haiku-5-5' },\n  'duo-chat-haiku-4-5': { provider: 'anthropic', model: 'claude-haiku-4-5-20251001' },\n\n  // OpenAI models - Responses API\n  // GPT-6 models reject `reasoning_effort` with function tools on Chat Completions;\n  // they must use the Responses API (matches OpenAI's own routing for GPT-5.x/GPT-6).\n  'duo-chat-gpt-6-astra': { provider: 'openai', model: 'gpt-6-astra', openaiApiType: 'responses' },\n  'duo-chat-gpt-6-1-sol': { provider: 'openai', model: 'gpt-6.1-sol', openaiApiType: 'responses' },\n  'duo-chat-gpt-6-sol': { provider: 'openai', model: 'gpt-6-sol', openaiApiType: 'responses' },\n  'duo-chat-gpt-6-luna': { provider: 'openai', model: 'gpt-6-luna', openaiApiType: 'responses' },\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-4': { provider: 'openai', model: 'gpt-5.4-2026-03-05', openaiApiType: 'chat' },\n  'duo-chat-gpt-5-5': { provider: 'openai', model: 'gpt-5.5-2026-04-23', openaiApiType: 'chat' },\n  'duo-chat-gpt-5-mini': {\n    provider: 'openai',\n    model: 'gpt-5-mini-2025-08-07',\n    openaiApiType: 'chat',\n  },\n  'duo-chat-gpt-5-4-mini': { provider: 'openai', model: 'gpt-5.4-mini', openaiApiType: 'chat' },\n  'duo-chat-gpt-5-4-nano': { provider: 'openai', model: 'gpt-5.4-nano', openaiApiType: 'chat' },\n\n  // OpenAI models - Responses API\n  // GPT-5.6 rejects `reasoning_effort` with function tools on Chat Completions;\n  // it must use the Responses API (matches OpenAI's own routing for GPT-5.x).\n  'duo-chat-gpt-5-6-sol': { provider: 'openai', model: 'gpt-5.6-sol', openaiApiType: 'responses' },\n  'duo-chat-gpt-5-6-terra': {\n    provider: 'openai',\n    model: 'gpt-5.6-terra',\n    openaiApiType: 'responses',\n  },\n  'duo-chat-gpt-5-6-luna': {\n    provider: 'openai',\n    model: 'gpt-5.6-luna',\n    openaiApiType: 'responses',\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  'duo-chat-gpt-5-3-codex': {\n    provider: 'openai',\n    model: 'gpt-5.3-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: 'claude_sonnet_4_5_20250929',\n  },\n  'duo-workflow-sonnet-5-5': { provider: 'workflow', model: 'claude_sonnet_5_5' },\n  'duo-workflow-sonnet-5': { provider: 'workflow', model: 'claude_sonnet_5' },\n  'duo-workflow-opus-5-5': { provider: 'workflow', model: 'claude_opus_5_5' },\n  'duo-workflow-opus-5': { provider: 'workflow', model: 'claude_opus_5' },\n  'duo-workflow-sonnet-4-6': { provider: 'workflow', model: 'claude_sonnet_4_6' },\n  'duo-workflow-opus-4-5': {\n    provider: 'workflow',\n    model: 'claude_opus_4_5_20251101',\n  },\n  'duo-workflow-haiku-4-5': { provider: 'workflow', model: 'claude_haiku_4_5_20251001' },\n  'duo-workflow-haiku-5-5': { provider: 'workflow', model: 'claude_haiku_5_5' },\n  'duo-workflow-opus-4-6': { provider: 'workflow', model: 'claude_opus_4_6_20260205' },\n  'duo-workflow-gemini-4-argon': { provider: 'workflow', model: 'gemini_4_argon_vertex' },\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 * LanguageModelV3 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 { AsyncResource } from 'node:async_hooks';\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 type { DiscoveryScope } from './gitlab-model-discovery';\nimport { GitLabModelCache } from './gitlab-model-cache';\nimport { GITLAB_COM_URL } from './gitlab-oauth-types';\nimport {\n  mapBuiltinTool,\n  sanitizeErrorMessage,\n  executeBuiltinFallback,\n} from './gitlab-workflow-builtins';\n\nimport type {\n  LanguageModelV3,\n  LanguageModelV3CallOptions,\n  LanguageModelV3StreamPart,\n  LanguageModelV3FinishReason,\n  LanguageModelV3Content,\n  LanguageModelV3Usage,\n  LanguageModelV3Message,\n  LanguageModelV3FunctionTool,\n  LanguageModelV3GenerateResult,\n  LanguageModelV3StreamResult,\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  ApprovalDecision,\n} from './gitlab-workflow-types';\n\ninterface StreamState {\n  streamClosed: boolean;\n  streamedInputChars: number;\n  streamedOutputChars: number;\n  pendingToolCount: number;\n  approvalPending: boolean;\n  deferredClose: (() => void) | null;\n  activeTextBlockId: string | null;\n  agentMessageEmitted: Map<string, number>;\n  currentAgentMessageId: string;\n  activeClient: GitLabWorkflowClient | null;\n  processedRequestIDs: Set<string>;\n  emittedToolEntries: Set<string>;\n  emittedToolKeys: Set<string>;\n  sessionKey: string;\n}\n\nimport {\n  DEFAULT_WORKFLOW_DEFINITION,\n  DEFAULT_CLIENT_CAPABILITIES,\n  CLIENT_VERSION,\n  WS_CLOSE_WORKFLOW_LOCKED,\n  WS_WORKFLOW_LOCK_RETRY_DELAY_MS,\n  WS_WORKFLOW_LOCK_MAX_RETRIES,\n} from './gitlab-workflow-types';\n\nexport interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {\n  /** Provider name (e.g., 'gitlab.workflow') */\n  provider: string;\n}\n\nconst GITLAB_COM_HOSTNAME = new URL(GITLAB_COM_URL).hostname;\n\n/**\n * Whether `instanceUrl` points at GitLab.com (as opposed to a self-managed or\n * Dedicated instance). Unparseable URLs are treated as not GitLab.com.\n */\nfunction isGitLabComInstance(instanceUrl: string): boolean {\n  try {\n    return new URL(instanceUrl).hostname.toLowerCase() === GITLAB_COM_HOSTNAME;\n  } catch {\n    return false;\n  }\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<{\n  result: string;\n  error?: string | null;\n  metadata?: Record<string, unknown>;\n  title?: string;\n}>;\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 LanguageModelV3 by bridging the DWS WebSocket protocol\n * to the Vercel AI SDK stream part format.\n */\nexport class GitLabWorkflowLanguageModel implements LanguageModelV3 {\n  readonly specificationVersion = 'v3' 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  // Per-session workflow state. Keyed by opencode sessionID (x-opencode-session header).\n  // Each opencode session gets its own DWS workflow, reused across turns within that session.\n  // Bounded: least-recently-used sessions are evicted beyond MAX_SESSION_WORKFLOWS\n  // to prevent unbounded memory growth in long-lived hosts.\n  private readonly sessionWorkflows = new Map<\n    string,\n    {\n      workflowId: string;\n      workflowDefinition: string | Record<string, unknown> | null;\n      agentEmitted: Map<string, number>;\n      toolEntries: Set<string>;\n    }\n  >();\n\n  private static readonly MAX_SESSION_WORKFLOWS = 50;\n\n  /**\n   * Store a session workflow entry, refreshing its LRU position and\n   * evicting the oldest entries beyond MAX_SESSION_WORKFLOWS.\n   */\n  private setSessionWorkflow(\n    key: string,\n    value: {\n      workflowId: string;\n      workflowDefinition: string | Record<string, unknown> | null;\n      agentEmitted: Map<string, number>;\n      toolEntries: Set<string>;\n    }\n  ): void {\n    this.sessionWorkflows.delete(key);\n    this.sessionWorkflows.set(key, value);\n    while (this.sessionWorkflows.size > GitLabWorkflowLanguageModel.MAX_SESSION_WORKFLOWS) {\n      const oldest = this.sessionWorkflows.keys().next().value;\n      if (oldest === undefined) break;\n      this.sessionWorkflows.delete(oldest);\n    }\n  }\n\n  // Fallback for callers that don't pass x-opencode-session (e.g. direct SDK use).\n  private currentWorkflowId: string | null = null;\n  private currentWorkflowDefinition: string | Record<string, unknown> | null = null;\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 _namespaceId?: string | null;\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._selectedModelName = undefined;\n    this.modelCache.saveSelection(ref, 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   * Tool names pre-approved for the current session.\n   * Set by the host (e.g., opencode) and merged into preapproved_tools on each StartRequest.\n   * Updated when the user chooses \"always\" in the approval prompt.\n   */\n  public sessionPreapprovedTools: string[] = [];\n\n  /**\n   * The opencode session ID. Set per-stream by the host to key per-session\n   * DWS workflows. Different sessions get different DWS workflows.\n   */\n  public sessionID: string = '';\n\n  /**\n   * Set the approval handler callback.\n   * Called when DWS requires tool call approval. Host (e.g., opencode) wires this\n   * to its permission system each stream call, similar to toolExecutor.\n   */\n  set approvalHandler(\n    handler:\n      | ((\n          tools: Array<{ name: string; args: string }>\n        ) => Promise<{ approved: boolean; message?: string }>)\n      | null\n  ) {\n    this.workflowOptions.approvalHandler = handler ?? undefined;\n  }\n\n  get approvalHandler():\n    | ((\n        tools: Array<{ name: string; args: string }>\n      ) => Promise<{ approved: boolean; message?: string }>)\n    | null {\n    return this.workflowOptions.approvalHandler ?? null;\n  }\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  /**\n   * Set the system prompt to override DWS's default.\n   * Sent via `flowConfig.prompts[].prompt_template.system` at stream time.\n   * Can be updated between doStream() calls (e.g., per agent/session).\n   */\n  set systemPrompt(prompt: string | null) {\n    (this.workflowOptions as { systemPrompt?: string }).systemPrompt = prompt ?? undefined;\n  }\n\n  get systemPrompt(): string | null {\n    return this.workflowOptions.systemPrompt ?? null;\n  }\n\n  get toolExecutor(): WorkflowToolExecutor | null {\n    return this._toolExecutor;\n  }\n\n  set toolExecutor(executor: WorkflowToolExecutor | null) {\n    if (executor) {\n      try {\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 numeric namespace id for the DWS WebSocket.\n   *\n   * The `/api/v4/ai/duo_workflows/ws` endpoint needs a namespace. It reads the\n   * `x-gitlab-namespace-id` header, and only accepts the **plain numeric id** —\n   * a `gid://gitlab/Group/<n>` value is rejected, as is `x-gitlab-root-namespace-id`.\n   * Without it the upgrade fails with\n   * `403 Missing default GitLab Duo namespace user preference`.\n   *\n   * The header is validated, not just required: a namespace the user cannot\n   * use Duo in is rejected with `403` as well. On GitLab.com users normally\n   * have a default Duo namespace preference, and sending the namespace of\n   * whatever repository they happen to be in (a community fork, a personal\n   * project, a subgroup) could override that preference and break a\n   * connection that works today. So the git-remote fallback is limited to\n   * self-managed instances, where the missing preference is what refuses the\n   * connection in the first place.\n   *\n   * Priority:\n   *   1. Explicit `namespaceId` in workflowOptions (any instance)\n   *   2. Auto-detected from the git remote (self-managed instances only)\n   */\n  private async resolveNamespaceId(): Promise<string | null> {\n    if (this.workflowOptions.namespaceId) {\n      return this.workflowOptions.namespaceId;\n    }\n\n    if (isGitLabComInstance(this.config.instanceUrl)) {\n      return null;\n    }\n\n    if (this._namespaceId !== undefined) {\n      return this._namespaceId;\n    }\n\n    // Detection failures here are swallowed so the WebSocket can still fall\n    // back to the user's default Duo namespace. Note that `doStream` may\n    // already have run detection for the project id / discovery scope, which\n    // is not guarded; this only keeps namespace resolution itself best-effort.\n    try {\n      const workDir = this.workflowOptions.workingDirectory ?? process.cwd();\n      const project = await this.projectDetector.detectProject(workDir);\n      this._namespaceId = project?.namespaceId ? String(project.namespaceId) : null;\n    } catch {\n      this._namespaceId = null;\n    }\n    return this._namespaceId;\n  }\n\n  /**\n   * Resolve the model discovery scope to use for `aiChatAvailableModels`.\n   *\n   * `projectId` is preferred — it works for both group- and user-namespace\n   * projects — with `rootNamespaceId` attached as a fallback for GitLab\n   * instances too old to support `projectId`-scoped discovery.\n   */\n  private async resolveDiscoveryScope(): Promise<DiscoveryScope | null> {\n    const rootNamespaceId = await this.resolveRootNamespaceId();\n\n    const workDir = this.workflowOptions.workingDirectory ?? process.cwd();\n    const project = await this.projectDetector.detectProject(workDir);\n    if (project?.id) {\n      return {\n        projectId: `gid://gitlab/Project/${project.id}`,\n        ...(rootNamespaceId ? { rootNamespaceId } : {}),\n      };\n    }\n\n    return rootNamespaceId ? { rootNamespaceId } : 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 scope = await this.resolveDiscoveryScope();\n\n    if (!scope) {\n      this._selectedModelRef = 'default';\n      return 'default';\n    }\n\n    try {\n      const discovered = await this.modelDiscovery.discover(scope);\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 scope - Project or root namespace GID to discover models for.\n   *   A bare string is treated as a `rootNamespaceId` (e.g.\n   *   'gid://gitlab/Group/12345') for backwards compatibility.\n   * @returns Discovered models with default, selectable, and pinned models\n   */\n  async discoverModels(\n    scope: DiscoveryScope | string\n  ): Promise<import('./gitlab-model-discovery').DiscoveredModels> {\n    const result = await this.modelDiscovery.discover(scope);\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(sessionKey?: string): void {\n    if (sessionKey) {\n      this.sessionWorkflows.delete(sessionKey);\n    } else {\n      this.sessionWorkflows.clear();\n      this.currentWorkflowId = null;\n      this.persistedAgentEmitted.clear();\n    }\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  private createUsage(params?: {\n    inputTotal?: number;\n    outputTotal?: number;\n  }): LanguageModelV3Usage {\n    return {\n      inputTokens: {\n        total: params?.inputTotal,\n        noCache: params?.inputTotal,\n        cacheRead: undefined,\n        cacheWrite: undefined,\n      },\n      outputTokens: {\n        total: params?.outputTotal,\n        text: params?.outputTotal,\n        reasoning: undefined,\n      },\n    };\n  }\n\n  private createFinishReason(\n    unified: LanguageModelV3FinishReason['unified'],\n    raw?: string\n  ): LanguageModelV3FinishReason {\n    return { unified, raw };\n  }\n\n  // ---------------------------------------------------------------------------\n  // LanguageModelV3 — doGenerate (non-streaming)\n  // ---------------------------------------------------------------------------\n\n  async doGenerate(options: LanguageModelV3CallOptions): Promise<LanguageModelV3GenerateResult> {\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: LanguageModelV3Content[] = [];\n    let finishReason: LanguageModelV3FinishReason = { unified: 'other', raw: undefined };\n    let usage: LanguageModelV3Usage = this.createUsage();\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 = value.usage;\n            }\n            break;\n          case 'error':\n            try {\n              await reader.cancel();\n            } catch {\n              // best-effort cleanup of the underlying workflow\n            }\n            throw value.error;\n        }\n      }\n    } finally {\n      reader.releaseLock();\n    }\n\n    const content: LanguageModelV3Content[] = [];\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  // LanguageModelV3 — doStream (streaming)\n  // ---------------------------------------------------------------------------\n\n  async doStream(options: LanguageModelV3CallOptions): Promise<LanguageModelV3StreamResult> {\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 no options provided, plus session approvals\n    const preapprovedTools = [\n      ...(this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name)),\n      ...this.sessionPreapprovedTools,\n    ];\n\n    // Build additional context from conversation history.\n    const additionalContext = this.buildAdditionalContext(options.prompt);\n\n    const toolExecutor = this.toolExecutor ?? null;\n\n    // Collect available host tool names so mapBuiltinTool can adapt\n    // (e.g., use apply_patch when edit/write are not available)\n    const availableToolNames = new Set<string>(options.tools?.map((t) => t.name) ?? []);\n\n    // Per-call overrides from providerOptions — allows the host (e.g. opencode) to\n    // pass per-agent settings without needing a separate LanguageModelV3 instance.\n    const gitlabProviderOptions = (\n      options.providerOptions as Record<string, unknown> | undefined\n    )?.['gitlab'] as Record<string, unknown> | undefined;\n    const callWorkflowDefinition =\n      (gitlabProviderOptions?.workflowDefinition as string | undefined) ??\n      this.workflowOptions.workflowDefinition;\n    const callFlowConfig =\n      (gitlabProviderOptions?.flowConfig as Record<string, unknown> | undefined) ?? undefined;\n    const callFlowConfigSchemaVersion =\n      (gitlabProviderOptions?.flowConfigSchemaVersion as string | undefined) ?? undefined;\n    const callAiCatalogItemVersionId =\n      (gitlabProviderOptions?.aiCatalogItemVersionId as number | undefined) ?? undefined;\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      callWorkflowDefinition ?? 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    // Use flowConfig as the effective key when present (custom agents)\n    const effectiveDefinition =\n      callFlowConfig ?? callWorkflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION;\n\n    const sessionKey = this.sessionID;\n\n    // Get or initialise per-session workflow state\n    let sess = this.sessionWorkflows.get(sessionKey);\n    if (sess && sess.workflowDefinition !== effectiveDefinition) {\n      // Agent changed within session — start a fresh workflow\n      this.sessionWorkflows.delete(sessionKey);\n      sess = undefined;\n    }\n    // Fallback path: no sessionKey (direct SDK use) — use legacy instance fields\n    const useLegacy = sessionKey === '';\n    if (\n      useLegacy &&\n      this.currentWorkflowId &&\n      this.currentWorkflowDefinition !== effectiveDefinition\n    ) {\n      this.currentWorkflowId = null;\n      this.currentWorkflowDefinition = null;\n    }\n\n    let workflowId: string;\n    if (sess) {\n      workflowId = sess.workflowId;\n    } else if (useLegacy && this.currentWorkflowId) {\n      workflowId = this.currentWorkflowId;\n    } else {\n      workflowId = await this.tokenClient.createWorkflow(goal, {\n        projectId,\n        namespaceId: this.workflowOptions.namespaceId,\n        workflowDefinition: callWorkflowDefinition,\n        agentPrivileges: this.workflowOptions.agentPrivileges,\n        aiCatalogItemVersionId: callAiCatalogItemVersionId,\n      });\n      if (useLegacy) {\n        this.currentWorkflowId = workflowId;\n        this.currentWorkflowDefinition = effectiveDefinition;\n      } else {\n        this.setSessionWorkflow(sessionKey, {\n          workflowId,\n          workflowDefinition: effectiveDefinition,\n          agentEmitted: new Map(),\n          toolEntries: new Set(),\n        });\n        sess = this.sessionWorkflows.get(sessionKey)!;\n      }\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      approvalPending: false,\n      deferredClose: null,\n      activeTextBlockId: null,\n      agentMessageEmitted: new Map(sess?.agentEmitted ?? this.persistedAgentEmitted),\n      currentAgentMessageId: '',\n      activeClient: wsClient,\n      processedRequestIDs: new Set(),\n      emittedToolEntries: new Set(sess?.toolEntries),\n      emittedToolKeys: new Set(),\n      sessionKey,\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    let startReq: StartRequest | undefined;\n\n    const resolvedNamespaceId = (await this.resolveNamespaceId()) ?? undefined;\n\n    const stream = new ReadableStream<LanguageModelV3StreamPart>({\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: resolvedNamespaceId,\n              rootNamespaceId: this.workflowOptions.rootNamespaceId,\n              aiCatalogItemVersionId: callAiCatalogItemVersionId,\n              workflowDefinition: callWorkflowDefinition ?? this.workflowOptions.workflowDefinition,\n            },\n            (event: WorkflowClientEvent) => {\n              this.handleWorkflowEvent(\n                ss,\n                event,\n                controller,\n                wsClient,\n                toolExecutor,\n                () => `text-${textBlockCounter++}`,\n                availableToolNames,\n                startReq,\n                {\n                  aiCatalogItemVersionId: callAiCatalogItemVersionId,\n                  workflowDefinition:\n                    callWorkflowDefinition ?? this.workflowOptions.workflowDefinition,\n                }\n              );\n            }\n          );\n\n          const workflowDef = callWorkflowDefinition ?? 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          startReq = {\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          // Per-call flowConfig overrides instance options (custom agents via providerOptions)\n          const resolvedFlowConfig = callFlowConfig ?? this.workflowOptions.flowConfig;\n          const resolvedFlowConfigSchemaVersion =\n            callFlowConfigSchemaVersion ?? this.workflowOptions.flowConfigSchemaVersion;\n\n          if (resolvedFlowConfig) {\n            startReq.flowConfig = resolvedFlowConfig;\n          }\n          if (resolvedFlowConfigSchemaVersion) {\n            startReq.flowConfigSchemaVersion = resolvedFlowConfigSchemaVersion;\n          } else if (startReq.flowConfig) {\n            startReq.flowConfigSchemaVersion = 'v1';\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: ${sanitizeErrorMessage(String(error))}`,\n                      cause: error,\n                    }),\n            });\n            ss.streamClosed = true;\n            controller.close();\n          }\n        }\n      },\n      cancel: (_reason) => {\n        if (abortListener && options.abortSignal) {\n          options.abortSignal.removeEventListener('abort', abortListener);\n        }\n        wsClient.stop();\n        wsClient.close();\n        this.activeClients.delete(wsClient);\n        ss.activeClient = null;\n        // Only clear workflow if stream was aborted (not a normal completion).\n        // Normal completion already closed the stream (ss.streamClosed=true) — keep\n        // the workflow alive so the next turn in the same opencode session reuses it.\n        if (!ss.streamClosed) {\n          if (ss.sessionKey) {\n            this.sessionWorkflows.delete(ss.sessionKey);\n          } else {\n            this.currentWorkflowId = null;\n          }\n        }\n      },\n    });\n\n    let abortListener: (() => void) | null = null;\n    if (options.abortSignal) {\n      abortListener = () => {\n        wsClient.stop();\n        wsClient.close();\n        this.activeClients.delete(wsClient);\n        ss.activeClient = null;\n        if (!ss.streamClosed) {\n          ss.streamClosed = true;\n          if (ss.sessionKey) {\n            this.sessionWorkflows.delete(ss.sessionKey);\n          } else {\n            this.currentWorkflowId = null;\n          }\n        }\n      };\n      if (options.abortSignal.aborted) {\n        abortListener();\n      } else {\n        options.abortSignal.addEventListener('abort', abortListener, { once: true });\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<LanguageModelV3StreamPart>,\n    wsClient: GitLabWorkflowClient,\n    toolExecutor: WorkflowToolExecutor | null,\n    nextTextId: () => string,\n    availableToolNames?: Set<string>,\n    startReq?: StartRequest,\n    wsExtras?: { aiCatalogItemVersionId?: number; workflowDefinition?: 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        if (ss.processedRequestIDs.has(requestID)) break;\n        ss.processedRequestIDs.add(requestID);\n        ss.emittedToolKeys.add(data.name);\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        if (ss.processedRequestIDs.has(event.requestID)) break;\n        ss.processedRequestIDs.add(event.requestID);\n        const mapped = mapBuiltinTool(event.toolName, event.data, availableToolNames);\n        ss.emittedToolKeys.add(mapped.toolName);\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 'approval-required': {\n        ss.approvalPending = true;\n        this.approveAndResume(\n          ss,\n          event.tools,\n          startReq,\n          controller,\n          toolExecutor,\n          nextTextId,\n          availableToolNames,\n          wsExtras\n        ).catch((_err) => {\n          ss.approvalPending = false;\n          if (ss.deferredClose) {\n            const close = ss.deferredClose;\n            ss.deferredClose = null;\n            close();\n          }\n        });\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: this.createFinishReason('stop', 'completed'),\n            usage: this.createUsage({ inputTotal: inputTokens, outputTotal: outputTokens }),\n          });\n          ss.streamClosed = true;\n          controller.close();\n          this.cleanupClient(ss, false); // keep workflow alive for next turn\n        };\n\n        if (ss.pendingToolCount > 0 || ss.approvalPending) {\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: this.createFinishReason('stop', 'closed'),\n              usage: this.createUsage({ inputTotal: inTok, outputTotal: outTok }),\n            });\n            ss.streamClosed = true;\n            controller.close();\n            this.cleanupClient(ss, false); // keep workflow alive for next turn\n          }\n        };\n\n        if (ss.pendingToolCount > 0 || ss.approvalPending) {\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<LanguageModelV3StreamPart>,\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      checkpoint.status !== 'TOOL_CALL_APPROVAL_REQUIRED'\n    ) {\n      return;\n    }\n\n    for (let i = 0; i < chatLog.length; i++) {\n      const entry = chatLog[i] as UiChatLogEntry;\n\n      if (entry.message_type === 'tool' && entry.tool_info) {\n        const toolId = entry.message_id || entry.correlation_id || `tool-${i}`;\n        if (ss.emittedToolEntries.has(toolId)) continue;\n\n        const name = entry.tool_info.name;\n        const args = JSON.stringify(entry.tool_info.args ?? {});\n\n        // Skip tools already handled via tool-request/builtin-tool-request.\n        // Those arrive as separate WorkflowAction events with their own stream IDs,\n        // then appear again in the checkpoint ui_chat_log as 'tool' entries.\n        if (ss.emittedToolKeys.has(name)) {\n          ss.emittedToolEntries.add(toolId);\n          const sess = this.sessionWorkflows.get(ss.sessionKey);\n          if (sess) sess.toolEntries.add(toolId);\n          continue;\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: toolId,\n          toolName: name,\n          providerExecuted: true,\n        });\n        controller.enqueue({ type: 'tool-input-delta', id: toolId, delta: args });\n        controller.enqueue({ type: 'tool-input-end', id: toolId });\n        controller.enqueue({\n          type: 'tool-call',\n          toolCallId: toolId,\n          toolName: name,\n          input: args,\n          providerExecuted: true,\n          dynamic: true,\n        });\n\n        const response = entry.tool_info.tool_response;\n        const output =\n          typeof response === 'string'\n            ? response\n            : response\n              ? response.content\n              : entry.content || '';\n\n        controller.enqueue({\n          type: 'tool-result',\n          toolCallId: toolId,\n          toolName: name,\n          result: { output, title: name, metadata: {} },\n          isError: false,\n        });\n\n        ss.emittedToolEntries.add(toolId);\n        const sess = this.sessionWorkflows.get(ss.sessionKey);\n        if (sess) sess.toolEntries.add(toolId);\n        continue;\n      }\n\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      const target =\n        this.sessionWorkflows.get(ss.sessionKey)?.agentEmitted ?? this.persistedAgentEmitted;\n      target.set(msgId, content.length);\n      ss.currentAgentMessageId = msgId;\n    }\n  }\n\n  private async executeToolAndRespond(\n    ss: StreamState,\n    wsClient: GitLabWorkflowClient,\n    controller: ReadableStreamDefaultController<LanguageModelV3StreamPart>,\n    requestID: string,\n    toolName: string,\n    argsJson: string,\n    toolExecutor: WorkflowToolExecutor | null\n  ): Promise<void> {\n    ss.pendingToolCount++;\n\n    const safeEnqueue = (part: LanguageModelV3StreamPart): 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        let result = await toolExecutor(toolName, argsJson, requestID);\n\n        // When the host doesn't have edit/write tools (e.g., GPT models use\n        // apply_patch instead), fall back to direct file operations so DWS\n        // builtins (runEditFile, runWriteFile) still work.\n        if (result.error && /^Unknown tool:/.test(result.error)) {\n          const fallback = executeBuiltinFallback(toolName, argsJson);\n          if (fallback) {\n            result = fallback;\n          }\n        }\n\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        const toolOutput = result.result;\n        // Use rich metadata/title from executor if provided (preserves diff, diagnostics, etc.)\n        const toolTitle: string = result.title ?? `${toolName} result`;\n        const toolMetadata: Record<string, unknown> = result.metadata ?? { output: result.result };\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          // When isError=true, the AI SDK uses `result` directly as the error value\n          // (not as an output object), so it must be a string to avoid \"[object Object]\"\n          // in the error display.\n          safeEnqueue({\n            type: 'tool-result',\n            toolCallId: requestID,\n            toolName,\n            result: errorText,\n            isError: 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 as Record<string, string>,\n            },\n            isError: false,\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: errorMsg,\n          isError: 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: errorMsg,\n        isError: 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      if (ss.sessionKey) {\n        this.sessionWorkflows.delete(ss.sessionKey);\n      } else {\n        this.currentWorkflowId = null;\n        this.persistedAgentEmitted.clear();\n      }\n    }\n  }\n\n  private async approveAndResume(\n    ss: StreamState,\n    tools: Array<{ name: string; args: string }>,\n    startReq: StartRequest | undefined,\n    controller: ReadableStreamDefaultController<LanguageModelV3StreamPart>,\n    toolExecutor: WorkflowToolExecutor | null,\n    nextTextId: () => string,\n    availableToolNames?: Set<string>,\n    wsExtras?: { aiCatalogItemVersionId?: number; workflowDefinition?: string }\n  ): Promise<void> {\n    const handler = this.workflowOptions.approvalHandler;\n    if (!handler || !startReq) {\n      ss.approvalPending = false;\n      if (ss.deferredClose) {\n        const close = ss.deferredClose;\n        ss.deferredClose = null;\n        close();\n      }\n      return;\n    }\n\n    let decision: { approved: boolean; message?: string };\n    try {\n      decision = await handler(tools);\n    } catch (err) {\n      ss.approvalPending = false;\n      if (!ss.streamClosed) controller.error(err);\n      return;\n    }\n\n    ss.approvalPending = false;\n    ss.deferredClose = null; // stale close from old WS — discard before reconnect\n\n    const approval: ApprovalDecision = decision.approved\n      ? { approval: { tool_name: tools[0]?.name, tool_args_json: tools[0]?.args } }\n      : { rejection: { message: decision.message ?? 'User rejected' } };\n\n    const newStartReq: StartRequest = {\n      ...startReq,\n      approval,\n      preapproved_tools: decision.approved\n        ? [...(startReq.preapproved_tools ?? []), ...tools.map((t) => t.name)]\n        : (startReq.preapproved_tools ?? []),\n    };\n\n    // DWS closes the socket after asking for approval, so the decision has to go\n    // out on a new one. Workhorse keeps the workflow lock until its stop\n    // handshake finishes, so wait for the close and retry while it reports the\n    // lock as still held, or the reconnect races it and is rejected with 1013.\n    const reconnect = async (): Promise<void> => {\n      if (ss.streamClosed) return;\n\n      await this.closeClientAndWait(ss);\n\n      const client = new GitLabWorkflowClient();\n      this.activeClients.add(client);\n      ss.activeClient = client;\n\n      const modelRef = await this.resolveModelRef();\n      // DWS closes the socket on every approval request, so this reconnect\n      // needs the same namespace as the initial connect or it is refused with\n      // 403 on instances that rely on the detected namespace. The result is\n      // cached, so this does not run detection again.\n      const namespaceId = (await this.resolveNamespaceId()) ?? undefined;\n      await client.connect(\n        {\n          instanceUrl: this.config.instanceUrl,\n          modelRef,\n          headers: this.config.getHeaders(),\n          projectId: this.workflowOptions.projectId,\n          namespaceId,\n          rootNamespaceId: this.workflowOptions.rootNamespaceId,\n          aiCatalogItemVersionId: wsExtras?.aiCatalogItemVersionId,\n          workflowDefinition: wsExtras?.workflowDefinition,\n        },\n        (event) => {\n          if (event.type === 'closed' && event.code === WS_CLOSE_WORKFLOW_LOCKED) {\n            void retryWhileLocked();\n            return;\n          }\n          this.handleWorkflowEvent(\n            ss,\n            event,\n            controller,\n            client,\n            toolExecutor,\n            nextTextId,\n            availableToolNames,\n            newStartReq,\n            wsExtras\n          );\n        }\n      );\n      client.sendStartRequest(newStartReq);\n    };\n\n    let lockRetries = 0;\n    const retryWhileLocked = async (): Promise<void> => {\n      if (ss.streamClosed) return;\n      if (++lockRetries > WS_WORKFLOW_LOCK_MAX_RETRIES) {\n        this.failStream(\n          ss,\n          controller,\n          new GitLabError({\n            message: 'Failed to acquire lock on workflow after reconnect retries',\n            statusCode: WS_CLOSE_WORKFLOW_LOCKED,\n          })\n        );\n        return;\n      }\n      await new Promise<void>((r) => setTimeout(r, WS_WORKFLOW_LOCK_RETRY_DELAY_MS * lockRetries));\n      await reconnect().catch((err) => this.failStream(ss, controller, err));\n    };\n\n    await reconnect().catch((err) => this.failStream(ss, controller, err));\n  }\n\n  /**\n   * Close the active client and wait for its close handshake, so a following\n   * reconnect to the same workflow does not race the Workhorse lock.\n   */\n  private async closeClientAndWait(ss: StreamState): Promise<void> {\n    const client = ss.activeClient;\n    if (!client) return;\n    this.activeClients.delete(client);\n    ss.activeClient = null;\n    await client.closeAndWait();\n  }\n\n  /**\n   * Surface a terminal error on the stream and drop the workflow.\n   */\n  private failStream(\n    ss: StreamState,\n    controller: ReadableStreamDefaultController<LanguageModelV3StreamPart>,\n    error: unknown\n  ): void {\n    this.cleanupClient(ss, true);\n    if (ss.streamClosed) return;\n    controller.error(error);\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      tool_approval_for_session_enabled: true,\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 static readonly SYSTEM_REMINDER_RE = /<system-reminder>([\\s\\S]*?)<\\/system-reminder>/g;\n\n  private extractGoalFromPrompt(prompt: LanguageModelV3Message[]): 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          const raw = textParts.join('\\n');\n          const cleaned = raw.replace(GitLabWorkflowLanguageModel.SYSTEM_REMINDER_RE, '').trim();\n          return cleaned || raw;\n        }\n      }\n    }\n    return '';\n  }\n\n  /**\n   * Convert AI SDK tools to DWS McpToolDefinition format.\n   */\n  private extractMcpTools(options: LanguageModelV3CallOptions): 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 LanguageModelV3FunctionTool => 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: LanguageModelV3Message[]): 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      } else if (message.role === 'user') {\n        for (const part of message.content) {\n          if (part.type === 'text') {\n            const text = (part as { type: 'text'; text: string }).text;\n            const matches = text.matchAll(GitLabWorkflowLanguageModel.SYSTEM_REMINDER_RE);\n            for (const match of matches) {\n              const inner = match[1].trim();\n              if (inner) {\n                context.push({\n                  category: 'agent_context',\n                  content: inner,\n                  metadata: JSON.stringify({ source: 'system-reminder' }),\n                });\n              }\n            }\n          }\n        }\n      }\n    }\n\n    return context;\n  }\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  CheckpointData,\n  UiChatLogEntry,\n  UiChatLogToolInfo,\n  NewCheckpoint,\n} from './gitlab-workflow-types';\nimport {\n  WS_KEEPALIVE_PING_INTERVAL_MS,\n  WS_HEARTBEAT_INTERVAL_MS,\n  WS_CLOSE_WAIT_TIMEOUT_MS,\n  STOP_REASON_USER,\n  CLIENT_VERSION,\n} from './gitlab-workflow-types';\nimport { GitLabError } from './gitlab-error';\n\nconst WS_CONNECT_TIMEOUT_MS = 30_000;\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  /** AI Catalog item version ID — required for Workhorse to inject MCP tools */\n  aiCatalogItemVersionId?: number;\n  /** Workflow definition type (e.g. 'chat') — used by Workhorse for MCP config */\n  workflowDefinition?: 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 closedEmitted = 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.disposeSocket();\n    this.eventCallback = onEvent;\n    this.closed = false;\n    this.closedEmitted = 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      const connectTimer = setTimeout(() => {\n        if (resolved) return;\n        resolved = true;\n        const sock = this.socket;\n        this.socket = null;\n        try {\n          sock?.close(1000, 'Connect timeout');\n        } catch {\n          // socket may already be closed\n        }\n        reject(\n          new GitLabError({\n            message: `WebSocket connect timed out after ${WS_CONNECT_TIMEOUT_MS}ms`,\n          })\n        );\n      }, WS_CONNECT_TIMEOUT_MS);\n\n      this.socket.onopen = () => {\n        clearTimeout(connectTimer);\n        if (resolved) return;\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 = this.decodeMessageData(event.data);\n          const action = JSON.parse(data) as WorkflowAction;\n\n          // Basic validation of message structure\n          if (!action || typeof action !== 'object') {\n            throw new GitLabError({ message: '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 GitLabError({\n          message: `WebSocket error: ${event.message || 'unknown'}`,\n        });\n        if (!resolved) {\n          clearTimeout(connectTimer);\n          resolved = true;\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          clearTimeout(connectTimer);\n          resolved = true;\n          reject(\n            new GitLabError({\n              message: `WebSocket closed before open: code=${event.code} reason=${event.reason || ''}`,\n            })\n          );\n          return;\n        }\n        if (!this.closed) {\n          this.emitClosed(event.code, event.reason || '');\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   * Sends a stopWorkflow event, then closes the socket and clears all\n   * timers so no heartbeats keep firing if the server never closes.\n   */\n  stop(): void {\n    this.send({ stopWorkflow: { reason: STOP_REASON_USER } });\n    this.closed = true;\n    this.cleanup();\n    const sock = this.socket;\n    this.socket = null;\n    if (sock && (sock.readyState === WebSocket.OPEN || sock.readyState === WebSocket.CONNECTING)) {\n      sock.close(1000, 'Client stopping');\n    }\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   * Close the socket and wait for the close handshake to actually land.\n   *\n   * `close()` returns as soon as the close frame is queued. That is too early\n   * when the caller is about to reconnect to the same workflow, because\n   * Workhorse releases the workflow lock only once its own stop handshake with\n   * DWS completes. Awaiting `onclose` (or the timeout) keeps the reconnect from\n   * racing the lock and getting rejected with close code 1013.\n   *\n   * Best effort: never rejects, and resolves after `timeoutMs` if the server\n   * never answers.\n   *\n   * @param timeoutMs - Maximum time to wait for the close event\n   * @default WS_CLOSE_WAIT_TIMEOUT_MS\n   */\n  closeAndWait(timeoutMs: number = WS_CLOSE_WAIT_TIMEOUT_MS): Promise<void> {\n    const sock = this.socket;\n    const pending =\n      sock && (sock.readyState === WebSocket.OPEN || sock.readyState === WebSocket.CONNECTING);\n    if (this.closed || !pending) {\n      this.close();\n      return Promise.resolve();\n    }\n\n    return new Promise<void>((resolve) => {\n      let settled = false;\n      const finish = () => {\n        if (settled) return;\n        settled = true;\n        clearTimeout(timer);\n        resolve();\n      };\n      const timer = setTimeout(finish, timeoutMs);\n      const previous = sock.onclose;\n      sock.onclose = (event: WebSocket.CloseEvent) => {\n        try {\n          previous?.call(sock, event);\n        } finally {\n          finish();\n        }\n      };\n      this.close();\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 GitLabError({ message: 'instanceUrl is required' });\n    }\n    const parsed = new URL(options.instanceUrl);\n    if (parsed.protocol !== 'https:' && parsed.protocol !== 'http:') {\n      throw new GitLabError({ message: `Invalid instanceUrl protocol: ${parsed.protocol}` });\n    }\n    if (parsed.username || parsed.password) {\n      throw new GitLabError({\n        message: 'instanceUrl must not contain authentication credentials (username/password)',\n      });\n    }\n    if (!options.headers || typeof options.headers !== 'object') {\n      throw new GitLabError({ message: 'headers are required' });\n    }\n    if (options.modelRef && typeof options.modelRef !== 'string') {\n      throw new GitLabError({ message: 'modelRef must be a string' });\n    }\n  }\n\n  private buildWebSocketUrl(options: WorkflowWebSocketOptions): string {\n    // NO workflow_id in URL (it goes in startRequest.workflowID instead)\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('user_selected_model_identifier', options.modelRef);\n    }\n    if (options.aiCatalogItemVersionId) {\n      url.searchParams.set('ai_catalog_item_version_id', String(options.aiCatalogItemVersionId));\n    }\n    if (options.workflowDefinition) {\n      url.searchParams.set('workflow_definition', options.workflowDefinition);\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    headers['x-gitlab-language-server-version'] = CLIENT_VERSION;\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      } else if (checkpoint.status === 'TOOL_CALL_APPROVAL_REQUIRED') {\n        this.emit({ type: 'approval-required', tools: this.extractApprovalTools(checkpoint) });\n      } else if (checkpoint.status === 'PLAN_APPROVAL_REQUIRED') {\n        this.emit({\n          type: 'failed',\n          error: new GitLabError({\n            message: 'Workflow requires plan approval, which is not supported by this client',\n          }),\n        });\n      }\n      return;\n    }\n\n    // MCP tool invocation\n    if (action.runMCPTool) {\n      if (!action.requestID) {\n        this.emit({\n          type: 'failed',\n          error: new GitLabError({\n            message: 'Received runMCPTool action without requestID; workflow cannot continue',\n          }),\n        });\n        return;\n      }\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) {\n        if (!action.requestID) {\n          this.emit({\n            type: 'failed',\n            error: new GitLabError({\n              message: `Received ${toolName} action without requestID; workflow cannot continue`,\n            }),\n          });\n          return;\n        }\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 extractApprovalTools(checkpoint: NewCheckpoint): Array<{ name: string; args: string }> {\n    if (!checkpoint.checkpoint) return [];\n    let parsed: CheckpointData;\n    try {\n      parsed = JSON.parse(checkpoint.checkpoint);\n    } catch {\n      return [];\n    }\n    return (parsed.channel_values?.ui_chat_log ?? [])\n      .filter(\n        (e): e is UiChatLogEntry & { tool_info: UiChatLogToolInfo } =>\n          e.message_type === 'request' && e.tool_info !== null\n      )\n      .map((e) => ({ name: e.tool_info.name, args: JSON.stringify(e.tool_info.args) }));\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   * Emit the 'closed' event exactly once.\n   */\n  private emitClosed(code: number, reason: string): void {\n    if (this.closedEmitted) return;\n    this.closedEmitted = true;\n    this.emit({ type: 'closed', code, reason });\n  }\n\n  /**\n   * Decode an incoming WebSocket frame to a UTF-8 string.\n   * Handles string, Buffer, ArrayBuffer and Buffer[] payloads.\n   */\n  private decodeMessageData(data: WebSocket.Data): string {\n    if (typeof data === 'string') return data;\n    if (Array.isArray(data)) {\n      return Buffer.concat(data).toString('utf8');\n    }\n    if (data instanceof ArrayBuffer) {\n      return Buffer.from(data).toString('utf8');\n    }\n    return Buffer.from(data as Uint8Array).toString('utf8');\n  }\n\n  /**\n   * Detach and close any existing socket before creating a new one.\n   * Prevents socket and interval leaks on repeated connect() calls.\n   */\n  private disposeSocket(): void {\n    this.cleanup();\n    const sock = this.socket;\n    this.socket = null;\n    if (sock) {\n      sock.onopen = null as never;\n      sock.onmessage = null as never;\n      sock.onerror = null as never;\n      sock.onclose = null as never;\n      if (sock.readyState === WebSocket.OPEN || sock.readyState === WebSocket.CONNECTING) {\n        try {\n          sock.close(1000, 'Reconnecting');\n        } catch {\n          // socket may already be closed\n        }\n      }\n    }\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    if (this.keepaliveInterval) {\n      clearInterval(this.keepaliveInterval);\n    }\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    if (this.heartbeatInterval) {\n      clearInterval(this.heartbeatInterval);\n    }\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","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)}\\0${remoteName}`;\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: ssh://git@host[:port]/path.git\n      if (remoteUrl.startsWith('ssh://')) {\n        try {\n          const sshUrl = new URL(remoteUrl);\n          if (sshUrl.hostname === instanceHost) {\n            const sshPath = sshUrl.pathname.replace(/^\\//, '');\n            return sshPath.endsWith('.git') ? sshPath.slice(0, -4) : sshPath;\n          }\n        } catch {\n          // fall through to other formats\n        }\n        return null;\n      }\n\n      // scp-style SSH format: git@host:path.git (no port — paths start right\n      // after the colon, so numeric top-level namespaces are preserved)\n      const sshMatch = remoteUrl.match(/^git@([^:]+):(.+?)(?:\\.git)?$/);\n      if (sshMatch) {\n        const [, host, pathPart] = sshMatch;\n        if (host === instanceHost) {\n          return pathPart.endsWith('.git') ? pathPart.slice(0, -4) : pathPart;\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 {\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\n      child.stdout?.on('data', (data) => {\n        stdout += data.toString();\n      });\n\n      child.stderr?.resume();\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 project or namespace. Used to dynamically populate\n * `duo-workflow-*` model IDs at runtime.\n *\n * Requires GitLab 18.4+ (18.5+ for pinned model support). `projectId` scoping\n * requires a newer GitLab release than `rootNamespaceId` scoping; when a\n * `projectId` query fails and a `rootNamespaceId` is also known, discovery\n * falls back to the namespace-scoped query.\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') */\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 * Scope to discover models for. `projectId` is preferred (works for both\n * group- and user-namespace projects). An optional `rootNamespaceId` may be\n * supplied alongside it as a fallback for GitLab instances too old to\n * support `projectId`-scoped discovery.\n */\nexport type DiscoveryScope =\n  | { projectId: string; rootNamespaceId?: string }\n  | { rootNamespaceId: string };\n\nfunction scopeCacheKey(scope: DiscoveryScope): string {\n  return 'projectId' in scope ? `p:${scope.projectId}` : `n:${scope.rootNamespaceId}`;\n}\n\nfunction normalizeScope(scope: DiscoveryScope | string): DiscoveryScope {\n  return typeof scope === 'string' ? { rootNamespaceId: scope } : scope;\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($projectId: ProjectID, $rootNamespaceId: GroupID) {\n    metadata {\n      featureFlags(names: [\"ai_user_model_switching\"]) {\n        enabled\n        name\n      }\n      version\n    }\n\n    aiChatAvailableModels(projectId: $projectId, 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 project or root namespace.\n   *\n   * Results are cached per scope with a 10-minute TTL.\n   * Use `invalidateCache()` to force an immediate refresh.\n   *\n   * @param scope - `{ projectId }` (preferred), `{ rootNamespaceId }`, or a\n   *   bare string (treated as `rootNamespaceId` for backwards compatibility)\n   */\n  async discover(scope: DiscoveryScope | string): Promise<DiscoveredModels> {\n    const normalized = normalizeScope(scope);\n    const cacheKey = scopeCacheKey(normalized);\n    const cached = this.cache.get(cacheKey);\n    if (cached && cached.expiresAt > Date.now()) {\n      return cached.data;\n    }\n\n    try {\n      const result = await this.query(normalized);\n      this.cache.set(cacheKey, {\n        data: result,\n        expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS,\n      });\n      return result;\n    } catch (error) {\n      // Older GitLab instances don't support projectId-scoped discovery.\n      // Fall back to rootNamespaceId when the caller also supplied one.\n      if ('projectId' in normalized && normalized.rootNamespaceId) {\n        const fallbackScope: DiscoveryScope = { rootNamespaceId: normalized.rootNamespaceId };\n        const result = await this.query(fallbackScope);\n        this.cache.set(scopeCacheKey(fallbackScope), {\n          data: result,\n          expiresAt: Date.now() + DISCOVERY_CACHE_TTL_MS,\n        });\n        return result;\n      }\n      throw error;\n    }\n  }\n\n  private async query(scope: DiscoveryScope): Promise<DiscoveredModels> {\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:\n            'projectId' in scope\n              ? { projectId: scope.projectId, rootNamespaceId: undefined }\n              : { projectId: undefined, rootNamespaceId: scope.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      // The `ai_user_model_switching` flag has been removed on newer GitLab\n      // instances (rolled out permanently). Only treat model switching as\n      // disabled when the flag is present and explicitly reports `false`.\n      const flag = metadata?.featureFlags?.find((f) => f.name === 'ai_user_model_switching');\n      const modelSwitchingEnabled = flag ? flag.enabled : true;\n\n      return {\n        defaultModel: models?.defaultModel ?? null,\n        selectableModels: models?.selectableModels ?? [],\n        pinnedModel: models?.pinnedModel ?? null,\n        modelSwitchingEnabled,\n        instanceVersion: metadata?.version ?? null,\n      };\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 scope - Project or root namespace to discover models for\n   * @param userSelectedRef - Optional user preference\n   */\n  async getEffectiveModelRef(\n    scope: DiscoveryScope | string,\n    userSelectedRef?: string\n  ): Promise<string | null> {\n    const discovered = await this.discover(scope);\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 *   - `project`: The GitLab project detected for this workspace\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';\nimport type { GitLabProject } from './gitlab-project-cache';\n\nexport interface ModelCacheEntry {\n  discovery: DiscoveredModels | null;\n  project: GitLabProject | null;\n  selectedModelRef: string | null;\n  selectedModelName: string | null;\n  updatedAt: string;\n  /** Timestamp of the last successful discovery write — drives the discovery TTL. */\n  discoveryUpdatedAt?: string;\n}\n\ntype CacheFile = Record<string, ModelCacheEntry>;\n\nconst DISCOVERY_TTL_MS = 10 * 60 * 1000;\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, scope?: string): string {\n  const normalizedUrl = (instanceUrl || 'https://gitlab.com').replace(/\\/$/, '');\n  const input = scope ? `${workDir}\\0${normalizedUrl}\\0${scope}` : `${workDir}\\0${normalizedUrl}`;\n  return crypto.createHash('sha256').update(input).digest('hex').slice(0, 12);\n}\n\nexport class GitLabModelCache {\n  private readonly filePath: string;\n  private readonly key: string;\n\n  /**\n   * @param workDir - Workspace directory the cache entry belongs to\n   * @param instanceUrl - GitLab instance URL\n   * @param scope - Optional extra key component (e.g. an account identifier) that keeps\n   *   entries for different accounts on the same workspace and instance apart\n   */\n  constructor(workDir: string, instanceUrl?: string, scope?: string) {\n    this.filePath = getCacheFilePath();\n    this.key = computeCacheKey(workDir, instanceUrl, scope);\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      const tmpPath = `${this.filePath}.${process.pid}.${Date.now()}.tmp`;\n      fs.writeFileSync(tmpPath, JSON.stringify(data, null, 2), { mode: 0o600 });\n      fs.renameSync(tmpPath, this.filePath);\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   * Returns true if the discovery data is missing or older than DISCOVERY_TTL_MS.\n   * Invalid or missing timestamps are treated as expired (fail closed).\n   */\n  isDiscoveryExpired(): boolean {\n    const entry = this.load();\n    const timestamp = entry?.discoveryUpdatedAt;\n    if (!entry?.discovery || !timestamp) return true;\n    const updatedMs = new Date(timestamp).getTime();\n    if (!Number.isFinite(updatedMs)) return true;\n    return Date.now() - updatedMs > DISCOVERY_TTL_MS;\n  }\n\n  /**\n   * Update only the discovery portion of the cache, preserving selection.\n   * Optionally persists the associated GitLab project.\n   */\n  saveDiscovery(discovery: DiscoveredModels, project?: GitLabProject | null): void {\n    const existing = this.load();\n    const now = new Date().toISOString();\n    this.save({\n      discovery,\n      project: project !== undefined ? project : (existing?.project ?? null),\n      selectedModelRef: existing?.selectedModelRef ?? null,\n      selectedModelName: existing?.selectedModelName ?? null,\n      updatedAt: now,\n      discoveryUpdatedAt: now,\n    });\n  }\n\n  /**\n   * Update only the selected model, preserving the discovery data.\n   * If name is null but ref is provided, attempts to resolve the name\n   * from the cached discovery data.\n   */\n  saveSelection(ref: string | null, name: string | null): void {\n    const existing = this.load();\n    let resolved = name;\n    if (!resolved && ref && existing?.discovery) {\n      const d = existing.discovery;\n      const match =\n        d.pinnedModel?.ref === ref\n          ? d.pinnedModel\n          : (d.selectableModels.find((m) => m.ref === ref) ??\n            (d.defaultModel?.ref === ref ? d.defaultModel : null));\n      resolved = match?.name ?? null;\n    }\n    this.save({\n      discovery: existing?.discovery ?? null,\n      project: existing?.project ?? null,\n      selectedModelRef: ref,\n      selectedModelName: resolved,\n      updatedAt: new Date().toISOString(),\n      discoveryUpdatedAt: existing?.discoveryUpdatedAt,\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 * 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","import { z } from 'zod';\n\n// OAuth token response schema\nexport const gitlabOAuthTokenResponseSchema = z.object({\n  access_token: z.string(),\n  refresh_token: z.string().optional(),\n  expires_in: z.number(),\n  created_at: z.number(),\n});\n\nexport type GitLabOAuthTokenResponse = z.infer<typeof gitlabOAuthTokenResponseSchema>;\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 { gitlabOAuthTokenResponseSchema } from './gitlab-api-types';\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\n/**\n * Module-global in-flight refresh map.\n *\n * GitLab OAuth refresh tokens are single-use: a successful refresh rotates the\n * refresh token, so a second concurrent refresh that reuses the same (now\n * consumed) refresh token fails with 401. opencode creates a separate provider\n * (and therefore a separate GitLabOAuthManager) per model, and several agents\n * can request a token concurrently. Keying the dedup on a per-instance Map was\n * therefore ineffective across those concurrent callers. Sharing the map at\n * module scope ensures all concurrent refreshes for the same refresh token\n * collapse into a single network exchange and all receive the rotated token.\n */\nconst globalInFlightRefreshes = new Map<string, Promise<GitLabOAuthTokens>>();\n\nexport class GitLabOAuthManager {\n  private fetch: typeof fetch;\n  private inFlightRefreshes = globalInFlightRefreshes;\n\n  constructor(fetchImpl: typeof fetch = fetch) {\n    this.fetch = fetchImpl;\n  }\n\n  /**\n   * Check if a token is expired.\n   * Invalid expiry values (NaN) are treated as expired (fail closed).\n   */\n  isTokenExpired(expiresAt: number): boolean {\n    if (!Number.isFinite(expiresAt)) {\n      return true;\n    }\n    return Date.now() >= expiresAt;\n  }\n\n  /**\n   * Check if a token needs refresh (within skew window).\n   * Invalid expiry values (NaN) are treated as needing refresh (fail closed).\n   */\n  needsRefresh(expiresAt: number): boolean {\n    if (!Number.isFinite(expiresAt)) {\n      return true;\n    }\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 (!tokens.refreshToken) {\n      throw new GitLabError({\n        message: 'OAuth token has expired and no refresh token is available',\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    const inFlightKey = `${instanceUrl}:${refreshToken}`;\n\n    const existing = this.inFlightRefreshes.get(inFlightKey);\n    if (existing) {\n      return existing;\n    }\n\n    const refreshPromise = (async () => {\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, refreshToken);\n    })();\n\n    this.inFlightRefreshes.set(inFlightKey, refreshPromise);\n\n    try {\n      return await refreshPromise;\n    } finally {\n      this.inFlightRefreshes.delete(inFlightKey);\n    }\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      const parsed = gitlabOAuthTokenResponseSchema.safeParse(data);\n      if (!parsed.success) {\n        throw new GitLabError({\n          message: `Invalid OAuth token response: ${parsed.error.message}`,\n          cause: parsed.error,\n        });\n      }\n      return parsed.data;\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   * Falls back to the previous refresh token when the server omits one.\n   */\n  private createTokensFromResponse(\n    response: GitLabOAuthTokenResponse,\n    instanceUrl: string,\n    previousRefreshToken?: string\n  ): GitLabOAuthTokens {\n    const expiresAt = this.createExpiresTimestamp(response);\n\n    return {\n      accessToken: response.access_token,\n      refreshToken: response.refresh_token || previousRefreshToken || '',\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 type { GitLabThinkingConfig } 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 { LanguageModelV3 } from '@ai-sdk/provider';\nimport { GitLabOAuthManager } from './gitlab-oauth-manager';\nimport type { OpenCodeAuth } from './gitlab-oauth-types';\nimport { GITLAB_COM_URL } 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): LanguageModelV3;\n  readonly specificationVersion: 'v3';\n  languageModel(modelId: string): LanguageModelV3;\n  chat(modelId: string): LanguageModelV3;\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  embeddingModel(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   * Default reasoning effort for OpenAI models.\n   * Can be overridden per call through `providerOptions.gitlab.reasoningEffort`.\n   */\n  reasoningEffort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n  /**\n   * Default extended thinking configuration for Anthropic Messages API models.\n   * Can be overridden per call through `providerOptions.gitlab.thinking`.\n   */\n  thinking?: GitLabThinkingConfig;\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   * Default workflow options for `duo-workflow-*` models.\n   *\n   * Hosts that construct models through the plain `provider(modelId)` /\n   * `languageModel(modelId)` entry points — OpenCode does — cannot pass\n   * `GitLabWorkflowOptions`, so without this there is no way to supply a\n   * namespace from configuration. The Duo Agent Platform needs one: both\n   * `POST /api/v4/ai/duo_workflows/workflows` and the DWS WebSocket reject the\n   * request otherwise, unless the user has a default Duo namespace preference.\n   */\n  workflowOptions?: GitLabWorkflowOptions;\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   * Private POSIX directory for shared direct-access tokens; empty string disables caching.\n   * Falls back to GITLAB_DIRECT_ACCESS_CACHE_DIR when omitted.\n   * @default undefined\n   */\n  directAccessCacheDir?: 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    const normalizedUrl = instanceUrl.replace(/\\/$/, '');\n\n    // Priority 1: Check 'gitlab' key (used by opencode-gitlab-auth plugin)\n    const gitlabAuth = authData.gitlab;\n    if (gitlabAuth?.type === 'oauth') {\n      // Verify it matches the requested instance URL (normalize trailing slashes on both sides).\n      // The auth plugin does not always write enterpriseUrl; when it is missing/null we treat the\n      // entry as belonging to the default gitlab.com instance so OAuth tokens are not silently dropped.\n      const normalizedEnterpriseUrl =\n        typeof gitlabAuth.enterpriseUrl === 'string'\n          ? gitlabAuth.enterpriseUrl.replace(/\\/$/, '')\n          : undefined;\n      const matchesInstance =\n        normalizedEnterpriseUrl === normalizedUrl ||\n        (normalizedEnterpriseUrl === undefined && normalizedUrl === GITLAB_COM_URL);\n      if (matchesInstance) {\n        return gitlabAuth as OpenCodeAuth;\n      }\n    } else if (gitlabAuth?.type === 'api' && typeof gitlabAuth.key === 'string') {\n      // Personal access token stored under the 'gitlab' key by the auth plugin.\n      return gitlabAuth as OpenCodeAuth;\n    }\n\n    // Priority 2: Try to find auth for this instance by URL\n    // Check both with and without trailing slash\n    const auth = authData[normalizedUrl] || authData[`${normalizedUrl}/`];\n\n    return auth as OpenCodeAuth | undefined;\n  } catch {\n    return undefined;\n  }\n}\n\n/**\n * Module-global dedup for OAuth token refresh, keyed by instance URL.\n *\n * GitLab refresh tokens are single-use. opencode creates a separate provider\n * per model and several agents can request a token concurrently; without\n * cross-caller dedup, each would read the same stored refresh token and race to\n * exchange it, so only the first succeeds and the rest fail with 401\n * (\"Forbidden by auth provider\"). Keying on instance URL (rather than the\n * refresh token) collapses all concurrent refreshes for an instance into one,\n * regardless of which token each caller happened to read first.\n */\nconst inFlightOAuthRefreshes = new Map<string, Promise<string>>();\n\n/**\n * Refresh an OAuth token and persist the rotated tokens to auth.json,\n * deduplicating concurrent refreshes for the same instance.\n */\nasync function refreshOAuthToken(\n  auth: { refresh: string },\n  instanceUrl: string,\n  clientId?: string\n): Promise<string> {\n  const existing = inFlightOAuthRefreshes.get(instanceUrl);\n  if (existing) {\n    return existing;\n  }\n\n  const refreshPromise = (async () => {\n    const oauthManager = new GitLabOAuthManager();\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  })();\n\n  inFlightOAuthRefreshes.set(instanceUrl, refreshPromise);\n\n  try {\n    return await refreshPromise;\n  } finally {\n    inFlightOAuthRefreshes.delete(instanceUrl);\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: Auth from OpenCode auth.json\n  const auth = await loadOpenCodeAuth(instanceUrl);\n  if (auth?.type === 'api') {\n    return auth.key;\n  }\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        return await refreshOAuthToken(auth, instanceUrl, clientId);\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\n/**\n * Merge provider-level workflow defaults with per-call workflow options.\n *\n * Per-call values win, but keys explicitly set to `undefined` are ignored so a\n * host that forwards optional fields as-is (OpenCode passes\n * `workflowDefinition: undefined`) does not erase the configured default.\n * `featureFlags` are merged rather than replaced.\n *\n * @param defaults - Provider-level `workflowOptions` from settings\n * @param overrides - Per-call options passed to `workflowChat()`\n * @returns The effective options, or `undefined` when neither is set\n */\nfunction mergeWorkflowOptions(\n  defaults: GitLabWorkflowOptions | undefined,\n  overrides: GitLabWorkflowOptions | undefined\n): GitLabWorkflowOptions | undefined {\n  if (!defaults && !overrides) return undefined;\n\n  const definedOverrides = Object.fromEntries(\n    Object.entries(overrides ?? {}).filter(([, value]) => value !== undefined)\n  ) as GitLabWorkflowOptions;\n\n  const merged: GitLabWorkflowOptions = { ...defaults, ...definedOverrides };\n\n  if (defaults?.featureFlags || overrides?.featureFlags) {\n    merged.featureFlags = { ...defaults?.featureFlags, ...overrides?.featureFlags };\n  }\n\n  return merged;\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  let refreshPromise: Promise<void> | 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    try {\n      cachedApiKey = await apiKeyPromise;\n      return cachedApiKey;\n    } finally {\n      apiKeyPromise = undefined;\n    }\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    if (refreshPromise) {\n      return refreshPromise;\n    }\n\n    refreshPromise = (async () => {\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    try {\n      return await refreshPromise;\n    } finally {\n      refreshPromise = undefined;\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  // Ensure the API key is loaded before synchronous getHeaders() is used.\n  // getHeaders is synchronous but the key loads asynchronously; awaiting this\n  // avoids a cold-start race where the first request throws \"API key is missing\"\n  // or sends an empty Authorization header. Swallows errors so getHeaders can\n  // surface a clear message (or env/explicit-key fallbacks still apply).\n  const ensureApiKey = async (): Promise<void> => {\n    try {\n      await getApiKey();\n    } catch {\n      // Ignore — getHeaders falls back to options.apiKey / GITLAB_TOKEN or throws.\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      ensureApiKey,\n      refreshApiKey,\n      fetch: options.fetch,\n      maxTokens: agenticOptions?.maxTokens,\n      featureFlags,\n      aiGatewayUrl: options.aiGatewayUrl,\n      directAccessCacheDir: options.directAccessCacheDir,\n      aiGatewayHeaders,\n    };\n\n    if (mapping.provider === 'openai') {\n      return new GitLabOpenAILanguageModel(modelId, {\n        ...baseConfig,\n        openaiModel: agenticOptions?.providerModel ?? mapping.model,\n        reasoningEffort: agenticOptions?.reasoningEffort,\n      });\n    }\n\n    return new GitLabAnthropicLanguageModel(modelId, {\n      ...baseConfig,\n      anthropicModel: agenticOptions?.providerModel ?? mapping.model,\n      thinking: agenticOptions?.thinking,\n    });\n  };\n\n  const createWorkflowChatModel = (\n    modelId: string,\n    workflowOptions?: GitLabWorkflowOptions\n  ): GitLabWorkflowLanguageModel => {\n    const effectiveWorkflowOptions = mergeWorkflowOptions(options.workflowOptions, workflowOptions);\n\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          ...effectiveWorkflowOptions?.featureFlags,\n        },\n        aiGatewayUrl: options.aiGatewayUrl,\n      },\n      effectiveWorkflowOptions\n    );\n  };\n\n  // Default model factory - uses Anthropic backend for tool support\n  const createDefaultModel = (modelId: string): LanguageModelV3 => {\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: 'v3' as const,\n    languageModel: createDefaultModel,\n    chat: createDefaultModel,\n    agenticChat: createAgenticChatModel,\n    workflowChat: createWorkflowChatModel,\n  }) as GitLabProvider;\n\n  // Unsupported model types\n  provider.embeddingModel = (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","/**\n * Fetches and caches model configuration from the GitLab AI Gateway's\n * models.yml definition file. Provides per-model context window and\n * output token limits keyed by `gitlab_identifier`.\n *\n * Results are cached both in memory and on disk at\n * `~/.cache/opencode/gitlab-model-configs.json`\n * (or `$XDG_CACHE_HOME/opencode/...` when set).\n *\n * @see https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/ai_gateway/model_selection/models.yml\n */\n\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\nimport { GitLabError } from './gitlab-error';\n\nexport interface ModelConfig {\n  /** Maximum input context tokens */\n  context: number;\n  /** Maximum output tokens (from params.max_tokens) */\n  output: number;\n}\n\nexport interface ModelConfigRegistryOptions {\n  /** Override the URL to fetch models.yml from */\n  url?: string;\n  /** Cache TTL in milliseconds (default: 24 hours) */\n  ttlMs?: number;\n  /** Custom fetch implementation */\n  fetch?: typeof fetch;\n}\n\nconst DEFAULT_MODELS_YML_URL =\n  'https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/raw/main/ai_gateway/model_selection/models.yml';\nconst DEFAULT_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours\n\nconst DEFAULT_CONTEXT = 200_000;\nconst DEFAULT_OUTPUT = 64_000;\n\n// ---------------------------------------------------------------------------\n// File cache\n// ---------------------------------------------------------------------------\n\ninterface CacheFile {\n  configs: Record<string, ModelConfig>;\n  updatedAt: string;\n}\n\ninterface FileCacheResult {\n  configs: Map<string, ModelConfig>;\n  writtenAt: number;\n}\n\nfunction getCacheFilePath(): string {\n  const cacheHome = process.env.XDG_CACHE_HOME || path.join(os.homedir(), '.cache');\n  return path.join(cacheHome, 'opencode', 'gitlab-model-configs.json');\n}\n\nfunction readCacheFile(): CacheFile | null {\n  try {\n    const filePath = getCacheFilePath();\n    if (!fs.existsSync(filePath)) return null;\n    const raw = fs.readFileSync(filePath, 'utf-8');\n    return JSON.parse(raw) as CacheFile;\n  } catch {\n    return null;\n  }\n}\n\nfunction writeCacheFile(configs: Map<string, ModelConfig>): void {\n  try {\n    const filePath = getCacheFilePath();\n    const dir = path.dirname(filePath);\n    fs.mkdirSync(dir, { recursive: true, mode: 0o700 });\n    const data: CacheFile = {\n      configs: Object.fromEntries(configs),\n      updatedAt: new Date().toISOString(),\n    };\n    fs.writeFileSync(filePath, JSON.stringify(data, null, 2), { mode: 0o600 });\n  } catch {\n    // Best-effort — cache write failures are non-fatal\n  }\n}\n\nfunction loadCacheFile(ttlMs: number): FileCacheResult | null {\n  const cached = readCacheFile();\n  if (!cached) return null;\n  const writtenAt = new Date(cached.updatedAt).getTime();\n  const age = Date.now() - writtenAt;\n  if (age > ttlMs) return null;\n  return { configs: new Map(Object.entries(cached.configs)), writtenAt };\n}\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nexport class GitLabModelConfigRegistry {\n  private readonly url: string;\n  private readonly ttlMs: number;\n  private readonly fetchFn: typeof fetch;\n  private memCache: Map<string, ModelConfig> | null = null;\n  private memExpiresAt = 0;\n  private pending: Promise<Map<string, ModelConfig>> | null = null;\n\n  constructor(options?: ModelConfigRegistryOptions) {\n    this.url = options?.url ?? DEFAULT_MODELS_YML_URL;\n    this.ttlMs = options?.ttlMs ?? DEFAULT_TTL_MS;\n    this.fetchFn = options?.fetch ?? fetch;\n  }\n\n  /**\n   * Get model configs, fetching and caching as needed.\n   * Returns a Map keyed by `gitlab_identifier` (the discovery `ref`).\n   */\n  async getConfigs(): Promise<Map<string, ModelConfig>> {\n    // 1. In-memory cache\n    if (this.memCache && Date.now() < this.memExpiresAt) {\n      return this.memCache;\n    }\n\n    // 2. File cache\n    const fileCached = loadCacheFile(this.ttlMs);\n    if (fileCached) {\n      this.memCache = fileCached.configs;\n      this.memExpiresAt = fileCached.writtenAt + this.ttlMs;\n      return fileCached.configs;\n    }\n\n    // 3. Fetch (deduplicate concurrent requests)\n    if (this.pending) return this.pending;\n\n    this.pending = this.fetchConfigs();\n    try {\n      return await this.pending;\n    } finally {\n      this.pending = null;\n    }\n  }\n\n  /**\n   * Look up config for a single model ref.\n   * Returns defaults if the ref is not found or fetch fails.\n   */\n  async getConfig(ref: string): Promise<ModelConfig> {\n    const configs = await this.getConfigs();\n    return configs.get(ref) ?? { context: DEFAULT_CONTEXT, output: DEFAULT_OUTPUT };\n  }\n\n  /** Invalidate both in-memory and file caches. */\n  invalidateCache(): void {\n    this.memCache = null;\n    this.memExpiresAt = 0;\n    try {\n      const filePath = getCacheFilePath();\n      if (fs.existsSync(filePath)) {\n        fs.unlinkSync(filePath);\n      }\n    } catch {\n      // Best-effort\n    }\n  }\n\n  private async fetchConfigs(): Promise<Map<string, ModelConfig>> {\n    try {\n      const res = await this.fetchFn(this.url);\n      if (!res.ok) {\n        throw new GitLabError({\n          message: `Failed to fetch model configs: HTTP ${res.status}`,\n          statusCode: res.status,\n        });\n      }\n      const text = await res.text();\n      const configs = parseModelsYml(text);\n\n      // Persist to memory + disk\n      this.memCache = configs;\n      this.memExpiresAt = Date.now() + this.ttlMs;\n      writeCacheFile(configs);\n\n      return configs;\n    } catch (error) {\n      console.warn(\n        `gitlab-ai-provider: model config fetch failed (${\n          error instanceof Error ? error.message : String(error)\n        }); falling back to cached or default model limits`\n      );\n      // Return stale memory/file cache on failure, or empty map\n      return this.memCache ?? loadCacheFile(Infinity)?.configs ?? new Map();\n    }\n  }\n}\n\n/**\n * Parse models.yml to extract gitlab_identifier → { context, output } mapping.\n * Uses simple line-by-line parsing to avoid a YAML dependency.\n */\nexport function parseModelsYml(text: string): Map<string, ModelConfig> {\n  const configs = new Map<string, ModelConfig>();\n  let currentIdentifier: string | null = null;\n  let currentContext = 0;\n  let currentOutput = 0;\n  let inParams = false;\n  let paramsIndent = -1;\n\n  for (const line of text.split('\\n')) {\n    const idMatch = line.match(/^\\s*gitlab_identifier:\\s*\"?([^\"#\\s]+)\"?/);\n    if (idMatch) {\n      if (currentIdentifier) {\n        configs.set(currentIdentifier, {\n          context: currentContext || DEFAULT_CONTEXT,\n          output: currentOutput || DEFAULT_OUTPUT,\n        });\n      }\n      currentIdentifier = idMatch[1];\n      currentContext = 0;\n      currentOutput = 0;\n      inParams = false;\n      paramsIndent = -1;\n    }\n\n    const ctxMatch = line.match(/^\\s*max_context_tokens:\\s*([0-9_]+)/);\n    if (ctxMatch && currentIdentifier) {\n      currentContext = parseInt(ctxMatch[1].replace(/_/g, ''), 10);\n    }\n\n    if (/^\\s*params:\\s*$/.test(line)) {\n      inParams = true;\n      paramsIndent = line.match(/^(\\s*)/)?.[1].length ?? 0;\n    } else if (inParams && /^\\s*\\S+:/.test(line)) {\n      const indent = line.match(/^(\\s*)/)?.[1].length ?? 0;\n      if (indent <= paramsIndent) {\n        inParams = false;\n        paramsIndent = -1;\n      }\n    }\n\n    if (inParams) {\n      const maxTokensMatch = line.match(/^\\s*max_tokens:\\s*([0-9_]+)/);\n      if (maxTokensMatch && currentIdentifier) {\n        currentOutput = parseInt(maxTokensMatch[1].replace(/_/g, ''), 10);\n      }\n    }\n  }\n\n  if (currentIdentifier) {\n    configs.set(currentIdentifier, {\n      context: currentContext || DEFAULT_CONTEXT,\n      output: currentOutput || DEFAULT_OUTPUT,\n    });\n  }\n\n  return configs;\n}\n","/**\n * High-level workflow model discovery.\n *\n * Combines project detection, GraphQL model discovery, model config lookup,\n * and MODEL_MAPPINGS to produce a list of available workflow models with\n * their token limits. Consumers map these into their own internal model\n * representations.\n */\n\nimport { GitLabModelDiscovery } from './gitlab-model-discovery';\nimport type { DiscoveredModels, DiscoveryScope } from './gitlab-model-discovery';\nimport { GitLabModelConfigRegistry } from './gitlab-model-config';\nimport { GitLabProjectDetector } from './gitlab-project-detector';\nimport { MODEL_MAPPINGS } from './model-mappings';\nimport type { GitLabProject } from './gitlab-project-cache';\nimport { GitLabModelCache } from './gitlab-model-cache';\n\nexport interface DiscoveredWorkflowModel {\n  /** Model ID suitable for use with `sdk.workflowChat()` (e.g. \"duo-workflow-sonnet-4-6\") */\n  id: string;\n  /** Upstream model ref (e.g. \"claude_sonnet_4_6\") */\n  ref: string;\n  /** Human-readable name (e.g. \"Claude Sonnet 4.6\") */\n  name: string;\n  /** Max input context tokens */\n  context: number;\n  /** Max output tokens */\n  output: number;\n  /** Whether this model was admin-pinned */\n  pinned: boolean;\n}\n\nexport interface WorkflowDiscoveryConfig {\n  instanceUrl: string;\n  getHeaders: () => Record<string, string>;\n  fetch?: typeof fetch;\n}\n\nexport interface WorkflowDiscoveryOptions {\n  workingDirectory: string;\n  /**\n   * Optional opaque identifier of the account the discovery runs for. When set, cached\n   * results are scoped to it so switching accounts on the same workspace and instance\n   * never returns another account's models. The value is hashed before being stored.\n   */\n  cacheKey?: string;\n}\n\nexport interface WorkflowDiscoveryResult {\n  models: DiscoveredWorkflowModel[];\n  project: GitLabProject | null;\n}\n\nconst configRegistry = new GitLabModelConfigRegistry();\n\nasync function buildModels(\n  discovered: DiscoveredModels,\n  project: GitLabProject | null\n): Promise<WorkflowDiscoveryResult> {\n  const configs = await configRegistry.getConfigs();\n\n  const refToID = new Map<string, string>();\n  for (const [id, mapping] of Object.entries(MODEL_MAPPINGS)) {\n    if (mapping.provider === 'workflow' && id !== 'duo-workflow' && id !== 'duo-workflow-default') {\n      refToID.set(mapping.model, id);\n    }\n  }\n\n  const all = discovered.pinnedModel\n    ? [discovered.pinnedModel]\n    : [\n        ...(discovered.selectableModels ?? []),\n        ...(discovered.defaultModel ? [discovered.defaultModel] : []),\n      ];\n\n  const seen = new Set<string>();\n  const models: DiscoveredWorkflowModel[] = [];\n\n  for (const model of all) {\n    if (!model.ref || seen.has(model.ref)) continue;\n    seen.add(model.ref);\n\n    const id =\n      refToID.get(model.ref) ??\n      (model.ref.startsWith('__default__')\n        ? 'duo-workflow-default'\n        : `duo-workflow-${model.ref.replace(/[/_]/g, '-')}`);\n    const limits = configs.get(model.ref);\n\n    models.push({\n      id,\n      ref: model.ref,\n      name: model.name,\n      context: limits?.context ?? 200_000,\n      output: limits?.output ?? 64_000,\n      pinned: !!discovered.pinnedModel && discovered.pinnedModel.ref === model.ref,\n    });\n  }\n\n  return { models, project };\n}\n\nexport async function discoverWorkflowModels(\n  config: WorkflowDiscoveryConfig,\n  options: WorkflowDiscoveryOptions\n): Promise<WorkflowDiscoveryResult> {\n  const cache = new GitLabModelCache(\n    options.workingDirectory,\n    config.instanceUrl,\n    options.cacheKey\n  );\n\n  if (!cache.isDiscoveryExpired()) {\n    const entry = cache.load();\n    if (entry?.discovery) {\n      return buildModels(entry.discovery, entry.project);\n    }\n  }\n\n  const detector = new GitLabProjectDetector({\n    instanceUrl: config.instanceUrl,\n    getHeaders: config.getHeaders,\n    fetch: config.fetch,\n  });\n\n  let project: GitLabProject | null = null;\n  try {\n    project = await detector.detectProject(options.workingDirectory);\n  } catch {\n    return { models: [], project: null };\n  }\n\n  if (!project?.id) return { models: [], project };\n\n  const scope: DiscoveryScope = {\n    projectId: `gid://gitlab/Project/${project.id}`,\n    ...(project.namespaceId\n      ? { rootNamespaceId: `gid://gitlab/Group/${project.namespaceId}` }\n      : {}),\n  };\n\n  const discovery = new GitLabModelDiscovery({\n    instanceUrl: config.instanceUrl,\n    getHeaders: config.getHeaders,\n    fetch: config.fetch,\n  });\n\n  let discovered: DiscoveredModels;\n  try {\n    discovered = await discovery.discover(scope);\n  } catch {\n    // Discovery can legitimately fail (e.g. Duo Agent Platform not\n    // available for this namespace, or an unsupported GitLab version).\n    // Degrade to no workflow models rather than surfacing the error.\n    return { models: [], project };\n  }\n\n  cache.saveDiscovery(discovered, project);\n\n  if (!cache.getSelectedModelRef()) {\n    const pick = discovered.pinnedModel ?? discovered.defaultModel;\n    if (pick) cache.saveSelection(pick.ref, pick.name);\n  }\n\n  return buildModels(discovered, project);\n}\n"],"mappings":"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","names":["join","filesystem","path","constants","lstat","open","unlink","isAbsolute","join","lock","path","lifetime","response","body","z","filePath","safePath","content","WorkflowType","z","resolve","hasToolCalls","resolve","path","resolve","fs","path","sess","z","fs","path","os","fs","path","os","getCacheFilePath"]}