opencode-gitlab-duo-agentic 0.1.3 → 0.1.5

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 +49 -51
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1179,6 +1179,20 @@ var TokenUsageEstimator = class {
1179
1179
  }
1180
1180
  };
1181
1181
 
1182
+ // src/provider/core/debug_log.ts
1183
+ import { appendFileSync, writeFileSync } from "fs";
1184
+ var LOG_PATH = "/tmp/duo-debug.log";
1185
+ function duoLog(...args) {
1186
+ const ts = (/* @__PURE__ */ new Date()).toISOString().slice(11, 23);
1187
+ const line = ts + " " + args.map(
1188
+ (a) => typeof a === "object" && a !== null ? JSON.stringify(a) : String(a)
1189
+ ).join(" ");
1190
+ try {
1191
+ appendFileSync(LOG_PATH, line + "\n");
1192
+ } catch {
1193
+ }
1194
+ }
1195
+
1182
1196
  // src/provider/application/model.ts
1183
1197
  var GitLabDuoAgenticLanguageModel = class {
1184
1198
  specificationVersion = "v2";
@@ -1225,14 +1239,7 @@ var GitLabDuoAgenticLanguageModel = class {
1225
1239
  const workflowType = "chat";
1226
1240
  const promptText = extractLastUserText(options.prompt);
1227
1241
  const toolResults = extractToolResults(options.prompt);
1228
- console.warn("[duo-debug] doStream called", {
1229
- promptText: promptText?.slice(0, 80),
1230
- toolResultCount: toolResults.length,
1231
- hasStarted: this.#runtime.hasStarted,
1232
- lastSentPrompt: this.#lastSentPrompt?.slice(0, 80) ?? null,
1233
- pendingToolRequests: this.#pendingToolRequests.size,
1234
- sentToolCallIds: this.#sentToolCallIds.size
1235
- });
1242
+ duoLog("--- doStream", "hasStarted=" + this.#runtime.hasStarted, "prompt=" + (promptText?.slice(0, 60) ?? "null"), "toolResults=" + toolResults.length);
1236
1243
  this.#runtime.resetMapperState();
1237
1244
  if (!this.#runtime.hasStarted) {
1238
1245
  this.#sentToolCallIds.clear();
@@ -1242,18 +1249,15 @@ var GitLabDuoAgenticLanguageModel = class {
1242
1249
  }
1243
1250
  }
1244
1251
  this.#lastSentPrompt = null;
1245
- console.warn("[duo-debug] hasStarted=false => reset sentToolCallIds, lastSentPrompt=null");
1246
1252
  }
1247
1253
  const freshToolResults = toolResults.filter((r) => !this.#sentToolCallIds.has(r.toolCallId));
1248
- console.warn("[duo-debug] freshToolResults:", freshToolResults.length);
1249
1254
  const modelRef = this.modelId === GITLAB_DUO_DEFAULT_MODEL_ID ? void 0 : this.modelId;
1250
1255
  this.#runtime.setSelectedModelIdentifier(modelRef);
1251
1256
  await this.#runtime.ensureConnected(promptText || "", workflowType);
1252
- console.warn("[duo-debug] ensureConnected returned OK");
1253
1257
  const mcpTools = this.#options.enableMcp === false ? [] : buildMcpTools(options);
1254
1258
  const toolContext = buildToolContext(mcpTools);
1255
1259
  const isNewUserMessage = promptText != null && promptText !== this.#lastSentPrompt;
1256
- console.warn("[duo-debug] isNewUserMessage:", isNewUserMessage, "promptText != null:", promptText != null, "promptText !== lastSentPrompt:", promptText !== this.#lastSentPrompt);
1260
+ duoLog("gate", "isNewUserMessage=" + isNewUserMessage, "freshTools=" + freshToolResults.length, "lastSent=" + (this.#lastSentPrompt?.slice(0, 40) ?? "null"));
1257
1261
  let sentToolResults = false;
1258
1262
  if (freshToolResults.length > 0) {
1259
1263
  for (const result of freshToolResults) {
@@ -1300,7 +1304,6 @@ var GitLabDuoAgenticLanguageModel = class {
1300
1304
  this.#pendingToolRequests.delete(result.toolCallId);
1301
1305
  }
1302
1306
  }
1303
- console.warn("[duo-debug] startRequest gate: !sentToolResults:", !sentToolResults, "isNewUserMessage:", isNewUserMessage, "=> will send:", !sentToolResults && isNewUserMessage);
1304
1307
  if (!sentToolResults && isNewUserMessage) {
1305
1308
  const extraContext = [];
1306
1309
  if (toolContext) extraContext.push(toolContext);
@@ -1362,7 +1365,7 @@ var GitLabDuoAgenticLanguageModel = class {
1362
1365
  }
1363
1366
  });
1364
1367
  }
1365
- console.warn("[duo-debug] >>> calling sendStartRequest", { goal: promptText?.slice(0, 80), hasStarted: this.#runtime.hasStarted, extraContextCount: extraContext.length });
1368
+ duoLog("sendStartRequest", "hasStarted=" + this.#runtime.hasStarted);
1366
1369
  this.#runtime.sendStartRequest(
1367
1370
  promptText,
1368
1371
  workflowType,
@@ -1371,15 +1374,13 @@ var GitLabDuoAgenticLanguageModel = class {
1371
1374
  extraContext
1372
1375
  );
1373
1376
  this.#lastSentPrompt = promptText;
1374
- console.warn("[duo-debug] >>> sendStartRequest completed, lastSentPrompt set");
1375
1377
  this.#usageEstimator.addInputChars(promptText);
1376
1378
  for (const ctx of extraContext) {
1377
1379
  if (ctx.content) this.#usageEstimator.addInputChars(ctx.content);
1378
1380
  }
1379
1381
  } else {
1380
- console.warn("[duo-debug] SKIPPED sendStartRequest (sentToolResults:", sentToolResults, "isNewUserMessage:", isNewUserMessage, ")");
1382
+ duoLog("SKIP startRequest", "sentToolResults=" + sentToolResults, "isNewUserMessage=" + isNewUserMessage);
1381
1383
  }
1382
- console.warn("[duo-debug] creating event stream iterator");
1383
1384
  const iterator = this.#mapEventsToStream(this.#runtime.getEventStream());
1384
1385
  const stream = asyncIteratorToReadableStream(iterator);
1385
1386
  return {
@@ -1393,12 +1394,11 @@ var GitLabDuoAgenticLanguageModel = class {
1393
1394
  const state = { textStarted: false };
1394
1395
  const estimator = this.#usageEstimator;
1395
1396
  let eventCount = 0;
1396
- console.warn("[duo-debug] #mapEventsToStream: starting iteration");
1397
1397
  yield { type: "stream-start", warnings: [] };
1398
1398
  try {
1399
1399
  for await (const event of events) {
1400
1400
  eventCount++;
1401
- console.warn("[duo-debug] #mapEventsToStream event #" + eventCount + ":", event.type, event.type === "TEXT_CHUNK" ? "(len=" + event.content.length + ")" : "");
1401
+ duoLog("evt", event.type, eventCount);
1402
1402
  if (event.type === "TEXT_CHUNK") {
1403
1403
  if (event.content.length > 0) {
1404
1404
  estimator.addOutputChars(event.content);
@@ -1444,11 +1444,11 @@ var GitLabDuoAgenticLanguageModel = class {
1444
1444
  }
1445
1445
  }
1446
1446
  } catch (streamErr) {
1447
- console.warn("[duo-debug] #mapEventsToStream: caught error after", eventCount, "events:", streamErr instanceof Error ? streamErr.message : String(streamErr));
1447
+ duoLog("streamErr", streamErr instanceof Error ? streamErr.message : String(streamErr));
1448
1448
  yield { type: "error", error: streamErr instanceof Error ? streamErr : new Error(String(streamErr)) };
1449
1449
  return;
1450
1450
  }
1451
- console.warn("[duo-debug] #mapEventsToStream: loop ended normally after", eventCount, "events => yielding finish:stop");
1451
+ duoLog("finish", "events=" + eventCount);
1452
1452
  yield { type: "finish", finishReason: "stop", usage: this.#currentUsage };
1453
1453
  }
1454
1454
  // ---------------------------------------------------------------------------
@@ -1873,6 +1873,7 @@ var GitLabAgenticRuntime = class {
1873
1873
  #mapper = new WorkflowEventMapper();
1874
1874
  #containerParams;
1875
1875
  #startRequestSent = false;
1876
+ #connectingPromise;
1876
1877
  constructor(options, dependencies) {
1877
1878
  this.#options = options;
1878
1879
  this.#dependencies = dependencies;
@@ -1895,26 +1896,32 @@ var GitLabAgenticRuntime = class {
1895
1896
  // Connection lifecycle
1896
1897
  // ---------------------------------------------------------------------------
1897
1898
  async ensureConnected(goal, workflowType) {
1898
- console.warn("[duo-debug] ensureConnected called", {
1899
- hasStream: !!this.#stream,
1900
- hasWorkflowId: !!this.#workflowId,
1901
- workflowId: this.#workflowId?.slice(0, 12),
1902
- hasQueue: !!this.#queue,
1903
- startRequestSent: this.#startRequestSent
1904
- });
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
+ }
1905
1905
  if (this.#stream && this.#workflowId && this.#queue) {
1906
- console.warn("[duo-debug] ensureConnected: short-circuit (already connected)");
1906
+ duoLog("ensureConnected", "skip (connected)");
1907
1907
  return;
1908
1908
  }
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) {
1909
1917
  if (!this.#containerParams) {
1910
1918
  this.#containerParams = await this.#resolveContainerParams();
1911
1919
  }
1912
1920
  if (!this.#workflowId) {
1913
- console.warn("[duo-debug] ensureConnected: creating new workflow");
1914
1921
  this.#workflowId = await this.#createWorkflow(goal, workflowType);
1915
- console.warn("[duo-debug] ensureConnected: workflow created:", this.#workflowId?.slice(0, 12));
1922
+ duoLog("workflow created", this.#workflowId);
1916
1923
  } else {
1917
- console.warn("[duo-debug] ensureConnected: reusing existing workflowId:", this.#workflowId?.slice(0, 12));
1924
+ duoLog("workflow reuse", this.#workflowId);
1918
1925
  }
1919
1926
  const token = await this.#dependencies.workflowService.getWorkflowToken(
1920
1927
  this.#options.instanceUrl,
@@ -1922,19 +1929,17 @@ var GitLabAgenticRuntime = class {
1922
1929
  workflowType
1923
1930
  );
1924
1931
  this.#workflowToken = token;
1925
- console.warn("[duo-debug] ensureConnected: got workflow token");
1926
1932
  const MAX_LOCK_RETRIES = 3;
1927
1933
  const LOCK_RETRY_DELAY_MS = 3e3;
1928
1934
  for (let attempt = 1; attempt <= MAX_LOCK_RETRIES; attempt++) {
1929
1935
  this.#queue = new AsyncQueue();
1930
1936
  try {
1931
- console.warn("[duo-debug] ensureConnected: connecting WebSocket (attempt", attempt, ")");
1932
1937
  await this.#connectWebSocket();
1933
- console.warn("[duo-debug] ensureConnected: WebSocket connected OK");
1938
+ duoLog("ws connected", "attempt=" + attempt);
1934
1939
  return;
1935
1940
  } catch (err2) {
1936
1941
  const msg = err2 instanceof Error ? err2.message : String(err2);
1937
- console.warn("[duo-debug] ensureConnected: WebSocket error:", msg);
1942
+ duoLog("ws error", msg);
1938
1943
  if ((msg.includes("1013") || msg.includes("lock")) && attempt < MAX_LOCK_RETRIES) {
1939
1944
  this.#resetStreamState();
1940
1945
  await this.#dependencies.clock.sleep(LOCK_RETRY_DELAY_MS);
@@ -1979,13 +1984,8 @@ var GitLabAgenticRuntime = class {
1979
1984
  preapproved_tools: preapprovedTools
1980
1985
  }
1981
1986
  };
1982
- console.warn("[duo-debug] sendStartRequest: writing to stream", {
1983
- workflowId: this.#workflowId?.slice(0, 12),
1984
- goal: goal?.slice(0, 80),
1985
- contextCount: additionalContext.length
1986
- });
1987
- const writeResult = this.#stream.write(startRequest);
1988
- console.warn("[duo-debug] sendStartRequest: write() returned:", writeResult);
1987
+ const ok2 = this.#stream.write(startRequest);
1988
+ duoLog("startReq write=" + ok2, "wf=" + this.#workflowId);
1989
1989
  this.#startRequestSent = true;
1990
1990
  }
1991
1991
  sendToolResponse(requestId, response, responseType) {
@@ -2074,14 +2074,14 @@ var GitLabAgenticRuntime = class {
2074
2074
  #bindStream(stream, queue) {
2075
2075
  const now = () => this.#dependencies.clock.now();
2076
2076
  const closeWithError = (message) => {
2077
- console.warn("[duo-debug] stream closeWithError:", message);
2077
+ duoLog("streamErr", message);
2078
2078
  queue.push({ type: "ERROR", message, timestamp: now() });
2079
2079
  queue.close();
2080
2080
  this.#resetStreamState();
2081
2081
  };
2082
2082
  const handleAction = async (action) => {
2083
2083
  if (action.newCheckpoint) {
2084
- console.warn("[duo-debug] stream data: newCheckpoint status=", action.newCheckpoint.status, "goal=", action.newCheckpoint.goal?.slice(0, 40));
2084
+ duoLog("checkpoint", action.newCheckpoint.status);
2085
2085
  const duoEvent = {
2086
2086
  checkpoint: action.newCheckpoint.checkpoint,
2087
2087
  errors: action.newCheckpoint.errors || [],
@@ -2089,7 +2089,7 @@ var GitLabAgenticRuntime = class {
2089
2089
  workflowStatus: action.newCheckpoint.status
2090
2090
  };
2091
2091
  const events = await this.#mapper.mapWorkflowEvent(duoEvent);
2092
- console.warn("[duo-debug] mapper produced", events.length, "events:", events.map((e) => e.type));
2092
+ duoLog("mapped", events.length, events.map((e) => e.type).join(","));
2093
2093
  for (const event of events) {
2094
2094
  queue.push(event);
2095
2095
  }
@@ -2097,7 +2097,7 @@ var GitLabAgenticRuntime = class {
2097
2097
  }
2098
2098
  const toolRequest = mapWorkflowActionToToolRequest(action);
2099
2099
  if (toolRequest) {
2100
- console.warn("[duo-debug] stream data: toolRequest", toolRequest.toolName);
2100
+ duoLog("toolReq", toolRequest.toolName);
2101
2101
  queue.push({
2102
2102
  type: "TOOL_REQUEST",
2103
2103
  ...toolRequest,
@@ -2105,7 +2105,6 @@ var GitLabAgenticRuntime = class {
2105
2105
  });
2106
2106
  return;
2107
2107
  }
2108
- console.warn("[duo-debug] stream data: unhandled action", Object.keys(action));
2109
2108
  };
2110
2109
  stream.on("data", (action) => {
2111
2110
  void handleAction(action).catch((error) => {
@@ -2114,11 +2113,10 @@ var GitLabAgenticRuntime = class {
2114
2113
  });
2115
2114
  });
2116
2115
  stream.on("error", (err2) => {
2117
- console.warn("[duo-debug] stream error:", err2.message);
2118
2116
  closeWithError(err2.message);
2119
2117
  });
2120
2118
  stream.on("end", () => {
2121
- console.warn("[duo-debug] stream end => closing queue + resetStreamState");
2119
+ duoLog("stream end");
2122
2120
  queue.close();
2123
2121
  this.#resetStreamState();
2124
2122
  });
@@ -2140,7 +2138,7 @@ var GitLabAgenticRuntime = class {
2140
2138
  this.#bindStream(stream, this.#queue);
2141
2139
  }
2142
2140
  #resetStreamState() {
2143
- console.warn("[duo-debug] #resetStreamState called", { hadStream: !!this.#stream, hadQueue: !!this.#queue, workflowId: this.#workflowId?.slice(0, 12) });
2141
+ duoLog("reset", "wf=" + this.#workflowId);
2144
2142
  this.#stream = void 0;
2145
2143
  this.#queue = void 0;
2146
2144
  this.#startRequestSent = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opencode-gitlab-duo-agentic",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "OpenCode plugin and provider for GitLab Duo Agentic workflows",
5
5
  "license": "MIT",
6
6
  "type": "module",