gitlab-ai-provider 6.0.0 → 6.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,21 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
4
4
 
5
+ ## <small>6.1.1 (2026-03-29)</small>
6
+
7
+ - fix: update dist ([9f4b816](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/9f4b816))
8
+
9
+ ## 6.1.0 (2026-03-29)
10
+
11
+ - fix(approval): defer stream close while approval is pending and send rejection to DWS ([9344828](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/9344828))
12
+ - feat(client): emit approval-required event for TOOL_CALL_APPROVAL_REQUIRED checkpoints ([500eff1](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/500eff1))
13
+ - feat(model): add approveAndResume, sessionPreapprovedTools, processedRequestIDs dedup ([f543831](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/f543831))
14
+ - feat(model): add public approvalHandler getter/setter for external wiring ([ee075b9](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/ee075b9))
15
+ - feat(options): add agentPrivileges to GitLabWorkflowOptions for testing approval flow ([475f2c7](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/475f2c7))
16
+ - feat(types): add ApprovalDecision, approval on StartRequest, approval-required event ([9a4ccf4](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/9a4ccf4))
17
+ - chore: rebuild dist with approval integration changes ([d66deb9](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/d66deb9))
18
+ - chore: rebuild dist with approval integration changes ([daacc33](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/daacc33))
19
+
5
20
  ## 6.0.0 (2026-03-26)
6
21
 
7
22
  - feat!: migrate to AI SDK v6 (LanguageModelV3) ([21c1165](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/21c1165))
package/dist/index.d.mts CHANGED
@@ -346,6 +346,17 @@ interface StartRequest {
346
346
  preapproved_tools?: string[];
347
347
  flowConfig?: unknown;
348
348
  flowConfigSchemaVersion?: string;
349
+ approval?: ApprovalDecision;
350
+ }
351
+ interface ApprovalDecision {
352
+ approval?: {
353
+ remember_approval?: boolean;
354
+ tool_name?: string;
355
+ tool_args_json?: string;
356
+ };
357
+ rejection?: {
358
+ message?: string;
359
+ };
349
360
  }
350
361
  interface ActionResponsePayload {
351
362
  requestID: string;
@@ -551,6 +562,25 @@ interface GitLabWorkflowOptions {
551
562
  * @returns The selected model ref, or null/undefined for default
552
563
  */
553
564
  onSelectModel?: (models: AiModel[]) => Promise<string | null | undefined>;
565
+ /**
566
+ * Agent privileges to request when creating the workflow.
567
+ * Defaults to DEFAULT_AGENT_PRIVILEGES (all privileges).
568
+ * Pass a subset to restrict which tools DWS pre-approves server-side,
569
+ * causing TOOL_CALL_APPROVAL_REQUIRED for excluded privileges.
570
+ */
571
+ agentPrivileges?: number[];
572
+ /**
573
+ * Called when DWS requires approval for a tool call.
574
+ * Return `{ approved: true }` to proceed or `{ approved: false, message? }` to reject.
575
+ * If not set, the stream ends silently when approval is required (backward compat).
576
+ */
577
+ approvalHandler?: (tools: Array<{
578
+ name: string;
579
+ args: string;
580
+ }>) => Promise<{
581
+ approved: boolean;
582
+ message?: string;
583
+ }>;
554
584
  }
555
585
  interface GitLabWorkflowClientConfig {
556
586
  /** GitLab instance URL (e.g., 'https://gitlab.com') */
@@ -584,6 +614,12 @@ type WorkflowClientEvent = {
584
614
  requestID: string;
585
615
  toolName: string;
586
616
  data: Record<string, unknown>;
617
+ } | {
618
+ type: 'approval-required';
619
+ tools: Array<{
620
+ name: string;
621
+ args: string;
622
+ }>;
587
623
  } | {
588
624
  type: 'completed';
589
625
  } | {
@@ -713,6 +749,31 @@ declare class GitLabWorkflowLanguageModel implements LanguageModelV3 {
713
749
  inputTokens: number;
714
750
  outputTokens: number;
715
751
  }) => void) | null;
752
+ /**
753
+ * Tool names pre-approved for the current session.
754
+ * Set by the host (e.g., opencode) and merged into preapproved_tools on each StartRequest.
755
+ * Updated when the user chooses "always" in the approval prompt.
756
+ */
757
+ sessionPreapprovedTools: string[];
758
+ /**
759
+ * Set the approval handler callback.
760
+ * Called when DWS requires tool call approval. Host (e.g., opencode) wires this
761
+ * to its permission system each stream call, similar to toolExecutor.
762
+ */
763
+ set approvalHandler(handler: ((tools: Array<{
764
+ name: string;
765
+ args: string;
766
+ }>) => Promise<{
767
+ approved: boolean;
768
+ message?: string;
769
+ }>) | null);
770
+ get approvalHandler(): ((tools: Array<{
771
+ name: string;
772
+ args: string;
773
+ }>) => Promise<{
774
+ approved: boolean;
775
+ message?: string;
776
+ }>) | null;
716
777
  /**
717
778
  * Optional callback invoked when multiple workflow models are available
718
779
  * and the user should pick one. Set per-stream by the host (e.g., OpenCode)
@@ -795,6 +856,7 @@ declare class GitLabWorkflowLanguageModel implements LanguageModelV3 {
795
856
  private processCheckpoint;
796
857
  private executeToolAndRespond;
797
858
  private cleanupClient;
859
+ private approveAndResume;
798
860
  private buildWorkflowMetadata;
799
861
  private getGitInfo;
800
862
  /**
@@ -1444,6 +1506,7 @@ declare class GitLabWorkflowClient {
1444
1506
  private buildWebSocketUrl;
1445
1507
  private buildWebSocketHeaders;
1446
1508
  private handleAction;
1509
+ private extractApprovalTools;
1447
1510
  private send;
1448
1511
  private sendHeartbeatIfNeeded;
1449
1512
  private emit;
@@ -1620,4 +1683,4 @@ interface WorkflowDiscoveryResult {
1620
1683
  }
1621
1684
  declare function discoverWorkflowModels(config: WorkflowDiscoveryConfig, options: WorkflowDiscoveryOptions): Promise<WorkflowDiscoveryResult>;
1622
1685
 
1623
- 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, type DiscoveredWorkflowModel, 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 WorkflowDiscoveryConfig, type WorkflowDiscoveryOptions, type WorkflowDiscoveryResult, type WorkflowStatus, type WorkflowToolExecutor, WorkflowType, type WorkflowWebSocketOptions, createGitLab, discoverWorkflowModels, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, getWorkflowModelRef, gitlab, isResponsesApiModel, isWorkflowModel, parseModelsYml };
1686
+ export { AGENT_PRIVILEGES, type ActionResponsePayload, type AdditionalContext, type AiChatAvailableModels, type AiModel, type ApprovalDecision, BUNDLED_CLIENT_ID, CLIENT_VERSION, type ClientEvent, DEFAULT_AGENT_PRIVILEGES, DEFAULT_AI_GATEWAY_URL, DEFAULT_CLIENT_CAPABILITIES, DEFAULT_WORKFLOW_DEFINITION, type DirectAccessToken, type DiscoveredModels, type DiscoveredWorkflowModel, 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 WorkflowDiscoveryConfig, type WorkflowDiscoveryOptions, type WorkflowDiscoveryResult, type WorkflowStatus, type WorkflowToolExecutor, WorkflowType, type WorkflowWebSocketOptions, createGitLab, discoverWorkflowModels, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, getWorkflowModelRef, gitlab, isResponsesApiModel, isWorkflowModel, parseModelsYml };
package/dist/index.d.ts CHANGED
@@ -346,6 +346,17 @@ interface StartRequest {
346
346
  preapproved_tools?: string[];
347
347
  flowConfig?: unknown;
348
348
  flowConfigSchemaVersion?: string;
349
+ approval?: ApprovalDecision;
350
+ }
351
+ interface ApprovalDecision {
352
+ approval?: {
353
+ remember_approval?: boolean;
354
+ tool_name?: string;
355
+ tool_args_json?: string;
356
+ };
357
+ rejection?: {
358
+ message?: string;
359
+ };
349
360
  }
350
361
  interface ActionResponsePayload {
351
362
  requestID: string;
@@ -551,6 +562,25 @@ interface GitLabWorkflowOptions {
551
562
  * @returns The selected model ref, or null/undefined for default
552
563
  */
553
564
  onSelectModel?: (models: AiModel[]) => Promise<string | null | undefined>;
565
+ /**
566
+ * Agent privileges to request when creating the workflow.
567
+ * Defaults to DEFAULT_AGENT_PRIVILEGES (all privileges).
568
+ * Pass a subset to restrict which tools DWS pre-approves server-side,
569
+ * causing TOOL_CALL_APPROVAL_REQUIRED for excluded privileges.
570
+ */
571
+ agentPrivileges?: number[];
572
+ /**
573
+ * Called when DWS requires approval for a tool call.
574
+ * Return `{ approved: true }` to proceed or `{ approved: false, message? }` to reject.
575
+ * If not set, the stream ends silently when approval is required (backward compat).
576
+ */
577
+ approvalHandler?: (tools: Array<{
578
+ name: string;
579
+ args: string;
580
+ }>) => Promise<{
581
+ approved: boolean;
582
+ message?: string;
583
+ }>;
554
584
  }
555
585
  interface GitLabWorkflowClientConfig {
556
586
  /** GitLab instance URL (e.g., 'https://gitlab.com') */
@@ -584,6 +614,12 @@ type WorkflowClientEvent = {
584
614
  requestID: string;
585
615
  toolName: string;
586
616
  data: Record<string, unknown>;
617
+ } | {
618
+ type: 'approval-required';
619
+ tools: Array<{
620
+ name: string;
621
+ args: string;
622
+ }>;
587
623
  } | {
588
624
  type: 'completed';
589
625
  } | {
@@ -713,6 +749,31 @@ declare class GitLabWorkflowLanguageModel implements LanguageModelV3 {
713
749
  inputTokens: number;
714
750
  outputTokens: number;
715
751
  }) => void) | null;
752
+ /**
753
+ * Tool names pre-approved for the current session.
754
+ * Set by the host (e.g., opencode) and merged into preapproved_tools on each StartRequest.
755
+ * Updated when the user chooses "always" in the approval prompt.
756
+ */
757
+ sessionPreapprovedTools: string[];
758
+ /**
759
+ * Set the approval handler callback.
760
+ * Called when DWS requires tool call approval. Host (e.g., opencode) wires this
761
+ * to its permission system each stream call, similar to toolExecutor.
762
+ */
763
+ set approvalHandler(handler: ((tools: Array<{
764
+ name: string;
765
+ args: string;
766
+ }>) => Promise<{
767
+ approved: boolean;
768
+ message?: string;
769
+ }>) | null);
770
+ get approvalHandler(): ((tools: Array<{
771
+ name: string;
772
+ args: string;
773
+ }>) => Promise<{
774
+ approved: boolean;
775
+ message?: string;
776
+ }>) | null;
716
777
  /**
717
778
  * Optional callback invoked when multiple workflow models are available
718
779
  * and the user should pick one. Set per-stream by the host (e.g., OpenCode)
@@ -795,6 +856,7 @@ declare class GitLabWorkflowLanguageModel implements LanguageModelV3 {
795
856
  private processCheckpoint;
796
857
  private executeToolAndRespond;
797
858
  private cleanupClient;
859
+ private approveAndResume;
798
860
  private buildWorkflowMetadata;
799
861
  private getGitInfo;
800
862
  /**
@@ -1444,6 +1506,7 @@ declare class GitLabWorkflowClient {
1444
1506
  private buildWebSocketUrl;
1445
1507
  private buildWebSocketHeaders;
1446
1508
  private handleAction;
1509
+ private extractApprovalTools;
1447
1510
  private send;
1448
1511
  private sendHeartbeatIfNeeded;
1449
1512
  private emit;
@@ -1620,4 +1683,4 @@ interface WorkflowDiscoveryResult {
1620
1683
  }
1621
1684
  declare function discoverWorkflowModels(config: WorkflowDiscoveryConfig, options: WorkflowDiscoveryOptions): Promise<WorkflowDiscoveryResult>;
1622
1685
 
1623
- 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, type DiscoveredWorkflowModel, 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 WorkflowDiscoveryConfig, type WorkflowDiscoveryOptions, type WorkflowDiscoveryResult, type WorkflowStatus, type WorkflowToolExecutor, WorkflowType, type WorkflowWebSocketOptions, createGitLab, discoverWorkflowModels, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, getWorkflowModelRef, gitlab, isResponsesApiModel, isWorkflowModel, parseModelsYml };
1686
+ export { AGENT_PRIVILEGES, type ActionResponsePayload, type AdditionalContext, type AiChatAvailableModels, type AiModel, type ApprovalDecision, BUNDLED_CLIENT_ID, CLIENT_VERSION, type ClientEvent, DEFAULT_AGENT_PRIVILEGES, DEFAULT_AI_GATEWAY_URL, DEFAULT_CLIENT_CAPABILITIES, DEFAULT_WORKFLOW_DEFINITION, type DirectAccessToken, type DiscoveredModels, type DiscoveredWorkflowModel, 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 WorkflowDiscoveryConfig, type WorkflowDiscoveryOptions, type WorkflowDiscoveryResult, type WorkflowStatus, type WorkflowToolExecutor, WorkflowType, type WorkflowWebSocketOptions, createGitLab, discoverWorkflowModels, getAnthropicModelForModelId, getModelMapping, getOpenAIApiType, getOpenAIModelForModelId, getProviderForModelId, getValidModelsForProvider, getWorkflowModelRef, gitlab, isResponsesApiModel, isWorkflowModel, parseModelsYml };
package/dist/index.js CHANGED
@@ -1653,7 +1653,7 @@ var GitLabOpenAILanguageModel = class {
1653
1653
  var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
1654
1654
 
1655
1655
  // src/version.ts
1656
- var VERSION = true ? "5.3.3" : "0.0.0-dev";
1656
+ var VERSION = true ? "6.1.0" : "0.0.0-dev";
1657
1657
 
1658
1658
  // src/gitlab-workflow-types.ts
1659
1659
  var WorkflowType = /* @__PURE__ */ ((WorkflowType2) => {
@@ -1879,7 +1879,9 @@ var GitLabWorkflowClient = class {
1879
1879
  });
1880
1880
  } else if (checkpoint.status === "STOPPED" || checkpoint.status === "CANCELLED") {
1881
1881
  this.emit({ type: "completed" });
1882
- } else if (checkpoint.status === "TOOL_CALL_APPROVAL_REQUIRED" || checkpoint.status === "PLAN_APPROVAL_REQUIRED") {
1882
+ } else if (checkpoint.status === "TOOL_CALL_APPROVAL_REQUIRED") {
1883
+ this.emit({ type: "approval-required", tools: this.extractApprovalTools(checkpoint) });
1884
+ } else if (checkpoint.status === "PLAN_APPROVAL_REQUIRED") {
1883
1885
  this.emit({ type: "completed" });
1884
1886
  }
1885
1887
  return;
@@ -1918,6 +1920,18 @@ var GitLabWorkflowClient = class {
1918
1920
  }
1919
1921
  }
1920
1922
  }
1923
+ extractApprovalTools(checkpoint) {
1924
+ if (!checkpoint.checkpoint) return [];
1925
+ let parsed;
1926
+ try {
1927
+ parsed = JSON.parse(checkpoint.checkpoint);
1928
+ } catch {
1929
+ return [];
1930
+ }
1931
+ return (parsed.channel_values?.ui_chat_log ?? []).filter(
1932
+ (e) => e.message_type === "request" && e.tool_info !== null
1933
+ ).map((e) => ({ name: e.tool_info.name, args: JSON.stringify(e.tool_info.args) }));
1934
+ }
1921
1935
  send(event) {
1922
1936
  if (this.socket?.readyState === import_isomorphic_ws.default.OPEN) {
1923
1937
  const json = JSON.stringify(event);
@@ -3089,6 +3103,23 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3089
3103
  * the AI SDK only surfaces usage via finish-step at stream end.
3090
3104
  */
3091
3105
  onUsageUpdate = null;
3106
+ /**
3107
+ * Tool names pre-approved for the current session.
3108
+ * Set by the host (e.g., opencode) and merged into preapproved_tools on each StartRequest.
3109
+ * Updated when the user chooses "always" in the approval prompt.
3110
+ */
3111
+ sessionPreapprovedTools = [];
3112
+ /**
3113
+ * Set the approval handler callback.
3114
+ * Called when DWS requires tool call approval. Host (e.g., opencode) wires this
3115
+ * to its permission system each stream call, similar to toolExecutor.
3116
+ */
3117
+ set approvalHandler(handler) {
3118
+ this.workflowOptions.approvalHandler = handler ?? void 0;
3119
+ }
3120
+ get approvalHandler() {
3121
+ return this.workflowOptions.approvalHandler ?? null;
3122
+ }
3092
3123
  /**
3093
3124
  * Optional callback invoked when multiple workflow models are available
3094
3125
  * and the user should pick one. Set per-stream by the host (e.g., OpenCode)
@@ -3390,7 +3421,10 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3390
3421
  const goal = this.extractGoalFromPrompt(options.prompt);
3391
3422
  const modelRef = await this.resolveModelRef();
3392
3423
  const mcpTools = this.extractMcpTools(options);
3393
- const preapprovedTools = this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name);
3424
+ const preapprovedTools = [
3425
+ ...this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name),
3426
+ ...this.sessionPreapprovedTools
3427
+ ];
3394
3428
  const additionalContext = this.buildAdditionalContext(options.prompt);
3395
3429
  const toolExecutor = this.toolExecutor ?? null;
3396
3430
  const availableToolNames = new Set(options.tools?.map((t) => t.name) ?? []);
@@ -3406,7 +3440,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3406
3440
  workflowId = await this.tokenClient.createWorkflow(goal, {
3407
3441
  projectId,
3408
3442
  namespaceId: this.workflowOptions.namespaceId,
3409
- workflowDefinition: this.workflowOptions.workflowDefinition
3443
+ workflowDefinition: this.workflowOptions.workflowDefinition,
3444
+ agentPrivileges: this.workflowOptions.agentPrivileges
3410
3445
  });
3411
3446
  this.currentWorkflowId = workflowId;
3412
3447
  }
@@ -3418,11 +3453,13 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3418
3453
  streamedInputChars: 0,
3419
3454
  streamedOutputChars: 0,
3420
3455
  pendingToolCount: 0,
3456
+ approvalPending: false,
3421
3457
  deferredClose: null,
3422
3458
  activeTextBlockId: null,
3423
3459
  agentMessageEmitted: new Map(this.persistedAgentEmitted),
3424
3460
  currentAgentMessageId: "",
3425
- activeClient: wsClient
3461
+ activeClient: wsClient,
3462
+ processedRequestIDs: /* @__PURE__ */ new Set()
3426
3463
  };
3427
3464
  for (const msg of options.prompt) {
3428
3465
  if (msg.role === "system") {
@@ -3435,6 +3472,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3435
3472
  }
3436
3473
  }
3437
3474
  }
3475
+ let startReq;
3438
3476
  const stream = new ReadableStream({
3439
3477
  start: async (controller) => {
3440
3478
  try {
@@ -3455,7 +3493,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3455
3493
  wsClient,
3456
3494
  toolExecutor,
3457
3495
  () => `text-${textBlockCounter++}`,
3458
- availableToolNames
3496
+ availableToolNames,
3497
+ startReq
3459
3498
  );
3460
3499
  }
3461
3500
  );
@@ -3477,7 +3516,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3477
3516
  const trimmedPreapproved = preapprovedTools.filter(
3478
3517
  (name) => trimmed.mcpTools.some((t) => t.name === name)
3479
3518
  );
3480
- const startReq = {
3519
+ startReq = {
3481
3520
  workflowID: workflowId,
3482
3521
  clientVersion: CLIENT_VERSION,
3483
3522
  workflowDefinition: workflowDef,
@@ -3542,7 +3581,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3542
3581
  // ---------------------------------------------------------------------------
3543
3582
  // Event handling
3544
3583
  // ---------------------------------------------------------------------------
3545
- handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames) {
3584
+ handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames, startReq) {
3546
3585
  if (ss.streamClosed) {
3547
3586
  return;
3548
3587
  }
@@ -3553,6 +3592,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3553
3592
  }
3554
3593
  case "tool-request": {
3555
3594
  const { requestID, data } = event;
3595
+ if (ss.processedRequestIDs.has(requestID)) break;
3596
+ ss.processedRequestIDs.add(requestID);
3556
3597
  let parsedArgs;
3557
3598
  try {
3558
3599
  JSON.parse(data.args);
@@ -3599,6 +3640,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3599
3640
  break;
3600
3641
  }
3601
3642
  case "builtin-tool-request": {
3643
+ if (ss.processedRequestIDs.has(event.requestID)) break;
3644
+ ss.processedRequestIDs.add(event.requestID);
3602
3645
  const mapped = mapBuiltinTool(event.toolName, event.data, availableToolNames);
3603
3646
  const mappedArgs = JSON.stringify(mapped.args);
3604
3647
  if (ss.activeTextBlockId) {
@@ -3639,6 +3682,26 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3639
3682
  });
3640
3683
  break;
3641
3684
  }
3685
+ case "approval-required": {
3686
+ ss.approvalPending = true;
3687
+ this.approveAndResume(
3688
+ ss,
3689
+ event.tools,
3690
+ startReq,
3691
+ controller,
3692
+ toolExecutor,
3693
+ nextTextId,
3694
+ availableToolNames
3695
+ ).catch(() => {
3696
+ ss.approvalPending = false;
3697
+ if (ss.deferredClose) {
3698
+ const close = ss.deferredClose;
3699
+ ss.deferredClose = null;
3700
+ close();
3701
+ }
3702
+ });
3703
+ break;
3704
+ }
3642
3705
  case "completed": {
3643
3706
  if (ss.activeTextBlockId) {
3644
3707
  controller.enqueue({ type: "text-end", id: ss.activeTextBlockId });
@@ -3657,7 +3720,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3657
3720
  controller.close();
3658
3721
  this.cleanupClient(ss);
3659
3722
  };
3660
- if (ss.pendingToolCount > 0) {
3723
+ if (ss.pendingToolCount > 0 || ss.approvalPending) {
3661
3724
  ss.deferredClose = doCompleteClose;
3662
3725
  } else {
3663
3726
  ss.deferredClose = null;
@@ -3716,7 +3779,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3716
3779
  this.cleanupClient(ss);
3717
3780
  }
3718
3781
  };
3719
- if (ss.pendingToolCount > 0) {
3782
+ if (ss.pendingToolCount > 0 || ss.approvalPending) {
3720
3783
  ss.deferredClose = doClose;
3721
3784
  } else {
3722
3785
  ss.deferredClose = null;
@@ -3892,6 +3955,60 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3892
3955
  this.persistedAgentEmitted.clear();
3893
3956
  }
3894
3957
  }
3958
+ async approveAndResume(ss, tools, startReq, controller, toolExecutor, nextTextId, availableToolNames) {
3959
+ const handler = this.workflowOptions.approvalHandler;
3960
+ if (!handler || !startReq) {
3961
+ ss.approvalPending = false;
3962
+ if (ss.deferredClose) {
3963
+ const close = ss.deferredClose;
3964
+ ss.deferredClose = null;
3965
+ close();
3966
+ }
3967
+ return;
3968
+ }
3969
+ let decision;
3970
+ try {
3971
+ decision = await handler(tools);
3972
+ } catch (err) {
3973
+ ss.approvalPending = false;
3974
+ if (!ss.streamClosed) controller.error(err);
3975
+ return;
3976
+ }
3977
+ ss.approvalPending = false;
3978
+ this.cleanupClient(ss, false);
3979
+ const approval = decision.approved ? { approval: { tool_name: tools[0]?.name, tool_args_json: tools[0]?.args } } : { rejection: { message: decision.message ?? "User rejected" } };
3980
+ const newStartReq = { ...startReq, approval };
3981
+ const newClient = new GitLabWorkflowClient();
3982
+ this.activeClients.add(newClient);
3983
+ ss.activeClient = newClient;
3984
+ const modelRef = await this.resolveModelRef();
3985
+ try {
3986
+ await newClient.connect(
3987
+ {
3988
+ instanceUrl: this.config.instanceUrl,
3989
+ modelRef,
3990
+ headers: this.config.getHeaders(),
3991
+ projectId: this.workflowOptions.projectId,
3992
+ namespaceId: this.workflowOptions.namespaceId,
3993
+ rootNamespaceId: this.workflowOptions.rootNamespaceId
3994
+ },
3995
+ (event) => this.handleWorkflowEvent(
3996
+ ss,
3997
+ event,
3998
+ controller,
3999
+ newClient,
4000
+ toolExecutor,
4001
+ nextTextId,
4002
+ availableToolNames,
4003
+ newStartReq
4004
+ )
4005
+ );
4006
+ newClient.sendStartRequest(newStartReq);
4007
+ } catch (err) {
4008
+ this.cleanupClient(ss, true);
4009
+ if (!ss.streamClosed) controller.error(err);
4010
+ }
4011
+ }
3895
4012
  // ---------------------------------------------------------------------------
3896
4013
  // Workflow metadata
3897
4014
  // ---------------------------------------------------------------------------