@gitlab/gitlab-ai-provider 1.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,525 @@
1
+ import { LanguageModelV2, LanguageModelV2CallOptions, LanguageModelV2Content, LanguageModelV2FinishReason, LanguageModelV2Usage, LanguageModelV2CallWarning, LanguageModelV2StreamPart } from '@ai-sdk/provider';
2
+ import { z } from 'zod';
3
+ import { Tool } from '@anthropic-ai/sdk/resources/messages';
4
+
5
+ interface GitLabAgenticConfig {
6
+ provider: string;
7
+ instanceUrl: string;
8
+ getHeaders: () => Record<string, string>;
9
+ fetch?: typeof fetch;
10
+ /**
11
+ * Optional callback to refresh the API key when a 401 error occurs.
12
+ * Should clear cached credentials and re-fetch from auth provider.
13
+ */
14
+ refreshApiKey?: () => Promise<void>;
15
+ /**
16
+ * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')
17
+ * @default 'claude-sonnet-4-5-20250929'
18
+ */
19
+ anthropicModel?: string;
20
+ /**
21
+ * Maximum tokens to generate
22
+ * @default 8192
23
+ */
24
+ maxTokens?: number;
25
+ /**
26
+ * Feature flags to pass to the GitLab API
27
+ * @default { DuoAgentPlatformNext: true }
28
+ */
29
+ featureFlags?: {
30
+ DuoAgentPlatformNext: true;
31
+ } & Record<string, boolean>;
32
+ }
33
+ /**
34
+ * GitLab Agentic Language Model
35
+ *
36
+ * This model uses GitLab's Anthropic proxy to provide native tool calling support
37
+ * for the duo-chat model. It connects to Claude through GitLab's cloud proxy
38
+ * at https://cloud.gitlab.com/ai/v1/proxy/anthropic/
39
+ */
40
+ declare class GitLabAgenticLanguageModel implements LanguageModelV2 {
41
+ readonly specificationVersion: "v2";
42
+ readonly modelId: string;
43
+ readonly supportedUrls: Record<string, RegExp[]>;
44
+ private readonly config;
45
+ private readonly directAccessClient;
46
+ private anthropicClient;
47
+ constructor(modelId: string, config: GitLabAgenticConfig);
48
+ get provider(): string;
49
+ /**
50
+ * Get or create an Anthropic client with valid credentials
51
+ * @param forceRefresh - If true, forces a token refresh before creating the client
52
+ */
53
+ private getAnthropicClient;
54
+ /**
55
+ * Check if an error is a token-related authentication error that can be retried
56
+ */
57
+ private isTokenError;
58
+ /**
59
+ * Convert AI SDK tools to Anthropic tool format
60
+ */
61
+ private convertTools;
62
+ /**
63
+ * Convert AI SDK tool choice to Anthropic format
64
+ */
65
+ private convertToolChoice;
66
+ /**
67
+ * Convert AI SDK prompt to Anthropic messages format
68
+ */
69
+ private convertPrompt;
70
+ /**
71
+ * Convert Anthropic finish reason to AI SDK format
72
+ */
73
+ private convertFinishReason;
74
+ doGenerate(options: LanguageModelV2CallOptions): Promise<{
75
+ content: LanguageModelV2Content[];
76
+ finishReason: LanguageModelV2FinishReason;
77
+ usage: LanguageModelV2Usage;
78
+ warnings: LanguageModelV2CallWarning[];
79
+ }>;
80
+ private doGenerateWithRetry;
81
+ doStream(options: LanguageModelV2CallOptions): Promise<{
82
+ stream: ReadableStream<LanguageModelV2StreamPart>;
83
+ request?: {
84
+ body?: unknown;
85
+ };
86
+ response?: {
87
+ headers?: Record<string, string>;
88
+ };
89
+ }>;
90
+ private doStreamWithRetry;
91
+ }
92
+
93
+ interface GitLabProvider {
94
+ (modelId: string): LanguageModelV2;
95
+ readonly specificationVersion: 'v2';
96
+ languageModel(modelId: string): LanguageModelV2;
97
+ chat(modelId: string): LanguageModelV2;
98
+ agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAgenticLanguageModel;
99
+ textEmbeddingModel(modelId: string): never;
100
+ imageModel(modelId: string): never;
101
+ }
102
+ interface GitLabAgenticOptions {
103
+ /**
104
+ * The Anthropic model to use
105
+ * @default 'claude-sonnet-4-20250514'
106
+ */
107
+ anthropicModel?: string;
108
+ /**
109
+ * Maximum tokens to generate
110
+ * @default 8192
111
+ */
112
+ maxTokens?: number;
113
+ /**
114
+ * Feature flags to pass to the GitLab API
115
+ */
116
+ featureFlags?: Record<string, boolean>;
117
+ }
118
+ interface GitLabProviderSettings {
119
+ /**
120
+ * GitLab instance URL (e.g., 'https://gitlab.com')
121
+ * @default 'https://gitlab.com'
122
+ */
123
+ instanceUrl?: string;
124
+ /**
125
+ * API token (Personal Access Token or OAuth access token)
126
+ * Can also be set via GITLAB_TOKEN environment variable
127
+ */
128
+ apiKey?: string;
129
+ /**
130
+ * OAuth refresh token (optional, for OAuth flow)
131
+ */
132
+ refreshToken?: string;
133
+ /**
134
+ * OAuth client ID (required for OAuth flow)
135
+ */
136
+ clientId?: string;
137
+ /**
138
+ * OAuth redirect URI (required for OAuth flow)
139
+ */
140
+ redirectUri?: string;
141
+ /**
142
+ * Custom headers to include in requests
143
+ */
144
+ headers?: Record<string, string>;
145
+ /**
146
+ * Custom fetch implementation
147
+ */
148
+ fetch?: typeof fetch;
149
+ /**
150
+ * Provider name override
151
+ */
152
+ name?: string;
153
+ /**
154
+ * Default feature flags to pass to the GitLab API for all agentic chat models
155
+ */
156
+ featureFlags?: Record<string, boolean>;
157
+ }
158
+ declare function createGitLab(options?: GitLabProviderSettings): GitLabProvider;
159
+ /**
160
+ * Default GitLab Duo provider instance
161
+ *
162
+ * @example
163
+ * ```typescript
164
+ * import { gitlab } from '@ai-sdk/gitlab';
165
+ *
166
+ * const model = gitlab('duo-chat');
167
+ * ```
168
+ */
169
+ declare const gitlab: GitLabProvider;
170
+
171
+ interface GitLabErrorOptions {
172
+ message: string;
173
+ statusCode?: number;
174
+ responseBody?: string;
175
+ cause?: unknown;
176
+ }
177
+ declare class GitLabError extends Error {
178
+ readonly statusCode?: number;
179
+ readonly responseBody?: string;
180
+ readonly cause?: unknown;
181
+ constructor(options: GitLabErrorOptions);
182
+ static fromResponse(response: Response, body: string): GitLabError;
183
+ isAuthError(): boolean;
184
+ isRateLimitError(): boolean;
185
+ isForbiddenError(): boolean;
186
+ isServerError(): boolean;
187
+ }
188
+
189
+ declare const gitlabOAuthTokenResponseSchema: z.ZodObject<{
190
+ access_token: z.ZodString;
191
+ refresh_token: z.ZodOptional<z.ZodString>;
192
+ expires_in: z.ZodNumber;
193
+ created_at: z.ZodNumber;
194
+ }, "strip", z.ZodTypeAny, {
195
+ access_token?: string;
196
+ refresh_token?: string;
197
+ expires_in?: number;
198
+ created_at?: number;
199
+ }, {
200
+ access_token?: string;
201
+ refresh_token?: string;
202
+ expires_in?: number;
203
+ created_at?: number;
204
+ }>;
205
+ type GitLabOAuthTokenResponse = z.infer<typeof gitlabOAuthTokenResponseSchema>;
206
+
207
+ /**
208
+ * OAuth types and constants for GitLab authentication
209
+ * Based on gitlab-vscode-extension and gitlab-lsp patterns
210
+ */
211
+ interface GitLabOAuthTokens {
212
+ accessToken: string;
213
+ refreshToken: string;
214
+ expiresAt: number;
215
+ instanceUrl: string;
216
+ }
217
+ interface OpenCodeAuthOAuth {
218
+ type: 'oauth';
219
+ refresh: string;
220
+ access: string;
221
+ expires: number;
222
+ instanceUrl?: string;
223
+ }
224
+ interface OpenCodeAuthApi {
225
+ type: 'api';
226
+ key: string;
227
+ }
228
+ type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;
229
+ /**
230
+ * Bundled OAuth client ID for GitLab.com
231
+ * Same as used in gitlab-vscode-extension
232
+ */
233
+ declare const BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
234
+ /**
235
+ * GitLab.com URL constant
236
+ */
237
+ declare const GITLAB_COM_URL = "https://gitlab.com";
238
+ /**
239
+ * Token expiry skew in milliseconds (5 minutes)
240
+ * Refresh tokens this many milliseconds before they expire
241
+ */
242
+ declare const TOKEN_EXPIRY_SKEW_MS: number;
243
+ /**
244
+ * OAuth scopes to request
245
+ */
246
+ declare const OAUTH_SCOPES: string[];
247
+
248
+ /**
249
+ * GitLab OAuth Manager
250
+ * Handles OAuth token management, refresh, and exchange
251
+ * Based on gitlab-vscode-extension TokenExchangeService and gitlab-lsp OAuthClientProvider
252
+ */
253
+
254
+ interface TokenExchangeParams {
255
+ instanceUrl: string;
256
+ clientId?: string;
257
+ redirectUri?: string;
258
+ }
259
+ interface AuthorizationCodeParams extends TokenExchangeParams {
260
+ code: string;
261
+ codeVerifier: string;
262
+ }
263
+ interface RefreshTokenParams extends TokenExchangeParams {
264
+ refreshToken: string;
265
+ }
266
+ declare class GitLabOAuthManager {
267
+ private fetch;
268
+ constructor(fetchImpl?: typeof fetch);
269
+ /**
270
+ * Check if a token is expired
271
+ */
272
+ isTokenExpired(expiresAt: number): boolean;
273
+ /**
274
+ * Check if a token needs refresh (within skew window)
275
+ */
276
+ needsRefresh(expiresAt: number): boolean;
277
+ /**
278
+ * Refresh tokens if needed
279
+ * Returns the same tokens if refresh is not needed, or new tokens if refreshed
280
+ */
281
+ refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens>;
282
+ /**
283
+ * Exchange authorization code for tokens
284
+ * Based on gitlab-vscode-extension createOAuthAccountFromCode
285
+ */
286
+ exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens>;
287
+ /**
288
+ * Exchange refresh token for new tokens
289
+ * Based on gitlab-vscode-extension TokenExchangeService
290
+ */
291
+ exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens>;
292
+ /**
293
+ * Get the OAuth client ID for an instance
294
+ */
295
+ private getClientId;
296
+ /**
297
+ * Exchange token with GitLab OAuth endpoint
298
+ * Based on gitlab-vscode-extension GitLabService.exchangeToken
299
+ */
300
+ private exchangeToken;
301
+ /**
302
+ * Create GitLabOAuthTokens from token response
303
+ */
304
+ private createTokensFromResponse;
305
+ /**
306
+ * Create expiry timestamp from token response
307
+ * Based on gitlab-vscode-extension createExpiresTimestamp
308
+ */
309
+ private createExpiresTimestamp;
310
+ }
311
+
312
+ /**
313
+ * Tool definitions for Anthropic Claude
314
+ */
315
+ declare const ANTHROPIC_TOOLS: Tool[];
316
+ interface ToolResult {
317
+ result: string;
318
+ error?: string;
319
+ }
320
+ interface ToolInput {
321
+ [key: string]: unknown;
322
+ }
323
+ /**
324
+ * Tool executor for local file and command operations
325
+ */
326
+ declare class AnthropicToolExecutor {
327
+ private readonly workingDirectory;
328
+ constructor(workingDirectory: string);
329
+ /**
330
+ * Execute a tool by name with given input
331
+ */
332
+ execute(toolName: string, input: ToolInput): Promise<ToolResult>;
333
+ private resolvePath;
334
+ private listDir;
335
+ private readFile;
336
+ private writeFile;
337
+ private editFile;
338
+ private findFiles;
339
+ private mkdir;
340
+ private grep;
341
+ private runCommand;
342
+ private runGitCommand;
343
+ private executeCommand;
344
+ }
345
+
346
+ /**
347
+ * GitLab API tools for interacting with GitLab resources
348
+ * These tools allow the AI to access merge requests, issues, pipelines, etc.
349
+ */
350
+ declare const GITLAB_API_TOOLS: Tool[];
351
+ interface GitLabApiToolsConfig {
352
+ instanceUrl: string;
353
+ token: string;
354
+ fetch?: typeof fetch;
355
+ }
356
+ /**
357
+ * Executor for GitLab API tools
358
+ */
359
+ declare class GitLabApiToolExecutor {
360
+ private readonly config;
361
+ constructor(config: GitLabApiToolsConfig);
362
+ private get headers();
363
+ private fetchApi;
364
+ private encodeProjectId;
365
+ /**
366
+ * Execute a GitLab API tool by name
367
+ */
368
+ execute(toolName: string, input: ToolInput): Promise<ToolResult>;
369
+ private getMergeRequest;
370
+ private listMergeRequests;
371
+ private getMrChanges;
372
+ private listMrDiscussions;
373
+ private createMrNote;
374
+ private getIssue;
375
+ private listIssues;
376
+ private createIssueNote;
377
+ private listPipelines;
378
+ private getPipeline;
379
+ private listPipelineJobs;
380
+ private getJobLog;
381
+ private retryJob;
382
+ private getFile;
383
+ private listCommits;
384
+ private getCommitDiff;
385
+ private listBranches;
386
+ private search;
387
+ private getProject;
388
+ private listProjectMembers;
389
+ }
390
+ /**
391
+ * Check if a tool name is a GitLab API tool
392
+ */
393
+ declare function isGitLabApiTool(toolName: string): boolean;
394
+
395
+ /**
396
+ * Simple in-memory cache for GitLab project information
397
+ * Used to avoid repeated API calls when detecting projects from git remotes
398
+ */
399
+ interface GitLabProject {
400
+ id: number;
401
+ path: string;
402
+ pathWithNamespace: string;
403
+ name: string;
404
+ namespaceId?: number;
405
+ }
406
+ /**
407
+ * In-memory cache for GitLab project information with TTL support
408
+ */
409
+ declare class GitLabProjectCache {
410
+ private cache;
411
+ private defaultTTL;
412
+ /**
413
+ * Create a new project cache
414
+ * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)
415
+ */
416
+ constructor(defaultTTL?: number);
417
+ /**
418
+ * Get a cached project by key
419
+ * @param key - Cache key (typically the working directory path)
420
+ * @returns The cached project or null if not found or expired
421
+ */
422
+ get(key: string): GitLabProject | null;
423
+ /**
424
+ * Store a project in the cache
425
+ * @param key - Cache key (typically the working directory path)
426
+ * @param project - The project to cache
427
+ * @param ttl - Optional custom TTL in milliseconds
428
+ */
429
+ set(key: string, project: GitLabProject, ttl?: number): void;
430
+ /**
431
+ * Check if a key exists in the cache (and is not expired)
432
+ * @param key - Cache key to check
433
+ * @returns true if the key exists and is not expired
434
+ */
435
+ has(key: string): boolean;
436
+ /**
437
+ * Remove a specific entry from the cache
438
+ * @param key - Cache key to remove
439
+ */
440
+ delete(key: string): void;
441
+ /**
442
+ * Clear all entries from the cache
443
+ */
444
+ clear(): void;
445
+ /**
446
+ * Get the number of entries in the cache (including expired ones)
447
+ */
448
+ get size(): number;
449
+ /**
450
+ * Clean up expired entries from the cache
451
+ * This is useful for long-running processes to prevent memory leaks
452
+ */
453
+ cleanup(): void;
454
+ }
455
+
456
+ interface GitLabProjectDetectorConfig {
457
+ instanceUrl: string;
458
+ getHeaders: () => Record<string, string>;
459
+ fetch?: typeof fetch;
460
+ cache?: GitLabProjectCache;
461
+ gitTimeout?: number;
462
+ }
463
+ /**
464
+ * Detects GitLab project information from git remote URLs
465
+ *
466
+ * This class provides functionality to:
467
+ * - Parse git remote URLs (SSH, HTTPS, custom domains)
468
+ * - Execute git commands to get remote URLs
469
+ * - Fetch project details from GitLab API
470
+ * - Cache project information to avoid repeated API calls
471
+ */
472
+ declare class GitLabProjectDetector {
473
+ private readonly config;
474
+ private readonly fetchFn;
475
+ private readonly cache;
476
+ constructor(config: GitLabProjectDetectorConfig);
477
+ /**
478
+ * Auto-detect GitLab project from git remote in the working directory
479
+ *
480
+ * @param workingDirectory - The directory to check for git remote
481
+ * @param remoteName - The git remote name to use (default: 'origin')
482
+ * @returns The detected project or null if detection fails
483
+ */
484
+ detectProject(workingDirectory: string, remoteName?: string): Promise<GitLabProject | null>;
485
+ /**
486
+ * Parse a git remote URL to extract the project path
487
+ *
488
+ * Supports:
489
+ * - SSH: git@gitlab.com:namespace/project.git
490
+ * - HTTPS: https://gitlab.com/namespace/project.git
491
+ * - HTTP: http://gitlab.local/namespace/project.git
492
+ * - Custom domains and ports
493
+ *
494
+ * @param remoteUrl - The git remote URL
495
+ * @param instanceUrl - The GitLab instance URL to match against
496
+ * @returns The project path (e.g., "namespace/project") or null if parsing fails
497
+ */
498
+ parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null;
499
+ /**
500
+ * Get the git remote URL from a working directory
501
+ *
502
+ * @param workingDirectory - The directory to check
503
+ * @param remoteName - The git remote name (default: 'origin')
504
+ * @returns The remote URL or null if not found
505
+ */
506
+ getGitRemoteUrl(workingDirectory: string, remoteName?: string): Promise<string | null>;
507
+ /**
508
+ * Fetch project details from GitLab API by project path
509
+ *
510
+ * @param projectPath - The project path (e.g., "namespace/project")
511
+ * @returns The project details
512
+ * @throws GitLabError if the API call fails
513
+ */
514
+ getProjectByPath(projectPath: string): Promise<GitLabProject>;
515
+ /**
516
+ * Clear the project cache
517
+ */
518
+ clearCache(): void;
519
+ /**
520
+ * Get the cache instance (useful for testing)
521
+ */
522
+ getCache(): GitLabProjectCache;
523
+ }
524
+
525
+ export { ANTHROPIC_TOOLS, AnthropicToolExecutor, BUNDLED_CLIENT_ID, GITLAB_API_TOOLS, GITLAB_COM_URL, type GitLabAgenticConfig, GitLabAgenticLanguageModel, type GitLabAgenticOptions, GitLabApiToolExecutor, type GitLabApiToolsConfig, GitLabError, type GitLabErrorOptions, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, OAUTH_SCOPES, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, TOKEN_EXPIRY_SKEW_MS, type ToolInput, type ToolResult, createGitLab, gitlab, isGitLabApiTool };