duclaw-cli 1.8.31 → 1.8.33

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.31" : "unknown"}`);
30245
+ console.log(`duclaw-cli v${true ? "1.8.33" : "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}`);
@@ -41404,10 +41407,10 @@ var goalDelete = {
41404
41407
  };
41405
41408
 
41406
41409
  // src/tools/tools/department/DepartmentCreate.ts
41407
- var import_node_crypto4 = require("node:crypto");
41410
+ var import_node_crypto5 = require("node:crypto");
41408
41411
 
41409
41412
  // src/department/mailbox/mailbox.ts
41410
- var import_node_crypto3 = require("node:crypto");
41413
+ var import_node_crypto4 = require("node:crypto");
41411
41414
 
41412
41415
  // src/db/createDB.ts
41413
41416
  var import_better_sqlite3 = __toESM(require("better-sqlite3"));
@@ -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 [];
@@ -41592,8 +41610,148 @@ var drainInterrupts = (userId) => {
41592
41610
  return messages;
41593
41611
  };
41594
41612
 
41595
- // src/department/mailbox/events.ts
41613
+ // src/agent/events.ts
41596
41614
  var import_node_crypto2 = require("node:crypto");
41615
+ var rowToEvent = (row) => ({
41616
+ id: row.id,
41617
+ userId: row.userId,
41618
+ type: row.type,
41619
+ source: row.source,
41620
+ sourceId: row.sourceId,
41621
+ status: row.status,
41622
+ payload: JSON.parse(row.payloadJson || "{}"),
41623
+ createdAt: row.createdAt,
41624
+ injectedAt: row.injectedAt ?? void 0,
41625
+ handledAt: row.handledAt ?? void 0,
41626
+ updatedAt: row.updatedAt
41627
+ });
41628
+ var recordAgentEvent = (input) => {
41629
+ const db3 = createSqliteDB();
41630
+ const now = Date.now();
41631
+ const id = `evt_${(0, import_node_crypto2.randomUUID)().slice(0, 12)}`;
41632
+ const payloadJson = JSON.stringify(input.payload);
41633
+ db3.prepare(`
41634
+ INSERT INTO agent_events (
41635
+ id, user_id, type, source, source_id, status, payload_json, created_at, updated_at
41636
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
41637
+ ON CONFLICT(type, source, source_id) DO UPDATE SET
41638
+ user_id = excluded.user_id,
41639
+ status = CASE
41640
+ WHEN agent_events.status IN ('handled', 'ignored') THEN agent_events.status
41641
+ ELSE excluded.status
41642
+ END,
41643
+ payload_json = excluded.payload_json,
41644
+ updated_at = excluded.updated_at
41645
+ `).run(
41646
+ id,
41647
+ input.userId,
41648
+ input.type,
41649
+ input.source,
41650
+ input.sourceId,
41651
+ input.status ?? "pending",
41652
+ payloadJson,
41653
+ now,
41654
+ now
41655
+ );
41656
+ const row = db3.prepare(`
41657
+ SELECT
41658
+ id,
41659
+ user_id as userId,
41660
+ type,
41661
+ source,
41662
+ source_id as sourceId,
41663
+ status,
41664
+ payload_json as payloadJson,
41665
+ created_at as createdAt,
41666
+ injected_at as injectedAt,
41667
+ handled_at as handledAt,
41668
+ updated_at as updatedAt
41669
+ FROM agent_events
41670
+ WHERE type = ? AND source = ? AND source_id = ?
41671
+ `).get(input.type, input.source, input.sourceId);
41672
+ return rowToEvent(row);
41673
+ };
41674
+ var listPendingAgentEvents = (userId, limit = 10) => {
41675
+ const db3 = createSqliteDB();
41676
+ const rows = db3.prepare(`
41677
+ SELECT
41678
+ id,
41679
+ user_id as userId,
41680
+ type,
41681
+ source,
41682
+ source_id as sourceId,
41683
+ status,
41684
+ payload_json as payloadJson,
41685
+ created_at as createdAt,
41686
+ injected_at as injectedAt,
41687
+ handled_at as handledAt,
41688
+ updated_at as updatedAt
41689
+ FROM agent_events
41690
+ WHERE user_id = ?
41691
+ AND status IN ('pending', 'processing')
41692
+ ORDER BY created_at ASC
41693
+ LIMIT ?
41694
+ `).all(userId, limit);
41695
+ return rows.map(rowToEvent);
41696
+ };
41697
+ var markAgentEventsInjected = (eventIds) => {
41698
+ if (eventIds.length === 0) return;
41699
+ const db3 = createSqliteDB();
41700
+ const now = Date.now();
41701
+ const stmt = db3.prepare(`
41702
+ UPDATE agent_events
41703
+ SET status = CASE WHEN status = 'pending' THEN 'processing' ELSE status END,
41704
+ injected_at = COALESCE(injected_at, ?),
41705
+ updated_at = ?
41706
+ WHERE id = ?
41707
+ AND status IN ('pending', 'processing')
41708
+ `);
41709
+ const tx = db3.transaction((ids) => {
41710
+ for (const id of ids) stmt.run(now, now, id);
41711
+ });
41712
+ tx(eventIds);
41713
+ };
41714
+ var markAgentEventsHandled = (eventIds, status = "handled") => {
41715
+ if (eventIds.length === 0) return;
41716
+ const db3 = createSqliteDB();
41717
+ const now = Date.now();
41718
+ const stmt = db3.prepare(`
41719
+ UPDATE agent_events
41720
+ SET status = ?,
41721
+ handled_at = COALESCE(handled_at, ?),
41722
+ updated_at = ?
41723
+ WHERE id = ?
41724
+ AND status IN ('pending', 'processing')
41725
+ `);
41726
+ const tx = db3.transaction((ids) => {
41727
+ for (const id of ids) stmt.run(status, now, now, id);
41728
+ });
41729
+ tx(eventIds);
41730
+ };
41731
+ var renderAgentEventReminder = (events) => {
41732
+ if (events.length === 0) return "";
41733
+ const lines = events.map((event) => {
41734
+ const owner = typeof event.payload.ownerMailboxId === "string" ? event.payload.ownerMailboxId : void 0;
41735
+ const mailboxMessageId = typeof event.payload.mailboxMessageId === "string" ? event.payload.mailboxMessageId : event.sourceId;
41736
+ const summary = typeof event.payload.summary === "string" ? event.payload.summary : typeof event.payload.contentPreview === "string" ? event.payload.contentPreview : "";
41737
+ return [
41738
+ `- eventId=${event.id}`,
41739
+ `type=${event.type}`,
41740
+ owner ? `owner=${owner}` : "",
41741
+ mailboxMessageId ? `mailboxMessageId=${mailboxMessageId}` : "",
41742
+ summary ? `summary=${summary}` : ""
41743
+ ].filter(Boolean).join(" ");
41744
+ }).join("\n");
41745
+ return `<system-reminder>
41746
+ \u672C\u8F6E\u6709 ${events.length} \u6761\u5185\u90E8\u4E8B\u4EF6\u53EF\u7528\uFF1A
41747
+ ${lines}
41748
+
41749
+ \u8FD9\u4E9B\u4E8B\u4EF6\u4E0D\u662F\u7528\u6237\u7684\u65B0\u8BF7\u6C42\uFF0C\u4E5F\u4E0D\u5E94\u8BE5\u4F5C\u4E3A\u7528\u6237\u786E\u8BA4\u3002\u82E5\u4E8B\u4EF6\u7C7B\u578B\u662F mailbox.message_received\uFF0C\u8868\u793A\u4F60\u7684 mailbox \u5728\u5F53\u524D\u5DE5\u4F5C\u671F\u95F4\u6536\u5230\u65B0\u5185\u90E8\u534F\u4F5C\u6D88\u606F\uFF1B\u8BF7\u5C3D\u5FEB\u8C03\u7528 list_mailbox \u67E5\u770B\u961F\u5217\uFF0C\u5E76\u5728\u9700\u8981\u65F6\u7528 get_mailbox(message_id) \u9886\u53D6\u5173\u8054\u6D88\u606F\u3002\u4E0D\u8981\u76F4\u63A5\u628A\u4E8B\u4EF6\u5F53\u4F5C\u5DF2\u9886\u53D6\u90AE\u4EF6\u3002\u8BF7\u53EA\u5728\u9700\u8981\u65F6\u81EA\u7136\u5730\u6C47\u603B\u7ED9\u7528\u6237\uFF1B\u5982\u9700\u7EE7\u7EED\u534F\u4F5C\uFF0C\u4F18\u5148\u4F7F\u7528\u4E8B\u4EF6\u4E2D\u5173\u8054\u7684 mailboxMessageId/thread \u7EE7\u7EED\u5904\u7406\u3002\u4E0D\u8981\u590D\u8FF0\u672C system-reminder\u3002
41750
+ </system-reminder>`;
41751
+ };
41752
+
41753
+ // src/department/mailbox/events.ts
41754
+ var import_node_crypto3 = require("node:crypto");
41597
41755
  var parseDetail = (detailJson) => {
41598
41756
  if (!detailJson) return void 0;
41599
41757
  try {
@@ -41634,7 +41792,7 @@ var mapMailboxEventRow = (row) => {
41634
41792
  var recordMailboxEvent = (input) => {
41635
41793
  const db3 = createSqliteDB();
41636
41794
  const event = {
41637
- id: (0, import_node_crypto2.randomUUID)().slice(0, 12),
41795
+ id: (0, import_node_crypto3.randomUUID)().slice(0, 12),
41638
41796
  messageId: input.messageId,
41639
41797
  mailboxId: input.mailboxId,
41640
41798
  actorMailboxId: input.actorMailboxId,
@@ -41979,6 +42137,24 @@ var queueMailboxInterruptIfRunning = (msg) => {
41979
42137
  console.log(`[mailbox] \u76EE\u6807 agent ${msg.toMailboxId} \u6B63\u5728\u8FD0\u884C\uFF0C\u5DF2\u5C06\u65B0\u90AE\u4EF6 ${msg.id} \u4F5C\u4E3A\u4E2D\u65AD\u63D0\u9192\u5165\u961F`);
41980
42138
  }
41981
42139
  };
42140
+ var recordMailboxReceivedAgentEvent = (msg) => {
42141
+ if (msg.toMailboxId === "manager") return;
42142
+ recordAgentEvent({
42143
+ userId: msg.toMailboxId,
42144
+ type: "mailbox.message_received",
42145
+ source: "mailbox",
42146
+ sourceId: msg.id,
42147
+ payload: {
42148
+ ownerMailboxId: msg.toMailboxId,
42149
+ mailboxMessageId: msg.id,
42150
+ fromMailboxId: msg.fromMailboxId,
42151
+ toMailboxId: msg.toMailboxId,
42152
+ threadId: msg.threadId || msg.id,
42153
+ contentPreview: msg.content.slice(0, 160),
42154
+ summary: `\u6536\u5230\u6765\u81EA ${msg.fromMailboxId} \u7684\u65B0\u5185\u90E8\u534F\u4F5C\u6D88\u606F\uFF0C\u8BF7\u7528 list_mailbox/get_mailbox \u8BC4\u4F30\u5E76\u9886\u53D6\u3002`
42155
+ }
42156
+ });
42157
+ };
41982
42158
  var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
41983
42159
  const db3 = createSqliteDB();
41984
42160
  const stmt = db3.prepare(`insert into mailbox (
@@ -41993,7 +42169,7 @@ var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
41993
42169
  thread_id,
41994
42170
  parent_message_id
41995
42171
  ) values (?,?,?,?,?,?,?,?,?,?) `);
41996
- const id = (0, import_node_crypto3.randomUUID)().slice(0, 8);
42172
+ const id = (0, import_node_crypto4.randomUUID)().slice(0, 8);
41997
42173
  const threadId = options?.threadId || id;
41998
42174
  let mailboxMsg = {
41999
42175
  id,
@@ -42031,6 +42207,7 @@ var sendMessage2 = (fromMailboxId, toMailboxId, content, options) => {
42031
42207
  },
42032
42208
  createdAt: mailboxMsg.sendTime
42033
42209
  });
42210
+ recordMailboxReceivedAgentEvent(mailboxMsg);
42034
42211
  queueMailboxInterruptIfRunning(mailboxMsg);
42035
42212
  return mailboxMsg;
42036
42213
  };
@@ -42109,7 +42286,7 @@ var departmentCreate = {
42109
42286
  return `[departmentCreate] \u4E0D\u5B58\u5728 id=${sourceGoalId} \u7684\u76EE\u6807`;
42110
42287
  }
42111
42288
  let departmentDefinition = {
42112
- id: (0, import_node_crypto4.randomUUID)().slice(0, 8),
42289
+ id: (0, import_node_crypto5.randomUUID)().slice(0, 8),
42113
42290
  name,
42114
42291
  charter,
42115
42292
  sourceGoalId,
@@ -42323,7 +42500,7 @@ var departmentList = {
42323
42500
  };
42324
42501
 
42325
42502
  // src/tools/tools/department/DepartmentMemberCreate.ts
42326
- var import_node_crypto5 = require("node:crypto");
42503
+ var import_node_crypto6 = require("node:crypto");
42327
42504
  var DESCRIPTION24 = `
42328
42505
  \u521B\u5EFA\u90E8\u95E8\u6210\u5458\u3002
42329
42506
 
@@ -42389,7 +42566,7 @@ var departmentMemberCreate = {
42389
42566
  }
42390
42567
  }
42391
42568
  let departmentMember = {
42392
- id: (0, import_node_crypto5.randomUUID)().slice(0, 8),
42569
+ id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
42393
42570
  name,
42394
42571
  departmentId: department.id,
42395
42572
  mailBoxId: getMailBoxId(department.name, name),
@@ -42580,7 +42757,7 @@ ${replies}`;
42580
42757
  // src/department/learning.ts
42581
42758
  var import_node_fs4 = require("node:fs");
42582
42759
  var import_node_path12 = __toESM(require("node:path"));
42583
- var import_node_crypto6 = require("node:crypto");
42760
+ var import_node_crypto7 = require("node:crypto");
42584
42761
 
42585
42762
  // src/skill/SkillValidator.ts
42586
42763
  var import_node_fs3 = require("node:fs");
@@ -42818,7 +42995,7 @@ var listDepartmentMemories = (departmentName) => {
42818
42995
  var createDepartmentMemory = (departmentName, input) => {
42819
42996
  const now = Date.now();
42820
42997
  const memory = {
42821
- id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
42998
+ id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
42822
42999
  departmentName,
42823
43000
  title: input.title,
42824
43001
  content: input.content,
@@ -42869,7 +43046,7 @@ ${formatSkillValidationIssues(validation)}`);
42869
43046
  }
42870
43047
  const now = Date.now();
42871
43048
  const skill = {
42872
- id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
43049
+ id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
42873
43050
  departmentName,
42874
43051
  skillName: input.skillName,
42875
43052
  description: input.description,
@@ -42921,7 +43098,7 @@ var createDepartmentProposal = (input) => {
42921
43098
  const records = readJsonArray(proposalsPath());
42922
43099
  const proposal = {
42923
43100
  ...input,
42924
- id: (0, import_node_crypto6.randomUUID)().slice(0, 8),
43101
+ id: (0, import_node_crypto7.randomUUID)().slice(0, 8),
42925
43102
  status: "pending",
42926
43103
  createdAt: Date.now()
42927
43104
  };
@@ -43252,7 +43429,7 @@ var mailboxFollowup = {
43252
43429
 
43253
43430
  // src/tools/tools/Bash.ts
43254
43431
  var import_node_child_process = require("node:child_process");
43255
- var import_node_crypto7 = require("node:crypto");
43432
+ var import_node_crypto8 = require("node:crypto");
43256
43433
  var import_node_fs5 = require("node:fs");
43257
43434
  var DESCRIPTION29 = `\u5728\u7CFB\u7EDF shell \u4E2D\u6267\u884C\u547D\u4EE4\u3002
43258
43435
 
@@ -43456,7 +43633,7 @@ var bashTool = {
43456
43633
  ...options,
43457
43634
  stdio: ["pipe", "pipe", "pipe"]
43458
43635
  });
43459
- const id = (0, import_node_crypto7.randomUUID)().slice(0, 8);
43636
+ const id = (0, import_node_crypto8.randomUUID)().slice(0, 8);
43460
43637
  const session = {
43461
43638
  id,
43462
43639
  command,
@@ -44037,7 +44214,7 @@ var readDreamHistoryLimit = () => {
44037
44214
  var import_node_fs6 = require("node:fs");
44038
44215
  var import_node_os2 = require("node:os");
44039
44216
  var import_node_path13 = require("node:path");
44040
- var import_node_crypto8 = require("node:crypto");
44217
+ var import_node_crypto9 = require("node:crypto");
44041
44218
  var SkillForgeEngine = class {
44042
44219
  proposalStorage;
44043
44220
  draftRoot;
@@ -44071,7 +44248,7 @@ ${formatSkillValidationIssues(validation)}`);
44071
44248
  if (pending.some((p) => p.skillName === skillName)) {
44072
44249
  return null;
44073
44250
  }
44074
- const id = (0, import_node_crypto8.randomBytes)(4).toString("hex");
44251
+ const id = (0, import_node_crypto9.randomBytes)(4).toString("hex");
44075
44252
  const draftDir = (0, import_node_path13.join)(this.draftRoot, userId, id);
44076
44253
  (0, import_node_fs6.mkdirSync)(draftDir, { recursive: true });
44077
44254
  (0, import_node_fs6.writeFileSync)((0, import_node_path13.join)(draftDir, "SKILL.md"), skillMd, "utf-8");
@@ -44353,7 +44530,7 @@ var skillForgeDrop = (engine) => ({
44353
44530
  });
44354
44531
 
44355
44532
  // src/memory/MemoryEngine.ts
44356
- var import_node_crypto9 = require("node:crypto");
44533
+ var import_node_crypto10 = require("node:crypto");
44357
44534
  var MemoryEngine = class {
44358
44535
  storage;
44359
44536
  recallIndexStorage;
@@ -44381,7 +44558,7 @@ var MemoryEngine = class {
44381
44558
  }
44382
44559
  const now = Date.now();
44383
44560
  const memory = {
44384
- id: (0, import_node_crypto9.randomBytes)(4).toString("hex"),
44561
+ id: (0, import_node_crypto10.randomBytes)(4).toString("hex"),
44385
44562
  userId,
44386
44563
  title,
44387
44564
  content,
@@ -45033,146 +45210,6 @@ var microCompactMessages = (messages, config2) => {
45033
45210
  };
45034
45211
  };
45035
45212
 
45036
- // src/agent/events.ts
45037
- var import_node_crypto10 = require("node:crypto");
45038
- var rowToEvent = (row) => ({
45039
- id: row.id,
45040
- userId: row.userId,
45041
- type: row.type,
45042
- source: row.source,
45043
- sourceId: row.sourceId,
45044
- status: row.status,
45045
- payload: JSON.parse(row.payloadJson || "{}"),
45046
- createdAt: row.createdAt,
45047
- injectedAt: row.injectedAt ?? void 0,
45048
- handledAt: row.handledAt ?? void 0,
45049
- updatedAt: row.updatedAt
45050
- });
45051
- var recordAgentEvent = (input) => {
45052
- const db3 = createSqliteDB();
45053
- const now = Date.now();
45054
- const id = `evt_${(0, import_node_crypto10.randomUUID)().slice(0, 12)}`;
45055
- const payloadJson = JSON.stringify(input.payload);
45056
- db3.prepare(`
45057
- INSERT INTO agent_events (
45058
- id, user_id, type, source, source_id, status, payload_json, created_at, updated_at
45059
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
45060
- ON CONFLICT(type, source, source_id) DO UPDATE SET
45061
- user_id = excluded.user_id,
45062
- status = CASE
45063
- WHEN agent_events.status IN ('handled', 'ignored') THEN agent_events.status
45064
- ELSE excluded.status
45065
- END,
45066
- payload_json = excluded.payload_json,
45067
- updated_at = excluded.updated_at
45068
- `).run(
45069
- id,
45070
- input.userId,
45071
- input.type,
45072
- input.source,
45073
- input.sourceId,
45074
- input.status ?? "pending",
45075
- payloadJson,
45076
- now,
45077
- now
45078
- );
45079
- const row = db3.prepare(`
45080
- SELECT
45081
- id,
45082
- user_id as userId,
45083
- type,
45084
- source,
45085
- source_id as sourceId,
45086
- status,
45087
- payload_json as payloadJson,
45088
- created_at as createdAt,
45089
- injected_at as injectedAt,
45090
- handled_at as handledAt,
45091
- updated_at as updatedAt
45092
- FROM agent_events
45093
- WHERE type = ? AND source = ? AND source_id = ?
45094
- `).get(input.type, input.source, input.sourceId);
45095
- return rowToEvent(row);
45096
- };
45097
- var listPendingAgentEvents = (userId, limit = 10) => {
45098
- const db3 = createSqliteDB();
45099
- const rows = db3.prepare(`
45100
- SELECT
45101
- id,
45102
- user_id as userId,
45103
- type,
45104
- source,
45105
- source_id as sourceId,
45106
- status,
45107
- payload_json as payloadJson,
45108
- created_at as createdAt,
45109
- injected_at as injectedAt,
45110
- handled_at as handledAt,
45111
- updated_at as updatedAt
45112
- FROM agent_events
45113
- WHERE user_id = ?
45114
- AND status IN ('pending', 'processing')
45115
- ORDER BY created_at ASC
45116
- LIMIT ?
45117
- `).all(userId, limit);
45118
- return rows.map(rowToEvent);
45119
- };
45120
- var markAgentEventsInjected = (eventIds) => {
45121
- if (eventIds.length === 0) return;
45122
- const db3 = createSqliteDB();
45123
- const now = Date.now();
45124
- const stmt = db3.prepare(`
45125
- UPDATE agent_events
45126
- SET status = CASE WHEN status = 'pending' THEN 'processing' ELSE status END,
45127
- injected_at = COALESCE(injected_at, ?),
45128
- updated_at = ?
45129
- WHERE id = ?
45130
- AND status IN ('pending', 'processing')
45131
- `);
45132
- const tx = db3.transaction((ids) => {
45133
- for (const id of ids) stmt.run(now, now, id);
45134
- });
45135
- tx(eventIds);
45136
- };
45137
- var markAgentEventsHandled = (eventIds, status = "handled") => {
45138
- if (eventIds.length === 0) return;
45139
- const db3 = createSqliteDB();
45140
- const now = Date.now();
45141
- const stmt = db3.prepare(`
45142
- UPDATE agent_events
45143
- SET status = ?,
45144
- handled_at = COALESCE(handled_at, ?),
45145
- updated_at = ?
45146
- WHERE id = ?
45147
- AND status IN ('pending', 'processing')
45148
- `);
45149
- const tx = db3.transaction((ids) => {
45150
- for (const id of ids) stmt.run(status, now, now, id);
45151
- });
45152
- tx(eventIds);
45153
- };
45154
- var renderAgentEventReminder = (events) => {
45155
- if (events.length === 0) return "";
45156
- const lines = events.map((event) => {
45157
- const owner = typeof event.payload.ownerMailboxId === "string" ? event.payload.ownerMailboxId : void 0;
45158
- const mailboxMessageId = typeof event.payload.mailboxMessageId === "string" ? event.payload.mailboxMessageId : event.sourceId;
45159
- const summary = typeof event.payload.summary === "string" ? event.payload.summary : typeof event.payload.contentPreview === "string" ? event.payload.contentPreview : "";
45160
- return [
45161
- `- eventId=${event.id}`,
45162
- `type=${event.type}`,
45163
- owner ? `owner=${owner}` : "",
45164
- mailboxMessageId ? `mailboxMessageId=${mailboxMessageId}` : "",
45165
- summary ? `summary=${summary}` : ""
45166
- ].filter(Boolean).join(" ");
45167
- }).join("\n");
45168
- return `<system-reminder>
45169
- \u672C\u8F6E\u6709 ${events.length} \u6761\u5185\u90E8\u4E8B\u4EF6\u53EF\u7528\uFF1A
45170
- ${lines}
45171
-
45172
- \u8FD9\u4E9B\u4E8B\u4EF6\u4E0D\u662F\u7528\u6237\u7684\u65B0\u8BF7\u6C42\uFF0C\u4E5F\u4E0D\u5E94\u8BE5\u4F5C\u4E3A\u7528\u6237\u786E\u8BA4\u3002\u8BF7\u53EA\u5728\u9700\u8981\u65F6\u81EA\u7136\u5730\u6C47\u603B\u7ED9\u7528\u6237\uFF1B\u5982\u9700\u7EE7\u7EED\u534F\u4F5C\uFF0C\u4F18\u5148\u4F7F\u7528\u4E8B\u4EF6\u4E2D\u5173\u8054\u7684 mailboxMessageId/thread \u7EE7\u7EED\u5904\u7406\u3002\u4E0D\u8981\u590D\u8FF0\u672C system-reminder\u3002
45173
- </system-reminder>`;
45174
- };
45175
-
45176
45213
  // src/agent/createAgent.ts
45177
45214
  var DEFAULT_WORKSPACE_PATH = getDuclawWorkspaceDir();
45178
45215
  var assistantMessageFromResponse = (response) => ({
@@ -45182,6 +45219,10 @@ var assistantMessageFromResponse = (response) => ({
45182
45219
  ...response.providerResponseId ? { providerResponseId: response.providerResponseId } : {},
45183
45220
  ...response.model ? { model: response.model } : {}
45184
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
+ };
45185
45226
  var llmRequestIdForTurn = (request, messages, system, tools) => {
45186
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);
45187
45228
  return `dreq_${hash}`;
@@ -45454,6 +45495,32 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
45454
45495
  const { userId, content, job } = request;
45455
45496
  const internalOnly = request.metadata?.internalOnly === true;
45456
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
+ };
45457
45524
  const prev = signals.get(userId);
45458
45525
  if (prev) {
45459
45526
  prev.abort();
@@ -45466,6 +45533,10 @@ var createAgent = (config2 = getDefaultAgentConfig()) => {
45466
45533
  };
45467
45534
  signals.set(userId, signal);
45468
45535
  markRunning(userId);
45536
+ unregisterInterruptListener = registerInterruptListener(userId, () => {
45537
+ activeTurnAbortController?.abort();
45538
+ });
45539
+ durableEventPoller = setInterval(queuePendingDurableEvents, 1e3);
45469
45540
  try {
45470
45541
  if (dreamEngine) {
45471
45542
  try {
@@ -45596,6 +45667,7 @@ ${notifText}
45596
45667
  const interrupts = drainInterrupts(userId);
45597
45668
  if (interrupts.length > 0) {
45598
45669
  for (const interrupt of interrupts) {
45670
+ markInterruptEventIdsInjected(interrupt.metadata);
45599
45671
  const msg = interrupt.content;
45600
45672
  console.log(`[agent] \u6536\u5230\u4E2D\u65AD\u6D88\u606F\uFF0C\u6CE8\u5165\u5BF9\u8BDD: ${msg.slice(0, 80)}...`);
45601
45673
  if (interrupt.metadata) {
@@ -45690,19 +45762,32 @@ ${memoryInjection}` : "") + dreamInjection;
45690
45762
  }
45691
45763
  }
45692
45764
  let response;
45765
+ const turnAbortController = new AbortController();
45766
+ activeTurnAbortController = turnAbortController;
45693
45767
  try {
45694
45768
  response = await llm.chat(
45695
45769
  messages,
45696
45770
  effectiveSystemPrompt,
45697
45771
  tools,
45698
- { requestId: llmRequestIdForTurn(request, messages, effectiveSystemPrompt, tools) }
45772
+ {
45773
+ requestId: llmRequestIdForTurn(request, messages, effectiveSystemPrompt, tools),
45774
+ signal: turnAbortController.signal
45775
+ }
45699
45776
  );
45700
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
+ }
45701
45782
  if (compactConfig.enabled && isPromptTooLongError(error) && contextRecoveryAttempts < compactConfig.maxFailures) {
45702
45783
  await recoverFromContextOverflow("prompt_too_long", messages, effectiveSystemPrompt);
45703
45784
  continue;
45704
45785
  }
45705
45786
  throw error;
45787
+ } finally {
45788
+ if (activeTurnAbortController === turnAbortController) {
45789
+ activeTurnAbortController = void 0;
45790
+ }
45706
45791
  }
45707
45792
  if (response.stopReason === "model_context_window_exceeded") {
45708
45793
  await recoverFromContextOverflow("model_context_window_exceeded", messages, effectiveSystemPrompt);
@@ -45796,6 +45881,7 @@ ${memoryInjection}` : "") + dreamInjection;
45796
45881
  if (lateInterrupts.length > 0) {
45797
45882
  console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
45798
45883
  for (const interrupt of lateInterrupts) {
45884
+ markInterruptEventIdsInjected(interrupt.metadata);
45799
45885
  const msg = interrupt.content;
45800
45886
  if (interrupt.metadata) {
45801
45887
  request.metadata = {
@@ -45828,6 +45914,7 @@ ${msg}</user-interrupt>`
45828
45914
  if (lateInterrupts.length > 0) {
45829
45915
  console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
45830
45916
  for (const interrupt of lateInterrupts) {
45917
+ markInterruptEventIdsInjected(interrupt.metadata);
45831
45918
  const msg = interrupt.content;
45832
45919
  if (interrupt.metadata) {
45833
45920
  request.metadata = {
@@ -45872,6 +45959,9 @@ ${msg}</user-interrupt>`
45872
45959
  }
45873
45960
  throw new Error(`\u8FBE\u5230\u6700\u5927\u8FED\u4EE3\u6B21\u6570:${maxIterations}`);
45874
45961
  } finally {
45962
+ if (durableEventPoller) clearInterval(durableEventPoller);
45963
+ unregisterInterruptListener?.();
45964
+ activeTurnAbortController?.abort();
45875
45965
  markDone(userId);
45876
45966
  signals.delete(userId);
45877
45967
  }
@@ -46719,6 +46809,8 @@ var finalizeDepartmentAgentUnrepliedMessages = (mailboxId, msgIds, result) => {
46719
46809
  }
46720
46810
  };
46721
46811
  var polling = false;
46812
+ var inFlightDepartmentMailboxes = /* @__PURE__ */ new Set();
46813
+ var inFlightCeoReplyMessages = /* @__PURE__ */ new Set();
46722
46814
  var pollMailbox = async () => {
46723
46815
  if (polling) return;
46724
46816
  polling = true;
@@ -46735,21 +46827,30 @@ var pollMailbox = async () => {
46735
46827
  const ceoMsgs = grouped.get("manager") || [];
46736
46828
  grouped.delete("manager");
46737
46829
  for (const msg of ceoMsgs) {
46830
+ if (inFlightCeoReplyMessages.has(msg.id)) continue;
46831
+ inFlightCeoReplyMessages.add(msg.id);
46738
46832
  console.log(`[mailbox] \u6536\u5230 department agent \u56DE\u4FE1\uFF08\u6765\u81EA ${msg.fromMailboxId}\uFF09\uFF0C\u6B63\u5728\u5524\u9192\u4E3B agent...`);
46739
- try {
46740
- markMailboxStatus(msg.id, "processing");
46741
- await handleCeoReply(msg);
46742
- markMailboxStatus(msg.id, "done");
46743
- } catch (err) {
46744
- console.error(`[mailbox] \u5524\u9192\u4E3B agent \u5904\u7406\u56DE\u4FE1\u5931\u8D25:`, err);
46745
- markMailboxStatus(msg.id, "failed");
46746
- }
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
+ })();
46747
46845
  }
46748
- 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);
46749
46849
  const msgIds = msgs.map((m) => m.id);
46750
- await wakeDepartmentAgent(mailboxId, msgIds);
46751
- });
46752
- await Promise.all(tasks);
46850
+ void wakeDepartmentAgent(mailboxId, msgIds).finally(() => {
46851
+ inFlightDepartmentMailboxes.delete(mailboxId);
46852
+ });
46853
+ }
46753
46854
  } catch (err) {
46754
46855
  console.error("[mailbox] \u62C9\u53D6\u5931\u8D25:", err);
46755
46856
  } finally {
@@ -51831,7 +51932,7 @@ var systemRoutes = new Hono2();
51831
51932
  var startTime = Date.now();
51832
51933
  systemRoutes.get("/system/info", (c) => {
51833
51934
  return c.json({
51834
- version: true ? "1.8.31" : "unknown",
51935
+ version: true ? "1.8.33" : "unknown",
51835
51936
  uptime: Math.floor((Date.now() - startTime) / 1e3),
51836
51937
  env: process.env.NODE_ENV || "development",
51837
51938
  nodeVersion: process.version