gitlab-ai-provider 5.1.0 → 5.1.2
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 +11 -0
- package/dist/gitlab-ai-provider-5.1.2.tgz +0 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +147 -63
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +147 -63
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/dist/gitlab-ai-provider-5.1.0.tgz +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
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>5.1.2 (2026-03-17)</small>
|
|
6
|
+
|
|
7
|
+
- fix: regenerate dists ([091d3ae](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/091d3ae))
|
|
8
|
+
|
|
9
|
+
## <small>5.1.1 (2026-03-17)</small>
|
|
10
|
+
|
|
11
|
+
- Merge branch 'fix/builtin-fallback-security' into 'main' ([1026029](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/1026029))
|
|
12
|
+
- Merge branch 'vg/tools_fixes' into 'main' ([477d971](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/477d971))
|
|
13
|
+
- fix: add path validation and JSON error handling to executeBuiltinFallback ([a9ace75](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/a9ace75))
|
|
14
|
+
- fix: fixed tools calling for workflow models ([d52ec56](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/d52ec56))
|
|
15
|
+
|
|
5
16
|
## 5.1.0 (2026-03-17)
|
|
6
17
|
|
|
7
18
|
- Merge branch 'fix/model-config-inparams-cache-ttl' into 'main' ([a9fdfa0](https://gitlab.com/vglafirov/gitlab-ai-provider/commit/a9fdfa0))
|
|
Binary file
|
package/dist/index.d.mts
CHANGED
|
@@ -577,6 +577,8 @@ interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {
|
|
|
577
577
|
type WorkflowToolExecutor = (toolName: string, args: string, requestID: string) => Promise<{
|
|
578
578
|
result: string;
|
|
579
579
|
error?: string | null;
|
|
580
|
+
metadata?: Record<string, unknown>;
|
|
581
|
+
title?: string;
|
|
580
582
|
}>;
|
|
581
583
|
/**
|
|
582
584
|
* GitLab Duo Agent Platform Language Model.
|
package/dist/index.d.ts
CHANGED
|
@@ -577,6 +577,8 @@ interface GitLabWorkflowLanguageModelConfig extends GitLabWorkflowClientConfig {
|
|
|
577
577
|
type WorkflowToolExecutor = (toolName: string, args: string, requestID: string) => Promise<{
|
|
578
578
|
result: string;
|
|
579
579
|
error?: string | null;
|
|
580
|
+
metadata?: Record<string, unknown>;
|
|
581
|
+
title?: string;
|
|
580
582
|
}>;
|
|
581
583
|
/**
|
|
582
584
|
* GitLab Duo Agent Platform Language Model.
|
package/dist/index.js
CHANGED
|
@@ -1576,7 +1576,7 @@ var GitLabOpenAILanguageModel = class {
|
|
|
1576
1576
|
var import_isomorphic_ws = __toESM(require("isomorphic-ws"));
|
|
1577
1577
|
|
|
1578
1578
|
// src/version.ts
|
|
1579
|
-
var VERSION = true ? "5.
|
|
1579
|
+
var VERSION = true ? "5.1.1" : "0.0.0-dev";
|
|
1580
1580
|
|
|
1581
1581
|
// src/gitlab-workflow-types.ts
|
|
1582
1582
|
var WorkflowType = /* @__PURE__ */ ((WorkflowType2) => {
|
|
@@ -1913,7 +1913,8 @@ function sanitizeErrorMessage(message) {
|
|
|
1913
1913
|
if (!message) return "";
|
|
1914
1914
|
return message.replace(/\bBearer\s+[A-Za-z0-9\-_.~+/]+=*/gi, "Bearer [REDACTED]").replace(/\bgl(?:pat|oat|cbt|dt|oas|rt|soat|ffct|sapat)-[A-Za-z0-9_-]+/g, "[REDACTED]").replace(/([?&](?:private_token|access_token|token)=)[^&\s"']*/gi, "$1[REDACTED]").replace(/:\/\/([^:@/\s]+):([^@/\s]+)@/g, "://$1:[REDACTED]@");
|
|
1915
1915
|
}
|
|
1916
|
-
function mapBuiltinTool(dwsToolName, data) {
|
|
1916
|
+
function mapBuiltinTool(dwsToolName, data, availableTools) {
|
|
1917
|
+
const has = (name) => !availableTools || availableTools.has(name);
|
|
1917
1918
|
switch (dwsToolName) {
|
|
1918
1919
|
case "runReadFile":
|
|
1919
1920
|
return { toolName: "read", args: { filePath: data.filepath } };
|
|
@@ -1927,20 +1928,51 @@ function mapBuiltinTool(dwsToolName, data) {
|
|
|
1927
1928
|
args: { filePaths: paths }
|
|
1928
1929
|
};
|
|
1929
1930
|
}
|
|
1930
|
-
case "runWriteFile":
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
}
|
|
1943
|
-
|
|
1931
|
+
case "runWriteFile": {
|
|
1932
|
+
if (has("write")) {
|
|
1933
|
+
return {
|
|
1934
|
+
toolName: "write",
|
|
1935
|
+
args: { filePath: data.filepath, content: data.contents }
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
const filePath = String(data.filepath ?? "");
|
|
1939
|
+
const content = String(data.contents ?? "");
|
|
1940
|
+
const patchLines = [
|
|
1941
|
+
"*** Begin Patch",
|
|
1942
|
+
`*** Add File: ${filePath}`,
|
|
1943
|
+
...content.split("\n").map((l) => `+${l}`),
|
|
1944
|
+
"*** End Patch"
|
|
1945
|
+
].join("\n");
|
|
1946
|
+
return { toolName: "apply_patch", args: { patchText: patchLines } };
|
|
1947
|
+
}
|
|
1948
|
+
case "runEditFile": {
|
|
1949
|
+
const editOldString = String(data.oldString ?? data.old_string ?? "");
|
|
1950
|
+
const editNewString = String(data.newString ?? data.new_string ?? "");
|
|
1951
|
+
if (has("edit")) {
|
|
1952
|
+
return {
|
|
1953
|
+
toolName: "edit",
|
|
1954
|
+
args: {
|
|
1955
|
+
filePath: data.filepath,
|
|
1956
|
+
oldString: editOldString,
|
|
1957
|
+
newString: editNewString
|
|
1958
|
+
}
|
|
1959
|
+
};
|
|
1960
|
+
}
|
|
1961
|
+
const editPath = String(data.filepath ?? "");
|
|
1962
|
+
const oldStr = editOldString;
|
|
1963
|
+
const newStr = editNewString;
|
|
1964
|
+
const oldLines = oldStr.split("\n");
|
|
1965
|
+
const newLines = newStr.split("\n");
|
|
1966
|
+
const patchContent = [
|
|
1967
|
+
"*** Begin Patch",
|
|
1968
|
+
`*** Update File: ${editPath}`,
|
|
1969
|
+
"@@",
|
|
1970
|
+
...oldLines.map((l) => `-${l}`),
|
|
1971
|
+
...newLines.map((l) => `+${l}`),
|
|
1972
|
+
"*** End Patch"
|
|
1973
|
+
].join("\n");
|
|
1974
|
+
return { toolName: "apply_patch", args: { patchText: patchContent } };
|
|
1975
|
+
}
|
|
1944
1976
|
case "runShellCommand": {
|
|
1945
1977
|
const command = data.command;
|
|
1946
1978
|
if (!command || typeof command !== "string") {
|
|
@@ -2063,6 +2095,87 @@ function mapBuiltinTool(dwsToolName, data) {
|
|
|
2063
2095
|
return { toolName: dwsToolName, args: data };
|
|
2064
2096
|
}
|
|
2065
2097
|
}
|
|
2098
|
+
function validateSafePath(filePath) {
|
|
2099
|
+
if (!filePath) {
|
|
2100
|
+
throw new Error("filePath is required");
|
|
2101
|
+
}
|
|
2102
|
+
if (filePath.includes("\0")) {
|
|
2103
|
+
throw new Error("filePath contains null bytes");
|
|
2104
|
+
}
|
|
2105
|
+
const path5 = require("path");
|
|
2106
|
+
const resolved = path5.resolve(filePath);
|
|
2107
|
+
const cwd = process.cwd();
|
|
2108
|
+
if (!resolved.startsWith(cwd + path5.sep) && resolved !== cwd) {
|
|
2109
|
+
throw new Error(`filePath resolves outside the working directory: ${filePath}`);
|
|
2110
|
+
}
|
|
2111
|
+
return resolved;
|
|
2112
|
+
}
|
|
2113
|
+
function executeBuiltinFallback(toolName, argsJson) {
|
|
2114
|
+
if (toolName !== "edit" && toolName !== "write") {
|
|
2115
|
+
return null;
|
|
2116
|
+
}
|
|
2117
|
+
const fs4 = require("fs");
|
|
2118
|
+
let args;
|
|
2119
|
+
try {
|
|
2120
|
+
args = JSON.parse(argsJson);
|
|
2121
|
+
} catch {
|
|
2122
|
+
return { result: "", error: `${toolName} fallback: invalid JSON arguments` };
|
|
2123
|
+
}
|
|
2124
|
+
try {
|
|
2125
|
+
if (toolName === "write") {
|
|
2126
|
+
const filePath2 = String(args.filePath ?? "");
|
|
2127
|
+
if (!filePath2) {
|
|
2128
|
+
return { result: "", error: "write fallback: filePath is required" };
|
|
2129
|
+
}
|
|
2130
|
+
const safePath2 = validateSafePath(filePath2);
|
|
2131
|
+
const content2 = String(args.content ?? "");
|
|
2132
|
+
fs4.writeFileSync(safePath2, content2, "utf-8");
|
|
2133
|
+
return {
|
|
2134
|
+
result: "File written successfully.",
|
|
2135
|
+
title: filePath2,
|
|
2136
|
+
metadata: { output: "File written successfully." }
|
|
2137
|
+
};
|
|
2138
|
+
}
|
|
2139
|
+
const filePath = String(args.filePath ?? "");
|
|
2140
|
+
const oldString = String(args.oldString ?? "");
|
|
2141
|
+
const newString = String(args.newString ?? "");
|
|
2142
|
+
if (!filePath) {
|
|
2143
|
+
return { result: "", error: "edit fallback: filePath is required" };
|
|
2144
|
+
}
|
|
2145
|
+
if (!oldString && !newString) {
|
|
2146
|
+
return { result: "", error: "edit fallback: oldString and newString are both empty" };
|
|
2147
|
+
}
|
|
2148
|
+
const safePath = validateSafePath(filePath);
|
|
2149
|
+
let content;
|
|
2150
|
+
try {
|
|
2151
|
+
content = fs4.readFileSync(safePath, "utf-8");
|
|
2152
|
+
} catch {
|
|
2153
|
+
content = "";
|
|
2154
|
+
}
|
|
2155
|
+
if (oldString === "") {
|
|
2156
|
+
fs4.writeFileSync(safePath, newString, "utf-8");
|
|
2157
|
+
return {
|
|
2158
|
+
result: "Edit applied successfully.",
|
|
2159
|
+
title: filePath,
|
|
2160
|
+
metadata: { output: "Edit applied successfully." }
|
|
2161
|
+
};
|
|
2162
|
+
}
|
|
2163
|
+
const idx = content.indexOf(oldString);
|
|
2164
|
+
if (idx === -1) {
|
|
2165
|
+
return { result: "", error: `edit fallback: could not find oldString in ${filePath}` };
|
|
2166
|
+
}
|
|
2167
|
+
const newContent = content.substring(0, idx) + newString + content.substring(idx + oldString.length);
|
|
2168
|
+
fs4.writeFileSync(safePath, newContent, "utf-8");
|
|
2169
|
+
return {
|
|
2170
|
+
result: "Edit applied successfully.",
|
|
2171
|
+
title: filePath,
|
|
2172
|
+
metadata: { output: "Edit applied successfully." }
|
|
2173
|
+
};
|
|
2174
|
+
} catch (e) {
|
|
2175
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
2176
|
+
return { result: "", error: sanitizeErrorMessage(msg) };
|
|
2177
|
+
}
|
|
2178
|
+
}
|
|
2066
2179
|
|
|
2067
2180
|
// src/gitlab-workflow-token-client.ts
|
|
2068
2181
|
var TOKEN_CACHE_DURATION_MS = 25 * 60 * 1e3;
|
|
@@ -3153,6 +3266,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3153
3266
|
const preapprovedTools = this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name);
|
|
3154
3267
|
const additionalContext = this.buildAdditionalContext(options.prompt);
|
|
3155
3268
|
const toolExecutor = this.toolExecutor ?? null;
|
|
3269
|
+
const availableToolNames = new Set(options.tools?.map((t) => t.name) ?? []);
|
|
3156
3270
|
await this.tokenClient.getToken(
|
|
3157
3271
|
this.workflowOptions.workflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION,
|
|
3158
3272
|
this.workflowOptions.rootNamespaceId
|
|
@@ -3213,7 +3327,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3213
3327
|
controller,
|
|
3214
3328
|
wsClient,
|
|
3215
3329
|
toolExecutor,
|
|
3216
|
-
() => `text-${textBlockCounter++}
|
|
3330
|
+
() => `text-${textBlockCounter++}`,
|
|
3331
|
+
availableToolNames
|
|
3217
3332
|
);
|
|
3218
3333
|
}
|
|
3219
3334
|
);
|
|
@@ -3294,7 +3409,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3294
3409
|
// ---------------------------------------------------------------------------
|
|
3295
3410
|
// Event handling
|
|
3296
3411
|
// ---------------------------------------------------------------------------
|
|
3297
|
-
handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId) {
|
|
3412
|
+
handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames) {
|
|
3298
3413
|
if (ss.streamClosed) {
|
|
3299
3414
|
return;
|
|
3300
3415
|
}
|
|
@@ -3351,7 +3466,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3351
3466
|
break;
|
|
3352
3467
|
}
|
|
3353
3468
|
case "builtin-tool-request": {
|
|
3354
|
-
const mapped = mapBuiltinTool(event.toolName, event.data);
|
|
3469
|
+
const mapped = mapBuiltinTool(event.toolName, event.data, availableToolNames);
|
|
3355
3470
|
const mappedArgs = JSON.stringify(mapped.args);
|
|
3356
3471
|
if (ss.activeTextBlockId) {
|
|
3357
3472
|
controller.enqueue({ type: "text-end", id: ss.activeTextBlockId });
|
|
@@ -3551,37 +3666,19 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3551
3666
|
};
|
|
3552
3667
|
try {
|
|
3553
3668
|
if (toolExecutor) {
|
|
3554
|
-
|
|
3669
|
+
let result = await toolExecutor(toolName, argsJson, requestID);
|
|
3670
|
+
if (result.error && /^Unknown tool:/.test(result.error)) {
|
|
3671
|
+
const fallback = executeBuiltinFallback(toolName, argsJson);
|
|
3672
|
+
if (fallback) {
|
|
3673
|
+
result = fallback;
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3555
3676
|
wsClient.sendActionResponse(requestID, result.result, result.error);
|
|
3556
3677
|
ss.streamedInputChars += argsJson.length;
|
|
3557
3678
|
ss.streamedOutputChars += result.result.length;
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
try {
|
|
3562
|
-
const parsed = JSON.parse(result.result);
|
|
3563
|
-
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
3564
|
-
if (typeof parsed.output === "string") {
|
|
3565
|
-
toolOutput = parsed.output;
|
|
3566
|
-
} else if (parsed.output != null) {
|
|
3567
|
-
toolOutput = JSON.stringify(parsed.output);
|
|
3568
|
-
}
|
|
3569
|
-
if (typeof parsed.title === "string") toolTitle = parsed.title;
|
|
3570
|
-
if (parsed.metadata && typeof parsed.metadata === "object") {
|
|
3571
|
-
toolMetadata = {};
|
|
3572
|
-
for (const [k, v] of Object.entries(parsed.metadata)) {
|
|
3573
|
-
toolMetadata[k] = typeof v === "string" ? v : JSON.stringify(v);
|
|
3574
|
-
}
|
|
3575
|
-
if (!("output" in toolMetadata)) {
|
|
3576
|
-
toolMetadata.output = toolOutput;
|
|
3577
|
-
}
|
|
3578
|
-
}
|
|
3579
|
-
} else if (Array.isArray(parsed)) {
|
|
3580
|
-
toolOutput = JSON.stringify(parsed);
|
|
3581
|
-
toolMetadata = { output: toolOutput };
|
|
3582
|
-
}
|
|
3583
|
-
} catch {
|
|
3584
|
-
}
|
|
3679
|
+
const toolOutput = result.result;
|
|
3680
|
+
const toolTitle = result.title ?? `${toolName} result`;
|
|
3681
|
+
const toolMetadata = result.metadata ?? { output: result.result };
|
|
3585
3682
|
if (result.error) {
|
|
3586
3683
|
let errorText;
|
|
3587
3684
|
if (typeof result.error === "string") {
|
|
@@ -3591,16 +3688,11 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3591
3688
|
} else {
|
|
3592
3689
|
errorText = String(result.error);
|
|
3593
3690
|
}
|
|
3594
|
-
const errorOutput = toolOutput || errorText;
|
|
3595
3691
|
safeEnqueue({
|
|
3596
3692
|
type: "tool-result",
|
|
3597
3693
|
toolCallId: requestID,
|
|
3598
3694
|
toolName,
|
|
3599
|
-
result:
|
|
3600
|
-
output: errorOutput,
|
|
3601
|
-
title: toolTitle,
|
|
3602
|
-
metadata: { ...toolMetadata, error: errorText }
|
|
3603
|
-
},
|
|
3695
|
+
result: errorText,
|
|
3604
3696
|
isError: true,
|
|
3605
3697
|
providerExecuted: true
|
|
3606
3698
|
});
|
|
@@ -3625,11 +3717,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3625
3717
|
type: "tool-result",
|
|
3626
3718
|
toolCallId: requestID,
|
|
3627
3719
|
toolName,
|
|
3628
|
-
result:
|
|
3629
|
-
output: errorMsg,
|
|
3630
|
-
title: `${toolName} error`,
|
|
3631
|
-
metadata: { output: errorMsg }
|
|
3632
|
-
},
|
|
3720
|
+
result: errorMsg,
|
|
3633
3721
|
isError: true,
|
|
3634
3722
|
providerExecuted: true
|
|
3635
3723
|
});
|
|
@@ -3642,11 +3730,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
|
|
|
3642
3730
|
type: "tool-result",
|
|
3643
3731
|
toolCallId: requestID,
|
|
3644
3732
|
toolName,
|
|
3645
|
-
result:
|
|
3646
|
-
output: errorMsg,
|
|
3647
|
-
title: `${toolName} error`,
|
|
3648
|
-
metadata: { output: errorMsg }
|
|
3649
|
-
},
|
|
3733
|
+
result: errorMsg,
|
|
3650
3734
|
isError: true,
|
|
3651
3735
|
providerExecuted: true
|
|
3652
3736
|
});
|