opencode-gitlab-duo-agentic 0.1.5 → 0.1.7

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 +29 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1180,7 +1180,7 @@ var TokenUsageEstimator = class {
1180
1180
  };
1181
1181
 
1182
1182
  // src/provider/core/debug_log.ts
1183
- import { appendFileSync, writeFileSync } from "fs";
1183
+ import { appendFileSync } from "fs";
1184
1184
  var LOG_PATH = "/tmp/duo-debug.log";
1185
1185
  function duoLog(...args) {
1186
1186
  const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
@@ -1194,6 +1194,7 @@ function duoLog(...args) {
1194
1194
  }
1195
1195
 
1196
1196
  // src/provider/application/model.ts
1197
+ var EMPTY_USAGE = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
1197
1198
  var GitLabDuoAgenticLanguageModel = class {
1198
1199
  specificationVersion = "v2";
1199
1200
  provider = GITLAB_DUO_PROVIDER_ID;
@@ -1236,10 +1237,14 @@ var GitLabDuoAgenticLanguageModel = class {
1236
1237
  };
1237
1238
  }
1238
1239
  async doStream(options) {
1239
- const workflowType = "chat";
1240
1240
  const promptText = extractLastUserText(options.prompt);
1241
+ if (!this.#runtime.tryAcquireStreamLock()) {
1242
+ duoLog("--- doStream BUSY (rejected)", "prompt=" + (promptText?.slice(0, 40) ?? "null"));
1243
+ return { stream: emptyFinishStream() };
1244
+ }
1245
+ const workflowType = "chat";
1241
1246
  const toolResults = extractToolResults(options.prompt);
1242
- duoLog("--- doStream", "hasStarted=" + this.#runtime.hasStarted, "prompt=" + (promptText?.slice(0, 60) ?? "null"), "toolResults=" + toolResults.length);
1247
+ duoLog("--- doStream", "hasStarted=" + this.#runtime.hasStarted, "prompt=" + (promptText?.slice(0, 60) ?? "null"));
1243
1248
  this.#runtime.resetMapperState();
1244
1249
  if (!this.#runtime.hasStarted) {
1245
1250
  this.#sentToolCallIds.clear();
@@ -1257,7 +1262,6 @@ var GitLabDuoAgenticLanguageModel = class {
1257
1262
  const mcpTools = this.#options.enableMcp === false ? [] : buildMcpTools(options);
1258
1263
  const toolContext = buildToolContext(mcpTools);
1259
1264
  const isNewUserMessage = promptText != null && promptText !== this.#lastSentPrompt;
1260
- duoLog("gate", "isNewUserMessage=" + isNewUserMessage, "freshTools=" + freshToolResults.length, "lastSent=" + (this.#lastSentPrompt?.slice(0, 40) ?? "null"));
1261
1265
  let sentToolResults = false;
1262
1266
  if (freshToolResults.length > 0) {
1263
1267
  for (const result of freshToolResults) {
@@ -1378,8 +1382,6 @@ var GitLabDuoAgenticLanguageModel = class {
1378
1382
  for (const ctx of extraContext) {
1379
1383
  if (ctx.content) this.#usageEstimator.addInputChars(ctx.content);
1380
1384
  }
1381
- } else {
1382
- duoLog("SKIP startRequest", "sentToolResults=" + sentToolResults, "isNewUserMessage=" + isNewUserMessage);
1383
1385
  }
1384
1386
  const iterator = this.#mapEventsToStream(this.#runtime.getEventStream());
1385
1387
  const stream = asyncIteratorToReadableStream(iterator);
@@ -1398,7 +1400,6 @@ var GitLabDuoAgenticLanguageModel = class {
1398
1400
  try {
1399
1401
  for await (const event of events) {
1400
1402
  eventCount++;
1401
- duoLog("evt", event.type, eventCount);
1402
1403
  if (event.type === "TEXT_CHUNK") {
1403
1404
  if (event.content.length > 0) {
1404
1405
  estimator.addOutputChars(event.content);
@@ -1447,6 +1448,8 @@ var GitLabDuoAgenticLanguageModel = class {
1447
1448
  duoLog("streamErr", streamErr instanceof Error ? streamErr.message : String(streamErr));
1448
1449
  yield { type: "error", error: streamErr instanceof Error ? streamErr : new Error(String(streamErr)) };
1449
1450
  return;
1451
+ } finally {
1452
+ this.#runtime.releaseStreamLock();
1450
1453
  }
1451
1454
  duoLog("finish", "events=" + eventCount);
1452
1455
  yield { type: "finish", finishReason: "stop", usage: this.#currentUsage };
@@ -1487,6 +1490,14 @@ var GitLabDuoAgenticLanguageModel = class {
1487
1490
  yield { type: "finish", finishReason: "tool-calls", usage: this.#currentUsage };
1488
1491
  }
1489
1492
  };
1493
+ function emptyFinishStream() {
1494
+ return new ReadableStream({
1495
+ start(controller) {
1496
+ controller.enqueue({ type: "finish", finishReason: "stop", usage: EMPTY_USAGE });
1497
+ controller.close();
1498
+ }
1499
+ });
1500
+ }
1490
1501
  function buildReminderContext(reminders, modeReminder) {
1491
1502
  const nonModeReminders = reminders.filter((reminder) => classifyModeReminder2(reminder) === "other");
1492
1503
  if (!modeReminder) {
@@ -1873,7 +1884,7 @@ var GitLabAgenticRuntime = class {
1873
1884
  #mapper = new WorkflowEventMapper();
1874
1885
  #containerParams;
1875
1886
  #startRequestSent = false;
1876
- #connectingPromise;
1887
+ #streamingLock = false;
1877
1888
  constructor(options, dependencies) {
1878
1889
  this.#options = options;
1879
1890
  this.#dependencies = dependencies;
@@ -1889,6 +1900,14 @@ var GitLabAgenticRuntime = class {
1889
1900
  this.#selectedModelIdentifier = ref;
1890
1901
  this.#resetStreamState();
1891
1902
  }
1903
+ tryAcquireStreamLock() {
1904
+ if (this.#streamingLock) return false;
1905
+ this.#streamingLock = true;
1906
+ return true;
1907
+ }
1908
+ releaseStreamLock() {
1909
+ this.#streamingLock = false;
1910
+ }
1892
1911
  resetMapperState() {
1893
1912
  this.#mapper.resetStreamState();
1894
1913
  }
@@ -1896,24 +1915,10 @@ var GitLabAgenticRuntime = class {
1896
1915
  // Connection lifecycle
1897
1916
  // ---------------------------------------------------------------------------
1898
1917
  async ensureConnected(goal, workflowType) {
1899
- duoLog("ensureConnected", "stream=" + !!this.#stream, "wfId=" + !!this.#workflowId, "queue=" + !!this.#queue, "connecting=" + !!this.#connectingPromise);
1900
- if (this.#connectingPromise) {
1901
- duoLog("ensureConnected", "awaiting in-flight connection");
1902
- await this.#connectingPromise;
1903
- return;
1904
- }
1918
+ duoLog("ensureConnected", "stream=" + !!this.#stream, "wfId=" + !!this.#workflowId, "queue=" + !!this.#queue);
1905
1919
  if (this.#stream && this.#workflowId && this.#queue) {
1906
- duoLog("ensureConnected", "skip (connected)");
1907
1920
  return;
1908
1921
  }
1909
- this.#connectingPromise = this.#doConnect(goal, workflowType);
1910
- try {
1911
- await this.#connectingPromise;
1912
- } finally {
1913
- this.#connectingPromise = void 0;
1914
- }
1915
- }
1916
- async #doConnect(goal, workflowType) {
1917
1922
  if (!this.#containerParams) {
1918
1923
  this.#containerParams = await this.#resolveContainerParams();
1919
1924
  }
@@ -1984,8 +1989,7 @@ var GitLabAgenticRuntime = class {
1984
1989
  preapproved_tools: preapprovedTools
1985
1990
  }
1986
1991
  };
1987
- const ok2 = this.#stream.write(startRequest);
1988
- duoLog("startReq write=" + ok2, "wf=" + this.#workflowId);
1992
+ this.#stream.write(startRequest);
1989
1993
  this.#startRequestSent = true;
1990
1994
  }
1991
1995
  sendToolResponse(requestId, response, responseType) {
@@ -2089,7 +2093,6 @@ var GitLabAgenticRuntime = class {
2089
2093
  workflowStatus: action.newCheckpoint.status
2090
2094
  };
2091
2095
  const events = await this.#mapper.mapWorkflowEvent(duoEvent);
2092
- duoLog("mapped", events.length, events.map((e) => e.type).join(","));
2093
2096
  for (const event of events) {
2094
2097
  queue.push(event);
2095
2098
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gitlab-duo-agentic",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "OpenCode plugin and provider for GitLab Duo Agentic workflows",
5
5
  "license": "MIT",
6
6
  "type": "module",