@gitlab/gitlab-ai-provider 3.5.0 → 3.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
4
4
 
5
+ ## 3.6.0 (2026-02-18)
6
+
7
+ - Merge branch 'feat/add-sonnet-4-6' into 'main' ([68d9e4f](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/commit/68d9e4f))
8
+ - feat: add Claude Sonnet 4.6 model mapping ([c4fd7b1](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/commit/c4fd7b1))
9
+
10
+ ## <small>3.5.1 (2026-02-16)</small>
11
+
12
+ - Merge branch 'vg/token-refresh' into 'main' ([38295cf](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/commit/38295cf))
13
+ - fix: resolve mid-session OAuth token refresh failures ([b495153](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/commit/b495153))
14
+
5
15
  ## 3.5.0 (2026-02-06)
6
16
 
7
17
  - Merge branch 'feat/add-opus-4-6' into 'main' ([b776bd7](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/commit/b776bd7))
package/dist/index.d.mts CHANGED
@@ -138,6 +138,8 @@ interface GitLabAgenticOptions {
138
138
  * Must be a valid model for the detected provider.
139
139
  *
140
140
  * For Anthropic models:
141
+ * - 'claude-opus-4-6'
142
+ * - 'claude-sonnet-4-6'
141
143
  * - 'claude-opus-4-5-20251101'
142
144
  * - 'claude-sonnet-4-5-20250929'
143
145
  * - 'claude-haiku-4-5-20251001'
@@ -392,7 +394,10 @@ interface OpenCodeAuthOAuth {
392
394
  refresh: string;
393
395
  access: string;
394
396
  expires: number;
397
+ /** @deprecated Use enterpriseUrl instead. Kept for backwards compatibility with older auth.json files. */
395
398
  instanceUrl?: string;
399
+ /** Instance URL as written by opencode-gitlab-auth plugin (e.g. 'https://gitlab.com') */
400
+ enterpriseUrl?: string;
396
401
  }
397
402
  interface OpenCodeAuthApi {
398
403
  type: 'api';
@@ -400,8 +405,16 @@ interface OpenCodeAuthApi {
400
405
  }
401
406
  type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;
402
407
  /**
403
- * Bundled OAuth client ID for GitLab.com
404
- * Same as used in gitlab-vscode-extension
408
+ * Default OAuth client ID for GitLab.com
409
+ * This is the same client ID used by opencode-gitlab-auth plugin.
410
+ * The GITLAB_OAUTH_CLIENT_ID env var takes precedence if set.
411
+ * Note: VS Code extension uses a different client ID ('36f2a70c...') but we use the opencode plugin's ID
412
+ * to ensure token refresh works correctly with tokens created by the auth plugin.
413
+ */
414
+ declare const OPENCODE_GITLAB_AUTH_CLIENT_ID = "1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e";
415
+ /**
416
+ * @deprecated Use OPENCODE_GITLAB_AUTH_CLIENT_ID instead. This is the VS Code extension's client ID
417
+ * and will cause refresh failures if used with tokens created by opencode-gitlab-auth.
405
418
  */
406
419
  declare const BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
407
420
  /**
@@ -463,7 +476,10 @@ declare class GitLabOAuthManager {
463
476
  */
464
477
  exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens>;
465
478
  /**
466
- * Get the OAuth client ID for an instance
479
+ * Get the OAuth client ID for an instance.
480
+ * Priority: env var > opencode-gitlab-auth default (for GitLab.com).
481
+ * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId
482
+ * that bypasses this method entirely.
467
483
  */
468
484
  private getClientId;
469
485
  /**
@@ -680,4 +696,4 @@ declare class GitLabDirectAccessClient {
680
696
  invalidateToken(): void;
681
697
  }
682
698
 
683
- export { BUNDLED_CLIENT_ID, DEFAULT_AI_GATEWAY_URL, type DirectAccessToken, GITLAB_COM_URL, type GitLabAgenticOptions, type GitLabAnthropicConfig, GitLabAnthropicLanguageModel, GitLabDirectAccessClient, type GitLabDirectAccessConfig, GitLabError, type GitLabErrorOptions, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabOpenAIConfig, GitLabOpenAILanguageModel, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, MODEL_ID_TO_ANTHROPIC_MODEL, MODEL_MAPPINGS, type ModelMapping, type ModelProvider, OAUTH_SCOPES, type OpenAIApiType, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, TOKEN_EXPIRY_SKEW_MS, VERSION, createGitLab, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, gitlab, isResponsesApiModel };
699
+ export { BUNDLED_CLIENT_ID, DEFAULT_AI_GATEWAY_URL, type DirectAccessToken, GITLAB_COM_URL, type GitLabAgenticOptions, type GitLabAnthropicConfig, GitLabAnthropicLanguageModel, GitLabDirectAccessClient, type GitLabDirectAccessConfig, GitLabError, type GitLabErrorOptions, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabOpenAIConfig, GitLabOpenAILanguageModel, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, MODEL_ID_TO_ANTHROPIC_MODEL, MODEL_MAPPINGS, type ModelMapping, type ModelProvider, OAUTH_SCOPES, OPENCODE_GITLAB_AUTH_CLIENT_ID, type OpenAIApiType, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, TOKEN_EXPIRY_SKEW_MS, VERSION, createGitLab, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, gitlab, isResponsesApiModel };
package/dist/index.d.ts CHANGED
@@ -138,6 +138,8 @@ interface GitLabAgenticOptions {
138
138
  * Must be a valid model for the detected provider.
139
139
  *
140
140
  * For Anthropic models:
141
+ * - 'claude-opus-4-6'
142
+ * - 'claude-sonnet-4-6'
141
143
  * - 'claude-opus-4-5-20251101'
142
144
  * - 'claude-sonnet-4-5-20250929'
143
145
  * - 'claude-haiku-4-5-20251001'
@@ -392,7 +394,10 @@ interface OpenCodeAuthOAuth {
392
394
  refresh: string;
393
395
  access: string;
394
396
  expires: number;
397
+ /** @deprecated Use enterpriseUrl instead. Kept for backwards compatibility with older auth.json files. */
395
398
  instanceUrl?: string;
399
+ /** Instance URL as written by opencode-gitlab-auth plugin (e.g. 'https://gitlab.com') */
400
+ enterpriseUrl?: string;
396
401
  }
397
402
  interface OpenCodeAuthApi {
398
403
  type: 'api';
@@ -400,8 +405,16 @@ interface OpenCodeAuthApi {
400
405
  }
401
406
  type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;
402
407
  /**
403
- * Bundled OAuth client ID for GitLab.com
404
- * Same as used in gitlab-vscode-extension
408
+ * Default OAuth client ID for GitLab.com
409
+ * This is the same client ID used by opencode-gitlab-auth plugin.
410
+ * The GITLAB_OAUTH_CLIENT_ID env var takes precedence if set.
411
+ * Note: VS Code extension uses a different client ID ('36f2a70c...') but we use the opencode plugin's ID
412
+ * to ensure token refresh works correctly with tokens created by the auth plugin.
413
+ */
414
+ declare const OPENCODE_GITLAB_AUTH_CLIENT_ID = "1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e";
415
+ /**
416
+ * @deprecated Use OPENCODE_GITLAB_AUTH_CLIENT_ID instead. This is the VS Code extension's client ID
417
+ * and will cause refresh failures if used with tokens created by opencode-gitlab-auth.
405
418
  */
406
419
  declare const BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
407
420
  /**
@@ -463,7 +476,10 @@ declare class GitLabOAuthManager {
463
476
  */
464
477
  exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens>;
465
478
  /**
466
- * Get the OAuth client ID for an instance
479
+ * Get the OAuth client ID for an instance.
480
+ * Priority: env var > opencode-gitlab-auth default (for GitLab.com).
481
+ * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId
482
+ * that bypasses this method entirely.
467
483
  */
468
484
  private getClientId;
469
485
  /**
@@ -680,4 +696,4 @@ declare class GitLabDirectAccessClient {
680
696
  invalidateToken(): void;
681
697
  }
682
698
 
683
- export { BUNDLED_CLIENT_ID, DEFAULT_AI_GATEWAY_URL, type DirectAccessToken, GITLAB_COM_URL, type GitLabAgenticOptions, type GitLabAnthropicConfig, GitLabAnthropicLanguageModel, GitLabDirectAccessClient, type GitLabDirectAccessConfig, GitLabError, type GitLabErrorOptions, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabOpenAIConfig, GitLabOpenAILanguageModel, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, MODEL_ID_TO_ANTHROPIC_MODEL, MODEL_MAPPINGS, type ModelMapping, type ModelProvider, OAUTH_SCOPES, type OpenAIApiType, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, TOKEN_EXPIRY_SKEW_MS, VERSION, createGitLab, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, gitlab, isResponsesApiModel };
699
+ export { BUNDLED_CLIENT_ID, DEFAULT_AI_GATEWAY_URL, type DirectAccessToken, GITLAB_COM_URL, type GitLabAgenticOptions, type GitLabAnthropicConfig, GitLabAnthropicLanguageModel, GitLabDirectAccessClient, type GitLabDirectAccessConfig, GitLabError, type GitLabErrorOptions, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabOpenAIConfig, GitLabOpenAILanguageModel, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, MODEL_ID_TO_ANTHROPIC_MODEL, MODEL_MAPPINGS, type ModelMapping, type ModelProvider, OAUTH_SCOPES, OPENCODE_GITLAB_AUTH_CLIENT_ID, type OpenAIApiType, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, TOKEN_EXPIRY_SKEW_MS, VERSION, createGitLab, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, gitlab, isResponsesApiModel };
package/dist/index.js CHANGED
@@ -42,6 +42,7 @@ __export(index_exports, {
42
42
  MODEL_ID_TO_ANTHROPIC_MODEL: () => MODEL_ID_TO_ANTHROPIC_MODEL,
43
43
  MODEL_MAPPINGS: () => MODEL_MAPPINGS,
44
44
  OAUTH_SCOPES: () => OAUTH_SCOPES,
45
+ OPENCODE_GITLAB_AUTH_CLIENT_ID: () => OPENCODE_GITLAB_AUTH_CLIENT_ID,
45
46
  TOKEN_EXPIRY_SKEW_MS: () => TOKEN_EXPIRY_SKEW_MS,
46
47
  VERSION: () => VERSION,
47
48
  createGitLab: () => createGitLab,
@@ -723,6 +724,7 @@ var import_openai = __toESM(require("openai"));
723
724
  var MODEL_MAPPINGS = {
724
725
  // Anthropic models
725
726
  "duo-chat-opus-4-6": { provider: "anthropic", model: "claude-opus-4-6" },
727
+ "duo-chat-sonnet-4-6": { provider: "anthropic", model: "claude-sonnet-4-6" },
726
728
  "duo-chat-opus-4-5": { provider: "anthropic", model: "claude-opus-4-5-20251101" },
727
729
  "duo-chat-sonnet-4-5": { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
728
730
  "duo-chat-haiku-4-5": { provider: "anthropic", model: "claude-haiku-4-5-20251001" },
@@ -1518,6 +1520,7 @@ var GitLabOpenAILanguageModel = class {
1518
1520
  };
1519
1521
 
1520
1522
  // src/gitlab-oauth-types.ts
1523
+ var OPENCODE_GITLAB_AUTH_CLIENT_ID = "1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e";
1521
1524
  var BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
1522
1525
  var GITLAB_COM_URL = "https://gitlab.com";
1523
1526
  var TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1e3;
@@ -1591,14 +1594,21 @@ var GitLabOAuthManager = class {
1591
1594
  return this.createTokensFromResponse(tokenResponse, instanceUrl);
1592
1595
  }
1593
1596
  /**
1594
- * Get the OAuth client ID for an instance
1597
+ * Get the OAuth client ID for an instance.
1598
+ * Priority: env var > opencode-gitlab-auth default (for GitLab.com).
1599
+ * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId
1600
+ * that bypasses this method entirely.
1595
1601
  */
1596
1602
  getClientId(instanceUrl) {
1603
+ const envClientId = process.env["GITLAB_OAUTH_CLIENT_ID"];
1604
+ if (envClientId) {
1605
+ return envClientId;
1606
+ }
1597
1607
  if (instanceUrl === GITLAB_COM_URL) {
1598
- return BUNDLED_CLIENT_ID;
1608
+ return OPENCODE_GITLAB_AUTH_CLIENT_ID;
1599
1609
  }
1600
1610
  throw new GitLabError({
1601
- message: `No OAuth client ID configured for instance ${instanceUrl}. Please provide a clientId parameter.`
1611
+ message: `No OAuth client ID configured for instance ${instanceUrl}. Please provide a clientId parameter or set GITLAB_OAUTH_CLIENT_ID environment variable.`
1602
1612
  });
1603
1613
  }
1604
1614
  /**
@@ -1680,7 +1690,7 @@ var GitLabOAuthManager = class {
1680
1690
  };
1681
1691
 
1682
1692
  // src/version.ts
1683
- var VERSION = true ? "3.4.1" : "0.0.0-dev";
1693
+ var VERSION = true ? "3.5.1" : "0.0.0-dev";
1684
1694
 
1685
1695
  // src/gitlab-provider.ts
1686
1696
  var fs = __toESM(require("fs"));
@@ -1733,20 +1743,26 @@ async function loadApiKey(options, instanceUrl, clientId) {
1733
1743
  });
1734
1744
  const authPath = getOpenCodeAuthPath();
1735
1745
  const authData = JSON.parse(fs.readFileSync(authPath, "utf-8"));
1736
- const normalizedUrl = instanceUrl.replace(/\/$/, "");
1737
- authData[normalizedUrl] = {
1746
+ authData.gitlab = {
1738
1747
  type: "oauth",
1739
1748
  refresh: refreshed.refreshToken,
1740
1749
  access: refreshed.accessToken,
1741
1750
  expires: refreshed.expiresAt,
1742
- instanceUrl
1751
+ enterpriseUrl: instanceUrl
1752
+ // Use enterpriseUrl to match auth plugin format
1743
1753
  };
1744
- fs.writeFileSync(authPath, JSON.stringify(authData, null, 2));
1754
+ fs.writeFileSync(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
1745
1755
  return refreshed.accessToken;
1746
1756
  } catch (error) {
1747
- console.warn(
1748
- `Failed to refresh OAuth token: ${error instanceof Error ? error.message : String(error)}`
1749
- );
1757
+ const refreshErrorMsg = error instanceof Error ? error.message : String(error);
1758
+ console.warn(`Failed to refresh OAuth token: ${refreshErrorMsg}`);
1759
+ const envApiKey = process.env[options.environmentVariableName];
1760
+ if (envApiKey) {
1761
+ return envApiKey;
1762
+ }
1763
+ throw new GitLabError({
1764
+ message: `OAuth token refresh failed and no fallback ${options.environmentVariableName} environment variable is set. Refresh error: ${refreshErrorMsg}. Re-authenticate with 'opencode auth login gitlab' or set ${options.environmentVariableName}.`
1765
+ });
1750
1766
  }
1751
1767
  } else {
1752
1768
  return auth.access;
@@ -1795,7 +1811,16 @@ function createGitLab(options = {}) {
1795
1811
  const refreshApiKey = async () => {
1796
1812
  cachedApiKey = void 0;
1797
1813
  apiKeyPromise = void 0;
1798
- cachedApiKey = await getApiKey();
1814
+ cachedApiKey = await loadApiKey(
1815
+ {
1816
+ apiKey: void 0,
1817
+ // Bypass stale options.apiKey to force auth.json read
1818
+ environmentVariableName: "GITLAB_TOKEN",
1819
+ description: "GitLab"
1820
+ },
1821
+ instanceUrl,
1822
+ options.clientId
1823
+ );
1799
1824
  };
1800
1825
  const getHeaders = () => {
1801
1826
  const apiKey = cachedApiKey || options.apiKey || process.env["GITLAB_TOKEN"] || "";
@@ -2172,6 +2197,7 @@ var GitLabProjectDetector = class {
2172
2197
  MODEL_ID_TO_ANTHROPIC_MODEL,
2173
2198
  MODEL_MAPPINGS,
2174
2199
  OAUTH_SCOPES,
2200
+ OPENCODE_GITLAB_AUTH_CLIENT_ID,
2175
2201
  TOKEN_EXPIRY_SKEW_MS,
2176
2202
  VERSION,
2177
2203
  createGitLab,