gitlab-ai-provider 6.3.0 → 6.4.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 +9 -0
- package/README.md +33 -0
- package/dist/gitlab-ai-provider-6.4.1.tgz +0 -0
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +75 -9
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +75 -9
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/gitlab-ai-provider-6.3.0.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,15 @@
|
|
|
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.4.1 (2026-04-06)</small>
|
|
6
|
+
|
|
7
|
+
- fix(workflow): surface server-side MCP tool calls as structured AI SDK events ([fcae357](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/fcae357))
|
|
8
|
+
|
|
9
|
+
## 6.4.0 (2026-04-02)
|
|
10
|
+
|
|
11
|
+
- chore: regenerate dist ([c6833c4](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/c6833c4))
|
|
12
|
+
- feat: pass ai_catalog_item_version_id to WebSocket for MCP tool injection ([19cd4e5](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/19cd4e5))
|
|
13
|
+
|
|
5
14
|
## 6.3.0 (2026-03-31)
|
|
6
15
|
|
|
7
16
|
- fix(model): clear deferredClose before reconnect to prevent stream dying after batch approval ([017f8fe](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/017f8fe))
|
package/README.md
CHANGED
|
@@ -334,6 +334,37 @@ The workflow service automatically maps DWS built-in tools to consumer tool name
|
|
|
334
334
|
| `mkdir` | `bash` | Create directory |
|
|
335
335
|
| `runHTTPRequest` | `bash` | Execute HTTP request |
|
|
336
336
|
|
|
337
|
+
**Server-Side Tool Visibility:**
|
|
338
|
+
|
|
339
|
+
When DWS executes tools on the server (e.g., MCP tools like Linear or Context7 that are configured in the agent's catalog), the provider automatically surfaces these as structured AI SDK stream events (`tool-input-start`, `tool-call`, `tool-result`) with `providerExecuted: true` and `dynamic: true`. This allows host applications to display server-side tool calls in their UI alongside locally-executed tools.
|
|
340
|
+
|
|
341
|
+
Server-side tool events are deduplicated across turns — the provider tracks emitted checkpoint tool entries in the persistent session state so that cumulative DWS checkpoints don't re-emit tools from previous turns. Tools that were already handled via `tool-request` (client-executed tools) are also excluded from checkpoint emission to avoid duplicates.
|
|
342
|
+
|
|
343
|
+
Since server-side MCP tools are not registered in the host's tool registry, the `dynamic: true` flag ensures the AI SDK's `parseToolCall` bypasses tool registry validation via the `parseProviderExecutedDynamicToolCall` path.
|
|
344
|
+
|
|
345
|
+
**Tool Call Approval:**
|
|
346
|
+
|
|
347
|
+
The workflow model supports an approval flow for tool execution. When DWS requires approval before executing a tool, it sends a `TOOL_CALL_APPROVAL_REQUIRED` checkpoint. The provider exposes this via the `approvalHandler` callback:
|
|
348
|
+
|
|
349
|
+
```typescript
|
|
350
|
+
const model = gitlab.workflowChat('duo-workflow');
|
|
351
|
+
|
|
352
|
+
// Set approval handler — called when DWS requests tool execution approval
|
|
353
|
+
model.approvalHandler = async (tools) => {
|
|
354
|
+
// tools: Array<{ name: string, args: string }>
|
|
355
|
+
console.log(
|
|
356
|
+
'Approval requested for:',
|
|
357
|
+
tools.map((t) => t.name)
|
|
358
|
+
);
|
|
359
|
+
return { approved: true }; // or { approved: false }
|
|
360
|
+
};
|
|
361
|
+
|
|
362
|
+
// Pre-approve specific tools to skip approval prompts
|
|
363
|
+
model.sessionPreapprovedTools = ['read', 'glob', 'grep'];
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
Approved tools are tracked per-session. When the user approves a tool via "allow always", the provider automatically pre-approves it on subsequent DWS reconnections within the same session.
|
|
367
|
+
|
|
337
368
|
**Workflow Options:**
|
|
338
369
|
|
|
339
370
|
```typescript
|
|
@@ -499,6 +530,8 @@ Provides server-side agentic execution through GitLab Duo Workflow Service.
|
|
|
499
530
|
- Dynamic model discovery via GraphQL (`aiChatAvailableModels`)
|
|
500
531
|
- Automatic model selection (pinned → user-selected → default)
|
|
501
532
|
- Built-in tool mapping and MCP tool support
|
|
533
|
+
- Server-side tool visibility — DWS-executed MCP tools are surfaced as structured AI SDK events
|
|
534
|
+
- Tool call approval flow with per-session pre-approval tracking
|
|
502
535
|
- Per-stream state isolation for concurrent requests
|
|
503
536
|
- Dual heartbeat (WebSocket ping + JSON heartbeat)
|
|
504
537
|
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -1472,6 +1472,10 @@ interface WorkflowWebSocketOptions {
|
|
|
1472
1472
|
projectId?: string;
|
|
1473
1473
|
namespaceId?: string;
|
|
1474
1474
|
rootNamespaceId?: string;
|
|
1475
|
+
/** AI Catalog item version ID — required for Workhorse to inject MCP tools */
|
|
1476
|
+
aiCatalogItemVersionId?: number;
|
|
1477
|
+
/** Workflow definition type (e.g. 'chat') — used by Workhorse for MCP config */
|
|
1478
|
+
workflowDefinition?: string;
|
|
1475
1479
|
}
|
|
1476
1480
|
type EventCallback = (event: WorkflowClientEvent) => void;
|
|
1477
1481
|
declare class GitLabWorkflowClient {
|
package/dist/index.d.ts
CHANGED
|
@@ -1472,6 +1472,10 @@ interface WorkflowWebSocketOptions {
|
|
|
1472
1472
|
projectId?: string;
|
|
1473
1473
|
namespaceId?: string;
|
|
1474
1474
|
rootNamespaceId?: string;
|
|
1475
|
+
/** AI Catalog item version ID — required for Workhorse to inject MCP tools */
|
|
1476
|
+
aiCatalogItemVersionId?: number;
|
|
1477
|
+
/** Workflow definition type (e.g. 'chat') — used by Workhorse for MCP config */
|
|
1478
|
+
workflowDefinition?: string;
|
|
1475
1479
|
}
|
|
1476
1480
|
type EventCallback = (event: WorkflowClientEvent) => void;
|
|
1477
1481
|
declare class GitLabWorkflowClient {
|
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 ? "6.
|
|
1656
|
+
var VERSION = true ? "6.4.0" : "0.0.0-dev";
|
|
1657
1657
|
|
|
1658
1658
|
// src/gitlab-workflow-types.ts
|
|
1659
1659
|
var WorkflowType = /* @__PURE__ */ ((WorkflowType2) => {
|
|
@@ -1837,6 +1837,12 @@ var GitLabWorkflowClient = class {
|
|
|
1837
1837
|
if (options.modelRef && options.modelRef !== "default") {
|
|
1838
1838
|
url.searchParams.set("user_selected_model_identifier", options.modelRef);
|
|
1839
1839
|
}
|
|
1840
|
+
if (options.aiCatalogItemVersionId) {
|
|
1841
|
+
url.searchParams.set("ai_catalog_item_version_id", String(options.aiCatalogItemVersionId));
|
|
1842
|
+
}
|
|
1843
|
+
if (options.workflowDefinition) {
|
|
1844
|
+
url.searchParams.set("workflow_definition", options.workflowDefinition);
|
|
1845
|
+
}
|
|
1840
1846
|
return url.toString();
|
|
1841
1847
|
}
|
|
1842
1848
|
buildWebSocketHeaders(options) {
|
|
@@ -3484,7 +3490,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3484
3490
|
this.sessionWorkflows.set(sessionKey, {
|
|
3485
3491
|
workflowId,
|
|
3486
3492
|
workflowDefinition: effectiveDefinition,
|
|
3487
|
-
agentEmitted: /* @__PURE__ */ new Map()
|
|
3493
|
+
agentEmitted: /* @__PURE__ */ new Map(),
|
|
3494
|
+
toolEntries: /* @__PURE__ */ new Set()
|
|
3488
3495
|
});
|
|
3489
3496
|
sess = this.sessionWorkflows.get(sessionKey);
|
|
3490
3497
|
}
|
|
@@ -3504,6 +3511,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3504
3511
|
currentAgentMessageId: "",
|
|
3505
3512
|
activeClient: wsClient,
|
|
3506
3513
|
processedRequestIDs: /* @__PURE__ */ new Set(),
|
|
3514
|
+
emittedToolEntries: new Set(sess?.toolEntries),
|
|
3515
|
+
emittedToolKeys: /* @__PURE__ */ new Set(),
|
|
3507
3516
|
sessionKey
|
|
3508
3517
|
};
|
|
3509
3518
|
for (const msg of options.prompt) {
|
|
@@ -3528,7 +3537,9 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3528
3537
|
headers: this.config.getHeaders(),
|
|
3529
3538
|
projectId: this.workflowOptions.projectId,
|
|
3530
3539
|
namespaceId: this.workflowOptions.namespaceId,
|
|
3531
|
-
rootNamespaceId: this.workflowOptions.rootNamespaceId
|
|
3540
|
+
rootNamespaceId: this.workflowOptions.rootNamespaceId,
|
|
3541
|
+
aiCatalogItemVersionId: callAiCatalogItemVersionId,
|
|
3542
|
+
workflowDefinition: callWorkflowDefinition ?? this.workflowOptions.workflowDefinition
|
|
3532
3543
|
},
|
|
3533
3544
|
(event) => {
|
|
3534
3545
|
this.handleWorkflowEvent(
|
|
@@ -3539,7 +3550,11 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3539
3550
|
toolExecutor,
|
|
3540
3551
|
() => `text-${textBlockCounter++}`,
|
|
3541
3552
|
availableToolNames,
|
|
3542
|
-
startReq
|
|
3553
|
+
startReq,
|
|
3554
|
+
{
|
|
3555
|
+
aiCatalogItemVersionId: callAiCatalogItemVersionId,
|
|
3556
|
+
workflowDefinition: callWorkflowDefinition ?? this.workflowOptions.workflowDefinition
|
|
3557
|
+
}
|
|
3543
3558
|
);
|
|
3544
3559
|
}
|
|
3545
3560
|
);
|
|
@@ -3634,7 +3649,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3634
3649
|
// ---------------------------------------------------------------------------
|
|
3635
3650
|
// Event handling
|
|
3636
3651
|
// ---------------------------------------------------------------------------
|
|
3637
|
-
handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames, startReq) {
|
|
3652
|
+
handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames, startReq, wsExtras) {
|
|
3638
3653
|
if (ss.streamClosed) {
|
|
3639
3654
|
return;
|
|
3640
3655
|
}
|
|
@@ -3647,6 +3662,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3647
3662
|
const { requestID, data } = event;
|
|
3648
3663
|
if (ss.processedRequestIDs.has(requestID)) break;
|
|
3649
3664
|
ss.processedRequestIDs.add(requestID);
|
|
3665
|
+
ss.emittedToolKeys.add(data.name);
|
|
3650
3666
|
let parsedArgs;
|
|
3651
3667
|
try {
|
|
3652
3668
|
JSON.parse(data.args);
|
|
@@ -3696,6 +3712,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3696
3712
|
if (ss.processedRequestIDs.has(event.requestID)) break;
|
|
3697
3713
|
ss.processedRequestIDs.add(event.requestID);
|
|
3698
3714
|
const mapped = mapBuiltinTool(event.toolName, event.data, availableToolNames);
|
|
3715
|
+
ss.emittedToolKeys.add(mapped.toolName);
|
|
3699
3716
|
const mappedArgs = JSON.stringify(mapped.args);
|
|
3700
3717
|
if (ss.activeTextBlockId) {
|
|
3701
3718
|
controller.enqueue({ type: "text-end", id: ss.activeTextBlockId });
|
|
@@ -3744,7 +3761,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3744
3761
|
controller,
|
|
3745
3762
|
toolExecutor,
|
|
3746
3763
|
nextTextId,
|
|
3747
|
-
availableToolNames
|
|
3764
|
+
availableToolNames,
|
|
3765
|
+
wsExtras
|
|
3748
3766
|
).catch((_err) => {
|
|
3749
3767
|
ss.approvalPending = false;
|
|
3750
3768
|
if (ss.deferredClose) {
|
|
@@ -3876,6 +3894,51 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3876
3894
|
}
|
|
3877
3895
|
for (let i = 0; i < chatLog.length; i++) {
|
|
3878
3896
|
const entry = chatLog[i];
|
|
3897
|
+
if (entry.message_type === "tool" && entry.tool_info) {
|
|
3898
|
+
const toolId = entry.message_id || entry.correlation_id || `tool-${i}`;
|
|
3899
|
+
if (ss.emittedToolEntries.has(toolId)) continue;
|
|
3900
|
+
const name = entry.tool_info.name;
|
|
3901
|
+
const args = JSON.stringify(entry.tool_info.args ?? {});
|
|
3902
|
+
if (ss.emittedToolKeys.has(name)) {
|
|
3903
|
+
ss.emittedToolEntries.add(toolId);
|
|
3904
|
+
const sess2 = this.sessionWorkflows.get(ss.sessionKey);
|
|
3905
|
+
if (sess2) sess2.toolEntries.add(toolId);
|
|
3906
|
+
continue;
|
|
3907
|
+
}
|
|
3908
|
+
if (ss.activeTextBlockId) {
|
|
3909
|
+
controller.enqueue({ type: "text-end", id: ss.activeTextBlockId });
|
|
3910
|
+
ss.activeTextBlockId = null;
|
|
3911
|
+
}
|
|
3912
|
+
controller.enqueue({
|
|
3913
|
+
type: "tool-input-start",
|
|
3914
|
+
id: toolId,
|
|
3915
|
+
toolName: name,
|
|
3916
|
+
providerExecuted: true
|
|
3917
|
+
});
|
|
3918
|
+
controller.enqueue({ type: "tool-input-delta", id: toolId, delta: args });
|
|
3919
|
+
controller.enqueue({ type: "tool-input-end", id: toolId });
|
|
3920
|
+
controller.enqueue({
|
|
3921
|
+
type: "tool-call",
|
|
3922
|
+
toolCallId: toolId,
|
|
3923
|
+
toolName: name,
|
|
3924
|
+
input: args,
|
|
3925
|
+
providerExecuted: true,
|
|
3926
|
+
dynamic: true
|
|
3927
|
+
});
|
|
3928
|
+
const response = entry.tool_info.tool_response;
|
|
3929
|
+
const output = typeof response === "string" ? response : response ? response.content : entry.content || "";
|
|
3930
|
+
controller.enqueue({
|
|
3931
|
+
type: "tool-result",
|
|
3932
|
+
toolCallId: toolId,
|
|
3933
|
+
toolName: name,
|
|
3934
|
+
result: { output, title: name, metadata: {} },
|
|
3935
|
+
isError: false
|
|
3936
|
+
});
|
|
3937
|
+
ss.emittedToolEntries.add(toolId);
|
|
3938
|
+
const sess = this.sessionWorkflows.get(ss.sessionKey);
|
|
3939
|
+
if (sess) sess.toolEntries.add(toolId);
|
|
3940
|
+
continue;
|
|
3941
|
+
}
|
|
3879
3942
|
if (entry.message_type !== "agent") continue;
|
|
3880
3943
|
const content = entry.content || "";
|
|
3881
3944
|
const msgId = entry.message_id || `idx-${i}`;
|
|
@@ -4013,7 +4076,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
4013
4076
|
}
|
|
4014
4077
|
}
|
|
4015
4078
|
}
|
|
4016
|
-
async approveAndResume(ss, tools, startReq, controller, toolExecutor, nextTextId, availableToolNames) {
|
|
4079
|
+
async approveAndResume(ss, tools, startReq, controller, toolExecutor, nextTextId, availableToolNames, wsExtras) {
|
|
4017
4080
|
const handler = this.workflowOptions.approvalHandler;
|
|
4018
4081
|
if (!handler || !startReq) {
|
|
4019
4082
|
ss.approvalPending = false;
|
|
@@ -4053,7 +4116,9 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
4053
4116
|
headers: this.config.getHeaders(),
|
|
4054
4117
|
projectId: this.workflowOptions.projectId,
|
|
4055
4118
|
namespaceId: this.workflowOptions.namespaceId,
|
|
4056
|
-
rootNamespaceId: this.workflowOptions.rootNamespaceId
|
|
4119
|
+
rootNamespaceId: this.workflowOptions.rootNamespaceId,
|
|
4120
|
+
aiCatalogItemVersionId: wsExtras?.aiCatalogItemVersionId,
|
|
4121
|
+
workflowDefinition: wsExtras?.workflowDefinition
|
|
4057
4122
|
},
|
|
4058
4123
|
(event) => this.handleWorkflowEvent(
|
|
4059
4124
|
ss,
|
|
@@ -4063,7 +4128,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
4063
4128
|
toolExecutor,
|
|
4064
4129
|
nextTextId,
|
|
4065
4130
|
availableToolNames,
|
|
4066
|
-
newStartReq
|
|
4131
|
+
newStartReq,
|
|
4132
|
+
wsExtras
|
|
4067
4133
|
)
|
|
4068
4134
|
);
|
|
4069
4135
|
newClient.sendStartRequest(newStartReq);
|