duclaw-cli 1.8.32 → 1.8.34

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/bundle.js CHANGED
@@ -30242,7 +30242,7 @@ function printHelp() {
30242
30242
  `);
30243
30243
  }
30244
30244
  function printVersion() {
30245
- console.log(`duclaw-cli v${true ? "1.8.32" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.8.34" : "unknown"}`);
30246
30246
  }
30247
30247
  function getDuclawTemplate() {
30248
30248
  return {
@@ -37599,7 +37599,10 @@ var createAnthropicAdapter = (options) => {
37599
37599
  }, chatOptions?.requestId ? {
37600
37600
  headers: {
37601
37601
  "X-Duclaw-Request-Id": chatOptions.requestId
37602
- }
37602
+ },
37603
+ signal: chatOptions.signal
37604
+ } : chatOptions?.signal ? {
37605
+ signal: chatOptions.signal
37603
37606
  } : void 0);
37604
37607
  if (!sdkResponse.stop_reason) {
37605
37608
  console.error(`${sdkResponse}`);
@@ -41567,7 +41570,7 @@ var markRunning = (userId) => {
41567
41570
  current.startedAt = Date.now();
41568
41571
  return;
41569
41572
  }
41570
- registry.set(userId, { messages: [], startedAt: Date.now() });
41573
+ registry.set(userId, { messages: [], startedAt: Date.now(), listeners: /* @__PURE__ */ new Set() });
41571
41574
  };
41572
41575
  var markDone = (userId) => {
41573
41576
  registry.delete(userId);
@@ -41581,8 +41584,23 @@ var queueInterrupt = (userId, message) => {
41581
41584
  const interruptMessage = typeof message === "string" ? { content: message } : message;
41582
41585
  entry.messages.push(interruptMessage);
41583
41586
  console.log(`[interrupt] \u7528\u6237 ${userId} \u65B0\u6D88\u606F\u5DF2\u5165\u961F\uFF0C\u5F53\u524D\u961F\u5217\u957F\u5EA6: ${entry.messages.length}`);
41587
+ for (const listener of entry.listeners) {
41588
+ try {
41589
+ listener();
41590
+ } catch (err) {
41591
+ console.warn(`[interrupt] \u7528\u6237 ${userId} \u4E2D\u65AD\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25: ${err.message}`);
41592
+ }
41593
+ }
41584
41594
  return true;
41585
41595
  };
41596
+ var registerInterruptListener = (userId, listener) => {
41597
+ const entry = registry.get(userId);
41598
+ if (!entry) return () => void 0;
41599
+ entry.listeners.add(listener);
41600
+ return () => {
41601
+ entry.listeners.delete(listener);
41602
+ };
41603
+ };
41586
41604
  var drainInterrupts = (userId) => {
41587
41605
  const entry = registry.get(userId);
41588
41606
  if (!entry || entry.messages.length === 0) return [];
@@ -42713,7 +42731,7 @@ var checkDepartmentReplies = {
42713
42731
  `- \u8FD9\u4E0D\u662F\u8BA9 CEO \u4EB2\u81EA read/bash/\u6D4B\u8BD5/\u6539\u4EE3\u7801\u7684\u4FE1\u53F7\u3002`,
42714
42732
  `- \u5982\u679C\u7528\u6237\u6B63\u5728\u7B49\u5F85\uFF0C\u8BF7\u5148\u7528 send_message \u7B80\u77ED\u8BF4\u660E\u201C\u8D1F\u8D23\u4EBA\u8FD8\u5728\u5904\u7406\uFF0C\u6211\u7A0D\u540E\u540C\u6B65\u7ED3\u679C\u201D\u3002`,
42715
42733
  `- \u5982\u679C\u5DF2\u7ECF\u7B49\u5F85\u8F83\u4E45\uFF0C\u4F7F\u7528 mailbox_followup \u6216 department_communicate \u50AC\u95EE\u5BF9\u5E94 Department Head \u7684\u771F\u5B9E\u8FDB\u5C55\u3001\u963B\u585E\u9879\u548C\u9884\u8BA1\u5B8C\u6210\u65F6\u95F4\u3002`,
42716
- `- \u4E4B\u540E\u518D\u8C03\u7528 check_department_replies \u67E5\u770B\u56DE\u4FE1\u3002`
42734
+ `- \u672C\u8F6E\u4E0D\u8981\u8FDE\u7EED\u91CD\u590D\u8C03\u7528 check_department_replies\uFF1B\u7B49\u5F85\u65B0\u7684\u90E8\u95E8\u56DE\u4FE1\u4E8B\u4EF6\u3001\u7528\u6237\u8FFD\u95EE\u6216\u50AC\u529E\u56DE\u4FE1\u540E\u518D\u67E5\u770B\u3002`
42717
42735
  ].join("\n");
42718
42736
  }
42719
42737
  const updateStmt = db3.prepare(`UPDATE mailbox SET status = 'read' WHERE id = ?`);
@@ -45201,6 +45219,10 @@ var assistantMessageFromResponse = (response) => ({
45201
45219
  ...response.providerResponseId ? { providerResponseId: response.providerResponseId } : {},
45202
45220
  ...response.model ? { model: response.model } : {}
45203
45221
  });
45222
+ var isAbortError2 = (error) => {
45223
+ if (!(error instanceof Error)) return false;
45224
+ return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
45225
+ };
45204
45226
  var llmRequestIdForTurn = (request, messages, system, tools) => {
45205
45227
  const hash = (0, import_node_crypto11.createHash)("sha256").update(request.requestId).update("\0").update(system).update("\0").update(JSON.stringify(messages)).update("\0").update(JSON.stringify(tools.map((tool) => tool.name).sort())).digest("hex").slice(0, 40);
45206
45228
  return `dreq_${hash}`;
@@ -45281,7 +45303,7 @@ The user will primarily request you perform software engineering tasks. This inc
45281
45303
  - \u53EA\u8981\u7EC4\u7EC7\u91CC\u5DF2\u7ECF\u5B58\u5728\u804C\u8D23\u5339\u914D\u7684 Department \u6216 Department Head\uFF0CCEO \u9ED8\u8BA4\u4E0D\u4EB2\u81EA\u505A\u8BE5\u4E13\u4E1A\u56E2\u961F\u8986\u76D6\u7684\u6267\u884C\u5DE5\u4F5C\u3002
45282
45304
  - \u201C\u4E13\u4E1A\u56E2\u961F\u8986\u76D6\u201D\u5305\u62EC\u4F46\u4E0D\u9650\u4E8E\uFF1A\u5199\u4EE3\u7801\u3001\u8BFB\u4EE3\u7801\u5B9A\u4F4D\u95EE\u9898\u3001\u6539\u6587\u4EF6\u3001\u8DD1\u6D4B\u8BD5\u3001\u8C03\u8BD5\u3001\u90E8\u7F72\u3001\u6570\u636E\u5904\u7406\u3001\u6587\u6863/\u97F3\u9891/\u56FE\u7247\u5904\u7406\u3001\u5916\u90E8 API \u9A8C\u8BC1\u3001\u62A5\u544A\u751F\u6210\u7B49\u3002
45283
45305
  - CEO \u7684\u6B63\u786E\u52A8\u4F5C\u662F department_list \u5B9A\u4F4D\u56E2\u961F\uFF0Cdepartment_communicate \u59D4\u6D3E\u6216\u8FFD\u95EE\uFF0Cmailbox_followup \u50AC\u529E/\u8865\u5145\u4E0A\u4E0B\u6587\uFF0Ccheck_department_replies \u6536\u96C6\u7ED3\u679C\uFF0C\u7136\u540E\u6C47\u603B\u7ED9\u7528\u6237\u3002
45284
- - Department Head \u6682\u65E0\u56DE\u4FE1\u3001\u56DE\u590D\u6162\u3001\u6216 check_department_replies \u8FD4\u56DE\u7A7A\uFF0C\u4E0D\u6784\u6210 CEO \u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\uFF1B\u5E94\u8BE5\u7A0D\u540E\u518D\u67E5\u3001\u50AC\u95EE\u8D1F\u8D23\u4EBA\uFF0C\u6216\u7528 send_message \u544A\u8BC9\u7528\u6237\u201C\u56E2\u961F\u4ECD\u5728\u5904\u7406\uFF0C\u6211\u7A0D\u540E\u540C\u6B65\u201D\u3002
45306
+ - Department Head \u6682\u65E0\u56DE\u4FE1\u3001\u56DE\u590D\u6162\u3001\u6216 check_department_replies \u8FD4\u56DE\u7A7A\uFF0C\u4E0D\u6784\u6210 CEO \u4E0B\u573A\u5E72\u6D3B\u7684\u7406\u7531\uFF1B\u672C\u8F6E\u4E0D\u8981\u8FDE\u7EED\u91CD\u590D\u8C03\u7528 check_department_replies\uFF0C\u5E94\u8BE5\u50AC\u95EE\u8D1F\u8D23\u4EBA\uFF0C\u6216\u7528 send_message \u544A\u8BC9\u7528\u6237\u201C\u56E2\u961F\u4ECD\u5728\u5904\u7406\uFF0C\u6211\u7A0D\u540E\u540C\u6B65\u201D\u5E76\u7ED3\u675F\u5F53\u524D\u8F6E\u6B21\uFF0C\u7B49\u5F85\u65B0\u7684\u90E8\u95E8\u56DE\u4FE1\u4E8B\u4EF6\u6216\u7528\u6237\u8FFD\u95EE\u3002
45285
45307
  - \u53EA\u6709\u5728\u7528\u6237\u660E\u786E\u8981\u6C42\u201CCEO/\u4F60\u4EB2\u81EA\u505A\u201D\u3001\u6CA1\u6709\u4EFB\u4F55\u804C\u8D23\u5339\u914D\u56E2\u961F/\u8D1F\u8D23\u4EBA\u3001\u6216\u56E2\u961F\u660E\u786E\u5931\u8D25\u4E14\u7528\u6237\u540C\u610F CEO \u63A5\u7BA1\u65F6\uFF0CCEO \u624D\u80FD\u8D8A\u8FC7\u56E2\u961F\u4EB2\u81EA\u6267\u884C\u4E13\u4E1A\u5DE5\u4F5C\u3002
45286
45308
 
45287
45309
  ## \u8D23\u4EFB\u5F52\u5C5E\u786C\u89C4\u5219
@@ -45473,6 +45495,32 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
45473
45495
  const { userId, content, job } = request;
45474
45496
  const internalOnly = request.metadata?.internalOnly === true;
45475
45497
  const injectedEventIds = /* @__PURE__ */ new Set();
45498
+ const interruptQueuedEventIds = /* @__PURE__ */ new Set();
45499
+ let durableEventPoller;
45500
+ let activeTurnAbortController;
45501
+ let unregisterInterruptListener;
45502
+ const markInterruptEventIdsInjected = (metadata) => {
45503
+ const ids = Array.isArray(metadata?.agentEventIds) ? metadata.agentEventIds.filter((id) => typeof id === "string") : [];
45504
+ if (ids.length === 0) return;
45505
+ for (const id of ids) injectedEventIds.add(id);
45506
+ markAgentEventsInjected(ids);
45507
+ };
45508
+ const queuePendingDurableEvents = () => {
45509
+ try {
45510
+ const events = listPendingAgentEvents(userId, 10).filter((event) => !injectedEventIds.has(event.id)).filter((event) => !interruptQueuedEventIds.has(event.id));
45511
+ if (events.length === 0) return;
45512
+ for (const event of events) interruptQueuedEventIds.add(event.id);
45513
+ queueInterrupt(userId, {
45514
+ content: renderAgentEventReminder(events),
45515
+ metadata: {
45516
+ trigger: "agent_events.pending",
45517
+ agentEventIds: events.map((event) => event.id)
45518
+ }
45519
+ });
45520
+ } catch (err) {
45521
+ console.warn(`[agent_events] durable event poll failed: ${err.message}`);
45522
+ }
45523
+ };
45476
45524
  const prev = signals.get(userId);
45477
45525
  if (prev) {
45478
45526
  prev.abort();
@@ -45485,6 +45533,10 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
45485
45533
  };
45486
45534
  signals.set(userId, signal);
45487
45535
  markRunning(userId);
45536
+ unregisterInterruptListener = registerInterruptListener(userId, () => {
45537
+ activeTurnAbortController?.abort();
45538
+ });
45539
+ durableEventPoller = setInterval(queuePendingDurableEvents, 1e3);
45488
45540
  try {
45489
45541
  if (dreamEngine) {
45490
45542
  try {
@@ -45615,6 +45667,7 @@ ${notifText}
45615
45667
  const interrupts = drainInterrupts(userId);
45616
45668
  if (interrupts.length > 0) {
45617
45669
  for (const interrupt of interrupts) {
45670
+ markInterruptEventIdsInjected(interrupt.metadata);
45618
45671
  const msg = interrupt.content;
45619
45672
  console.log(`[agent] \u6536\u5230\u4E2D\u65AD\u6D88\u606F\uFF0C\u6CE8\u5165\u5BF9\u8BDD: ${msg.slice(0, 80)}...`);
45620
45673
  if (interrupt.metadata) {
@@ -45709,19 +45762,32 @@ ${memoryInjection}` : "") + dreamInjection;
45709
45762
  }
45710
45763
  }
45711
45764
  let response;
45765
+ const turnAbortController = new AbortController();
45766
+ activeTurnAbortController = turnAbortController;
45712
45767
  try {
45713
45768
  response = await llm.chat(
45714
45769
  messages,
45715
45770
  effectiveSystemPrompt,
45716
45771
  tools,
45717
- { requestId: llmRequestIdForTurn(request, messages, effectiveSystemPrompt, tools) }
45772
+ {
45773
+ requestId: llmRequestIdForTurn(request, messages, effectiveSystemPrompt, tools),
45774
+ signal: turnAbortController.signal
45775
+ }
45718
45776
  );
45719
45777
  } catch (error) {
45778
+ if (isAbortError2(error)) {
45779
+ console.log(`[agent] \u5F53\u524D LLM \u8C03\u7528\u88AB\u4E2D\u65AD\uFF0C\u51C6\u5907\u6CE8\u5165 interrupt \u540E\u91CD\u65B0\u51B3\u7B56 userId=${userId}`);
45780
+ continue;
45781
+ }
45720
45782
  if (compactConfig.enabled && isPromptTooLongError(error) && contextRecoveryAttempts < compactConfig.maxFailures) {
45721
45783
  await recoverFromContextOverflow("prompt_too_long", messages, effectiveSystemPrompt);
45722
45784
  continue;
45723
45785
  }
45724
45786
  throw error;
45787
+ } finally {
45788
+ if (activeTurnAbortController === turnAbortController) {
45789
+ activeTurnAbortController = void 0;
45790
+ }
45725
45791
  }
45726
45792
  if (response.stopReason === "model_context_window_exceeded") {
45727
45793
  await recoverFromContextOverflow("model_context_window_exceeded", messages, effectiveSystemPrompt);
@@ -45815,6 +45881,7 @@ ${memoryInjection}` : "") + dreamInjection;
45815
45881
  if (lateInterrupts.length > 0) {
45816
45882
  console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
45817
45883
  for (const interrupt of lateInterrupts) {
45884
+ markInterruptEventIdsInjected(interrupt.metadata);
45818
45885
  const msg = interrupt.content;
45819
45886
  if (interrupt.metadata) {
45820
45887
  request.metadata = {
@@ -45847,6 +45914,7 @@ ${msg}</user-interrupt>`
45847
45914
  if (lateInterrupts.length > 0) {
45848
45915
  console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
45849
45916
  for (const interrupt of lateInterrupts) {
45917
+ markInterruptEventIdsInjected(interrupt.metadata);
45850
45918
  const msg = interrupt.content;
45851
45919
  if (interrupt.metadata) {
45852
45920
  request.metadata = {
@@ -45891,6 +45959,9 @@ ${msg}</user-interrupt>`
45891
45959
  }
45892
45960
  throw new Error(`\u8FBE\u5230\u6700\u5927\u8FED\u4EE3\u6B21\u6570:${maxIterations}`);
45893
45961
  } finally {
45962
+ if (durableEventPoller) clearInterval(durableEventPoller);
45963
+ unregisterInterruptListener?.();
45964
+ activeTurnAbortController?.abort();
45894
45965
  markDone(userId);
45895
45966
  signals.delete(userId);
45896
45967
  }
@@ -46738,6 +46809,8 @@ var finalizeDepartmentAgentUnrepliedMessages = (mailboxId, msgIds, result) => {
46738
46809
  }
46739
46810
  };
46740
46811
  var polling = false;
46812
+ var inFlightDepartmentMailboxes = /* @__PURE__ */ new Set();
46813
+ var inFlightCeoReplyMessages = /* @__PURE__ */ new Set();
46741
46814
  var pollMailbox = async () => {
46742
46815
  if (polling) return;
46743
46816
  polling = true;
@@ -46754,21 +46827,30 @@ var pollMailbox = async () => {
46754
46827
  const ceoMsgs = grouped.get("manager") || [];
46755
46828
  grouped.delete("manager");
46756
46829
  for (const msg of ceoMsgs) {
46830
+ if (inFlightCeoReplyMessages.has(msg.id)) continue;
46831
+ inFlightCeoReplyMessages.add(msg.id);
46757
46832
  console.log(`[mailbox] \u6536\u5230 department agent \u56DE\u4FE1\uFF08\u6765\u81EA ${msg.fromMailboxId}\uFF09\uFF0C\u6B63\u5728\u5524\u9192\u4E3B agent...`);
46758
- try {
46759
- markMailboxStatus(msg.id, "processing");
46760
- await handleCeoReply(msg);
46761
- markMailboxStatus(msg.id, "done");
46762
- } catch (err) {
46763
- console.error(`[mailbox] \u5524\u9192\u4E3B agent \u5904\u7406\u56DE\u4FE1\u5931\u8D25:`, err);
46764
- markMailboxStatus(msg.id, "failed");
46765
- }
46833
+ void (async () => {
46834
+ try {
46835
+ markMailboxStatus(msg.id, "processing");
46836
+ await handleCeoReply(msg);
46837
+ markMailboxStatus(msg.id, "done");
46838
+ } catch (err) {
46839
+ console.error(`[mailbox] \u5524\u9192\u4E3B agent \u5904\u7406\u56DE\u4FE1\u5931\u8D25:`, err);
46840
+ markMailboxStatus(msg.id, "failed");
46841
+ } finally {
46842
+ inFlightCeoReplyMessages.delete(msg.id);
46843
+ }
46844
+ })();
46766
46845
  }
46767
- const tasks = Array.from(grouped.entries()).map(async ([mailboxId, msgs]) => {
46846
+ for (const [mailboxId, msgs] of grouped.entries()) {
46847
+ if (inFlightDepartmentMailboxes.has(mailboxId)) continue;
46848
+ inFlightDepartmentMailboxes.add(mailboxId);
46768
46849
  const msgIds = msgs.map((m) => m.id);
46769
- await wakeDepartmentAgent(mailboxId, msgIds);
46770
- });
46771
- await Promise.all(tasks);
46850
+ void wakeDepartmentAgent(mailboxId, msgIds).finally(() => {
46851
+ inFlightDepartmentMailboxes.delete(mailboxId);
46852
+ });
46853
+ }
46772
46854
  } catch (err) {
46773
46855
  console.error("[mailbox] \u62C9\u53D6\u5931\u8D25:", err);
46774
46856
  } finally {
@@ -51850,7 +51932,7 @@ var systemRoutes = new Hono2();
51850
51932
  var startTime = Date.now();
51851
51933
  systemRoutes.get("/system/info", (c) => {
51852
51934
  return c.json({
51853
- version: true ? "1.8.32" : "unknown",
51935
+ version: true ? "1.8.34" : "unknown",
51854
51936
  uptime: Math.floor((Date.now() - startTime) / 1e3),
51855
51937
  env: process.env.NODE_ENV || "development",
51856
51938
  nodeVersion: process.version