gitlab-ai-provider 5.0.0 → 5.1.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/dist/index.d.ts CHANGED
@@ -1,52 +1,44 @@
1
- import {
2
- LanguageModelV2,
3
- LanguageModelV2CallOptions,
4
- LanguageModelV2Content,
5
- LanguageModelV2FinishReason,
6
- LanguageModelV2Usage,
7
- LanguageModelV2CallWarning,
8
- LanguageModelV2StreamPart,
9
- } from '@ai-sdk/provider';
1
+ import { LanguageModelV2, LanguageModelV2CallOptions, LanguageModelV2Content, LanguageModelV2FinishReason, LanguageModelV2Usage, LanguageModelV2CallWarning, LanguageModelV2StreamPart } from '@ai-sdk/provider';
10
2
  import { z } from 'zod';
11
3
 
12
4
  interface GitLabAnthropicConfig {
13
- provider: string;
14
- instanceUrl: string;
15
- getHeaders: () => Record<string, string>;
16
- fetch?: typeof fetch;
17
- /**
18
- * Optional callback to refresh the API key when a 401 error occurs.
19
- * Should clear cached credentials and re-fetch from auth provider.
20
- */
21
- refreshApiKey?: () => Promise<void>;
22
- /**
23
- * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')
24
- * @default 'claude-sonnet-4-5-20250929'
25
- */
26
- anthropicModel?: string;
27
- /**
28
- * Maximum tokens to generate
29
- * @default 8192
30
- */
31
- maxTokens?: number;
32
- /**
33
- * Feature flags to pass to the GitLab API
34
- * @default { DuoAgentPlatformNext: true }
35
- */
36
- featureFlags?: {
37
- DuoAgentPlatformNext: true;
38
- } & Record<string, boolean>;
39
- /**
40
- * AI Gateway URL for the Anthropic proxy.
41
- * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
42
- * @default 'https://cloud.gitlab.com'
43
- */
44
- aiGatewayUrl?: string;
45
- /**
46
- * Custom headers for AI Gateway Anthropic proxy requests.
47
- * Merged with headers from direct_access token response.
48
- */
49
- aiGatewayHeaders?: Record<string, string>;
5
+ provider: string;
6
+ instanceUrl: string;
7
+ getHeaders: () => Record<string, string>;
8
+ fetch?: typeof fetch;
9
+ /**
10
+ * Optional callback to refresh the API key when a 401 error occurs.
11
+ * Should clear cached credentials and re-fetch from auth provider.
12
+ */
13
+ refreshApiKey?: () => Promise<void>;
14
+ /**
15
+ * The Anthropic model to use (e.g., 'claude-sonnet-4-5-20250929')
16
+ * @default 'claude-sonnet-4-5-20250929'
17
+ */
18
+ anthropicModel?: string;
19
+ /**
20
+ * Maximum tokens to generate
21
+ * @default 8192
22
+ */
23
+ maxTokens?: number;
24
+ /**
25
+ * Feature flags to pass to the GitLab API
26
+ * @default { DuoAgentPlatformNext: true }
27
+ */
28
+ featureFlags?: {
29
+ DuoAgentPlatformNext: true;
30
+ } & Record<string, boolean>;
31
+ /**
32
+ * AI Gateway URL for the Anthropic proxy.
33
+ * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
34
+ * @default 'https://cloud.gitlab.com'
35
+ */
36
+ aiGatewayUrl?: string;
37
+ /**
38
+ * Custom headers for AI Gateway Anthropic proxy requests.
39
+ * Merged with headers from direct_access token response.
40
+ */
41
+ aiGatewayHeaders?: Record<string, string>;
50
42
  }
51
43
  /**
52
44
  * GitLab Anthropic Language Model
@@ -56,61 +48,61 @@ interface GitLabAnthropicConfig {
56
48
  * at https://cloud.gitlab.com/ai/v1/proxy/anthropic/
57
49
  */
58
50
  declare class GitLabAnthropicLanguageModel implements LanguageModelV2 {
59
- readonly specificationVersion: 'v2';
60
- readonly modelId: string;
61
- readonly supportedUrls: Record<string, RegExp[]>;
62
- private readonly config;
63
- private readonly directAccessClient;
64
- private anthropicClient;
65
- constructor(modelId: string, config: GitLabAnthropicConfig);
66
- get provider(): string;
67
- /**
68
- * Get or create an Anthropic client with valid credentials
69
- * @param forceRefresh - If true, forces a token refresh before creating the client
70
- */
71
- private getAnthropicClient;
72
- /**
73
- * Check if an error is a token-related authentication error that can be retried
74
- */
75
- private isTokenError;
76
- /**
77
- * Check if an error is a context overflow error (prompt too long)
78
- * These should NOT trigger token refresh and should be reported to the user.
79
- */
80
- private isContextOverflowError;
81
- /**
82
- * Convert AI SDK tools to Anthropic tool format
83
- */
84
- private convertTools;
85
- /**
86
- * Convert AI SDK tool choice to Anthropic format
87
- */
88
- private convertToolChoice;
89
- /**
90
- * Convert AI SDK prompt to Anthropic messages format
91
- */
92
- private convertPrompt;
93
- /**
94
- * Convert Anthropic finish reason to AI SDK format
95
- */
96
- private convertFinishReason;
97
- doGenerate(options: LanguageModelV2CallOptions): Promise<{
98
- content: LanguageModelV2Content[];
99
- finishReason: LanguageModelV2FinishReason;
100
- usage: LanguageModelV2Usage;
101
- warnings: LanguageModelV2CallWarning[];
102
- }>;
103
- private doGenerateWithRetry;
104
- doStream(options: LanguageModelV2CallOptions): Promise<{
105
- stream: ReadableStream<LanguageModelV2StreamPart>;
106
- request?: {
107
- body?: unknown;
108
- };
109
- response?: {
110
- headers?: Record<string, string>;
111
- };
112
- }>;
113
- private doStreamWithRetry;
51
+ readonly specificationVersion: "v2";
52
+ readonly modelId: string;
53
+ readonly supportedUrls: Record<string, RegExp[]>;
54
+ private readonly config;
55
+ private readonly directAccessClient;
56
+ private anthropicClient;
57
+ constructor(modelId: string, config: GitLabAnthropicConfig);
58
+ get provider(): string;
59
+ /**
60
+ * Get or create an Anthropic client with valid credentials
61
+ * @param forceRefresh - If true, forces a token refresh before creating the client
62
+ */
63
+ private getAnthropicClient;
64
+ /**
65
+ * Check if an error is a token-related authentication error that can be retried
66
+ */
67
+ private isTokenError;
68
+ /**
69
+ * Check if an error is a context overflow error (prompt too long)
70
+ * These should NOT trigger token refresh and should be reported to the user.
71
+ */
72
+ private isContextOverflowError;
73
+ /**
74
+ * Convert AI SDK tools to Anthropic tool format
75
+ */
76
+ private convertTools;
77
+ /**
78
+ * Convert AI SDK tool choice to Anthropic format
79
+ */
80
+ private convertToolChoice;
81
+ /**
82
+ * Convert AI SDK prompt to Anthropic messages format
83
+ */
84
+ private convertPrompt;
85
+ /**
86
+ * Convert Anthropic finish reason to AI SDK format
87
+ */
88
+ private convertFinishReason;
89
+ doGenerate(options: LanguageModelV2CallOptions): Promise<{
90
+ content: LanguageModelV2Content[];
91
+ finishReason: LanguageModelV2FinishReason;
92
+ usage: LanguageModelV2Usage;
93
+ warnings: LanguageModelV2CallWarning[];
94
+ }>;
95
+ private doGenerateWithRetry;
96
+ doStream(options: LanguageModelV2CallOptions): Promise<{
97
+ stream: ReadableStream<LanguageModelV2StreamPart>;
98
+ request?: {
99
+ body?: unknown;
100
+ };
101
+ response?: {
102
+ headers?: Record<string, string>;
103
+ };
104
+ }>;
105
+ private doStreamWithRetry;
114
106
  }
115
107
 
116
108
  /**
@@ -123,63 +115,63 @@ declare class GitLabAnthropicLanguageModel implements LanguageModelV2 {
123
115
  * Requires GitLab 18.4+ (18.5+ for pinned model support).
124
116
  */
125
117
  interface AiModel {
126
- /** Display name (e.g., 'Claude Sonnet 4.6') */
127
- name: string;
128
- /** Model reference for API use (e.g., 'claude_sonnet_4_6' or 'anthropic/claude-sonnet-4-5-20250929') */
129
- ref: string;
118
+ /** Display name (e.g., 'Claude Sonnet 4.6') */
119
+ name: string;
120
+ /** Model reference for API use (e.g., 'claude_sonnet_4_6' or 'anthropic/claude-sonnet-4-5-20250929') */
121
+ ref: string;
130
122
  }
131
123
  interface AiChatAvailableModels {
132
- defaultModel: AiModel | null;
133
- selectableModels: AiModel[];
134
- pinnedModel: AiModel | null;
124
+ defaultModel: AiModel | null;
125
+ selectableModels: AiModel[];
126
+ pinnedModel: AiModel | null;
135
127
  }
136
128
  interface DiscoveredModels {
137
- /** The effective model (pinned > user-selected > default) */
138
- defaultModel: AiModel | null;
139
- /** All models the user can select from */
140
- selectableModels: AiModel[];
141
- /** Admin-pinned model (overrides everything) */
142
- pinnedModel: AiModel | null;
143
- /** Whether the ai_user_model_switching feature flag is enabled */
144
- modelSwitchingEnabled: boolean;
145
- /** GitLab instance version */
146
- instanceVersion: string | null;
129
+ /** The effective model (pinned > user-selected > default) */
130
+ defaultModel: AiModel | null;
131
+ /** All models the user can select from */
132
+ selectableModels: AiModel[];
133
+ /** Admin-pinned model (overrides everything) */
134
+ pinnedModel: AiModel | null;
135
+ /** Whether the ai_user_model_switching feature flag is enabled */
136
+ modelSwitchingEnabled: boolean;
137
+ /** GitLab instance version */
138
+ instanceVersion: string | null;
147
139
  }
148
140
  interface ModelDiscoveryConfig {
149
- /** GitLab instance URL */
150
- instanceUrl: string;
151
- /** Function returning auth headers */
152
- getHeaders: () => Record<string, string>;
153
- /** Custom fetch */
154
- fetch?: typeof fetch;
141
+ /** GitLab instance URL */
142
+ instanceUrl: string;
143
+ /** Function returning auth headers */
144
+ getHeaders: () => Record<string, string>;
145
+ /** Custom fetch */
146
+ fetch?: typeof fetch;
155
147
  }
156
148
  declare class GitLabModelDiscovery {
157
- private readonly config;
158
- private readonly fetchFn;
159
- private cache;
160
- constructor(config: ModelDiscoveryConfig);
161
- /**
162
- * Discover available models for a given root namespace.
163
- *
164
- * Results are cached per `rootNamespaceId` with a 10-minute TTL.
165
- * Use `invalidateCache()` to force an immediate refresh.
166
- *
167
- * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')
168
- */
169
- discover(rootNamespaceId: string): Promise<DiscoveredModels>;
170
- /**
171
- * Get the effective model ref to use for a workflow.
172
- *
173
- * Priority: pinned > user-selected > default.
174
- *
175
- * @param rootNamespaceId - GitLab group ID
176
- * @param userSelectedRef - Optional user preference
177
- */
178
- getEffectiveModelRef(rootNamespaceId: string, userSelectedRef?: string): Promise<string | null>;
179
- /**
180
- * Invalidate the cached discovery results.
181
- */
182
- invalidateCache(): void;
149
+ private readonly config;
150
+ private readonly fetchFn;
151
+ private cache;
152
+ constructor(config: ModelDiscoveryConfig);
153
+ /**
154
+ * Discover available models for a given root namespace.
155
+ *
156
+ * Results are cached per `rootNamespaceId` with a 10-minute TTL.
157
+ * Use `invalidateCache()` to force an immediate refresh.
158
+ *
159
+ * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')
160
+ */
161
+ discover(rootNamespaceId: string): Promise<DiscoveredModels>;
162
+ /**
163
+ * Get the effective model ref to use for a workflow.
164
+ *
165
+ * Priority: pinned > user-selected > default.
166
+ *
167
+ * @param rootNamespaceId - GitLab group ID
168
+ * @param userSelectedRef - Optional user preference
169
+ */
170
+ getEffectiveModelRef(rootNamespaceId: string, userSelectedRef?: string): Promise<string | null>;
171
+ /**
172
+ * Invalidate the cached discovery results.
173
+ */
174
+ invalidateCache(): void;
183
175
  }
184
176
 
185
177
  /**
@@ -200,50 +192,50 @@ declare class GitLabModelDiscovery {
200
192
  */
201
193
 
202
194
  interface ModelCacheEntry {
203
- discovery: DiscoveredModels | null;
204
- selectedModelRef: string | null;
205
- selectedModelName: string | null;
206
- updatedAt: string;
195
+ discovery: DiscoveredModels | null;
196
+ selectedModelRef: string | null;
197
+ selectedModelName: string | null;
198
+ updatedAt: string;
207
199
  }
208
200
  declare class GitLabModelCache {
209
- private readonly filePath;
210
- private readonly key;
211
- constructor(workDir: string, instanceUrl?: string);
212
- private readAll;
213
- private writeAll;
214
- /**
215
- * Load the cached entry for this workspace.
216
- * Returns null if no cache exists or is unreadable.
217
- */
218
- load(): ModelCacheEntry | null;
219
- /**
220
- * Persist the full cache entry to disk.
221
- */
222
- save(entry: ModelCacheEntry): void;
223
- /**
224
- * Update only the discovery portion of the cache, preserving selection.
225
- */
226
- saveDiscovery(discovery: DiscoveredModels): void;
227
- /**
228
- * Update only the selected model, preserving the discovery data.
229
- */
230
- saveSelection(ref: string | null, name: string | null): void;
231
- /**
232
- * Remove the entry for this workspace from the cache file.
233
- */
234
- clear(): void;
235
- /**
236
- * Convenience: get the cached selected model ref (or null).
237
- */
238
- getSelectedModelRef(): string | null;
239
- /**
240
- * Convenience: get the cached selected model name (or null).
241
- */
242
- getSelectedModelName(): string | null;
243
- /**
244
- * Convenience: get the cached discovery result (or null).
245
- */
246
- getDiscovery(): DiscoveredModels | null;
201
+ private readonly filePath;
202
+ private readonly key;
203
+ constructor(workDir: string, instanceUrl?: string);
204
+ private readAll;
205
+ private writeAll;
206
+ /**
207
+ * Load the cached entry for this workspace.
208
+ * Returns null if no cache exists or is unreadable.
209
+ */
210
+ load(): ModelCacheEntry | null;
211
+ /**
212
+ * Persist the full cache entry to disk.
213
+ */
214
+ save(entry: ModelCacheEntry): void;
215
+ /**
216
+ * Update only the discovery portion of the cache, preserving selection.
217
+ */
218
+ saveDiscovery(discovery: DiscoveredModels): void;
219
+ /**
220
+ * Update only the selected model, preserving the discovery data.
221
+ */
222
+ saveSelection(ref: string | null, name: string | null): void;
223
+ /**
224
+ * Remove the entry for this workspace from the cache file.
225
+ */
226
+ clear(): void;
227
+ /**
228
+ * Convenience: get the cached selected model ref (or null).
229
+ */
230
+ getSelectedModelRef(): string | null;
231
+ /**
232
+ * Convenience: get the cached selected model name (or null).
233
+ */
234
+ getSelectedModelName(): string | null;
235
+ /**
236
+ * Convenience: get the cached discovery result (or null).
237
+ */
238
+ getDiscovery(): DiscoveredModels | null;
247
239
  }
248
240
 
249
241
  /**
@@ -256,148 +248,132 @@ declare class GitLabModelCache {
256
248
  * Message format is JSON-serialized protobuf with camelCase field names.
257
249
  */
258
250
  interface GenerateTokenResponse {
259
- gitlab_rails: {
260
- base_url: string;
261
- token: string;
262
- token_expires_at: string;
263
- };
264
- duo_workflow_service: {
265
- base_url: string;
266
- token: string;
267
- secure: boolean;
268
- token_expires_at: number;
269
- headers: Record<string, string>;
270
- };
271
- duo_workflow_executor: {
272
- executor_binary_url: string;
273
- version: string;
274
- };
251
+ gitlab_rails: {
252
+ base_url: string;
253
+ token: string;
254
+ token_expires_at: string;
255
+ };
256
+ duo_workflow_service: {
257
+ base_url: string;
258
+ token: string;
259
+ secure: boolean;
260
+ token_expires_at: number;
261
+ headers: Record<string, string>;
262
+ };
263
+ duo_workflow_executor: {
264
+ executor_binary_url: string;
265
+ version: string;
266
+ };
275
267
  }
276
268
  interface McpToolDefinition {
277
- name: string;
278
- description: string;
279
- inputSchema: string;
269
+ name: string;
270
+ description: string;
271
+ inputSchema: string;
280
272
  }
281
273
  interface AdditionalContext {
282
- category: string;
283
- id?: string;
284
- content?: string;
285
- metadata?: string;
274
+ category: string;
275
+ id?: string;
276
+ content?: string;
277
+ metadata?: string;
286
278
  }
287
279
  interface StartRequest {
288
- workflowID: string;
289
- clientVersion: string;
290
- workflowDefinition: string;
291
- goal: string;
292
- workflowMetadata?: string;
293
- additional_context?: AdditionalContext[];
294
- clientCapabilities?: string[];
295
- mcpTools?: McpToolDefinition[];
296
- preapproved_tools?: string[];
297
- flowConfig?: unknown;
298
- flowConfigSchemaVersion?: string;
280
+ workflowID: string;
281
+ clientVersion: string;
282
+ workflowDefinition: string;
283
+ goal: string;
284
+ workflowMetadata?: string;
285
+ additional_context?: AdditionalContext[];
286
+ clientCapabilities?: string[];
287
+ mcpTools?: McpToolDefinition[];
288
+ preapproved_tools?: string[];
289
+ flowConfig?: unknown;
290
+ flowConfigSchemaVersion?: string;
299
291
  }
300
292
  interface ActionResponsePayload {
301
- requestID: string;
302
- plainTextResponse: {
303
- response: string;
304
- error: string | null;
305
- };
293
+ requestID: string;
294
+ plainTextResponse: {
295
+ response: string;
296
+ error: string | null;
297
+ };
306
298
  }
307
299
  interface StopWorkflow {
308
- reason: string;
300
+ reason: string;
309
301
  }
310
302
  interface Heartbeat {
311
- timestamp: number;
303
+ timestamp: number;
312
304
  }
313
305
  /**
314
306
  * Client → Server event union.
315
307
  * Exactly one of the fields should be set per message.
316
308
  */
317
- type ClientEvent =
318
- | {
319
- startRequest: StartRequest;
320
- }
321
- | {
322
- actionResponse: ActionResponsePayload;
323
- }
324
- | {
325
- stopWorkflow: StopWorkflow;
326
- }
327
- | {
328
- heartbeat: Heartbeat;
329
- };
330
- type WorkflowStatus =
331
- | 'CREATED'
332
- | 'RUNNING'
333
- | 'FINISHED'
334
- | 'COMPLETED'
335
- | 'FAILED'
336
- | 'STOPPED'
337
- | 'CANCELLED'
338
- | 'PAUSED'
339
- | 'INPUT_REQUIRED'
340
- | 'PLAN_APPROVAL_REQUIRED'
341
- | 'TOOL_CALL_APPROVAL_REQUIRED'
342
- | 'UNKNOWN';
309
+ type ClientEvent = {
310
+ startRequest: StartRequest;
311
+ } | {
312
+ actionResponse: ActionResponsePayload;
313
+ } | {
314
+ stopWorkflow: StopWorkflow;
315
+ } | {
316
+ heartbeat: Heartbeat;
317
+ };
318
+ type WorkflowStatus = 'CREATED' | 'RUNNING' | 'FINISHED' | 'COMPLETED' | 'FAILED' | 'STOPPED' | 'CANCELLED' | 'PAUSED' | 'INPUT_REQUIRED' | 'PLAN_APPROVAL_REQUIRED' | 'TOOL_CALL_APPROVAL_REQUIRED' | 'UNKNOWN';
343
319
  interface NewCheckpoint {
344
- status: WorkflowStatus;
345
- goal?: string;
346
- /** Raw checkpoint JSON string from DWS (contains channel_values.ui_chat_log) */
347
- checkpoint?: string;
348
- /** Legacy content field (may be empty — text is in checkpoint.ui_chat_log) */
349
- content?: string;
320
+ status: WorkflowStatus;
321
+ goal?: string;
322
+ /** Raw checkpoint JSON string from DWS (contains channel_values.ui_chat_log) */
323
+ checkpoint?: string;
324
+ /** Legacy content field (may be empty — text is in checkpoint.ui_chat_log) */
325
+ content?: string;
350
326
  }
351
327
  interface RunMcpTool {
352
- name: string;
353
- args: string;
328
+ name: string;
329
+ args: string;
354
330
  }
355
331
  interface ReadFileAction {
356
- filepath: string;
332
+ filepath: string;
357
333
  }
358
334
  interface ReadFilesAction {
359
- filepaths: string[];
335
+ filepaths: string[];
360
336
  }
361
337
  interface WriteFileAction {
362
- filepath: string;
363
- contents: string;
338
+ filepath: string;
339
+ contents: string;
364
340
  }
365
341
  interface ShellCommandAction {
366
- command: string;
342
+ command: string;
367
343
  }
368
344
  interface EditFileAction {
369
- filepath: string;
370
- oldString: string;
371
- newString: string;
345
+ filepath: string;
346
+ oldString: string;
347
+ newString: string;
372
348
  }
373
349
  interface ListDirectoryAction {
374
- directory: string;
350
+ directory: string;
375
351
  }
376
352
  interface FindFilesAction {
377
- name_pattern: string;
353
+ name_pattern: string;
378
354
  }
379
355
  interface GrepAction {
380
- pattern: string;
381
- search_directory?: string;
382
- case_insensitive?: boolean;
356
+ pattern: string;
357
+ search_directory?: string;
358
+ case_insensitive?: boolean;
383
359
  }
384
360
  interface MkdirAction {
385
- directory_path: string;
361
+ directory_path: string;
386
362
  }
387
363
  interface RunCommandAction {
388
- program: string;
389
- flags?: string[];
390
- arguments?: string[];
364
+ program: string;
365
+ flags?: string[];
366
+ arguments?: string[];
391
367
  }
392
368
  interface RunGitCommandAction {
393
- command: string;
394
- arguments?: string[];
395
- repository_url?: string;
369
+ command: string;
370
+ arguments?: string[];
371
+ repository_url?: string;
396
372
  }
397
373
  interface GitLabApiRequestAction {
398
- method: string;
399
- path: string;
400
- body?: string;
374
+ method: string;
375
+ path: string;
376
+ body?: string;
401
377
  }
402
378
  /**
403
379
  * Server → Client action union.
@@ -406,154 +382,148 @@ interface GitLabApiRequestAction {
406
382
  * that need an `actionResponse` back).
407
383
  */
408
384
  interface WorkflowAction {
409
- requestID?: string;
410
- newCheckpoint?: NewCheckpoint;
411
- runMCPTool?: RunMcpTool;
412
- runReadFile?: ReadFileAction;
413
- runReadFiles?: ReadFilesAction;
414
- runWriteFile?: WriteFileAction;
415
- runShellCommand?: ShellCommandAction;
416
- runEditFile?: EditFileAction;
417
- listDirectory?: ListDirectoryAction;
418
- findFiles?: FindFilesAction;
419
- grep?: GrepAction;
420
- mkdir?: MkdirAction;
421
- runCommand?: RunCommandAction;
422
- runGitCommand?: RunGitCommandAction;
423
- runHTTPRequest?: GitLabApiRequestAction;
385
+ requestID?: string;
386
+ newCheckpoint?: NewCheckpoint;
387
+ runMCPTool?: RunMcpTool;
388
+ runReadFile?: ReadFileAction;
389
+ runReadFiles?: ReadFilesAction;
390
+ runWriteFile?: WriteFileAction;
391
+ runShellCommand?: ShellCommandAction;
392
+ runEditFile?: EditFileAction;
393
+ listDirectory?: ListDirectoryAction;
394
+ findFiles?: FindFilesAction;
395
+ grep?: GrepAction;
396
+ mkdir?: MkdirAction;
397
+ runCommand?: RunCommandAction;
398
+ runGitCommand?: RunGitCommandAction;
399
+ runHTTPRequest?: GitLabApiRequestAction;
424
400
  }
425
401
  /**
426
402
  * Options for creating a workflow chat model via `provider.workflowChat()`.
427
403
  */
428
404
  interface GitLabWorkflowOptions {
429
- /**
430
- * Workflow definition type.
431
- * @default 'chat'
432
- */
433
- workflowDefinition?: string;
434
- /**
435
- * Root namespace ID for the GitLab group/project.
436
- * Used for token scoping and model discovery.
437
- */
438
- rootNamespaceId?: string;
439
- /**
440
- * GitLab project ID (numeric or path).
441
- * Sent as `x-gitlab-project-id` header on WebSocket.
442
- */
443
- projectId?: string;
444
- /**
445
- * GitLab namespace ID.
446
- * Sent as `x-gitlab-namespace-id` header on WebSocket.
447
- */
448
- namespaceId?: string;
449
- /**
450
- * MCP tool definitions to expose to the workflow.
451
- * These are sent in `startRequest.mcpTools`.
452
- */
453
- mcpTools?: McpToolDefinition[];
454
- /**
455
- * Client capabilities to advertise.
456
- * @default ['shell_command']
457
- */
458
- clientCapabilities?: string[];
459
- /**
460
- * Tool names that are pre-approved for execution without user confirmation.
461
- * Sent in `startRequest.preapproved_tools`.
462
- */
463
- preapprovedTools?: string[];
464
- /**
465
- * Additional context items to send with the first request.
466
- * Used for conversation history continuity.
467
- */
468
- additionalContext?: AdditionalContext[];
469
- /**
470
- * Feature flags to pass to the GitLab API.
471
- */
472
- featureFlags?: Record<string, boolean>;
473
- /**
474
- * Working directory for auto-detecting GitLab project from git remote.
475
- * Used to resolve `projectId` when not explicitly set.
476
- * Defaults to `process.cwd()`.
477
- */
478
- workingDirectory?: string;
479
- /**
480
- * Flow configuration (parsed YAML object) to send to DWS.
481
- * Controls agent behavior, intermediate text generation, etc.
482
- * Sent as `startRequest.flowConfig`.
483
- */
484
- flowConfig?: unknown;
485
- /**
486
- * Schema version for the flow configuration.
487
- * Sent as `startRequest.flowConfigSchemaVersion`.
488
- */
489
- flowConfigSchemaVersion?: string;
490
- /**
491
- * Callback invoked when multiple workflow models are available for the
492
- * workspace and model switching is enabled by the instance admin.
493
- *
494
- * The provider calls this before starting the workflow so the host can
495
- * present a model picker to the user. Return the `ref` of the chosen
496
- * model, or `null`/`undefined` to fall back to the workspace default.
497
- *
498
- * If the returned ref is not in the list of selectable models it is
499
- * ignored and the workspace default is used instead.
500
- *
501
- * Not called when the admin has pinned a model — in that case the
502
- * pinned model is always used regardless of user preference.
503
- *
504
- * @param models - List of models the user can select from
505
- * @returns The selected model ref, or null/undefined for default
506
- */
507
- onSelectModel?: (models: AiModel[]) => Promise<string | null | undefined>;
405
+ /**
406
+ * Workflow definition type.
407
+ * @default 'chat'
408
+ */
409
+ workflowDefinition?: string;
410
+ /**
411
+ * Root namespace ID for the GitLab group/project.
412
+ * Used for token scoping and model discovery.
413
+ */
414
+ rootNamespaceId?: string;
415
+ /**
416
+ * GitLab project ID (numeric or path).
417
+ * Sent as `x-gitlab-project-id` header on WebSocket.
418
+ */
419
+ projectId?: string;
420
+ /**
421
+ * GitLab namespace ID.
422
+ * Sent as `x-gitlab-namespace-id` header on WebSocket.
423
+ */
424
+ namespaceId?: string;
425
+ /**
426
+ * MCP tool definitions to expose to the workflow.
427
+ * These are sent in `startRequest.mcpTools`.
428
+ */
429
+ mcpTools?: McpToolDefinition[];
430
+ /**
431
+ * Client capabilities to advertise.
432
+ * @default ['shell_command']
433
+ */
434
+ clientCapabilities?: string[];
435
+ /**
436
+ * Tool names that are pre-approved for execution without user confirmation.
437
+ * Sent in `startRequest.preapproved_tools`.
438
+ */
439
+ preapprovedTools?: string[];
440
+ /**
441
+ * Additional context items to send with the first request.
442
+ * Used for conversation history continuity.
443
+ */
444
+ additionalContext?: AdditionalContext[];
445
+ /**
446
+ * Feature flags to pass to the GitLab API.
447
+ */
448
+ featureFlags?: Record<string, boolean>;
449
+ /**
450
+ * Working directory for auto-detecting GitLab project from git remote.
451
+ * Used to resolve `projectId` when not explicitly set.
452
+ * Defaults to `process.cwd()`.
453
+ */
454
+ workingDirectory?: string;
455
+ /**
456
+ * Flow configuration (parsed YAML object) to send to DWS.
457
+ * Controls agent behavior, intermediate text generation, etc.
458
+ * Sent as `startRequest.flowConfig`.
459
+ */
460
+ flowConfig?: unknown;
461
+ /**
462
+ * Schema version for the flow configuration.
463
+ * Sent as `startRequest.flowConfigSchemaVersion`.
464
+ */
465
+ flowConfigSchemaVersion?: string;
466
+ /**
467
+ * Callback invoked when multiple workflow models are available for the
468
+ * workspace and model switching is enabled by the instance admin.
469
+ *
470
+ * The provider calls this before starting the workflow so the host can
471
+ * present a model picker to the user. Return the `ref` of the chosen
472
+ * model, or `null`/`undefined` to fall back to the workspace default.
473
+ *
474
+ * If the returned ref is not in the list of selectable models it is
475
+ * ignored and the workspace default is used instead.
476
+ *
477
+ * Not called when the admin has pinned a model — in that case the
478
+ * pinned model is always used regardless of user preference.
479
+ *
480
+ * @param models - List of models the user can select from
481
+ * @returns The selected model ref, or null/undefined for default
482
+ */
483
+ onSelectModel?: (models: AiModel[]) => Promise<string | null | undefined>;
508
484
  }
509
485
  interface GitLabWorkflowClientConfig {
510
- /** GitLab instance URL (e.g., 'https://gitlab.com') */
511
- instanceUrl: string;
512
- /** Function to get current auth headers */
513
- getHeaders: () => Record<string, string>;
514
- /**
515
- * Optional callback to refresh the API key when a 401 error occurs.
516
- */
517
- refreshApiKey?: () => Promise<void>;
518
- /** Custom fetch implementation */
519
- fetch?: typeof fetch;
520
- /** Feature flags for the token request */
521
- featureFlags?: Record<string, boolean>;
522
- /**
523
- * AI Gateway URL.
524
- * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
525
- * @default 'https://cloud.gitlab.com'
526
- */
527
- aiGatewayUrl?: string;
486
+ /** GitLab instance URL (e.g., 'https://gitlab.com') */
487
+ instanceUrl: string;
488
+ /** Function to get current auth headers */
489
+ getHeaders: () => Record<string, string>;
490
+ /**
491
+ * Optional callback to refresh the API key when a 401 error occurs.
492
+ */
493
+ refreshApiKey?: () => Promise<void>;
494
+ /** Custom fetch implementation */
495
+ fetch?: typeof fetch;
496
+ /** Feature flags for the token request */
497
+ featureFlags?: Record<string, boolean>;
498
+ /**
499
+ * AI Gateway URL.
500
+ * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
501
+ * @default 'https://cloud.gitlab.com'
502
+ */
503
+ aiGatewayUrl?: string;
528
504
  }
529
- type WorkflowClientEvent =
530
- | {
531
- type: 'checkpoint';
532
- data: NewCheckpoint;
533
- }
534
- | {
535
- type: 'tool-request';
536
- requestID: string;
537
- data: RunMcpTool;
538
- }
539
- | {
540
- type: 'builtin-tool-request';
541
- requestID: string;
542
- toolName: string;
543
- data: Record<string, unknown>;
544
- }
545
- | {
546
- type: 'completed';
547
- }
548
- | {
549
- type: 'failed';
550
- error: Error;
551
- }
552
- | {
553
- type: 'closed';
554
- code: number;
555
- reason: string;
556
- };
505
+ type WorkflowClientEvent = {
506
+ type: 'checkpoint';
507
+ data: NewCheckpoint;
508
+ } | {
509
+ type: 'tool-request';
510
+ requestID: string;
511
+ data: RunMcpTool;
512
+ } | {
513
+ type: 'builtin-tool-request';
514
+ requestID: string;
515
+ toolName: string;
516
+ data: Record<string, unknown>;
517
+ } | {
518
+ type: 'completed';
519
+ } | {
520
+ type: 'failed';
521
+ error: Error;
522
+ } | {
523
+ type: 'closed';
524
+ code: number;
525
+ reason: string;
526
+ };
557
527
  /**
558
528
  * Workflow type enum — matches gitlab-lsp WorkflowType.
559
529
  *
@@ -561,8 +531,8 @@ type WorkflowClientEvent =
561
531
  * - SOFTWARE_DEVELOPMENT: Per-workflow token, tokens revoked on completion
562
532
  */
563
533
  declare enum WorkflowType {
564
- CHAT = 'chat',
565
- SOFTWARE_DEVELOPMENT = 'software_development',
534
+ CHAT = "chat",
535
+ SOFTWARE_DEVELOPMENT = "software_development"
566
536
  }
567
537
  /** WebSocket ping interval (TCP keepalive) — 45s matching gitlab-lsp */
568
538
  declare const WS_KEEPALIVE_PING_INTERVAL_MS = 45000;
@@ -573,27 +543,27 @@ declare const DEFAULT_WORKFLOW_DEFINITION = WorkflowType.CHAT;
573
543
  /** Default client capabilities */
574
544
  declare const DEFAULT_CLIENT_CAPABILITIES: string[];
575
545
  /** Client version sent in startRequest */
576
- declare const CLIENT_VERSION = '1.0';
546
+ declare const CLIENT_VERSION = "1.0";
577
547
  /**
578
548
  * Agent privileges for workflow creation.
579
549
  * Matches gitlab-lsp AGENT_PRIVILEGES enum.
580
550
  */
581
551
  declare const AGENT_PRIVILEGES: {
582
- readonly READ_WRITE_FILES: 1;
583
- readonly READ_ONLY_GITLAB: 2;
584
- readonly READ_WRITE_GITLAB: 3;
585
- readonly RUN_COMMANDS: 4;
586
- readonly USE_GIT: 5;
587
- readonly RUN_MCP_TOOLS: 6;
552
+ readonly READ_WRITE_FILES: 1;
553
+ readonly READ_ONLY_GITLAB: 2;
554
+ readonly READ_WRITE_GITLAB: 3;
555
+ readonly RUN_COMMANDS: 4;
556
+ readonly USE_GIT: 5;
557
+ readonly RUN_MCP_TOOLS: 6;
588
558
  };
589
559
  /** Default agent privileges — matches gitlab-lsp defaults */
590
560
  declare const DEFAULT_AGENT_PRIVILEGES: (1 | 2 | 4 | 3 | 5 | 6)[];
591
561
  /** Workflow execution environment */
592
- declare const WORKFLOW_ENVIRONMENT: 'ide';
562
+ declare const WORKFLOW_ENVIRONMENT: "ide";
593
563
 
594
564
  interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {
595
- /** Provider name (e.g., 'gitlab.workflow') */
596
- provider: string;
565
+ /** Provider name (e.g., 'gitlab.workflow') */
566
+ provider: string;
597
567
  }
598
568
  /**
599
569
  * Callback for executing a tool requested by DWS.
@@ -604,13 +574,9 @@ interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {
604
574
  * @param args - JSON-encoded arguments
605
575
  * @returns Tool execution result as a string, or throws on error
606
576
  */
607
- type WorkflowToolExecutor = (
608
- toolName: string,
609
- args: string,
610
- requestID: string
611
- ) => Promise<{
612
- result: string;
613
- error?: string | null;
577
+ type WorkflowToolExecutor = (toolName: string, args: string, requestID: string) => Promise<{
578
+ result: string;
579
+ error?: string | null;
614
580
  }>;
615
581
  /**
616
582
  * GitLab Duo Agent Platform Language Model.
@@ -619,314 +585,313 @@ type WorkflowToolExecutor = (
619
585
  * to the Vercel AI SDK stream part format.
620
586
  */
621
587
  declare class GitLabWorkflowLanguageModel implements LanguageModelV2 {
622
- readonly specificationVersion: 'v2';
623
- readonly modelId: string;
624
- readonly supportedUrls: Record<string, RegExp[]>;
625
- private readonly config;
626
- private readonly workflowOptions;
627
- private readonly tokenClient;
628
- private readonly projectDetector;
629
- private readonly modelDiscovery;
630
- private readonly modelCache;
631
- private detectedProjectPath;
632
- private currentWorkflowId;
633
- private persistedAgentEmitted;
634
- private readonly activeClients;
635
- private _selectedModelRef?;
636
- private _selectedModelName?;
637
- private _rootNamespaceId?;
638
- private _discoveryPromise?;
639
- /**
640
- * Get the cached selected model ref.
641
- */
642
- get selectedModelRef(): string | null;
643
- /**
644
- * Set the selected model ref (e.g., from an eager discover call).
645
- * This will be used by resolveModelRef() to skip the picker.
646
- * Also persists to the file-based workspace cache.
647
- */
648
- set selectedModelRef(ref: string | null);
649
- /**
650
- * Get the cached selected model display name.
651
- */
652
- get selectedModelName(): string | null;
653
- /**
654
- * Set the selected model display name.
655
- * Also persists to the file-based workspace cache.
656
- */
657
- set selectedModelName(name: string | null);
658
- /**
659
- * Optional external tool executor. When set, this is called for tool
660
- * requests instead of looking up tools from `options.tools`.
661
- * This allows the consumer (OpenCode) to wire in its permission system.
662
- *
663
- * The executor is automatically bound to the async context at the time
664
- * it is set, so that AsyncLocalStorage-based contexts (like Instance)
665
- * remain available when the executor is invoked from WebSocket callbacks.
666
- */
667
- private _toolExecutor;
668
- /**
669
- * Optional callback invoked with intermediate token usage estimates
670
- * after each tool execution completes. This allows the consumer to
671
- * display live token counts during long-running DWS workflows, since
672
- * the AI SDK only surfaces usage via finish-step at stream end.
673
- */
674
- onUsageUpdate: ((usage: { inputTokens: number; outputTokens: number }) => void) | null;
675
- /**
676
- * Optional callback invoked when multiple workflow models are available
677
- * and the user should pick one. Set per-stream by the host (e.g., OpenCode)
678
- * alongside `toolExecutor`. Takes precedence over `workflowOptions.onSelectModel`.
679
- */
680
- onSelectModel: ((models: AiModel[]) => Promise<string | null | undefined>) | null;
681
- get toolExecutor(): WorkflowToolExecutor | null;
682
- set toolExecutor(executor: WorkflowToolExecutor | null);
683
- constructor(
684
- modelId: string,
685
- config: GitLabWorkflowLanguageModelConfig,
686
- workflowOptions?: GitLabWorkflowOptions
687
- );
688
- get provider(): string;
689
- /**
690
- * Resolve the project ID (path) to use for workflow creation.
691
- * Priority: explicit option > auto-detected from git remote > undefined.
692
- */
693
- private resolveProjectId;
694
- /**
695
- * Resolve the root namespace GID to use for model discovery.
696
- *
697
- * Priority:
698
- * 1. Explicit `rootNamespaceId` in workflowOptions (caller-provided GID)
699
- * 2. Auto-detected from git remote via project detector (namespace.id → GID)
700
- * 3. Cached from previous call
701
- */
702
- private resolveRootNamespaceId;
703
- /**
704
- * Resolve the effective DWS model ref to use for this stream.
705
- * Deduplicates concurrent calls via a shared promise.
706
- *
707
- * Priority for the canonical `duo-workflow` model ID:
708
- * 1. Admin-pinned model (from GitLabModelDiscovery) always wins
709
- * 2. User selection via onSelectModel callback (if model switching enabled)
710
- * 3. Workspace default model
711
- * 4. File-cached discovery/selectionused when live discovery fails
712
- * 5. Hard-coded 'default' (DWS decides) — fallback when discovery fails
713
- *
714
- * For all other `duo-workflow-*` model IDs the static mapping is used as-is.
715
- */
716
- private resolveModelRef;
717
- private doResolveModelRef;
718
- /**
719
- * Pre-fetch available models for the workspace.
720
- * Call this early (e.g., on IDE startup) to avoid blocking the first stream.
721
- * Results are persisted to the workspace model cache.
722
- *
723
- * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')
724
- * @returns Discovered models with default, selectable, and pinned models
725
- */
726
- discoverModels(rootNamespaceId: string): Promise<DiscoveredModels>;
727
- /**
728
- * Get the file-based model cache instance for this workspace.
729
- * Useful for consumers that need direct cache access (e.g., the discover route).
730
- */
731
- getModelCache(): GitLabModelCache;
732
- /**
733
- * Stop the active workflow.
734
- */
735
- stopWorkflow(): void;
736
- /**
737
- * Reset the workflow state, forcing a new workflow to be created on the
738
- * next doStream() call. Call this when starting a new conversation.
739
- */
740
- resetWorkflow(): void;
741
- /**
742
- * Get the current workflow ID (if any).
743
- * Useful for consumers that need to track workflow state.
744
- */
745
- get workflowId(): string | null;
746
- doGenerate(options: LanguageModelV2CallOptions): Promise<{
747
- content: LanguageModelV2Content[];
748
- finishReason: LanguageModelV2FinishReason;
749
- usage: LanguageModelV2Usage;
750
- warnings: LanguageModelV2CallWarning[];
751
- }>;
752
- doStream(options: LanguageModelV2CallOptions): Promise<{
753
- stream: ReadableStream<LanguageModelV2StreamPart>;
754
- request?: {
755
- body?: unknown;
756
- };
757
- }>;
758
- private handleWorkflowEvent;
759
- private processCheckpoint;
760
- private executeToolAndRespond;
761
- private cleanupClient;
762
- private buildWorkflowMetadata;
763
- private getGitInfo;
764
- /**
765
- * Extract the user's goal (last user message) from the AI SDK prompt.
766
- */
767
- private extractGoalFromPrompt;
768
- /**
769
- * Convert AI SDK tools to DWS McpToolDefinition format.
770
- */
771
- private extractMcpTools;
772
- private static readonly MAX_START_REQUEST_BYTES;
773
- /**
774
- * Trim mcpTools and additionalContext to fit within the DWS 4MB gRPC
775
- * message size limit (`MAX_MESSAGE_SIZE` in duo_workflow_service/server.py).
776
- *
777
- * DWS has no per-field limits on tool descriptions, schemas, or context items.
778
- * The only hard constraint is the total serialized message size.
779
- *
780
- * Strategy (progressive, only if over budget):
781
- * 1. Send everything as-is
782
- * 2. Simplify tool input schemas (strip descriptions from properties)
783
- * 3. Strip schemas to minimal form (type + property names only)
784
- * 4. Drop tools from the end until it fits
785
- */
786
- private trimPayload;
787
- private buildAdditionalContext;
588
+ readonly specificationVersion: "v2";
589
+ readonly modelId: string;
590
+ readonly supportedUrls: Record<string, RegExp[]>;
591
+ private readonly config;
592
+ private readonly workflowOptions;
593
+ private readonly tokenClient;
594
+ private readonly projectDetector;
595
+ private readonly modelDiscovery;
596
+ private readonly modelCache;
597
+ private detectedProjectPath;
598
+ private currentWorkflowId;
599
+ private persistedAgentEmitted;
600
+ private readonly activeClients;
601
+ private _selectedModelRef?;
602
+ private _selectedModelName?;
603
+ private _rootNamespaceId?;
604
+ private _discoveryPromise?;
605
+ /**
606
+ * Get the cached selected model ref.
607
+ */
608
+ get selectedModelRef(): string | null;
609
+ /**
610
+ * Set the selected model ref (e.g., from an eager discover call).
611
+ * This will be used by resolveModelRef() to skip the picker.
612
+ * Also persists to the file-based workspace cache.
613
+ */
614
+ set selectedModelRef(ref: string | null);
615
+ /**
616
+ * Get the cached selected model display name.
617
+ */
618
+ get selectedModelName(): string | null;
619
+ /**
620
+ * Set the selected model display name.
621
+ * Also persists to the file-based workspace cache.
622
+ */
623
+ set selectedModelName(name: string | null);
624
+ /**
625
+ * Optional external tool executor. When set, this is called for tool
626
+ * requests instead of looking up tools from `options.tools`.
627
+ * This allows the consumer (OpenCode) to wire in its permission system.
628
+ *
629
+ * The executor is automatically bound to the async context at the time
630
+ * it is set, so that AsyncLocalStorage-based contexts (like Instance)
631
+ * remain available when the executor is invoked from WebSocket callbacks.
632
+ */
633
+ private _toolExecutor;
634
+ /**
635
+ * Optional callback invoked with intermediate token usage estimates
636
+ * after each tool execution completes. This allows the consumer to
637
+ * display live token counts during long-running DWS workflows, since
638
+ * the AI SDK only surfaces usage via finish-step at stream end.
639
+ */
640
+ onUsageUpdate: ((usage: {
641
+ inputTokens: number;
642
+ outputTokens: number;
643
+ }) => void) | null;
644
+ /**
645
+ * Optional callback invoked when multiple workflow models are available
646
+ * and the user should pick one. Set per-stream by the host (e.g., OpenCode)
647
+ * alongside `toolExecutor`. Takes precedence over `workflowOptions.onSelectModel`.
648
+ */
649
+ onSelectModel: ((models: AiModel[]) => Promise<string | null | undefined>) | null;
650
+ get toolExecutor(): WorkflowToolExecutor | null;
651
+ set toolExecutor(executor: WorkflowToolExecutor | null);
652
+ constructor(modelId: string, config: GitLabWorkflowLanguageModelConfig, workflowOptions?: GitLabWorkflowOptions);
653
+ get provider(): string;
654
+ /**
655
+ * Resolve the project ID (path) to use for workflow creation.
656
+ * Priority: explicit option > auto-detected from git remote > undefined.
657
+ */
658
+ private resolveProjectId;
659
+ /**
660
+ * Resolve the root namespace GID to use for model discovery.
661
+ *
662
+ * Priority:
663
+ * 1. Explicit `rootNamespaceId` in workflowOptions (caller-provided GID)
664
+ * 2. Auto-detected from git remote via project detector (namespace.id GID)
665
+ * 3. Cached from previous call
666
+ */
667
+ private resolveRootNamespaceId;
668
+ /**
669
+ * Resolve the effective DWS model ref to use for this stream.
670
+ * Deduplicates concurrent calls via a shared promise.
671
+ *
672
+ * Priority for the canonical `duo-workflow` model ID:
673
+ * 1. Admin-pinned model (from GitLabModelDiscovery) always wins
674
+ * 2. User selection via onSelectModel callback (if model switching enabled)
675
+ * 3. Workspace default model
676
+ * 4. File-cached discovery/selection — used when live discovery fails
677
+ * 5. Hard-coded 'default' (DWS decides) fallback when discovery fails
678
+ *
679
+ * For all other `duo-workflow-*` model IDs the static mapping is used as-is.
680
+ */
681
+ private resolveModelRef;
682
+ private doResolveModelRef;
683
+ /**
684
+ * Pre-fetch available models for the workspace.
685
+ * Call this early (e.g., on IDE startup) to avoid blocking the first stream.
686
+ * Results are persisted to the workspace model cache.
687
+ *
688
+ * @param rootNamespaceId - GitLab group ID (e.g., 'gid://gitlab/Group/12345')
689
+ * @returns Discovered models with default, selectable, and pinned models
690
+ */
691
+ discoverModels(rootNamespaceId: string): Promise<DiscoveredModels>;
692
+ /**
693
+ * Get the file-based model cache instance for this workspace.
694
+ * Useful for consumers that need direct cache access (e.g., the discover route).
695
+ */
696
+ getModelCache(): GitLabModelCache;
697
+ /**
698
+ * Stop the active workflow.
699
+ */
700
+ stopWorkflow(): void;
701
+ /**
702
+ * Reset the workflow state, forcing a new workflow to be created on the
703
+ * next doStream() call. Call this when starting a new conversation.
704
+ */
705
+ resetWorkflow(): void;
706
+ /**
707
+ * Get the current workflow ID (if any).
708
+ * Useful for consumers that need to track workflow state.
709
+ */
710
+ get workflowId(): string | null;
711
+ doGenerate(options: LanguageModelV2CallOptions): Promise<{
712
+ content: LanguageModelV2Content[];
713
+ finishReason: LanguageModelV2FinishReason;
714
+ usage: LanguageModelV2Usage;
715
+ warnings: LanguageModelV2CallWarning[];
716
+ }>;
717
+ doStream(options: LanguageModelV2CallOptions): Promise<{
718
+ stream: ReadableStream<LanguageModelV2StreamPart>;
719
+ request?: {
720
+ body?: unknown;
721
+ };
722
+ }>;
723
+ private handleWorkflowEvent;
724
+ private processCheckpoint;
725
+ private executeToolAndRespond;
726
+ private cleanupClient;
727
+ private buildWorkflowMetadata;
728
+ private getGitInfo;
729
+ /**
730
+ * Extract the user's goal (last user message) from the AI SDK prompt.
731
+ */
732
+ private extractGoalFromPrompt;
733
+ /**
734
+ * Convert AI SDK tools to DWS McpToolDefinition format.
735
+ */
736
+ private extractMcpTools;
737
+ private static readonly MAX_START_REQUEST_BYTES;
738
+ /**
739
+ * Trim mcpTools and additionalContext to fit within the DWS 4MB gRPC
740
+ * message size limit (`MAX_MESSAGE_SIZE` in duo_workflow_service/server.py).
741
+ *
742
+ * DWS has no per-field limits on tool descriptions, schemas, or context items.
743
+ * The only hard constraint is the total serialized message size.
744
+ *
745
+ * Strategy (progressive, only if over budget):
746
+ * 1. Send everything as-is
747
+ * 2. Simplify tool input schemas (strip descriptions from properties)
748
+ * 3. Strip schemas to minimal form (type + property names only)
749
+ * 4. Drop tools from the end until it fits
750
+ */
751
+ private trimPayload;
752
+ private buildAdditionalContext;
788
753
  }
789
754
 
790
755
  interface GitLabProvider {
791
- (modelId: string): LanguageModelV2;
792
- readonly specificationVersion: 'v2';
793
- languageModel(modelId: string): LanguageModelV2;
794
- chat(modelId: string): LanguageModelV2;
795
- /**
796
- * Create an agentic chat model with tool calling support
797
- *
798
- * @param modelId - GitLab model identifier. Some IDs automatically map to specific Anthropic models.
799
- * @param options - Configuration options for the agentic model
800
- * @returns A language model with native tool calling support via Anthropic
801
- *
802
- * @example
803
- * // Automatic model mapping
804
- * const model = gitlab.agenticChat('duo-chat-opus-4-5');
805
- * // Uses claude-opus-4-5-20251101
806
- *
807
- * @example
808
- * // Explicit model override
809
- * const model = gitlab.agenticChat('duo-chat', {
810
- * anthropicModel: 'claude-sonnet-4-5-20250929'
811
- * });
812
- */
813
- agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAnthropicLanguageModel;
814
- /**
815
- * Create a workflow chat model using GitLab Duo Agent Platform.
816
- *
817
- * Workflow models use a server-side agentic loop where GitLab's DWS drives
818
- * the LLM, requests tool executions from the client via WebSocket, and
819
- * streams text/status back.
820
- *
821
- * Requires GitLab Ultimate with Duo Enterprise add-on.
822
- *
823
- * @param modelId - Workflow model identifier (e.g., 'duo-workflow-sonnet-4-6')
824
- * @param options - Workflow-specific configuration
825
- * @returns A language model backed by the DWS WebSocket protocol
826
- *
827
- * @example
828
- * const model = gitlab.workflowChat('duo-workflow-sonnet-4-6', {
829
- * mcpTools: [...],
830
- * preapprovedTools: ['read_file', 'write_file'],
831
- * });
832
- */
833
- workflowChat(modelId: string, options?: GitLabWorkflowOptions): GitLabWorkflowLanguageModel;
834
- textEmbeddingModel(modelId: string): never;
835
- imageModel(modelId: string): never;
756
+ (modelId: string): LanguageModelV2;
757
+ readonly specificationVersion: 'v2';
758
+ languageModel(modelId: string): LanguageModelV2;
759
+ chat(modelId: string): LanguageModelV2;
760
+ /**
761
+ * Create an agentic chat model with tool calling support
762
+ *
763
+ * @param modelId - GitLab model identifier. Some IDs automatically map to specific Anthropic models.
764
+ * @param options - Configuration options for the agentic model
765
+ * @returns A language model with native tool calling support via Anthropic
766
+ *
767
+ * @example
768
+ * // Automatic model mapping
769
+ * const model = gitlab.agenticChat('duo-chat-opus-4-5');
770
+ * // Uses claude-opus-4-5-20251101
771
+ *
772
+ * @example
773
+ * // Explicit model override
774
+ * const model = gitlab.agenticChat('duo-chat', {
775
+ * anthropicModel: 'claude-sonnet-4-5-20250929'
776
+ * });
777
+ */
778
+ agenticChat(modelId: string, options?: GitLabAgenticOptions): GitLabAnthropicLanguageModel;
779
+ /**
780
+ * Create a workflow chat model using GitLab Duo Agent Platform.
781
+ *
782
+ * Workflow models use a server-side agentic loop where GitLab's DWS drives
783
+ * the LLM, requests tool executions from the client via WebSocket, and
784
+ * streams text/status back.
785
+ *
786
+ * Requires GitLab Ultimate with Duo Enterprise add-on.
787
+ *
788
+ * @param modelId - Workflow model identifier (e.g., 'duo-workflow-sonnet-4-6')
789
+ * @param options - Workflow-specific configuration
790
+ * @returns A language model backed by the DWS WebSocket protocol
791
+ *
792
+ * @example
793
+ * const model = gitlab.workflowChat('duo-workflow-sonnet-4-6', {
794
+ * mcpTools: [...],
795
+ * preapprovedTools: ['read_file', 'write_file'],
796
+ * });
797
+ */
798
+ workflowChat(modelId: string, options?: GitLabWorkflowOptions): GitLabWorkflowLanguageModel;
799
+ textEmbeddingModel(modelId: string): never;
800
+ imageModel(modelId: string): never;
836
801
  }
837
802
  interface GitLabAgenticOptions {
838
- /**
839
- * Override the provider-specific model (optional).
840
- * Must be a valid model for the detected provider.
841
- *
842
- * For Anthropic models:
843
- * - 'claude-opus-4-6'
844
- * - 'claude-sonnet-4-6'
845
- * - 'claude-opus-4-5-20251101'
846
- * - 'claude-sonnet-4-5-20250929'
847
- * - 'claude-haiku-4-5-20251001'
848
- *
849
- * For OpenAI models:
850
- * - 'gpt-5.1-2025-11-13'
851
- * - 'gpt-5-mini-2025-08-07'
852
- * - 'gpt-5-codex'
853
- * - 'gpt-5.2-codex'
854
- *
855
- * @example
856
- * // Override with explicit model
857
- * const model = gitlab.agenticChat('duo-chat-opus-4-5', {
858
- * providerModel: 'claude-sonnet-4-5-20250929'
859
- * });
860
- */
861
- providerModel?: string;
862
- /**
863
- * Maximum tokens to generate
864
- * @default 8192
865
- */
866
- maxTokens?: number;
867
- /**
868
- * Feature flags to pass to the GitLab API
869
- */
870
- featureFlags?: Record<string, boolean>;
871
- /**
872
- * Custom headers for AI Gateway requests (per-model override).
873
- * These headers are sent to the Anthropic/OpenAI proxy endpoints.
874
- * Merged with provider-level aiGatewayHeaders (model-level takes precedence).
875
- */
876
- aiGatewayHeaders?: Record<string, string>;
803
+ /**
804
+ * Override the provider-specific model (optional).
805
+ * Must be a valid model for the detected provider.
806
+ *
807
+ * For Anthropic models:
808
+ * - 'claude-opus-4-6'
809
+ * - 'claude-sonnet-4-6'
810
+ * - 'claude-opus-4-5-20251101'
811
+ * - 'claude-sonnet-4-5-20250929'
812
+ * - 'claude-haiku-4-5-20251001'
813
+ *
814
+ * For OpenAI models:
815
+ * - 'gpt-5.1-2025-11-13'
816
+ * - 'gpt-5-mini-2025-08-07'
817
+ * - 'gpt-5-codex'
818
+ * - 'gpt-5.2-codex'
819
+ *
820
+ * @example
821
+ * // Override with explicit model
822
+ * const model = gitlab.agenticChat('duo-chat-opus-4-5', {
823
+ * providerModel: 'claude-sonnet-4-5-20250929'
824
+ * });
825
+ */
826
+ providerModel?: string;
827
+ /**
828
+ * Maximum tokens to generate
829
+ * @default 8192
830
+ */
831
+ maxTokens?: number;
832
+ /**
833
+ * Feature flags to pass to the GitLab API
834
+ */
835
+ featureFlags?: Record<string, boolean>;
836
+ /**
837
+ * Custom headers for AI Gateway requests (per-model override).
838
+ * These headers are sent to the Anthropic/OpenAI proxy endpoints.
839
+ * Merged with provider-level aiGatewayHeaders (model-level takes precedence).
840
+ */
841
+ aiGatewayHeaders?: Record<string, string>;
877
842
  }
878
843
  interface GitLabProviderSettings {
879
- /**
880
- * GitLab instance URL (e.g., 'https://gitlab.com')
881
- * Can also be set via GITLAB_INSTANCE_URL environment variable.
882
- * @default 'https://gitlab.com'
883
- */
884
- instanceUrl?: string;
885
- /**
886
- * API token (Personal Access Token or OAuth access token)
887
- * Can also be set via GITLAB_TOKEN environment variable
888
- */
889
- apiKey?: string;
890
- /**
891
- * OAuth refresh token (optional, for OAuth flow)
892
- */
893
- refreshToken?: string;
894
- /**
895
- * OAuth client ID (required for OAuth flow)
896
- */
897
- clientId?: string;
898
- /**
899
- * OAuth redirect URI (required for OAuth flow)
900
- */
901
- redirectUri?: string;
902
- /**
903
- * Custom headers to include in requests
904
- */
905
- headers?: Record<string, string>;
906
- /**
907
- * Custom fetch implementation
908
- */
909
- fetch?: typeof fetch;
910
- /**
911
- * Provider name override
912
- */
913
- name?: string;
914
- /**
915
- * Default feature flags to pass to the GitLab API for all agentic chat models
916
- */
917
- featureFlags?: Record<string, boolean>;
918
- /**
919
- * AI Gateway URL for the Anthropic proxy.
920
- * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
921
- * @default 'https://cloud.gitlab.com'
922
- */
923
- aiGatewayUrl?: string;
924
- /**
925
- * Custom headers to include in AI Gateway requests (Anthropic/OpenAI proxy).
926
- * These headers are merged with the default headers from direct_access response.
927
- * Default User-Agent: gitlab-ai-provider/{version}
928
- */
929
- aiGatewayHeaders?: Record<string, string>;
844
+ /**
845
+ * GitLab instance URL (e.g., 'https://gitlab.com')
846
+ * Can also be set via GITLAB_INSTANCE_URL environment variable.
847
+ * @default 'https://gitlab.com'
848
+ */
849
+ instanceUrl?: string;
850
+ /**
851
+ * API token (Personal Access Token or OAuth access token)
852
+ * Can also be set via GITLAB_TOKEN environment variable
853
+ */
854
+ apiKey?: string;
855
+ /**
856
+ * OAuth refresh token (optional, for OAuth flow)
857
+ */
858
+ refreshToken?: string;
859
+ /**
860
+ * OAuth client ID (required for OAuth flow)
861
+ */
862
+ clientId?: string;
863
+ /**
864
+ * OAuth redirect URI (required for OAuth flow)
865
+ */
866
+ redirectUri?: string;
867
+ /**
868
+ * Custom headers to include in requests
869
+ */
870
+ headers?: Record<string, string>;
871
+ /**
872
+ * Custom fetch implementation
873
+ */
874
+ fetch?: typeof fetch;
875
+ /**
876
+ * Provider name override
877
+ */
878
+ name?: string;
879
+ /**
880
+ * Default feature flags to pass to the GitLab API for all agentic chat models
881
+ */
882
+ featureFlags?: Record<string, boolean>;
883
+ /**
884
+ * AI Gateway URL for the Anthropic proxy.
885
+ * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
886
+ * @default 'https://cloud.gitlab.com'
887
+ */
888
+ aiGatewayUrl?: string;
889
+ /**
890
+ * Custom headers to include in AI Gateway requests (Anthropic/OpenAI proxy).
891
+ * These headers are merged with the default headers from direct_access response.
892
+ * Default User-Agent: gitlab-ai-provider/{version}
893
+ */
894
+ aiGatewayHeaders?: Record<string, string>;
930
895
  }
931
896
  declare function createGitLab(options?: GitLabProviderSettings): GitLabProvider;
932
897
  /**
@@ -944,92 +909,92 @@ declare const gitlab: GitLabProvider;
944
909
  declare const VERSION: string;
945
910
 
946
911
  interface GitLabOpenAIConfig {
947
- provider: string;
948
- instanceUrl: string;
949
- getHeaders: () => Record<string, string>;
950
- fetch?: typeof fetch;
951
- refreshApiKey?: () => Promise<void>;
952
- openaiModel?: string;
953
- maxTokens?: number;
954
- featureFlags?: {
955
- DuoAgentPlatformNext: true;
956
- } & Record<string, boolean>;
957
- aiGatewayUrl?: string;
958
- /** Whether to use the Responses API instead of Chat Completions API */
959
- useResponsesApi?: boolean;
960
- /**
961
- * Custom headers for AI Gateway OpenAI proxy requests.
962
- * Merged with headers from direct_access token response.
963
- */
964
- aiGatewayHeaders?: Record<string, string>;
912
+ provider: string;
913
+ instanceUrl: string;
914
+ getHeaders: () => Record<string, string>;
915
+ fetch?: typeof fetch;
916
+ refreshApiKey?: () => Promise<void>;
917
+ openaiModel?: string;
918
+ maxTokens?: number;
919
+ featureFlags?: {
920
+ DuoAgentPlatformNext: true;
921
+ } & Record<string, boolean>;
922
+ aiGatewayUrl?: string;
923
+ /** Whether to use the Responses API instead of Chat Completions API */
924
+ useResponsesApi?: boolean;
925
+ /**
926
+ * Custom headers for AI Gateway OpenAI proxy requests.
927
+ * Merged with headers from direct_access token response.
928
+ */
929
+ aiGatewayHeaders?: Record<string, string>;
965
930
  }
966
931
  declare class GitLabOpenAILanguageModel implements LanguageModelV2 {
967
- readonly specificationVersion: 'v2';
968
- readonly modelId: string;
969
- readonly supportedUrls: Record<string, RegExp[]>;
970
- private readonly config;
971
- private readonly directAccessClient;
972
- private readonly useResponsesApi;
973
- private openaiClient;
974
- constructor(modelId: string, config: GitLabOpenAIConfig);
975
- get provider(): string;
976
- private getOpenAIClient;
977
- private isTokenError;
978
- /**
979
- * Check if an error is a context overflow error (prompt too long)
980
- * These should NOT trigger token refresh and should be reported to the user.
981
- */
982
- private isContextOverflowError;
983
- private convertTools;
984
- private convertToolChoice;
985
- private convertPrompt;
986
- private convertFinishReason;
987
- /**
988
- * Convert tools to Responses API format
989
- */
990
- private convertToolsForResponses;
991
- /**
992
- * Convert prompt to Responses API input format
993
- */
994
- private convertPromptForResponses;
995
- /**
996
- * Extract system instructions from prompt
997
- */
998
- private extractSystemInstructions;
999
- /**
1000
- * Convert Responses API status to finish reason
1001
- * Note: Responses API returns 'completed' even when making tool calls,
1002
- * so we need to check the content for tool calls separately.
1003
- */
1004
- private convertResponsesStatus;
1005
- doGenerate(options: LanguageModelV2CallOptions): Promise<{
1006
- content: LanguageModelV2Content[];
1007
- finishReason: LanguageModelV2FinishReason;
1008
- usage: LanguageModelV2Usage;
1009
- warnings: LanguageModelV2CallWarning[];
1010
- }>;
1011
- private doGenerateWithChatApi;
1012
- private doGenerateWithResponsesApi;
1013
- doStream(options: LanguageModelV2CallOptions): Promise<{
1014
- stream: ReadableStream<LanguageModelV2StreamPart>;
1015
- request?: {
1016
- body?: unknown;
1017
- };
1018
- response?: {
1019
- headers?: Record<string, string>;
1020
- };
1021
- }>;
1022
- private doStreamWithChatApi;
1023
- private doStreamWithResponsesApi;
932
+ readonly specificationVersion: "v2";
933
+ readonly modelId: string;
934
+ readonly supportedUrls: Record<string, RegExp[]>;
935
+ private readonly config;
936
+ private readonly directAccessClient;
937
+ private readonly useResponsesApi;
938
+ private openaiClient;
939
+ constructor(modelId: string, config: GitLabOpenAIConfig);
940
+ get provider(): string;
941
+ private getOpenAIClient;
942
+ private isTokenError;
943
+ /**
944
+ * Check if an error is a context overflow error (prompt too long)
945
+ * These should NOT trigger token refresh and should be reported to the user.
946
+ */
947
+ private isContextOverflowError;
948
+ private convertTools;
949
+ private convertToolChoice;
950
+ private convertPrompt;
951
+ private convertFinishReason;
952
+ /**
953
+ * Convert tools to Responses API format
954
+ */
955
+ private convertToolsForResponses;
956
+ /**
957
+ * Convert prompt to Responses API input format
958
+ */
959
+ private convertPromptForResponses;
960
+ /**
961
+ * Extract system instructions from prompt
962
+ */
963
+ private extractSystemInstructions;
964
+ /**
965
+ * Convert Responses API status to finish reason
966
+ * Note: Responses API returns 'completed' even when making tool calls,
967
+ * so we need to check the content for tool calls separately.
968
+ */
969
+ private convertResponsesStatus;
970
+ doGenerate(options: LanguageModelV2CallOptions): Promise<{
971
+ content: LanguageModelV2Content[];
972
+ finishReason: LanguageModelV2FinishReason;
973
+ usage: LanguageModelV2Usage;
974
+ warnings: LanguageModelV2CallWarning[];
975
+ }>;
976
+ private doGenerateWithChatApi;
977
+ private doGenerateWithResponsesApi;
978
+ doStream(options: LanguageModelV2CallOptions): Promise<{
979
+ stream: ReadableStream<LanguageModelV2StreamPart>;
980
+ request?: {
981
+ body?: unknown;
982
+ };
983
+ response?: {
984
+ headers?: Record<string, string>;
985
+ };
986
+ }>;
987
+ private doStreamWithChatApi;
988
+ private doStreamWithResponsesApi;
1024
989
  }
1025
990
 
1026
991
  type ModelProvider = 'anthropic' | 'openai' | 'workflow';
1027
992
  type OpenAIApiType = 'chat' | 'responses';
1028
993
  interface ModelMapping {
1029
- provider: ModelProvider;
1030
- model: string;
1031
- /** For OpenAI models, which API to use: 'chat' for /v1/chat/completions, 'responses' for /v1/responses */
1032
- openaiApiType?: OpenAIApiType;
994
+ provider: ModelProvider;
995
+ model: string;
996
+ /** For OpenAI models, which API to use: 'chat' for /v1/chat/completions, 'responses' for /v1/responses */
997
+ openaiApiType?: OpenAIApiType;
1033
998
  }
1034
999
  declare const MODEL_MAPPINGS: Record<string, ModelMapping>;
1035
1000
  declare function getModelMapping(modelId: string): ModelMapping | undefined;
@@ -1044,50 +1009,44 @@ declare function getWorkflowModelRef(modelId: string): string | undefined;
1044
1009
  declare const MODEL_ID_TO_ANTHROPIC_MODEL: Record<string, string>;
1045
1010
 
1046
1011
  interface GitLabErrorOptions {
1047
- message: string;
1048
- statusCode?: number;
1049
- responseBody?: string;
1050
- cause?: unknown;
1012
+ message: string;
1013
+ statusCode?: number;
1014
+ responseBody?: string;
1015
+ cause?: unknown;
1051
1016
  }
1052
1017
  declare class GitLabError extends Error {
1053
- readonly statusCode?: number;
1054
- readonly responseBody?: string;
1055
- readonly cause?: unknown;
1056
- constructor(options: GitLabErrorOptions);
1057
- static fromResponse(response: Response, body: string): GitLabError;
1058
- isAuthError(): boolean;
1059
- isRateLimitError(): boolean;
1060
- isForbiddenError(): boolean;
1061
- isServerError(): boolean;
1062
- /**
1063
- * Check if this error is a context overflow error (prompt too long).
1064
- * These errors occur when the conversation exceeds the model's token limit.
1065
- */
1066
- isContextOverflowError(): boolean;
1018
+ readonly statusCode?: number;
1019
+ readonly responseBody?: string;
1020
+ readonly cause?: unknown;
1021
+ constructor(options: GitLabErrorOptions);
1022
+ static fromResponse(response: Response, body: string): GitLabError;
1023
+ isAuthError(): boolean;
1024
+ isRateLimitError(): boolean;
1025
+ isForbiddenError(): boolean;
1026
+ isServerError(): boolean;
1027
+ /**
1028
+ * Check if this error is a context overflow error (prompt too long).
1029
+ * These errors occur when the conversation exceeds the model's token limit.
1030
+ */
1031
+ isContextOverflowError(): boolean;
1067
1032
  }
1068
1033
 
1069
- declare const gitlabOAuthTokenResponseSchema: z.ZodObject<
1070
- {
1034
+ declare const gitlabOAuthTokenResponseSchema: z.ZodObject<{
1071
1035
  access_token: z.ZodString;
1072
1036
  refresh_token: z.ZodOptional<z.ZodString>;
1073
1037
  expires_in: z.ZodNumber;
1074
1038
  created_at: z.ZodNumber;
1075
- },
1076
- 'strip',
1077
- z.ZodTypeAny,
1078
- {
1039
+ }, "strip", z.ZodTypeAny, {
1079
1040
  created_at?: number;
1080
1041
  access_token?: string;
1081
1042
  refresh_token?: string;
1082
1043
  expires_in?: number;
1083
- },
1084
- {
1044
+ }, {
1085
1045
  created_at?: number;
1086
1046
  access_token?: string;
1087
1047
  refresh_token?: string;
1088
1048
  expires_in?: number;
1089
- }
1090
- >;
1049
+ }>;
1091
1050
  type GitLabOAuthTokenResponse = z.infer<typeof gitlabOAuthTokenResponseSchema>;
1092
1051
 
1093
1052
  /**
@@ -1095,24 +1054,24 @@ type GitLabOAuthTokenResponse = z.infer<typeof gitlabOAuthTokenResponseSchema>;
1095
1054
  * Based on gitlab-vscode-extension and gitlab-lsp patterns
1096
1055
  */
1097
1056
  interface GitLabOAuthTokens {
1098
- accessToken: string;
1099
- refreshToken: string;
1100
- expiresAt: number;
1101
- instanceUrl: string;
1057
+ accessToken: string;
1058
+ refreshToken: string;
1059
+ expiresAt: number;
1060
+ instanceUrl: string;
1102
1061
  }
1103
1062
  interface OpenCodeAuthOAuth {
1104
- type: 'oauth';
1105
- refresh: string;
1106
- access: string;
1107
- expires: number;
1108
- /** @deprecated Use enterpriseUrl instead. Kept for backwards compatibility with older auth.json files. */
1109
- instanceUrl?: string;
1110
- /** Instance URL as written by opencode-gitlab-auth plugin (e.g. 'https://gitlab.com') */
1111
- enterpriseUrl?: string;
1063
+ type: 'oauth';
1064
+ refresh: string;
1065
+ access: string;
1066
+ expires: number;
1067
+ /** @deprecated Use enterpriseUrl instead. Kept for backwards compatibility with older auth.json files. */
1068
+ instanceUrl?: string;
1069
+ /** Instance URL as written by opencode-gitlab-auth plugin (e.g. 'https://gitlab.com') */
1070
+ enterpriseUrl?: string;
1112
1071
  }
1113
1072
  interface OpenCodeAuthApi {
1114
- type: 'api';
1115
- key: string;
1073
+ type: 'api';
1074
+ key: string;
1116
1075
  }
1117
1076
  type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;
1118
1077
  /**
@@ -1122,18 +1081,16 @@ type OpenCodeAuth = OpenCodeAuthOAuth | OpenCodeAuthApi;
1122
1081
  * Note: VS Code extension uses a different client ID ('36f2a70c...') but we use the opencode plugin's ID
1123
1082
  * to ensure token refresh works correctly with tokens created by the auth plugin.
1124
1083
  */
1125
- declare const OPENCODE_GITLAB_AUTH_CLIENT_ID =
1126
- '1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e';
1084
+ declare const OPENCODE_GITLAB_AUTH_CLIENT_ID = "1d89f9fdb23ee96d4e603201f6861dab6e143c5c3c00469a018a2d94bdc03d4e";
1127
1085
  /**
1128
1086
  * @deprecated Use OPENCODE_GITLAB_AUTH_CLIENT_ID instead. This is the VS Code extension's client ID
1129
1087
  * and will cause refresh failures if used with tokens created by opencode-gitlab-auth.
1130
1088
  */
1131
- declare const BUNDLED_CLIENT_ID =
1132
- '36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5';
1089
+ declare const BUNDLED_CLIENT_ID = "36f2a70cddeb5a0889d4fd8295c241b7e9848e89cf9e599d0eed2d8e5350fbf5";
1133
1090
  /**
1134
1091
  * GitLab.com URL constant
1135
1092
  */
1136
- declare const GITLAB_COM_URL = 'https://gitlab.com';
1093
+ declare const GITLAB_COM_URL = "https://gitlab.com";
1137
1094
  /**
1138
1095
  * Token expiry skew in milliseconds (5 minutes)
1139
1096
  * Refresh tokens this many milliseconds before they expire
@@ -1151,64 +1108,64 @@ declare const OAUTH_SCOPES: string[];
1151
1108
  */
1152
1109
 
1153
1110
  interface TokenExchangeParams {
1154
- instanceUrl: string;
1155
- clientId?: string;
1156
- redirectUri?: string;
1111
+ instanceUrl: string;
1112
+ clientId?: string;
1113
+ redirectUri?: string;
1157
1114
  }
1158
1115
  interface AuthorizationCodeParams extends TokenExchangeParams {
1159
- code: string;
1160
- codeVerifier: string;
1116
+ code: string;
1117
+ codeVerifier: string;
1161
1118
  }
1162
1119
  interface RefreshTokenParams extends TokenExchangeParams {
1163
- refreshToken: string;
1120
+ refreshToken: string;
1164
1121
  }
1165
1122
  declare class GitLabOAuthManager {
1166
- private fetch;
1167
- constructor(fetchImpl?: typeof fetch);
1168
- /**
1169
- * Check if a token is expired
1170
- */
1171
- isTokenExpired(expiresAt: number): boolean;
1172
- /**
1173
- * Check if a token needs refresh (within skew window)
1174
- */
1175
- needsRefresh(expiresAt: number): boolean;
1176
- /**
1177
- * Refresh tokens if needed
1178
- * Returns the same tokens if refresh is not needed, or new tokens if refreshed
1179
- */
1180
- refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens>;
1181
- /**
1182
- * Exchange authorization code for tokens
1183
- * Based on gitlab-vscode-extension createOAuthAccountFromCode
1184
- */
1185
- exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens>;
1186
- /**
1187
- * Exchange refresh token for new tokens
1188
- * Based on gitlab-vscode-extension TokenExchangeService
1189
- */
1190
- exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens>;
1191
- /**
1192
- * Get the OAuth client ID for an instance.
1193
- * Priority: env var > opencode-gitlab-auth default (for GitLab.com).
1194
- * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId
1195
- * that bypasses this method entirely.
1196
- */
1197
- private getClientId;
1198
- /**
1199
- * Exchange token with GitLab OAuth endpoint
1200
- * Based on gitlab-vscode-extension GitLabService.exchangeToken
1201
- */
1202
- private exchangeToken;
1203
- /**
1204
- * Create GitLabOAuthTokens from token response
1205
- */
1206
- private createTokensFromResponse;
1207
- /**
1208
- * Create expiry timestamp from token response
1209
- * Based on gitlab-vscode-extension createExpiresTimestamp
1210
- */
1211
- private createExpiresTimestamp;
1123
+ private fetch;
1124
+ constructor(fetchImpl?: typeof fetch);
1125
+ /**
1126
+ * Check if a token is expired
1127
+ */
1128
+ isTokenExpired(expiresAt: number): boolean;
1129
+ /**
1130
+ * Check if a token needs refresh (within skew window)
1131
+ */
1132
+ needsRefresh(expiresAt: number): boolean;
1133
+ /**
1134
+ * Refresh tokens if needed
1135
+ * Returns the same tokens if refresh is not needed, or new tokens if refreshed
1136
+ */
1137
+ refreshIfNeeded(tokens: GitLabOAuthTokens, clientId?: string): Promise<GitLabOAuthTokens>;
1138
+ /**
1139
+ * Exchange authorization code for tokens
1140
+ * Based on gitlab-vscode-extension createOAuthAccountFromCode
1141
+ */
1142
+ exchangeAuthorizationCode(params: AuthorizationCodeParams): Promise<GitLabOAuthTokens>;
1143
+ /**
1144
+ * Exchange refresh token for new tokens
1145
+ * Based on gitlab-vscode-extension TokenExchangeService
1146
+ */
1147
+ exchangeRefreshToken(params: RefreshTokenParams): Promise<GitLabOAuthTokens>;
1148
+ /**
1149
+ * Get the OAuth client ID for an instance.
1150
+ * Priority: env var > opencode-gitlab-auth default (for GitLab.com).
1151
+ * Note: callers (e.g. exchangeRefreshToken) may pass an explicit clientId
1152
+ * that bypasses this method entirely.
1153
+ */
1154
+ private getClientId;
1155
+ /**
1156
+ * Exchange token with GitLab OAuth endpoint
1157
+ * Based on gitlab-vscode-extension GitLabService.exchangeToken
1158
+ */
1159
+ private exchangeToken;
1160
+ /**
1161
+ * Create GitLabOAuthTokens from token response
1162
+ */
1163
+ private createTokensFromResponse;
1164
+ /**
1165
+ * Create expiry timestamp from token response
1166
+ * Based on gitlab-vscode-extension createExpiresTimestamp
1167
+ */
1168
+ private createExpiresTimestamp;
1212
1169
  }
1213
1170
 
1214
1171
  /**
@@ -1216,68 +1173,68 @@ declare class GitLabOAuthManager {
1216
1173
  * Used to avoid repeated API calls when detecting projects from git remotes
1217
1174
  */
1218
1175
  interface GitLabProject {
1219
- id: number;
1220
- path: string;
1221
- pathWithNamespace: string;
1222
- name: string;
1223
- namespaceId?: number;
1176
+ id: number;
1177
+ path: string;
1178
+ pathWithNamespace: string;
1179
+ name: string;
1180
+ namespaceId?: number;
1224
1181
  }
1225
1182
  /**
1226
1183
  * In-memory cache for GitLab project information with TTL support
1227
1184
  */
1228
1185
  declare class GitLabProjectCache {
1229
- private cache;
1230
- private defaultTTL;
1231
- /**
1232
- * Create a new project cache
1233
- * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)
1234
- */
1235
- constructor(defaultTTL?: number);
1236
- /**
1237
- * Get a cached project by key
1238
- * @param key - Cache key (typically the working directory path)
1239
- * @returns The cached project or null if not found or expired
1240
- */
1241
- get(key: string): GitLabProject | null;
1242
- /**
1243
- * Store a project in the cache
1244
- * @param key - Cache key (typically the working directory path)
1245
- * @param project - The project to cache
1246
- * @param ttl - Optional custom TTL in milliseconds
1247
- */
1248
- set(key: string, project: GitLabProject, ttl?: number): void;
1249
- /**
1250
- * Check if a key exists in the cache (and is not expired)
1251
- * @param key - Cache key to check
1252
- * @returns true if the key exists and is not expired
1253
- */
1254
- has(key: string): boolean;
1255
- /**
1256
- * Remove a specific entry from the cache
1257
- * @param key - Cache key to remove
1258
- */
1259
- delete(key: string): void;
1260
- /**
1261
- * Clear all entries from the cache
1262
- */
1263
- clear(): void;
1264
- /**
1265
- * Get the number of entries in the cache (including expired ones)
1266
- */
1267
- get size(): number;
1268
- /**
1269
- * Clean up expired entries from the cache
1270
- * This is useful for long-running processes to prevent memory leaks
1271
- */
1272
- cleanup(): void;
1186
+ private cache;
1187
+ private defaultTTL;
1188
+ /**
1189
+ * Create a new project cache
1190
+ * @param defaultTTL - Default time-to-live in milliseconds (default: 5 minutes)
1191
+ */
1192
+ constructor(defaultTTL?: number);
1193
+ /**
1194
+ * Get a cached project by key
1195
+ * @param key - Cache key (typically the working directory path)
1196
+ * @returns The cached project or null if not found or expired
1197
+ */
1198
+ get(key: string): GitLabProject | null;
1199
+ /**
1200
+ * Store a project in the cache
1201
+ * @param key - Cache key (typically the working directory path)
1202
+ * @param project - The project to cache
1203
+ * @param ttl - Optional custom TTL in milliseconds
1204
+ */
1205
+ set(key: string, project: GitLabProject, ttl?: number): void;
1206
+ /**
1207
+ * Check if a key exists in the cache (and is not expired)
1208
+ * @param key - Cache key to check
1209
+ * @returns true if the key exists and is not expired
1210
+ */
1211
+ has(key: string): boolean;
1212
+ /**
1213
+ * Remove a specific entry from the cache
1214
+ * @param key - Cache key to remove
1215
+ */
1216
+ delete(key: string): void;
1217
+ /**
1218
+ * Clear all entries from the cache
1219
+ */
1220
+ clear(): void;
1221
+ /**
1222
+ * Get the number of entries in the cache (including expired ones)
1223
+ */
1224
+ get size(): number;
1225
+ /**
1226
+ * Clean up expired entries from the cache
1227
+ * This is useful for long-running processes to prevent memory leaks
1228
+ */
1229
+ cleanup(): void;
1273
1230
  }
1274
1231
 
1275
1232
  interface GitLabProjectDetectorConfig {
1276
- instanceUrl: string;
1277
- getHeaders: () => Record<string, string>;
1278
- fetch?: typeof fetch;
1279
- cache?: GitLabProjectCache;
1280
- gitTimeout?: number;
1233
+ instanceUrl: string;
1234
+ getHeaders: () => Record<string, string>;
1235
+ fetch?: typeof fetch;
1236
+ cache?: GitLabProjectCache;
1237
+ gitTimeout?: number;
1281
1238
  }
1282
1239
  /**
1283
1240
  * Detects GitLab project information from git remote URLs
@@ -1289,131 +1246,125 @@ interface GitLabProjectDetectorConfig {
1289
1246
  * - Cache project information to avoid repeated API calls
1290
1247
  */
1291
1248
  declare class GitLabProjectDetector {
1292
- private readonly config;
1293
- private readonly fetchFn;
1294
- private readonly cache;
1295
- constructor(config: GitLabProjectDetectorConfig);
1296
- /**
1297
- * Auto-detect GitLab project from git remote in the working directory
1298
- *
1299
- * @param workingDirectory - The directory to check for git remote
1300
- * @param remoteName - The git remote name to use (default: 'origin')
1301
- * @returns The detected project or null if not a git repo / no matching remote
1302
- * @throws GitLabError if the API call or an unexpected error occurs
1303
- */
1304
- detectProject(workingDirectory: string, remoteName?: string): Promise<GitLabProject | null>;
1305
- /**
1306
- * Parse a git remote URL to extract the project path
1307
- *
1308
- * Supports:
1309
- * - SSH: git@gitlab.com:namespace/project.git
1310
- * - HTTPS: https://gitlab.com/namespace/project.git
1311
- * - HTTP: http://gitlab.local/namespace/project.git
1312
- * - Custom domains and ports
1313
- *
1314
- * @param remoteUrl - The git remote URL
1315
- * @param instanceUrl - The GitLab instance URL to match against
1316
- * @returns The project path (e.g., "namespace/project") or null if parsing fails
1317
- */
1318
- parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null;
1319
- /**
1320
- * Get the git remote URL from a working directory
1321
- *
1322
- * @param workingDirectory - The directory to check
1323
- * @param remoteName - The git remote name (default: 'origin')
1324
- * @returns The remote URL or null if not found
1325
- */
1326
- getGitRemoteUrl(workingDirectory: string, remoteName?: string): Promise<string | null>;
1327
- /**
1328
- * Fetch project details from GitLab API by project path
1329
- *
1330
- * @param projectPath - The project path (e.g., "namespace/project")
1331
- * @returns The project details
1332
- * @throws GitLabError if the API call fails
1333
- */
1334
- getProjectByPath(projectPath: string): Promise<GitLabProject>;
1335
- /**
1336
- * Clear the project cache
1337
- */
1338
- clearCache(): void;
1339
- /**
1340
- * Get the cache instance (useful for testing)
1341
- */
1342
- getCache(): GitLabProjectCache;
1249
+ private readonly config;
1250
+ private readonly fetchFn;
1251
+ private readonly cache;
1252
+ constructor(config: GitLabProjectDetectorConfig);
1253
+ /**
1254
+ * Auto-detect GitLab project from git remote in the working directory
1255
+ *
1256
+ * @param workingDirectory - The directory to check for git remote
1257
+ * @param remoteName - The git remote name to use (default: 'origin')
1258
+ * @returns The detected project or null if not a git repo / no matching remote
1259
+ * @throws GitLabError if the API call or an unexpected error occurs
1260
+ */
1261
+ detectProject(workingDirectory: string, remoteName?: string): Promise<GitLabProject | null>;
1262
+ /**
1263
+ * Parse a git remote URL to extract the project path
1264
+ *
1265
+ * Supports:
1266
+ * - SSH: git@gitlab.com:namespace/project.git
1267
+ * - HTTPS: https://gitlab.com/namespace/project.git
1268
+ * - HTTP: http://gitlab.local/namespace/project.git
1269
+ * - Custom domains and ports
1270
+ *
1271
+ * @param remoteUrl - The git remote URL
1272
+ * @param instanceUrl - The GitLab instance URL to match against
1273
+ * @returns The project path (e.g., "namespace/project") or null if parsing fails
1274
+ */
1275
+ parseGitRemoteUrl(remoteUrl: string, instanceUrl: string): string | null;
1276
+ /**
1277
+ * Get the git remote URL from a working directory
1278
+ *
1279
+ * @param workingDirectory - The directory to check
1280
+ * @param remoteName - The git remote name (default: 'origin')
1281
+ * @returns The remote URL or null if not found
1282
+ */
1283
+ getGitRemoteUrl(workingDirectory: string, remoteName?: string): Promise<string | null>;
1284
+ /**
1285
+ * Fetch project details from GitLab API by project path
1286
+ *
1287
+ * @param projectPath - The project path (e.g., "namespace/project")
1288
+ * @returns The project details
1289
+ * @throws GitLabError if the API call fails
1290
+ */
1291
+ getProjectByPath(projectPath: string): Promise<GitLabProject>;
1292
+ /**
1293
+ * Clear the project cache
1294
+ */
1295
+ clearCache(): void;
1296
+ /**
1297
+ * Get the cache instance (useful for testing)
1298
+ */
1299
+ getCache(): GitLabProjectCache;
1343
1300
  }
1344
1301
 
1345
1302
  /**
1346
1303
  * Response from /api/v4/ai/third_party_agents/direct_access
1347
1304
  */
1348
- declare const directAccessTokenSchema: z.ZodObject<
1349
- {
1305
+ declare const directAccessTokenSchema: z.ZodObject<{
1350
1306
  headers: z.ZodRecord<z.ZodString, z.ZodString>;
1351
1307
  token: z.ZodString;
1352
- },
1353
- 'strip',
1354
- z.ZodTypeAny,
1355
- {
1308
+ }, "strip", z.ZodTypeAny, {
1356
1309
  headers?: Record<string, string>;
1357
1310
  token?: string;
1358
- },
1359
- {
1311
+ }, {
1360
1312
  headers?: Record<string, string>;
1361
1313
  token?: string;
1362
- }
1363
- >;
1314
+ }>;
1364
1315
  type DirectAccessToken = z.infer<typeof directAccessTokenSchema>;
1365
- declare const DEFAULT_AI_GATEWAY_URL = 'https://cloud.gitlab.com';
1316
+ declare const DEFAULT_AI_GATEWAY_URL = "https://cloud.gitlab.com";
1366
1317
  interface GitLabDirectAccessConfig {
1367
- instanceUrl: string;
1368
- getHeaders: () => Record<string, string>;
1369
- fetch?: typeof fetch;
1370
- /**
1371
- * Optional callback to refresh the API key when a 401 error occurs.
1372
- * Should clear cached credentials and re-fetch from auth provider.
1373
- */
1374
- refreshApiKey?: () => Promise<void>;
1375
- /**
1376
- * Feature flags to pass to the GitLab API
1377
- */
1378
- featureFlags?: Record<string, boolean>;
1379
- /**
1380
- * AI Gateway URL for the Anthropic proxy.
1381
- * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
1382
- * @default 'https://cloud.gitlab.com'
1383
- */
1384
- aiGatewayUrl?: string;
1318
+ instanceUrl: string;
1319
+ getHeaders: () => Record<string, string>;
1320
+ fetch?: typeof fetch;
1321
+ /**
1322
+ * Optional callback to refresh the API key when a 401 error occurs.
1323
+ * Should clear cached credentials and re-fetch from auth provider.
1324
+ */
1325
+ refreshApiKey?: () => Promise<void>;
1326
+ /**
1327
+ * Feature flags to pass to the GitLab API
1328
+ */
1329
+ featureFlags?: Record<string, boolean>;
1330
+ /**
1331
+ * AI Gateway URL for the Anthropic proxy.
1332
+ * Can also be set via GITLAB_AI_GATEWAY_URL environment variable.
1333
+ * @default 'https://cloud.gitlab.com'
1334
+ */
1335
+ aiGatewayUrl?: string;
1385
1336
  }
1386
1337
  /**
1387
1338
  * Client for GitLab's third-party agents direct access API.
1388
1339
  * This allows routing requests through GitLab's proxy to Anthropic.
1389
1340
  */
1390
1341
  declare class GitLabDirectAccessClient {
1391
- private readonly config;
1392
- private readonly fetchFn;
1393
- private readonly aiGatewayUrl;
1394
- private cachedToken;
1395
- private tokenExpiresAt;
1396
- constructor(config: GitLabDirectAccessConfig);
1397
- /**
1398
- * Get a direct access token for the Anthropic proxy.
1399
- * Tokens are cached for 25 minutes (they expire after 30 minutes).
1400
- * @param forceRefresh - If true, ignores the cache and fetches a new token
1401
- */
1402
- getDirectAccessToken(forceRefresh?: boolean): Promise<DirectAccessToken>;
1403
- /**
1404
- * Get the Anthropic proxy base URL
1405
- */
1406
- getAnthropicProxyUrl(): string;
1407
- /**
1408
- * Get the OpenAI proxy base URL
1409
- * Note: The OpenAI SDK expects a base URL like https://api.openai.com/v1
1410
- * and appends paths like /chat/completions. So we need /v1 at the end.
1411
- */
1412
- getOpenAIProxyUrl(): string;
1413
- /**
1414
- * Invalidate the cached token
1415
- */
1416
- invalidateToken(): void;
1342
+ private readonly config;
1343
+ private readonly fetchFn;
1344
+ private readonly aiGatewayUrl;
1345
+ private cachedToken;
1346
+ private tokenExpiresAt;
1347
+ constructor(config: GitLabDirectAccessConfig);
1348
+ /**
1349
+ * Get a direct access token for the Anthropic proxy.
1350
+ * Tokens are cached for 25 minutes (they expire after 30 minutes).
1351
+ * @param forceRefresh - If true, ignores the cache and fetches a new token
1352
+ */
1353
+ getDirectAccessToken(forceRefresh?: boolean): Promise<DirectAccessToken>;
1354
+ /**
1355
+ * Get the Anthropic proxy base URL
1356
+ */
1357
+ getAnthropicProxyUrl(): string;
1358
+ /**
1359
+ * Get the OpenAI proxy base URL
1360
+ * Note: The OpenAI SDK expects a base URL like https://api.openai.com/v1
1361
+ * and appends paths like /chat/completions. So we need /v1 at the end.
1362
+ */
1363
+ getOpenAIProxyUrl(): string;
1364
+ /**
1365
+ * Invalidate the cached token
1366
+ */
1367
+ invalidateToken(): void;
1417
1368
  }
1418
1369
 
1419
1370
  /**
@@ -1428,77 +1379,77 @@ declare class GitLabDirectAccessClient {
1428
1379
  */
1429
1380
 
1430
1381
  interface WorkflowWebSocketOptions {
1431
- /** GitLab instance URL */
1432
- instanceUrl: string;
1433
- /** Model reference for DWS (e.g. 'anthropic/claude-sonnet-4-5-20250929' or 'default') */
1434
- modelRef: string;
1435
- /** Auth headers — must include Authorization */
1436
- headers: Record<string, string>;
1437
- /** Optional correlation ID */
1438
- requestId?: string;
1439
- /** Optional project context */
1440
- projectId?: string;
1441
- namespaceId?: string;
1442
- rootNamespaceId?: string;
1382
+ /** GitLab instance URL */
1383
+ instanceUrl: string;
1384
+ /** Model reference for DWS (e.g. 'anthropic/claude-sonnet-4-5-20250929' or 'default') */
1385
+ modelRef: string;
1386
+ /** Auth headers — must include Authorization */
1387
+ headers: Record<string, string>;
1388
+ /** Optional correlation ID */
1389
+ requestId?: string;
1390
+ /** Optional project context */
1391
+ projectId?: string;
1392
+ namespaceId?: string;
1393
+ rootNamespaceId?: string;
1443
1394
  }
1444
1395
  type EventCallback = (event: WorkflowClientEvent) => void;
1445
1396
  declare class GitLabWorkflowClient {
1446
- private socket;
1447
- private keepaliveInterval;
1448
- private heartbeatInterval;
1449
- private eventCallback;
1450
- private closed;
1451
- private lastSendTime;
1452
- /**
1453
- * Connect to the DWS WebSocket and start listening for events.
1454
- *
1455
- * @param options - Connection parameters
1456
- * @param onEvent - Callback invoked for each WorkflowClientEvent
1457
- * @returns Promise that resolves when the connection is open
1458
- */
1459
- connect(options: WorkflowWebSocketOptions, onEvent: EventCallback): Promise<void>;
1460
- /**
1461
- * Send a startRequest to begin the workflow.
1462
- */
1463
- sendStartRequest(request: StartRequest): void;
1464
- /**
1465
- * Send an actionResponse (tool result) back to DWS.
1466
- */
1467
- sendActionResponse(requestID: string, response: string, error?: string | null): void;
1468
- /**
1469
- * Stop the workflow gracefully.
1470
- */
1471
- stop(): void;
1472
- /**
1473
- * Close the WebSocket connection.
1474
- */
1475
- close(): void;
1476
- /**
1477
- * Check if the WebSocket is currently connected.
1478
- */
1479
- get isConnected(): boolean;
1480
- private validateOptions;
1481
- private buildWebSocketUrl;
1482
- private buildWebSocketHeaders;
1483
- private handleAction;
1484
- private send;
1485
- private sendHeartbeatIfNeeded;
1486
- private emit;
1487
- /**
1488
- * Start ws.ping() keepalive (45s interval).
1489
- * Keeps TCP connection alive through proxies/load balancers.
1490
- */
1491
- private startKeepalive;
1492
- /**
1493
- * Start application-level heartbeat (60s interval).
1494
- * Prevents DWS from timing out the workflow.
1495
- */
1496
- private startHeartbeat;
1497
- private cleanedUp;
1498
- /**
1499
- * Clean up intervals. Idempotent — safe to call multiple times.
1500
- */
1501
- private cleanup;
1397
+ private socket;
1398
+ private keepaliveInterval;
1399
+ private heartbeatInterval;
1400
+ private eventCallback;
1401
+ private closed;
1402
+ private lastSendTime;
1403
+ /**
1404
+ * Connect to the DWS WebSocket and start listening for events.
1405
+ *
1406
+ * @param options - Connection parameters
1407
+ * @param onEvent - Callback invoked for each WorkflowClientEvent
1408
+ * @returns Promise that resolves when the connection is open
1409
+ */
1410
+ connect(options: WorkflowWebSocketOptions, onEvent: EventCallback): Promise<void>;
1411
+ /**
1412
+ * Send a startRequest to begin the workflow.
1413
+ */
1414
+ sendStartRequest(request: StartRequest): void;
1415
+ /**
1416
+ * Send an actionResponse (tool result) back to DWS.
1417
+ */
1418
+ sendActionResponse(requestID: string, response: string, error?: string | null): void;
1419
+ /**
1420
+ * Stop the workflow gracefully.
1421
+ */
1422
+ stop(): void;
1423
+ /**
1424
+ * Close the WebSocket connection.
1425
+ */
1426
+ close(): void;
1427
+ /**
1428
+ * Check if the WebSocket is currently connected.
1429
+ */
1430
+ get isConnected(): boolean;
1431
+ private validateOptions;
1432
+ private buildWebSocketUrl;
1433
+ private buildWebSocketHeaders;
1434
+ private handleAction;
1435
+ private send;
1436
+ private sendHeartbeatIfNeeded;
1437
+ private emit;
1438
+ /**
1439
+ * Start ws.ping() keepalive (45s interval).
1440
+ * Keeps TCP connection alive through proxies/load balancers.
1441
+ */
1442
+ private startKeepalive;
1443
+ /**
1444
+ * Start application-level heartbeat (60s interval).
1445
+ * Prevents DWS from timing out the workflow.
1446
+ */
1447
+ private startHeartbeat;
1448
+ private cleanedUp;
1449
+ /**
1450
+ * Clean up intervals. Idempotent — safe to call multiple times.
1451
+ */
1452
+ private cleanup;
1502
1453
  }
1503
1454
 
1504
1455
  /**
@@ -1514,145 +1465,110 @@ declare class GitLabWorkflowClient {
1514
1465
  */
1515
1466
 
1516
1467
  declare class GitLabWorkflowTokenClient {
1517
- private readonly config;
1518
- private readonly fetchFn;
1519
- /**
1520
- * Token cache keyed by workflow definition type.
1521
- *
1522
- * - CHAT workflows use a shared key (CHAT_SHARED_TOKEN_KEY) so tokens
1523
- * are reused across ALL chat sessions (matching gitlab-lsp behavior).
1524
- * - SOFTWARE_DEVELOPMENT workflows would use per-workflow-id keys,
1525
- * but since we fetch tokens before creating workflows, we key by type.
1526
- */
1527
- private tokenCache;
1528
- constructor(config: GitLabWorkflowClientConfig);
1529
- /**
1530
- * Resolve the cache key for a given workflow definition.
1531
- * CHAT workflows share a single token per namespace; other types get per-type keys.
1532
- */
1533
- private getCacheKey;
1534
- /**
1535
- * Get a DWS token, using cached value if still valid.
1536
- *
1537
- * Token caching strategy (matches gitlab-lsp):
1538
- * - CHAT workflows: shared token across all sessions
1539
- * - Other workflows: per-type token
1540
- *
1541
- * @param workflowDefinition - Workflow type (default: 'chat')
1542
- * @param rootNamespaceId - Optional root namespace for scoping
1543
- * @param forceRefresh - Bypass cache
1544
- */
1545
- getToken(
1546
- workflowDefinition?: string,
1547
- rootNamespaceId?: string,
1548
- forceRefresh?: boolean
1549
- ): Promise<GenerateTokenResponse>;
1550
- /**
1551
- * Create a new workflow on the GitLab instance.
1552
- *
1553
- * @param goal - The user's message / goal for this workflow
1554
- * @param options - Additional workflow creation options
1555
- * @returns The created workflow's ID
1556
- */
1557
- createWorkflow(
1558
- goal: string,
1559
- options?: {
1560
- projectId?: string;
1561
- namespaceId?: string;
1562
- workflowDefinition?: string;
1563
- agentPrivileges?: number[];
1564
- environment?: string;
1565
- allowAgentToRequestUser?: boolean;
1566
- }
1567
- ): Promise<string>;
1568
- /**
1569
- * Invalidate cached tokens.
1570
- *
1571
- * @param workflowDefinition - If provided, only invalidate for this type.
1572
- * If omitted, clears ALL cached tokens.
1573
- */
1574
- invalidateToken(workflowDefinition?: string, rootNamespaceId?: string): void;
1468
+ private readonly config;
1469
+ private readonly fetchFn;
1470
+ /**
1471
+ * Token cache keyed by workflow definition type.
1472
+ *
1473
+ * - CHAT workflows use a shared key (CHAT_SHARED_TOKEN_KEY) so tokens
1474
+ * are reused across ALL chat sessions (matching gitlab-lsp behavior).
1475
+ * - SOFTWARE_DEVELOPMENT workflows would use per-workflow-id keys,
1476
+ * but since we fetch tokens before creating workflows, we key by type.
1477
+ */
1478
+ private tokenCache;
1479
+ constructor(config: GitLabWorkflowClientConfig);
1480
+ /**
1481
+ * Resolve the cache key for a given workflow definition.
1482
+ * CHAT workflows share a single token per namespace; other types get per-type keys.
1483
+ */
1484
+ private getCacheKey;
1485
+ /**
1486
+ * Get a DWS token, using cached value if still valid.
1487
+ *
1488
+ * Token caching strategy (matches gitlab-lsp):
1489
+ * - CHAT workflows: shared token across all sessions
1490
+ * - Other workflows: per-type token
1491
+ *
1492
+ * @param workflowDefinition - Workflow type (default: 'chat')
1493
+ * @param rootNamespaceId - Optional root namespace for scoping
1494
+ * @param forceRefresh - Bypass cache
1495
+ */
1496
+ getToken(workflowDefinition?: string, rootNamespaceId?: string, forceRefresh?: boolean): Promise<GenerateTokenResponse>;
1497
+ /**
1498
+ * Create a new workflow on the GitLab instance.
1499
+ *
1500
+ * @param goal - The user's message / goal for this workflow
1501
+ * @param options - Additional workflow creation options
1502
+ * @returns The created workflow's ID
1503
+ */
1504
+ createWorkflow(goal: string, options?: {
1505
+ projectId?: string;
1506
+ namespaceId?: string;
1507
+ workflowDefinition?: string;
1508
+ agentPrivileges?: number[];
1509
+ environment?: string;
1510
+ allowAgentToRequestUser?: boolean;
1511
+ }): Promise<string>;
1512
+ /**
1513
+ * Invalidate cached tokens.
1514
+ *
1515
+ * @param workflowDefinition - If provided, only invalidate for this type.
1516
+ * If omitted, clears ALL cached tokens.
1517
+ */
1518
+ invalidateToken(workflowDefinition?: string, rootNamespaceId?: string): void;
1575
1519
  }
1576
1520
 
1577
- export {
1578
- AGENT_PRIVILEGES,
1579
- type ActionResponsePayload,
1580
- type AdditionalContext,
1581
- type AiChatAvailableModels,
1582
- type AiModel,
1583
- BUNDLED_CLIENT_ID,
1584
- CLIENT_VERSION,
1585
- type ClientEvent,
1586
- DEFAULT_AGENT_PRIVILEGES,
1587
- DEFAULT_AI_GATEWAY_URL,
1588
- DEFAULT_CLIENT_CAPABILITIES,
1589
- DEFAULT_WORKFLOW_DEFINITION,
1590
- type DirectAccessToken,
1591
- type DiscoveredModels,
1592
- GITLAB_COM_URL,
1593
- type GenerateTokenResponse,
1594
- type GitLabAgenticOptions,
1595
- type GitLabAnthropicConfig,
1596
- GitLabAnthropicLanguageModel,
1597
- GitLabDirectAccessClient,
1598
- type GitLabDirectAccessConfig,
1599
- GitLabError,
1600
- type GitLabErrorOptions,
1601
- GitLabModelCache,
1602
- GitLabModelDiscovery,
1603
- GitLabOAuthManager,
1604
- type GitLabOAuthTokenResponse,
1605
- type GitLabOAuthTokens,
1606
- type GitLabOpenAIConfig,
1607
- GitLabOpenAILanguageModel,
1608
- type GitLabProject,
1609
- GitLabProjectCache,
1610
- GitLabProjectDetector,
1611
- type GitLabProjectDetectorConfig,
1612
- type GitLabProvider,
1613
- type GitLabProviderSettings,
1614
- GitLabWorkflowClient,
1615
- type GitLabWorkflowClientConfig,
1616
- GitLabWorkflowLanguageModel,
1617
- type GitLabWorkflowLanguageModelConfig,
1618
- type GitLabWorkflowOptions,
1619
- GitLabWorkflowTokenClient,
1620
- MODEL_ID_TO_ANTHROPIC_MODEL,
1621
- MODEL_MAPPINGS,
1622
- type McpToolDefinition,
1623
- type ModelCacheEntry,
1624
- type ModelDiscoveryConfig,
1625
- type ModelMapping,
1626
- type ModelProvider,
1627
- type NewCheckpoint,
1628
- OAUTH_SCOPES,
1629
- OPENCODE_GITLAB_AUTH_CLIENT_ID,
1630
- type OpenAIApiType,
1631
- type OpenCodeAuth,
1632
- type OpenCodeAuthApi,
1633
- type OpenCodeAuthOAuth,
1634
- type RunMcpTool,
1635
- type StartRequest,
1636
- TOKEN_EXPIRY_SKEW_MS,
1637
- VERSION,
1638
- WORKFLOW_ENVIRONMENT,
1639
- WS_HEARTBEAT_INTERVAL_MS,
1640
- WS_KEEPALIVE_PING_INTERVAL_MS,
1641
- type WorkflowAction,
1642
- type WorkflowClientEvent,
1643
- type WorkflowStatus,
1644
- type WorkflowToolExecutor,
1645
- WorkflowType,
1646
- type WorkflowWebSocketOptions,
1647
- createGitLab,
1648
- getAnthropicModelForModelId,
1649
- getModelMapping,
1650
- getOpenAIApiType,
1651
- getOpenAIModelForModelId,
1652
- getProviderForModelId,
1653
- getValidModelsForProvider,
1654
- getWorkflowModelRef,
1655
- gitlab,
1656
- isResponsesApiModel,
1657
- isWorkflowModel,
1658
- };
1521
+ /**
1522
+ * Fetches and caches model configuration from the GitLab AI Gateway's
1523
+ * models.yml definition file. Provides per-model context window and
1524
+ * output token limits keyed by `gitlab_identifier`.
1525
+ *
1526
+ * Results are cached both in memory and on disk at
1527
+ * `~/.cache/opencode/gitlab-model-configs.json`
1528
+ * (or `$XDG_CACHE_HOME/opencode/...` when set).
1529
+ *
1530
+ * @see https://gitlab.com/gitlab-org/modelops/applied-ml/code-suggestions/ai-assist/-/blob/main/ai_gateway/model_selection/models.yml
1531
+ */
1532
+ interface ModelConfig {
1533
+ /** Maximum input context tokens */
1534
+ context: number;
1535
+ /** Maximum output tokens (from params.max_tokens) */
1536
+ output: number;
1537
+ }
1538
+ interface ModelConfigRegistryOptions {
1539
+ /** Override the URL to fetch models.yml from */
1540
+ url?: string;
1541
+ /** Cache TTL in milliseconds (default: 24 hours) */
1542
+ ttlMs?: number;
1543
+ /** Custom fetch implementation */
1544
+ fetch?: typeof fetch;
1545
+ }
1546
+ declare class GitLabModelConfigRegistry {
1547
+ private readonly url;
1548
+ private readonly ttlMs;
1549
+ private readonly fetchFn;
1550
+ private memCache;
1551
+ private memExpiresAt;
1552
+ private pending;
1553
+ constructor(options?: ModelConfigRegistryOptions);
1554
+ /**
1555
+ * Get model configs, fetching and caching as needed.
1556
+ * Returns a Map keyed by `gitlab_identifier` (the discovery `ref`).
1557
+ */
1558
+ getConfigs(): Promise<Map<string, ModelConfig>>;
1559
+ /**
1560
+ * Look up config for a single model ref.
1561
+ * Returns defaults if the ref is not found or fetch fails.
1562
+ */
1563
+ getConfig(ref: string): Promise<ModelConfig>;
1564
+ /** Invalidate both in-memory and file caches. */
1565
+ invalidateCache(): void;
1566
+ private fetchConfigs;
1567
+ }
1568
+ /**
1569
+ * Parse models.yml to extract gitlab_identifier → { context, output } mapping.
1570
+ * Uses simple line-by-line parsing to avoid a YAML dependency.
1571
+ */
1572
+ declare function parseModelsYml(text: string): Map<string, ModelConfig>;
1573
+
1574
+ export { AGENT_PRIVILEGES, type ActionResponsePayload, type AdditionalContext, type AiChatAvailableModels, type AiModel, BUNDLED_CLIENT_ID, CLIENT_VERSION, type ClientEvent, DEFAULT_AGENT_PRIVILEGES, DEFAULT_AI_GATEWAY_URL, DEFAULT_CLIENT_CAPABILITIES, DEFAULT_WORKFLOW_DEFINITION, type DirectAccessToken, type DiscoveredModels, GITLAB_COM_URL, type GenerateTokenResponse, type GitLabAgenticOptions, type GitLabAnthropicConfig, GitLabAnthropicLanguageModel, GitLabDirectAccessClient, type GitLabDirectAccessConfig, GitLabError, type GitLabErrorOptions, GitLabModelCache, GitLabModelConfigRegistry, GitLabModelDiscovery, GitLabOAuthManager, type GitLabOAuthTokenResponse, type GitLabOAuthTokens, type GitLabOpenAIConfig, GitLabOpenAILanguageModel, type GitLabProject, GitLabProjectCache, GitLabProjectDetector, type GitLabProjectDetectorConfig, type GitLabProvider, type GitLabProviderSettings, GitLabWorkflowClient, type GitLabWorkflowClientConfig, GitLabWorkflowLanguageModel, type GitLabWorkflowLanguageModelConfig, type GitLabWorkflowOptions, GitLabWorkflowTokenClient, MODEL_ID_TO_ANTHROPIC_MODEL, MODEL_MAPPINGS, type McpToolDefinition, type ModelCacheEntry, type ModelConfig, type ModelConfigRegistryOptions, type ModelDiscoveryConfig, type ModelMapping, type ModelProvider, type NewCheckpoint, OAUTH_SCOPES, OPENCODE_GITLAB_AUTH_CLIENT_ID, type OpenAIApiType, type OpenCodeAuth, type OpenCodeAuthApi, type OpenCodeAuthOAuth, type RunMcpTool, type StartRequest, TOKEN_EXPIRY_SKEW_MS, VERSION, WORKFLOW_ENVIRONMENT, WS_HEARTBEAT_INTERVAL_MS, WS_KEEPALIVE_PING_INTERVAL_MS, type WorkflowAction, type WorkflowClientEvent, type WorkflowStatus, type WorkflowToolExecutor, WorkflowType, type WorkflowWebSocketOptions, createGitLab, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, getWorkflowModelRef, gitlab, isResponsesApiModel, isWorkflowModel, parseModelsYml };