gitlab-ai-provider 6.9.2 → 6.10.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 +11 -0
- package/dist/gitlab-ai-provider-6.10.0.tgz +0 -0
- package/dist/index.d.mts +14 -0
- package/dist/index.d.ts +14 -0
- package/dist/index.js +51 -19
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +51 -19
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/gitlab-ai-provider-6.9.2.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
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
|
+
## 6.10.0 (2026-07-01)
|
|
6
|
+
|
|
7
|
+
- Merge branch 'feature-add-claude-sonnet-5' into 'main' ([5294b5e](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/5294b5e))
|
|
8
|
+
- feat(models): add Claude Sonnet 5 model mappings ([85976b4](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/85976b4))
|
|
9
|
+
- chore(skill): add add-gitlab-model skill to automate model onboarding ([6bbfc4d](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/6bbfc4d))
|
|
10
|
+
|
|
11
|
+
## <small>6.9.3 (2026-06-11)</small>
|
|
12
|
+
|
|
13
|
+
- Merge branch 'fix/concurrent-auth-token-race' into 'main' ([7306083](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/7306083))
|
|
14
|
+
- fix(auth): prevent concurrent auth failures from token races ([49ed5c7](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/49ed5c7))
|
|
15
|
+
|
|
5
16
|
## <small>6.9.2 (2026-06-10)</small>
|
|
6
17
|
|
|
7
18
|
- Merge branch 'fix/auth-json-api-token-handling' into 'main' ([19a6e58](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/19a6e58))
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -6,6 +6,11 @@ interface GitLabAnthropicConfig {
|
|
|
6
6
|
instanceUrl: string;
|
|
7
7
|
getHeaders: () => Record<string, string>;
|
|
8
8
|
fetch?: typeof fetch;
|
|
9
|
+
/**
|
|
10
|
+
* Optional async hook that resolves once credentials are loaded, awaited
|
|
11
|
+
* before the synchronous getHeaders() is used for the direct-access request.
|
|
12
|
+
*/
|
|
13
|
+
ensureApiKey?: () => Promise<void>;
|
|
9
14
|
/**
|
|
10
15
|
* Optional callback to refresh the API key when a 401 error occurs.
|
|
11
16
|
* Should clear cached credentials and re-fetch from auth provider.
|
|
@@ -1073,6 +1078,7 @@ interface GitLabOpenAIConfig {
|
|
|
1073
1078
|
instanceUrl: string;
|
|
1074
1079
|
getHeaders: () => Record<string, string>;
|
|
1075
1080
|
fetch?: typeof fetch;
|
|
1081
|
+
ensureApiKey?: () => Promise<void>;
|
|
1076
1082
|
refreshApiKey?: () => Promise<void>;
|
|
1077
1083
|
openaiModel?: string;
|
|
1078
1084
|
maxTokens?: number;
|
|
@@ -1431,6 +1437,14 @@ declare const DEFAULT_AI_GATEWAY_URL = "https://cloud.gitlab.com";
|
|
|
1431
1437
|
interface GitLabDirectAccessConfig {
|
|
1432
1438
|
instanceUrl: string;
|
|
1433
1439
|
getHeaders: () => Record<string, string>;
|
|
1440
|
+
/**
|
|
1441
|
+
* Optional async hook that resolves once credentials are loaded.
|
|
1442
|
+
* `getHeaders` is synchronous, but the API key is loaded asynchronously; the
|
|
1443
|
+
* client awaits this before building request headers so the first request on
|
|
1444
|
+
* a cold provider doesn't race the lazy key load (which would otherwise throw
|
|
1445
|
+
* "API key is missing" or send an empty Authorization header).
|
|
1446
|
+
*/
|
|
1447
|
+
ensureApiKey?: () => Promise<void>;
|
|
1434
1448
|
fetch?: typeof fetch;
|
|
1435
1449
|
/**
|
|
1436
1450
|
* Optional callback to refresh the API key when a 401 error occurs.
|
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,11 @@ interface GitLabAnthropicConfig {
|
|
|
6
6
|
instanceUrl: string;
|
|
7
7
|
getHeaders: () => Record<string, string>;
|
|
8
8
|
fetch?: typeof fetch;
|
|
9
|
+
/**
|
|
10
|
+
* Optional async hook that resolves once credentials are loaded, awaited
|
|
11
|
+
* before the synchronous getHeaders() is used for the direct-access request.
|
|
12
|
+
*/
|
|
13
|
+
ensureApiKey?: () => Promise<void>;
|
|
9
14
|
/**
|
|
10
15
|
* Optional callback to refresh the API key when a 401 error occurs.
|
|
11
16
|
* Should clear cached credentials and re-fetch from auth provider.
|
|
@@ -1073,6 +1078,7 @@ interface GitLabOpenAIConfig {
|
|
|
1073
1078
|
instanceUrl: string;
|
|
1074
1079
|
getHeaders: () => Record<string, string>;
|
|
1075
1080
|
fetch?: typeof fetch;
|
|
1081
|
+
ensureApiKey?: () => Promise<void>;
|
|
1076
1082
|
refreshApiKey?: () => Promise<void>;
|
|
1077
1083
|
openaiModel?: string;
|
|
1078
1084
|
maxTokens?: number;
|
|
@@ -1431,6 +1437,14 @@ declare const DEFAULT_AI_GATEWAY_URL = "https://cloud.gitlab.com";
|
|
|
1431
1437
|
interface GitLabDirectAccessConfig {
|
|
1432
1438
|
instanceUrl: string;
|
|
1433
1439
|
getHeaders: () => Record<string, string>;
|
|
1440
|
+
/**
|
|
1441
|
+
* Optional async hook that resolves once credentials are loaded.
|
|
1442
|
+
* `getHeaders` is synchronous, but the API key is loaded asynchronously; the
|
|
1443
|
+
* client awaits this before building request headers so the first request on
|
|
1444
|
+
* a cold provider doesn't race the lazy key load (which would otherwise throw
|
|
1445
|
+
* "API key is missing" or send an empty Authorization header).
|
|
1446
|
+
*/
|
|
1447
|
+
ensureApiKey?: () => Promise<void>;
|
|
1434
1448
|
fetch?: typeof fetch;
|
|
1435
1449
|
/**
|
|
1436
1450
|
* Optional callback to refresh the API key when a 401 error occurs.
|
package/dist/index.js
CHANGED
|
@@ -727,6 +727,9 @@ var GitLabDirectAccessClient = class {
|
|
|
727
727
|
if (this.config.featureFlags && Object.keys(this.config.featureFlags).length > 0) {
|
|
728
728
|
requestBody.feature_flags = this.config.featureFlags;
|
|
729
729
|
}
|
|
730
|
+
if (this.config.ensureApiKey) {
|
|
731
|
+
await this.config.ensureApiKey();
|
|
732
|
+
}
|
|
730
733
|
try {
|
|
731
734
|
const response = await this.fetchFn(url, {
|
|
732
735
|
method: "POST",
|
|
@@ -822,6 +825,7 @@ var GitLabAnthropicLanguageModel = class {
|
|
|
822
825
|
this.directAccessClient = new GitLabDirectAccessClient({
|
|
823
826
|
instanceUrl: config.instanceUrl,
|
|
824
827
|
getHeaders: config.getHeaders,
|
|
828
|
+
ensureApiKey: config.ensureApiKey,
|
|
825
829
|
refreshApiKey: config.refreshApiKey,
|
|
826
830
|
fetch: config.fetch,
|
|
827
831
|
featureFlags: config.featureFlags,
|
|
@@ -1457,6 +1461,7 @@ var MODEL_MAPPINGS = {
|
|
|
1457
1461
|
"duo-chat-opus-4-8": { provider: "anthropic", model: "claude-opus-4-8" },
|
|
1458
1462
|
"duo-chat-opus-4-7": { provider: "anthropic", model: "claude-opus-4-7" },
|
|
1459
1463
|
"duo-chat-opus-4-6": { provider: "anthropic", model: "claude-opus-4-6" },
|
|
1464
|
+
"duo-chat-sonnet-5": { provider: "anthropic", model: "claude-sonnet-5" },
|
|
1460
1465
|
"duo-chat-sonnet-4-6": { provider: "anthropic", model: "claude-sonnet-4-6" },
|
|
1461
1466
|
"duo-chat-opus-4-5": { provider: "anthropic", model: "claude-opus-4-5-20251101" },
|
|
1462
1467
|
"duo-chat-sonnet-4-5": { provider: "anthropic", model: "claude-sonnet-4-5-20250929" },
|
|
@@ -1496,6 +1501,7 @@ var MODEL_MAPPINGS = {
|
|
|
1496
1501
|
provider: "workflow",
|
|
1497
1502
|
model: "anthropic/claude-sonnet-4-5-20250929"
|
|
1498
1503
|
},
|
|
1504
|
+
"duo-workflow-sonnet-5": { provider: "workflow", model: "claude_sonnet_5" },
|
|
1499
1505
|
"duo-workflow-sonnet-4-6": { provider: "workflow", model: "claude_sonnet_4_6" },
|
|
1500
1506
|
"duo-workflow-opus-4-5": {
|
|
1501
1507
|
provider: "workflow",
|
|
@@ -1555,6 +1561,7 @@ var GitLabOpenAILanguageModel = class {
|
|
|
1555
1561
|
this.directAccessClient = new GitLabDirectAccessClient({
|
|
1556
1562
|
instanceUrl: config.instanceUrl,
|
|
1557
1563
|
getHeaders: config.getHeaders,
|
|
1564
|
+
ensureApiKey: config.ensureApiKey,
|
|
1558
1565
|
refreshApiKey: config.refreshApiKey,
|
|
1559
1566
|
fetch: config.fetch,
|
|
1560
1567
|
featureFlags: config.featureFlags,
|
|
@@ -2496,7 +2503,7 @@ var import_node_async_hooks = require("async_hooks");
|
|
|
2496
2503
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
2497
2504
|
|
|
2498
2505
|
// src/version.ts
|
|
2499
|
-
var VERSION = true ? "6.9.
|
|
2506
|
+
var VERSION = true ? "6.9.3" : "0.0.0-dev";
|
|
2500
2507
|
|
|
2501
2508
|
// src/gitlab-workflow-client.ts
|
|
2502
2509
|
var WS_CONNECT_TIMEOUT_MS = 3e4;
|
|
@@ -4833,9 +4840,10 @@ var TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1e3;
|
|
|
4833
4840
|
var OAUTH_SCOPES = ["api"];
|
|
4834
4841
|
|
|
4835
4842
|
// src/gitlab-oauth-manager.ts
|
|
4843
|
+
var globalInFlightRefreshes = /* @__PURE__ */ new Map();
|
|
4836
4844
|
var GitLabOAuthManager = class {
|
|
4837
4845
|
fetch;
|
|
4838
|
-
inFlightRefreshes =
|
|
4846
|
+
inFlightRefreshes = globalInFlightRefreshes;
|
|
4839
4847
|
constructor(fetchImpl = fetch) {
|
|
4840
4848
|
this.fetch = fetchImpl;
|
|
4841
4849
|
}
|
|
@@ -5064,6 +5072,39 @@ async function loadOpenCodeAuth(instanceUrl) {
|
|
|
5064
5072
|
return void 0;
|
|
5065
5073
|
}
|
|
5066
5074
|
}
|
|
5075
|
+
var inFlightOAuthRefreshes = /* @__PURE__ */ new Map();
|
|
5076
|
+
async function refreshOAuthToken(auth, instanceUrl, clientId) {
|
|
5077
|
+
const existing = inFlightOAuthRefreshes.get(instanceUrl);
|
|
5078
|
+
if (existing) {
|
|
5079
|
+
return existing;
|
|
5080
|
+
}
|
|
5081
|
+
const refreshPromise = (async () => {
|
|
5082
|
+
const oauthManager = new GitLabOAuthManager();
|
|
5083
|
+
const refreshed = await oauthManager.exchangeRefreshToken({
|
|
5084
|
+
instanceUrl,
|
|
5085
|
+
refreshToken: auth.refresh,
|
|
5086
|
+
clientId
|
|
5087
|
+
});
|
|
5088
|
+
const authPath = getOpenCodeAuthPath();
|
|
5089
|
+
const authData = JSON.parse(fs3.readFileSync(authPath, "utf-8"));
|
|
5090
|
+
authData.gitlab = {
|
|
5091
|
+
type: "oauth",
|
|
5092
|
+
refresh: refreshed.refreshToken,
|
|
5093
|
+
access: refreshed.accessToken,
|
|
5094
|
+
expires: refreshed.expiresAt,
|
|
5095
|
+
enterpriseUrl: instanceUrl
|
|
5096
|
+
// Use enterpriseUrl to match auth plugin format
|
|
5097
|
+
};
|
|
5098
|
+
fs3.writeFileSync(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
|
|
5099
|
+
return refreshed.accessToken;
|
|
5100
|
+
})();
|
|
5101
|
+
inFlightOAuthRefreshes.set(instanceUrl, refreshPromise);
|
|
5102
|
+
try {
|
|
5103
|
+
return await refreshPromise;
|
|
5104
|
+
} finally {
|
|
5105
|
+
inFlightOAuthRefreshes.delete(instanceUrl);
|
|
5106
|
+
}
|
|
5107
|
+
}
|
|
5067
5108
|
async function loadApiKey(options, instanceUrl, clientId) {
|
|
5068
5109
|
if (options.apiKey) {
|
|
5069
5110
|
return options.apiKey;
|
|
@@ -5076,23 +5117,7 @@ async function loadApiKey(options, instanceUrl, clientId) {
|
|
|
5076
5117
|
const oauthManager = new GitLabOAuthManager();
|
|
5077
5118
|
if (oauthManager.needsRefresh(auth.expires)) {
|
|
5078
5119
|
try {
|
|
5079
|
-
|
|
5080
|
-
instanceUrl,
|
|
5081
|
-
refreshToken: auth.refresh,
|
|
5082
|
-
clientId
|
|
5083
|
-
});
|
|
5084
|
-
const authPath = getOpenCodeAuthPath();
|
|
5085
|
-
const authData = JSON.parse(fs3.readFileSync(authPath, "utf-8"));
|
|
5086
|
-
authData.gitlab = {
|
|
5087
|
-
type: "oauth",
|
|
5088
|
-
refresh: refreshed.refreshToken,
|
|
5089
|
-
access: refreshed.accessToken,
|
|
5090
|
-
expires: refreshed.expiresAt,
|
|
5091
|
-
enterpriseUrl: instanceUrl
|
|
5092
|
-
// Use enterpriseUrl to match auth plugin format
|
|
5093
|
-
};
|
|
5094
|
-
fs3.writeFileSync(authPath, JSON.stringify(authData, null, 2), { mode: 384 });
|
|
5095
|
-
return refreshed.accessToken;
|
|
5120
|
+
return await refreshOAuthToken(auth, instanceUrl, clientId);
|
|
5096
5121
|
} catch (error) {
|
|
5097
5122
|
const refreshErrorMsg = error instanceof Error ? error.message : String(error);
|
|
5098
5123
|
const envApiKey = process.env[options.environmentVariableName];
|
|
@@ -5191,6 +5216,12 @@ function createGitLab(options = {}) {
|
|
|
5191
5216
|
`ai-sdk-gitlab/${VERSION}`
|
|
5192
5217
|
);
|
|
5193
5218
|
};
|
|
5219
|
+
const ensureApiKey = async () => {
|
|
5220
|
+
try {
|
|
5221
|
+
await getApiKey();
|
|
5222
|
+
} catch {
|
|
5223
|
+
}
|
|
5224
|
+
};
|
|
5194
5225
|
getApiKey().catch(() => {
|
|
5195
5226
|
});
|
|
5196
5227
|
const createAgenticChatModel = (modelId, agenticOptions) => {
|
|
@@ -5225,6 +5256,7 @@ function createGitLab(options = {}) {
|
|
|
5225
5256
|
provider: `${providerName}.agentic`,
|
|
5226
5257
|
instanceUrl,
|
|
5227
5258
|
getHeaders,
|
|
5259
|
+
ensureApiKey,
|
|
5228
5260
|
refreshApiKey,
|
|
5229
5261
|
fetch: options.fetch,
|
|
5230
5262
|
maxTokens: agenticOptions?.maxTokens,
|