opencode-gitlab-duo-agentic 0.2.22 → 0.2.24

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.
Files changed (2) hide show
  1. package/dist/index.js +67 -91
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -382,6 +382,7 @@ function isUtilityAgent(agent) {
382
382
  return UTILITY_AGENTS.has(name);
383
383
  }
384
384
  function isGitLabProvider(model) {
385
+ if (model.api?.npm === "opencode-gitlab-duo-agentic") return true;
385
386
  if (model.api?.npm === "opencode-gitlab-duo-agentic") return true;
386
387
  if (model.providerID === "gitlab" && model.api?.npm !== "@gitlab/gitlab-ai-provider") return true;
387
388
  return model.providerID.toLowerCase().includes("gitlab-duo");
@@ -779,6 +780,8 @@ function dlog(msg) {
779
780
  }
780
781
 
781
782
  // src/workflow/session.ts
783
+ var BLOCKED_HTTP_REQUEST_ERROR = "gitlab_api_request is disabled by client policy";
784
+ var BLOCKED_GIT_COMMAND_ERROR = "run_git_command is disabled by client policy";
782
785
  var WorkflowSession = class {
783
786
  #client;
784
787
  #tokenService;
@@ -981,9 +984,13 @@ var WorkflowSession = class {
981
984
  }
982
985
  const toolAction = action;
983
986
  if (toolAction.runHTTPRequest && toolAction.requestID) {
984
- dlog(`standalone: httpRequest ${toolAction.runHTTPRequest.method} ${toolAction.runHTTPRequest.path} reqId=${toolAction.requestID}`);
985
- this.#executeHttpRequest(toolAction.requestID, toolAction.runHTTPRequest).catch(() => {
986
- });
987
+ dlog(`standalone: BLOCKED httpRequest ${toolAction.runHTTPRequest.method} ${toolAction.runHTTPRequest.path} reqId=${toolAction.requestID}`);
988
+ this.sendHttpResult(toolAction.requestID, 403, {}, "", BLOCKED_HTTP_REQUEST_ERROR);
989
+ return;
990
+ }
991
+ if (toolAction.runGitCommand && toolAction.requestID) {
992
+ dlog(`standalone: BLOCKED runGitCommand ${toolAction.runGitCommand.command} reqId=${toolAction.requestID}`);
993
+ this.sendToolResult(toolAction.requestID, "", BLOCKED_GIT_COMMAND_ERROR);
987
994
  return;
988
995
  }
989
996
  const mapped = mapActionToToolRequest(toolAction);
@@ -1000,42 +1007,6 @@ var WorkflowSession = class {
1000
1007
  }
1001
1008
  }
1002
1009
  // ---------------------------------------------------------------------------
1003
- // Private: HTTP request handling (gitlab_api_request)
1004
- // ---------------------------------------------------------------------------
1005
- /**
1006
- * Execute a GitLab API request directly and send the response as httpResponse.
1007
- * DWS is the only action that expects httpResponse instead of plainTextResponse.
1008
- * Runs async in the background (fire-and-forget from #handleAction).
1009
- */
1010
- async #executeHttpRequest(requestId, request2) {
1011
- try {
1012
- const url = `${this.#client.instanceUrl}/api/v4/${request2.path}`;
1013
- dlog(`httpRequest: ${request2.method} ${request2.path} reqId=${requestId}`);
1014
- const init = {
1015
- method: request2.method,
1016
- headers: {
1017
- "authorization": `Bearer ${this.#client.token}`,
1018
- "content-type": "application/json"
1019
- }
1020
- };
1021
- if (request2.body) {
1022
- init.body = request2.body;
1023
- }
1024
- const response = await fetch(url, init);
1025
- const body = await response.text();
1026
- const headers = {};
1027
- response.headers.forEach((value, key) => {
1028
- headers[key] = value;
1029
- });
1030
- dlog(`httpRequest: ${request2.method} ${request2.path} \u2192 ${response.status} body=${body.length}b`);
1031
- this.sendHttpResult(requestId, response.status, headers, body);
1032
- } catch (error) {
1033
- const message = error instanceof Error ? error.message : String(error);
1034
- dlog(`httpRequest: ERROR ${request2.method} ${request2.path} \u2192 ${message}`);
1035
- this.sendHttpResult(requestId, 0, {}, "", message);
1036
- }
1037
- }
1038
- // ---------------------------------------------------------------------------
1039
1010
  // Private: connection management
1040
1011
  // ---------------------------------------------------------------------------
1041
1012
  /**
@@ -1069,7 +1040,11 @@ var WorkflowSession = class {
1069
1040
  mcpTools,
1070
1041
  additional_context: [],
1071
1042
  preapproved_tools: mcpTools.map((t) => t.name),
1072
- approval: { approval: {} }
1043
+ approval: { approval: {} },
1044
+ ...this.#toolsConfig?.flowConfig ? {
1045
+ flowConfig: this.#toolsConfig.flowConfig,
1046
+ flowConfigSchemaVersion: this.#toolsConfig.flowConfigSchemaVersion ?? "v1"
1047
+ } : {}
1073
1048
  }
1074
1049
  });
1075
1050
  this.#startRequestSent = true;
@@ -1514,6 +1489,44 @@ function loadWorkflowId(key) {
1514
1489
  return store[key];
1515
1490
  }
1516
1491
 
1492
+ // src/workflow/flow-config.ts
1493
+ var TOOL_ALLOWLIST = [
1494
+ "read_file",
1495
+ "read_files",
1496
+ "create_file_with_contents",
1497
+ "edit_file",
1498
+ "list_dir",
1499
+ "find_files",
1500
+ "grep",
1501
+ "mkdir",
1502
+ "run_command"
1503
+ ];
1504
+ function buildFlowConfig(systemPrompt) {
1505
+ return {
1506
+ version: "v1",
1507
+ environment: "chat-partial",
1508
+ components: [
1509
+ {
1510
+ // Keep "chat" for behavior parity with GitLab Duo CLI flow metadata.
1511
+ name: "chat",
1512
+ type: "AgentComponent",
1513
+ prompt_id: "chat/agent",
1514
+ toolset: [...TOOL_ALLOWLIST]
1515
+ }
1516
+ ],
1517
+ prompts: [
1518
+ {
1519
+ name: "chat",
1520
+ prompt_id: "chat/agent",
1521
+ unit_primitives: ["duo_chat"],
1522
+ prompt_template: {
1523
+ system: systemPrompt
1524
+ }
1525
+ }
1526
+ ]
1527
+ };
1528
+ }
1529
+
1517
1530
  // src/provider/duo-workflow-model.ts
1518
1531
  var sessions = /* @__PURE__ */ new Map();
1519
1532
  var UNKNOWN_USAGE = {
@@ -1535,8 +1548,6 @@ var DuoWorkflowModel = class {
1535
1548
  #sentToolCallIds = /* @__PURE__ */ new Set();
1536
1549
  #lastSentGoal = null;
1537
1550
  #stateSessionId;
1538
- #agentMode;
1539
- #agentModeReminder;
1540
1551
  constructor(modelId, client, cwd) {
1541
1552
  this.modelId = modelId;
1542
1553
  this.#client = client;
@@ -1577,8 +1588,6 @@ var DuoWorkflowModel = class {
1577
1588
  this.#multiCallGroups.clear();
1578
1589
  this.#sentToolCallIds.clear();
1579
1590
  this.#lastSentGoal = null;
1580
- this.#agentMode = void 0;
1581
- this.#agentModeReminder = void 0;
1582
1591
  this.#stateSessionId = sessionID;
1583
1592
  }
1584
1593
  const model = this;
@@ -1647,31 +1656,24 @@ var DuoWorkflowModel = class {
1647
1656
  await session.ensureConnected(goal);
1648
1657
  if (!session.hasStarted) {
1649
1658
  const extraContext = [];
1659
+ const extractedSystemPrompt = extractSystemPrompt(options.prompt);
1660
+ const sanitizedSystemPrompt = sanitizeSystemPrompt(
1661
+ extractedSystemPrompt ?? "You are GitLab Duo, an AI coding assistant."
1662
+ );
1663
+ session.setToolsConfig({
1664
+ mcpTools: [],
1665
+ flowConfig: buildFlowConfig(sanitizedSystemPrompt),
1666
+ flowConfigSchemaVersion: "v1"
1667
+ });
1650
1668
  extraContext.push(...buildSystemContext());
1651
- const systemPrompt = extractSystemPrompt(options.prompt);
1652
- if (systemPrompt) {
1653
- extraContext.push({
1654
- category: "agent_context",
1655
- content: sanitizeSystemPrompt(systemPrompt),
1656
- id: "agent_system_prompt",
1657
- metadata: JSON.stringify({
1658
- title: "Agent System Prompt",
1659
- enabled: true,
1660
- subType: "system_prompt"
1661
- })
1662
- });
1663
- }
1664
1669
  const agentReminders = extractAgentReminders(options.prompt);
1665
- const modeReminder = detectLatestModeReminder(agentReminders);
1666
- if (modeReminder) {
1667
- model.#agentMode = modeReminder.mode;
1668
- model.#agentModeReminder = modeReminder.reminder;
1669
- }
1670
- const remindersForContext = buildReminderContext(agentReminders, model.#agentModeReminder);
1671
- if (remindersForContext.length > 0) {
1670
+ if (agentReminders.length > 0) {
1672
1671
  extraContext.push({
1673
1672
  category: "agent_context",
1674
- content: sanitizeSystemPrompt(remindersForContext.join("\n\n")),
1673
+ content: sanitizeSystemPrompt(
1674
+ `[context-id:${Date.now()}]
1675
+ ${agentReminders.join("\n\n")}`
1676
+ ),
1675
1677
  id: "agent_reminders",
1676
1678
  metadata: JSON.stringify({
1677
1679
  title: "Agent Reminders",
@@ -1810,32 +1812,6 @@ var DuoWorkflowModel = class {
1810
1812
  function sessionKey(instanceUrl, modelId, sessionID) {
1811
1813
  return `${instanceUrl}::${modelId}::${sessionID}`;
1812
1814
  }
1813
- function detectLatestModeReminder(reminders) {
1814
- let latest;
1815
- for (const reminder of reminders) {
1816
- const classification = classifyModeReminder(reminder);
1817
- if (classification === "other") continue;
1818
- latest = { mode: classification, reminder };
1819
- }
1820
- return latest;
1821
- }
1822
- function buildReminderContext(reminders, modeReminder) {
1823
- const nonModeReminders = reminders.filter(
1824
- (r) => classifyModeReminder(r) === "other"
1825
- );
1826
- if (!modeReminder) return nonModeReminders;
1827
- return [...nonModeReminders, modeReminder];
1828
- }
1829
- function classifyModeReminder(reminder) {
1830
- const text2 = reminder.toLowerCase();
1831
- if (text2.includes("operational mode has changed from build to plan")) return "plan";
1832
- if (text2.includes("operational mode has changed from plan to build")) return "build";
1833
- if (text2.includes("you are no longer in read-only mode")) return "build";
1834
- if (text2.includes("you are now in read-only mode")) return "plan";
1835
- if (text2.includes("you are in read-only mode")) return "plan";
1836
- if (text2.includes("you are permitted to make file changes")) return "build";
1837
- return "other";
1838
- }
1839
1815
 
1840
1816
  // src/provider/index.ts
1841
1817
  function createFallbackProvider(input = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gitlab-duo-agentic",
3
- "version": "0.2.22",
3
+ "version": "0.2.24",
4
4
  "description": "OpenCode plugin and provider for GitLab Duo Agentic workflows",
5
5
  "license": "MIT",
6
6
  "type": "module",