gitlab-ai-provider 5.1.0 → 5.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/dist/index.mjs CHANGED
@@ -1506,7 +1506,7 @@ var GitLabOpenAILanguageModel = class {
1506
1506
  import WebSocket from "isomorphic-ws";
1507
1507
 
1508
1508
  // src/version.ts
1509
- var VERSION = true ? "5.0.0" : "0.0.0-dev";
1509
+ var VERSION = true ? "5.1.0" : "0.0.0-dev";
1510
1510
 
1511
1511
  // src/gitlab-workflow-types.ts
1512
1512
  var WorkflowType = /* @__PURE__ */ ((WorkflowType2) => {
@@ -1843,7 +1843,8 @@ function sanitizeErrorMessage(message) {
1843
1843
  if (!message) return "";
1844
1844
  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]@");
1845
1845
  }
1846
- function mapBuiltinTool(dwsToolName, data) {
1846
+ function mapBuiltinTool(dwsToolName, data, availableTools) {
1847
+ const has = (name) => !availableTools || availableTools.has(name);
1847
1848
  switch (dwsToolName) {
1848
1849
  case "runReadFile":
1849
1850
  return { toolName: "read", args: { filePath: data.filepath } };
@@ -1857,20 +1858,51 @@ function mapBuiltinTool(dwsToolName, data) {
1857
1858
  args: { filePaths: paths }
1858
1859
  };
1859
1860
  }
1860
- case "runWriteFile":
1861
- return {
1862
- toolName: "write",
1863
- args: { filePath: data.filepath, content: data.contents }
1864
- };
1865
- case "runEditFile":
1866
- return {
1867
- toolName: "edit",
1868
- args: {
1869
- filePath: data.filepath,
1870
- oldString: data.oldString ?? data.old_string,
1871
- newString: data.newString ?? data.new_string
1872
- }
1873
- };
1861
+ case "runWriteFile": {
1862
+ if (has("write")) {
1863
+ return {
1864
+ toolName: "write",
1865
+ args: { filePath: data.filepath, content: data.contents }
1866
+ };
1867
+ }
1868
+ const filePath = String(data.filepath ?? "");
1869
+ const content = String(data.contents ?? "");
1870
+ const patchLines = [
1871
+ "*** Begin Patch",
1872
+ `*** Add File: ${filePath}`,
1873
+ ...content.split("\n").map((l) => `+${l}`),
1874
+ "*** End Patch"
1875
+ ].join("\n");
1876
+ return { toolName: "apply_patch", args: { patchText: patchLines } };
1877
+ }
1878
+ case "runEditFile": {
1879
+ const editOldString = String(data.oldString ?? data.old_string ?? "");
1880
+ const editNewString = String(data.newString ?? data.new_string ?? "");
1881
+ if (has("edit")) {
1882
+ return {
1883
+ toolName: "edit",
1884
+ args: {
1885
+ filePath: data.filepath,
1886
+ oldString: editOldString,
1887
+ newString: editNewString
1888
+ }
1889
+ };
1890
+ }
1891
+ const editPath = String(data.filepath ?? "");
1892
+ const oldStr = editOldString;
1893
+ const newStr = editNewString;
1894
+ const oldLines = oldStr.split("\n");
1895
+ const newLines = newStr.split("\n");
1896
+ const patchContent = [
1897
+ "*** Begin Patch",
1898
+ `*** Update File: ${editPath}`,
1899
+ "@@",
1900
+ ...oldLines.map((l) => `-${l}`),
1901
+ ...newLines.map((l) => `+${l}`),
1902
+ "*** End Patch"
1903
+ ].join("\n");
1904
+ return { toolName: "apply_patch", args: { patchText: patchContent } };
1905
+ }
1874
1906
  case "runShellCommand": {
1875
1907
  const command = data.command;
1876
1908
  if (!command || typeof command !== "string") {
@@ -1993,6 +2025,87 @@ function mapBuiltinTool(dwsToolName, data) {
1993
2025
  return { toolName: dwsToolName, args: data };
1994
2026
  }
1995
2027
  }
2028
+ function validateSafePath(filePath) {
2029
+ if (!filePath) {
2030
+ throw new Error("filePath is required");
2031
+ }
2032
+ if (filePath.includes("\0")) {
2033
+ throw new Error("filePath contains null bytes");
2034
+ }
2035
+ const path5 = __require("path");
2036
+ const resolved = path5.resolve(filePath);
2037
+ const cwd = process.cwd();
2038
+ if (!resolved.startsWith(cwd + path5.sep) && resolved !== cwd) {
2039
+ throw new Error(`filePath resolves outside the working directory: ${filePath}`);
2040
+ }
2041
+ return resolved;
2042
+ }
2043
+ function executeBuiltinFallback(toolName, argsJson) {
2044
+ if (toolName !== "edit" && toolName !== "write") {
2045
+ return null;
2046
+ }
2047
+ const fs4 = __require("fs");
2048
+ let args;
2049
+ try {
2050
+ args = JSON.parse(argsJson);
2051
+ } catch {
2052
+ return { result: "", error: `${toolName} fallback: invalid JSON arguments` };
2053
+ }
2054
+ try {
2055
+ if (toolName === "write") {
2056
+ const filePath2 = String(args.filePath ?? "");
2057
+ if (!filePath2) {
2058
+ return { result: "", error: "write fallback: filePath is required" };
2059
+ }
2060
+ const safePath2 = validateSafePath(filePath2);
2061
+ const content2 = String(args.content ?? "");
2062
+ fs4.writeFileSync(safePath2, content2, "utf-8");
2063
+ return {
2064
+ result: "File written successfully.",
2065
+ title: filePath2,
2066
+ metadata: { output: "File written successfully." }
2067
+ };
2068
+ }
2069
+ const filePath = String(args.filePath ?? "");
2070
+ const oldString = String(args.oldString ?? "");
2071
+ const newString = String(args.newString ?? "");
2072
+ if (!filePath) {
2073
+ return { result: "", error: "edit fallback: filePath is required" };
2074
+ }
2075
+ if (!oldString && !newString) {
2076
+ return { result: "", error: "edit fallback: oldString and newString are both empty" };
2077
+ }
2078
+ const safePath = validateSafePath(filePath);
2079
+ let content;
2080
+ try {
2081
+ content = fs4.readFileSync(safePath, "utf-8");
2082
+ } catch {
2083
+ content = "";
2084
+ }
2085
+ if (oldString === "") {
2086
+ fs4.writeFileSync(safePath, newString, "utf-8");
2087
+ return {
2088
+ result: "Edit applied successfully.",
2089
+ title: filePath,
2090
+ metadata: { output: "Edit applied successfully." }
2091
+ };
2092
+ }
2093
+ const idx = content.indexOf(oldString);
2094
+ if (idx === -1) {
2095
+ return { result: "", error: `edit fallback: could not find oldString in ${filePath}` };
2096
+ }
2097
+ const newContent = content.substring(0, idx) + newString + content.substring(idx + oldString.length);
2098
+ fs4.writeFileSync(safePath, newContent, "utf-8");
2099
+ return {
2100
+ result: "Edit applied successfully.",
2101
+ title: filePath,
2102
+ metadata: { output: "Edit applied successfully." }
2103
+ };
2104
+ } catch (e) {
2105
+ const msg = e instanceof Error ? e.message : String(e);
2106
+ return { result: "", error: sanitizeErrorMessage(msg) };
2107
+ }
2108
+ }
1996
2109
 
1997
2110
  // src/gitlab-workflow-token-client.ts
1998
2111
  var TOKEN_CACHE_DURATION_MS = 25 * 60 * 1e3;
@@ -3083,6 +3196,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3083
3196
  const preapprovedTools = this.workflowOptions.preapprovedTools ?? mcpTools.map((t) => t.name);
3084
3197
  const additionalContext = this.buildAdditionalContext(options.prompt);
3085
3198
  const toolExecutor = this.toolExecutor ?? null;
3199
+ const availableToolNames = new Set(options.tools?.map((t) => t.name) ?? []);
3086
3200
  await this.tokenClient.getToken(
3087
3201
  this.workflowOptions.workflowDefinition ?? DEFAULT_WORKFLOW_DEFINITION,
3088
3202
  this.workflowOptions.rootNamespaceId
@@ -3143,7 +3257,8 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3143
3257
  controller,
3144
3258
  wsClient,
3145
3259
  toolExecutor,
3146
- () => `text-${textBlockCounter++}`
3260
+ () => `text-${textBlockCounter++}`,
3261
+ availableToolNames
3147
3262
  );
3148
3263
  }
3149
3264
  );
@@ -3224,7 +3339,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3224
3339
  // ---------------------------------------------------------------------------
3225
3340
  // Event handling
3226
3341
  // ---------------------------------------------------------------------------
3227
- handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId) {
3342
+ handleWorkflowEvent(ss, event, controller, wsClient, toolExecutor, nextTextId, availableToolNames) {
3228
3343
  if (ss.streamClosed) {
3229
3344
  return;
3230
3345
  }
@@ -3281,7 +3396,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3281
3396
  break;
3282
3397
  }
3283
3398
  case "builtin-tool-request": {
3284
- const mapped = mapBuiltinTool(event.toolName, event.data);
3399
+ const mapped = mapBuiltinTool(event.toolName, event.data, availableToolNames);
3285
3400
  const mappedArgs = JSON.stringify(mapped.args);
3286
3401
  if (ss.activeTextBlockId) {
3287
3402
  controller.enqueue({ type: "text-end", id: ss.activeTextBlockId });
@@ -3481,37 +3596,19 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3481
3596
  };
3482
3597
  try {
3483
3598
  if (toolExecutor) {
3484
- const result = await toolExecutor(toolName, argsJson, requestID);
3599
+ let result = await toolExecutor(toolName, argsJson, requestID);
3600
+ if (result.error && /^Unknown tool:/.test(result.error)) {
3601
+ const fallback = executeBuiltinFallback(toolName, argsJson);
3602
+ if (fallback) {
3603
+ result = fallback;
3604
+ }
3605
+ }
3485
3606
  wsClient.sendActionResponse(requestID, result.result, result.error);
3486
3607
  ss.streamedInputChars += argsJson.length;
3487
3608
  ss.streamedOutputChars += result.result.length;
3488
- let toolOutput = result.result;
3489
- let toolTitle = `${toolName} result`;
3490
- let toolMetadata = { output: result.result };
3491
- try {
3492
- const parsed = JSON.parse(result.result);
3493
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
3494
- if (typeof parsed.output === "string") {
3495
- toolOutput = parsed.output;
3496
- } else if (parsed.output != null) {
3497
- toolOutput = JSON.stringify(parsed.output);
3498
- }
3499
- if (typeof parsed.title === "string") toolTitle = parsed.title;
3500
- if (parsed.metadata && typeof parsed.metadata === "object") {
3501
- toolMetadata = {};
3502
- for (const [k, v] of Object.entries(parsed.metadata)) {
3503
- toolMetadata[k] = typeof v === "string" ? v : JSON.stringify(v);
3504
- }
3505
- if (!("output" in toolMetadata)) {
3506
- toolMetadata.output = toolOutput;
3507
- }
3508
- }
3509
- } else if (Array.isArray(parsed)) {
3510
- toolOutput = JSON.stringify(parsed);
3511
- toolMetadata = { output: toolOutput };
3512
- }
3513
- } catch {
3514
- }
3609
+ const toolOutput = result.result;
3610
+ const toolTitle = result.title ?? `${toolName} result`;
3611
+ const toolMetadata = result.metadata ?? { output: result.result };
3515
3612
  if (result.error) {
3516
3613
  let errorText;
3517
3614
  if (typeof result.error === "string") {
@@ -3521,16 +3618,11 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3521
3618
  } else {
3522
3619
  errorText = String(result.error);
3523
3620
  }
3524
- const errorOutput = toolOutput || errorText;
3525
3621
  safeEnqueue({
3526
3622
  type: "tool-result",
3527
3623
  toolCallId: requestID,
3528
3624
  toolName,
3529
- result: {
3530
- output: errorOutput,
3531
- title: toolTitle,
3532
- metadata: { ...toolMetadata, error: errorText }
3533
- },
3625
+ result: errorText,
3534
3626
  isError: true,
3535
3627
  providerExecuted: true
3536
3628
  });
@@ -3555,11 +3647,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3555
3647
  type: "tool-result",
3556
3648
  toolCallId: requestID,
3557
3649
  toolName,
3558
- result: {
3559
- output: errorMsg,
3560
- title: `${toolName} error`,
3561
- metadata: { output: errorMsg }
3562
- },
3650
+ result: errorMsg,
3563
3651
  isError: true,
3564
3652
  providerExecuted: true
3565
3653
  });
@@ -3572,11 +3660,7 @@ var GitLabWorkflowLanguageModel = class _GitLabWorkflowLanguageModel {
3572
3660
  type: "tool-result",
3573
3661
  toolCallId: requestID,
3574
3662
  toolName,
3575
- result: {
3576
- output: errorMsg,
3577
- title: `${toolName} error`,
3578
- metadata: { output: errorMsg }
3579
- },
3663
+ result: errorMsg,
3580
3664
  isError: true,
3581
3665
  providerExecuted: true
3582
3666
  });