opencode-gitlab-duo-agentic 0.2.21 → 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.
- package/dist/index.js +80 -96
- 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;
|
|
@@ -793,6 +796,7 @@ var WorkflowSession = class {
|
|
|
793
796
|
#queue;
|
|
794
797
|
#startRequestSent = false;
|
|
795
798
|
#pendingApproval = false;
|
|
799
|
+
#resumed = false;
|
|
796
800
|
#onWorkflowCreated;
|
|
797
801
|
constructor(client, modelId, cwd, options) {
|
|
798
802
|
this.#client = client;
|
|
@@ -801,6 +805,7 @@ var WorkflowSession = class {
|
|
|
801
805
|
this.#cwd = cwd;
|
|
802
806
|
if (options?.existingWorkflowId) {
|
|
803
807
|
this.#workflowId = options.existingWorkflowId;
|
|
808
|
+
this.#resumed = true;
|
|
804
809
|
}
|
|
805
810
|
this.#onWorkflowCreated = options?.onWorkflowCreated;
|
|
806
811
|
}
|
|
@@ -822,6 +827,7 @@ var WorkflowSession = class {
|
|
|
822
827
|
this.#tokenService.clear();
|
|
823
828
|
this.#closeConnection();
|
|
824
829
|
this.#pendingApproval = false;
|
|
830
|
+
this.#resumed = false;
|
|
825
831
|
this.#startRequestSent = false;
|
|
826
832
|
}
|
|
827
833
|
// ---------------------------------------------------------------------------
|
|
@@ -953,11 +959,16 @@ var WorkflowSession = class {
|
|
|
953
959
|
const status = action.newCheckpoint.status;
|
|
954
960
|
dlog(`checkpoint: status=${status} ckptLen=${ckpt.length}`);
|
|
955
961
|
const deltas = extractAgentTextDeltas(ckpt, this.#checkpoint);
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
962
|
+
if (this.#resumed) {
|
|
963
|
+
dlog(`checkpoint: RESUMED \u2014 discarding ${deltas.length} old deltas, fast-forwarding state`);
|
|
964
|
+
this.#resumed = false;
|
|
965
|
+
} else {
|
|
966
|
+
for (const delta of deltas) {
|
|
967
|
+
queue.push({ type: "text-delta", value: delta });
|
|
968
|
+
}
|
|
969
|
+
if (deltas.length > 0) {
|
|
970
|
+
dlog(`checkpoint: ${deltas.length} text deltas`);
|
|
971
|
+
}
|
|
961
972
|
}
|
|
962
973
|
if (isToolApproval(status)) {
|
|
963
974
|
dlog(`checkpoint: TOOL_APPROVAL \u2192 pendingApproval=true (waiting for DWS close)`);
|
|
@@ -973,9 +984,13 @@ var WorkflowSession = class {
|
|
|
973
984
|
}
|
|
974
985
|
const toolAction = action;
|
|
975
986
|
if (toolAction.runHTTPRequest && toolAction.requestID) {
|
|
976
|
-
dlog(`standalone: httpRequest ${toolAction.runHTTPRequest.method} ${toolAction.runHTTPRequest.path} reqId=${toolAction.requestID}`);
|
|
977
|
-
this
|
|
978
|
-
|
|
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);
|
|
979
994
|
return;
|
|
980
995
|
}
|
|
981
996
|
const mapped = mapActionToToolRequest(toolAction);
|
|
@@ -992,42 +1007,6 @@ var WorkflowSession = class {
|
|
|
992
1007
|
}
|
|
993
1008
|
}
|
|
994
1009
|
// ---------------------------------------------------------------------------
|
|
995
|
-
// Private: HTTP request handling (gitlab_api_request)
|
|
996
|
-
// ---------------------------------------------------------------------------
|
|
997
|
-
/**
|
|
998
|
-
* Execute a GitLab API request directly and send the response as httpResponse.
|
|
999
|
-
* DWS is the only action that expects httpResponse instead of plainTextResponse.
|
|
1000
|
-
* Runs async in the background (fire-and-forget from #handleAction).
|
|
1001
|
-
*/
|
|
1002
|
-
async #executeHttpRequest(requestId, request2) {
|
|
1003
|
-
try {
|
|
1004
|
-
const url = `${this.#client.instanceUrl}/api/v4/${request2.path}`;
|
|
1005
|
-
dlog(`httpRequest: ${request2.method} ${request2.path} reqId=${requestId}`);
|
|
1006
|
-
const init = {
|
|
1007
|
-
method: request2.method,
|
|
1008
|
-
headers: {
|
|
1009
|
-
"authorization": `Bearer ${this.#client.token}`,
|
|
1010
|
-
"content-type": "application/json"
|
|
1011
|
-
}
|
|
1012
|
-
};
|
|
1013
|
-
if (request2.body) {
|
|
1014
|
-
init.body = request2.body;
|
|
1015
|
-
}
|
|
1016
|
-
const response = await fetch(url, init);
|
|
1017
|
-
const body = await response.text();
|
|
1018
|
-
const headers = {};
|
|
1019
|
-
response.headers.forEach((value, key) => {
|
|
1020
|
-
headers[key] = value;
|
|
1021
|
-
});
|
|
1022
|
-
dlog(`httpRequest: ${request2.method} ${request2.path} \u2192 ${response.status} body=${body.length}b`);
|
|
1023
|
-
this.sendHttpResult(requestId, response.status, headers, body);
|
|
1024
|
-
} catch (error) {
|
|
1025
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1026
|
-
dlog(`httpRequest: ERROR ${request2.method} ${request2.path} \u2192 ${message}`);
|
|
1027
|
-
this.sendHttpResult(requestId, 0, {}, "", message);
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
// ---------------------------------------------------------------------------
|
|
1031
1010
|
// Private: connection management
|
|
1032
1011
|
// ---------------------------------------------------------------------------
|
|
1033
1012
|
/**
|
|
@@ -1061,7 +1040,11 @@ var WorkflowSession = class {
|
|
|
1061
1040
|
mcpTools,
|
|
1062
1041
|
additional_context: [],
|
|
1063
1042
|
preapproved_tools: mcpTools.map((t) => t.name),
|
|
1064
|
-
approval: { approval: {} }
|
|
1043
|
+
approval: { approval: {} },
|
|
1044
|
+
...this.#toolsConfig?.flowConfig ? {
|
|
1045
|
+
flowConfig: this.#toolsConfig.flowConfig,
|
|
1046
|
+
flowConfigSchemaVersion: this.#toolsConfig.flowConfigSchemaVersion ?? "v1"
|
|
1047
|
+
} : {}
|
|
1065
1048
|
}
|
|
1066
1049
|
});
|
|
1067
1050
|
this.#startRequestSent = true;
|
|
@@ -1506,6 +1489,44 @@ function loadWorkflowId(key) {
|
|
|
1506
1489
|
return store[key];
|
|
1507
1490
|
}
|
|
1508
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
|
+
|
|
1509
1530
|
// src/provider/duo-workflow-model.ts
|
|
1510
1531
|
var sessions = /* @__PURE__ */ new Map();
|
|
1511
1532
|
var UNKNOWN_USAGE = {
|
|
@@ -1527,8 +1548,6 @@ var DuoWorkflowModel = class {
|
|
|
1527
1548
|
#sentToolCallIds = /* @__PURE__ */ new Set();
|
|
1528
1549
|
#lastSentGoal = null;
|
|
1529
1550
|
#stateSessionId;
|
|
1530
|
-
#agentMode;
|
|
1531
|
-
#agentModeReminder;
|
|
1532
1551
|
constructor(modelId, client, cwd) {
|
|
1533
1552
|
this.modelId = modelId;
|
|
1534
1553
|
this.#client = client;
|
|
@@ -1569,8 +1588,6 @@ var DuoWorkflowModel = class {
|
|
|
1569
1588
|
this.#multiCallGroups.clear();
|
|
1570
1589
|
this.#sentToolCallIds.clear();
|
|
1571
1590
|
this.#lastSentGoal = null;
|
|
1572
|
-
this.#agentMode = void 0;
|
|
1573
|
-
this.#agentModeReminder = void 0;
|
|
1574
1591
|
this.#stateSessionId = sessionID;
|
|
1575
1592
|
}
|
|
1576
1593
|
const model = this;
|
|
@@ -1639,31 +1656,24 @@ var DuoWorkflowModel = class {
|
|
|
1639
1656
|
await session.ensureConnected(goal);
|
|
1640
1657
|
if (!session.hasStarted) {
|
|
1641
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
|
+
});
|
|
1642
1668
|
extraContext.push(...buildSystemContext());
|
|
1643
|
-
const systemPrompt = extractSystemPrompt(options.prompt);
|
|
1644
|
-
if (systemPrompt) {
|
|
1645
|
-
extraContext.push({
|
|
1646
|
-
category: "agent_context",
|
|
1647
|
-
content: sanitizeSystemPrompt(systemPrompt),
|
|
1648
|
-
id: "agent_system_prompt",
|
|
1649
|
-
metadata: JSON.stringify({
|
|
1650
|
-
title: "Agent System Prompt",
|
|
1651
|
-
enabled: true,
|
|
1652
|
-
subType: "system_prompt"
|
|
1653
|
-
})
|
|
1654
|
-
});
|
|
1655
|
-
}
|
|
1656
1669
|
const agentReminders = extractAgentReminders(options.prompt);
|
|
1657
|
-
|
|
1658
|
-
if (modeReminder) {
|
|
1659
|
-
model.#agentMode = modeReminder.mode;
|
|
1660
|
-
model.#agentModeReminder = modeReminder.reminder;
|
|
1661
|
-
}
|
|
1662
|
-
const remindersForContext = buildReminderContext(agentReminders, model.#agentModeReminder);
|
|
1663
|
-
if (remindersForContext.length > 0) {
|
|
1670
|
+
if (agentReminders.length > 0) {
|
|
1664
1671
|
extraContext.push({
|
|
1665
1672
|
category: "agent_context",
|
|
1666
|
-
content: sanitizeSystemPrompt(
|
|
1673
|
+
content: sanitizeSystemPrompt(
|
|
1674
|
+
`[context-id:${Date.now()}]
|
|
1675
|
+
${agentReminders.join("\n\n")}`
|
|
1676
|
+
),
|
|
1667
1677
|
id: "agent_reminders",
|
|
1668
1678
|
metadata: JSON.stringify({
|
|
1669
1679
|
title: "Agent Reminders",
|
|
@@ -1802,32 +1812,6 @@ var DuoWorkflowModel = class {
|
|
|
1802
1812
|
function sessionKey(instanceUrl, modelId, sessionID) {
|
|
1803
1813
|
return `${instanceUrl}::${modelId}::${sessionID}`;
|
|
1804
1814
|
}
|
|
1805
|
-
function detectLatestModeReminder(reminders) {
|
|
1806
|
-
let latest;
|
|
1807
|
-
for (const reminder of reminders) {
|
|
1808
|
-
const classification = classifyModeReminder(reminder);
|
|
1809
|
-
if (classification === "other") continue;
|
|
1810
|
-
latest = { mode: classification, reminder };
|
|
1811
|
-
}
|
|
1812
|
-
return latest;
|
|
1813
|
-
}
|
|
1814
|
-
function buildReminderContext(reminders, modeReminder) {
|
|
1815
|
-
const nonModeReminders = reminders.filter(
|
|
1816
|
-
(r) => classifyModeReminder(r) === "other"
|
|
1817
|
-
);
|
|
1818
|
-
if (!modeReminder) return nonModeReminders;
|
|
1819
|
-
return [...nonModeReminders, modeReminder];
|
|
1820
|
-
}
|
|
1821
|
-
function classifyModeReminder(reminder) {
|
|
1822
|
-
const text2 = reminder.toLowerCase();
|
|
1823
|
-
if (text2.includes("operational mode has changed from build to plan")) return "plan";
|
|
1824
|
-
if (text2.includes("operational mode has changed from plan to build")) return "build";
|
|
1825
|
-
if (text2.includes("you are no longer in read-only mode")) return "build";
|
|
1826
|
-
if (text2.includes("you are now in read-only mode")) return "plan";
|
|
1827
|
-
if (text2.includes("you are in read-only mode")) return "plan";
|
|
1828
|
-
if (text2.includes("you are permitted to make file changes")) return "build";
|
|
1829
|
-
return "other";
|
|
1830
|
-
}
|
|
1831
1815
|
|
|
1832
1816
|
// src/provider/index.ts
|
|
1833
1817
|
function createFallbackProvider(input = {}) {
|