opencode-gitlab-duo-agentic 0.2.22 → 0.3.0
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.js +67 -91
- 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
|
|
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
|
-
|
|
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(
|
|
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 = {}) {
|