@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.
package/README.md ADDED
@@ -0,0 +1,432 @@
1
+ # GitLab AI Provider
2
+
3
+ A comprehensive TypeScript provider for integrating GitLab Duo AI capabilities with the Vercel AI SDK. This package enables seamless access to GitLab's AI-powered features including chat, agentic workflows, and tool calling through a unified interface.
4
+
5
+ ## 🌟 Features
6
+
7
+ - **🤖 Agentic Chat**: Native tool calling support via GitLab's Anthropic proxy
8
+ - **🔐 Multiple Authentication**: Support for OAuth, Personal Access Tokens, and OpenCode auth
9
+ - **🌐 Self-Hosted Support**: Works with both GitLab.com and self-hosted instances
10
+ - **📦 Tool Executors**: Built-in Anthropic and GitLab API tool executors
11
+ - **🔍 Project Detection**: Automatic GitLab project detection from git remotes
12
+ - **💾 Smart Caching**: Project and token caching for optimal performance
13
+ - **🎯 Type-Safe**: Complete TypeScript definitions with Zod validation
14
+
15
+ ## 📦 Installation
16
+
17
+ ```bash
18
+ npm install @gitlab/gitlab-ai-provider
19
+ ```
20
+
21
+ ### Peer Dependencies
22
+
23
+ ```bash
24
+ npm install @ai-sdk/provider @ai-sdk/provider-utils
25
+ ```
26
+
27
+ ## 🚀 Quick Start
28
+
29
+ ### Basic Chat
30
+
31
+ ```typescript
32
+ import { createGitLab } from '@gitlab/gitlab-ai-provider';
33
+ import { generateText } from 'ai';
34
+
35
+ const gitlab = createGitLab({
36
+ apiKey: process.env.GITLAB_TOKEN,
37
+ instanceUrl: 'https://gitlab.com', // optional, defaults to gitlab.com
38
+ });
39
+
40
+ // All equivalent ways to create a chat model:
41
+ const model = gitlab('duo-chat'); // callable provider
42
+ const model2 = gitlab.chat('duo-chat'); // .chat() alias (recommended)
43
+ const model3 = gitlab.languageModel('duo-chat'); // explicit method
44
+
45
+ const { text } = await generateText({
46
+ model: gitlab.chat('duo-chat'),
47
+ prompt: 'Explain how to create a merge request in GitLab',
48
+ });
49
+
50
+ console.log(text);
51
+ ```
52
+
53
+ ### Agentic Chat with Tool Calling
54
+
55
+ ```typescript
56
+ import { createGitLab } from '@gitlab/gitlab-ai-provider';
57
+ import { generateText } from 'ai';
58
+
59
+ const gitlab = createGitLab({
60
+ apiKey: process.env.GITLAB_TOKEN,
61
+ });
62
+
63
+ // Use agentic model for native tool calling support
64
+ const model = gitlab.agenticChat('duo-chat', {
65
+ anthropicModel: 'claude-sonnet-4-20250514',
66
+ maxTokens: 8192,
67
+ });
68
+
69
+ const { text } = await generateText({
70
+ model,
71
+ prompt: 'List all open merge requests in my project',
72
+ tools: {
73
+ // Your custom tools here
74
+ },
75
+ });
76
+ ```
77
+
78
+ ### Agentic Chat with Feature Flags
79
+
80
+ You can pass feature flags to enable experimental features in GitLab's Anthropic proxy:
81
+
82
+ ```typescript
83
+ import { createGitLab } from '@gitlab/gitlab-ai-provider';
84
+
85
+ // Option 1: Set feature flags globally for all agentic chat models
86
+ const gitlab = createGitLab({
87
+ apiKey: process.env.GITLAB_TOKEN,
88
+ featureFlags: {
89
+ duo_agent_platform_agentic_chat: true,
90
+ duo_agent_platform: true,
91
+ },
92
+ });
93
+
94
+ const model = gitlab.agenticChat('duo-chat');
95
+
96
+ // Option 2: Set feature flags per model (overrides global flags)
97
+ const modelWithFlags = gitlab.agenticChat('duo-chat', {
98
+ featureFlags: {
99
+ duo_agent_platform_agentic_chat: true,
100
+ duo_agent_platform: true,
101
+ custom_feature_flag: false,
102
+ },
103
+ });
104
+
105
+ // Option 3: Merge both (model-level flags take precedence)
106
+ const gitlab2 = createGitLab({
107
+ featureFlags: {
108
+ duo_agent_platform: true, // will be overridden
109
+ },
110
+ });
111
+
112
+ const mergedModel = gitlab2.agenticChat('duo-chat', {
113
+ featureFlags: {
114
+ duo_agent_platform: false, // overrides provider-level
115
+ duo_agent_platform_agentic_chat: true, // adds new flag
116
+ },
117
+ });
118
+ ```
119
+
120
+ ## 🔑 Authentication
121
+
122
+ ### Personal Access Token
123
+
124
+ ```typescript
125
+ const gitlab = createGitLab({
126
+ apiKey: 'glpat-xxxxxxxxxxxxxxxxxxxx',
127
+ });
128
+ ```
129
+
130
+ ### Environment Variable
131
+
132
+ ```bash
133
+ export GITLAB_TOKEN=glpat-xxxxxxxxxxxxxxxxxxxx
134
+ ```
135
+
136
+ ```typescript
137
+ const gitlab = createGitLab(); // Automatically uses GITLAB_TOKEN
138
+ ```
139
+
140
+ ### OAuth (OpenCode Auth)
141
+
142
+ The provider automatically detects and uses OpenCode authentication if available:
143
+
144
+ ```typescript
145
+ const gitlab = createGitLab({
146
+ instanceUrl: 'https://gitlab.com',
147
+ // OAuth tokens are loaded from ~/.opencode/auth.json
148
+ });
149
+ ```
150
+
151
+ ### Custom Headers
152
+
153
+ ```typescript
154
+ const gitlab = createGitLab({
155
+ apiKey: 'your-token',
156
+ headers: {
157
+ 'X-Custom-Header': 'value',
158
+ },
159
+ });
160
+ ```
161
+
162
+ ## 🏗️ Architecture
163
+
164
+ ### Core Components
165
+
166
+ #### 1. **GitLabProvider**
167
+
168
+ Main provider factory that creates language models with different capabilities.
169
+
170
+ ```typescript
171
+ interface GitLabProvider {
172
+ (modelId: string): LanguageModelV2;
173
+ languageModel(modelId: string): LanguageModelV2;
174
+ agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAgenticLanguageModel;
175
+ }
176
+ ```
177
+
178
+ #### 2. **GitLabAgenticLanguageModel**
179
+
180
+ Provides native tool calling through GitLab's Anthropic proxy.
181
+
182
+ - Uses Claude models via `https://cloud.gitlab.com/ai/v1/proxy/anthropic/`
183
+ - Automatic token refresh and retry logic
184
+ - Direct access token management
185
+ - Supports all Anthropic tool calling features
186
+
187
+ ### Tool Executors
188
+
189
+ #### AnthropicToolExecutor
190
+
191
+ Executes local file system and command tools:
192
+
193
+ - `list_dir` - List directory contents
194
+ - `read_file` - Read file contents
195
+ - `write_file` - Write to files
196
+ - `edit_file` - Edit file with find/replace
197
+ - `find_files` - Find files by pattern
198
+ - `mkdir` - Create directories
199
+ - `grep` - Search file contents
200
+ - `run_command` - Execute shell commands
201
+ - `run_git_command` - Execute git commands
202
+
203
+ #### GitLabApiToolExecutor
204
+
205
+ Executes GitLab API operations:
206
+
207
+ - Merge Requests: get, list, changes, discussions, notes
208
+ - Issues: get, list, notes
209
+ - Pipelines: list, get, jobs, logs
210
+ - Repository: files, commits, branches
211
+ - Search: global and project search
212
+ - Projects: get, members
213
+
214
+ ### Supporting Utilities
215
+
216
+ #### GitLabProjectDetector
217
+
218
+ Automatically detects GitLab projects from git remotes.
219
+
220
+ ```typescript
221
+ const detector = new GitLabProjectDetector({
222
+ instanceUrl: 'https://gitlab.com',
223
+ getHeaders: () => ({ Authorization: `Bearer ${token}` }),
224
+ });
225
+
226
+ const project = await detector.detectProject(process.cwd());
227
+ // Returns: { id: 12345, path: 'group/project', namespaceId: 67890 }
228
+ ```
229
+
230
+ #### GitLabProjectCache
231
+
232
+ Caches project information with TTL.
233
+
234
+ ```typescript
235
+ const cache = new GitLabProjectCache(5 * 60 * 1000); // 5 minutes
236
+ cache.set('key', project);
237
+ const cached = cache.get('key');
238
+ ```
239
+
240
+ #### GitLabOAuthManager
241
+
242
+ Manages OAuth token lifecycle.
243
+
244
+ ```typescript
245
+ const oauthManager = new GitLabOAuthManager();
246
+
247
+ // Exchange authorization code
248
+ const tokens = await oauthManager.exchangeAuthorizationCode({
249
+ instanceUrl: 'https://gitlab.com',
250
+ code: 'auth-code',
251
+ codeVerifier: 'verifier',
252
+ });
253
+
254
+ // Refresh tokens
255
+ const refreshed = await oauthManager.refreshIfNeeded(tokens);
256
+ ```
257
+
258
+ #### GitLabDirectAccessClient
259
+
260
+ Manages direct access tokens for Anthropic proxy.
261
+
262
+ ```typescript
263
+ const client = new GitLabDirectAccessClient({
264
+ instanceUrl: 'https://gitlab.com',
265
+ getHeaders: () => ({ Authorization: `Bearer ${token}` }),
266
+ });
267
+
268
+ const directToken = await client.getDirectAccessToken();
269
+ // Returns: { token: 'xxx', headers: {...}, expiresAt: 123456 }
270
+ ```
271
+
272
+ ## 📚 API Reference
273
+
274
+ ### Provider Configuration
275
+
276
+ ```typescript
277
+ interface GitLabProviderSettings {
278
+ instanceUrl?: string; // Default: 'https://gitlab.com'
279
+ apiKey?: string; // PAT or OAuth access token
280
+ refreshToken?: string; // OAuth refresh token
281
+ name?: string; // Provider name prefix
282
+ headers?: Record<string, string>; // Custom headers
283
+ fetch?: typeof fetch; // Custom fetch implementation
284
+ }
285
+ ```
286
+
287
+ ### Agentic Chat Options
288
+
289
+ ```typescript
290
+ interface GitLabAgenticOptions {
291
+ anthropicModel?: string; // Default: 'claude-sonnet-4-20250514'
292
+ maxTokens?: number; // Default: 8192
293
+ }
294
+ ```
295
+
296
+ ### Error Handling
297
+
298
+ ```typescript
299
+ import { GitLabError } from '@gitlab/gitlab-ai-provider';
300
+
301
+ try {
302
+ const result = await generateText({ model, prompt });
303
+ } catch (error) {
304
+ if (error instanceof GitLabError) {
305
+ if (error.isAuthError()) {
306
+ console.error('Authentication failed');
307
+ } else if (error.isRateLimitError()) {
308
+ console.error('Rate limit exceeded');
309
+ } else if (error.isServerError()) {
310
+ console.error('Server error:', error.statusCode);
311
+ }
312
+ }
313
+ }
314
+ ```
315
+
316
+ ## 🔧 Development
317
+
318
+ ### Build
319
+
320
+ ```bash
321
+ npm run build # Build once
322
+ npm run build:watch # Build in watch mode
323
+ ```
324
+
325
+ ### Testing
326
+
327
+ ```bash
328
+ npm test # Run all tests
329
+ npm run test:watch # Run tests in watch mode
330
+ ```
331
+
332
+ ### Code Quality
333
+
334
+ ```bash
335
+ npm run lint # Lint code
336
+ npm run lint:fix # Lint and auto-fix
337
+ npm run format # Format code
338
+ npm run format:check # Check formatting
339
+ npm run type-check # TypeScript type checking
340
+ ```
341
+
342
+ ### Project Structure
343
+
344
+ ```
345
+ gitlab-ai-provider/
346
+ ├── src/
347
+ │ ├── index.ts # Main exports
348
+ │ ├── gitlab-provider.ts # Provider factory
349
+ │ ├── gitlab-agentic-language-model.ts # Agentic chat model
350
+ │ ├── gitlab-direct-access.ts # Direct access tokens
351
+ │ ├── gitlab-oauth-manager.ts # OAuth management
352
+ │ ├── gitlab-oauth-types.ts # OAuth types
353
+ │ ├── gitlab-project-detector.ts # Project detection
354
+ │ ├── gitlab-project-cache.ts # Project caching
355
+ │ ├── gitlab-anthropic-tools.ts # Anthropic tool executor
356
+ │ ├── gitlab-api-tools.ts # GitLab API tool executor
357
+ │ ├── gitlab-api-types.ts # API types
358
+ │ ├── gitlab-error.ts # Error handling
359
+ │ └── gitlab-workflow-debug.ts # Debug logging
360
+ ├── tests/ # Test files
361
+ ├── dist/ # Build output
362
+ ├── package.json
363
+ ├── tsconfig.json
364
+ ├── tsup.config.ts
365
+ └── vitest.config.ts
366
+ ```
367
+
368
+ ## 📝 Code Style
369
+
370
+ - **Imports**: Named imports, organized by external → internal → types
371
+ - **Formatting**: Single quotes, semicolons, 100 char line width, 2 space indent
372
+ - **Types**: Interfaces for public APIs, Zod schemas for runtime validation
373
+ - **Naming**: camelCase (variables/functions), PascalCase (classes/types), kebab-case (files)
374
+ - **Exports**: Named exports only (no default exports)
375
+ - **Comments**: JSDoc for public APIs with @param/@returns
376
+
377
+ ---
378
+
379
+ ## Assistant
380
+
381
+ ## 🤝 Contributing
382
+
383
+ Contributions are welcome! Please see our [Contributing Guide](./CONTRIBUTING.md) for detailed guidelines on:
384
+
385
+ - Code style and conventions
386
+ - Development workflow
387
+ - Testing requirements
388
+ - Submitting merge requests
389
+ - Developer Certificate of Origin and License
390
+
391
+ **Quick Start for Contributors**:
392
+
393
+ 1. **Commit Messages**: Use conventional commits format
394
+
395
+ ```
396
+ feat(scope): add new feature
397
+ fix(scope): fix bug
398
+ docs(scope): update documentation
399
+ ```
400
+
401
+ 2. **Code Quality**: Ensure all checks pass
402
+
403
+ ```bash
404
+ npm run lint
405
+ npm run type-check
406
+ npm test
407
+ ```
408
+
409
+ 3. **Testing**: Add tests for new features
410
+
411
+ ## 🔗 Links
412
+
413
+ - [GitLab Repository](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider)
414
+ - [npm Package](https://www.npmjs.com/package/@gitlab/gitlab-ai-provider)
415
+ - [Issue Tracker](https://gitlab.com/gitlab-org/editor-extensions/gitlab-ai-provider/-/issues)
416
+ - [Contributing Guide](./CONTRIBUTING.md)
417
+ - [Changelog](./CHANGELOG.md)
418
+ - [Agent Guidelines](./AGENTS.md)
419
+
420
+ ## 🙏 Acknowledgments
421
+
422
+ This project is built on top of:
423
+
424
+ - [Vercel AI SDK](https://sdk.vercel.ai/)
425
+ - [Anthropic SDK](https://github.com/anthropics/anthropic-sdk-typescript)
426
+ - [GitLab Duo](https://about.gitlab.com/gitlab-duo/)
427
+
428
+ ---
429
+
430
+ **Made with ❤️ for the OpenCode community**
431
+
432
+ ---