duclaw-cli 3.0.0 → 3.0.1

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.
@@ -39840,11 +39840,13 @@ var init_langsmith = __esm({
39840
39840
  // src/sdk/duclaw.ts
39841
39841
  var duclaw_exports = {};
39842
39842
  __export(duclaw_exports, {
39843
+ createAgent: () => createAgent,
39843
39844
  createDefaultToolHookPlugins: () => createDefaultToolHookPlugins,
39844
39845
  createDefaultTools: () => createDefaultTools,
39845
39846
  createDuclawTools: () => createDuclawTools,
39846
39847
  duclawPreset: () => duclawPreset,
39847
- getDefaultAgentConfig: () => getDefaultAgentConfig
39848
+ getDefaultAgentConfig: () => getDefaultAgentConfig,
39849
+ getDefaultDuclawAgentConfig: () => getDefaultAgentConfig
39848
39850
  });
39849
39851
  module.exports = __toCommonJS(duclaw_exports);
39850
39852
 
@@ -50431,6 +50433,11 @@ var imageBase64 = (data, mediaType = "image/png") => ({
50431
50433
  data
50432
50434
  }
50433
50435
  });
50436
+ var toolResult = (toolUseId, content) => ({
50437
+ type: "tool_result",
50438
+ tool_use_id: toolUseId,
50439
+ content
50440
+ });
50434
50441
  var userMessage = (...content) => ({
50435
50442
  role: "user",
50436
50443
  content: content.map((block) => {
@@ -50440,9 +50447,14 @@ var userMessage = (...content) => ({
50440
50447
  return block;
50441
50448
  })
50442
50449
  });
50450
+ var assistantMessage = (...content) => ({
50451
+ role: "assistant",
50452
+ content
50453
+ });
50443
50454
 
50444
50455
  // src/types/guards.ts
50445
50456
  var isTextBlock = (block) => block.type === `text`;
50457
+ var isToolUseBlock = (block) => block.type === "tool_use";
50446
50458
  var extractText = (blocks) => blocks.filter(isTextBlock).map((b) => b.text).join("\n");
50447
50459
 
50448
50460
  // src/tools/tools/ImageUnderstandMetering.ts
@@ -51719,6 +51731,46 @@ var recordAgentEvent = (input) => {
51719
51731
  `).get(input.type, input.source, input.sourceId);
51720
51732
  return rowToEvent(row);
51721
51733
  };
51734
+ var listPendingAgentEvents = (userId, limit = 10) => {
51735
+ const db2 = createSqliteDB();
51736
+ const rows = db2.prepare(`
51737
+ SELECT
51738
+ id,
51739
+ user_id as userId,
51740
+ type,
51741
+ source,
51742
+ source_id as sourceId,
51743
+ status,
51744
+ payload_json as payloadJson,
51745
+ created_at as createdAt,
51746
+ injected_at as injectedAt,
51747
+ handled_at as handledAt,
51748
+ updated_at as updatedAt
51749
+ FROM agent_events
51750
+ WHERE user_id = ?
51751
+ AND status IN ('pending', 'processing')
51752
+ ORDER BY created_at ASC
51753
+ LIMIT ?
51754
+ `).all(userId, limit);
51755
+ return rows.map(rowToEvent);
51756
+ };
51757
+ var markAgentEventsInjected = (eventIds) => {
51758
+ if (eventIds.length === 0) return;
51759
+ const db2 = createSqliteDB();
51760
+ const now = Date.now();
51761
+ const stmt = db2.prepare(`
51762
+ UPDATE agent_events
51763
+ SET status = CASE WHEN status = 'pending' THEN 'processing' ELSE status END,
51764
+ injected_at = COALESCE(injected_at, ?),
51765
+ updated_at = ?
51766
+ WHERE id = ?
51767
+ AND status IN ('pending', 'processing')
51768
+ `);
51769
+ const tx = db2.transaction((ids) => {
51770
+ for (const id of ids) stmt.run(now, now, id);
51771
+ });
51772
+ tx(eventIds);
51773
+ };
51722
51774
  var markAgentEventsHandled = (eventIds, status = "handled") => {
51723
51775
  if (eventIds.length === 0) return;
51724
51776
  const db2 = createSqliteDB();
@@ -51757,6 +51809,42 @@ var listAgentEventsByIds = (eventIds) => {
51757
51809
  `);
51758
51810
  return eventIds.map((id) => stmt.get(id)).filter((row) => Boolean(row)).map(rowToEvent);
51759
51811
  };
51812
+ var renderAgentEventReminder = (events) => {
51813
+ if (events.length === 0) return "";
51814
+ const lines = events.map((event) => {
51815
+ const owner = typeof event.payload.ownerMailboxId === "string" ? event.payload.ownerMailboxId : void 0;
51816
+ const mailboxMessageId = typeof event.payload.mailboxMessageId === "string" ? event.payload.mailboxMessageId : event.sourceId;
51817
+ const summary = typeof event.payload.summary === "string" ? event.payload.summary : typeof event.payload.contentPreview === "string" ? event.payload.contentPreview : "";
51818
+ return [
51819
+ `- eventId=${event.id}`,
51820
+ `type=${event.type}`,
51821
+ owner ? `owner=${owner}` : "",
51822
+ mailboxMessageId ? `mailboxMessageId=${mailboxMessageId}` : "",
51823
+ summary ? `summary=${summary}` : ""
51824
+ ].filter(Boolean).join(" ");
51825
+ }).join("\n");
51826
+ const hasCeoFollowup = events.some((event) => event.type === "ceo.followup_required");
51827
+ const ceoFollowupInstruction = hasCeoFollowup ? [
51828
+ ``,
51829
+ `\u5176\u4E2D type=ceo.followup_required \u7684\u4E8B\u4EF6\uFF0C\u662F\u56E2\u961F\u5DF2\u7ECF\u628A\u7ED3\u679C\u56DE\u5230\u4E86\u4F60\u8FD9\u91CC\u2014\u2014\u8001\u677F\u8FD8\u5728\u7B49\u4F60\u628A\u8FD9\u4E9B\u7ED3\u679C\u8F6C\u8FBE\u7ED9\u4ED6\u3002`,
51830
+ `\u8BFB\u4E00\u904D\uFF0C\u7528\u4F60\u81EA\u5DF1\u7684\u8BDD\u7ED9\u8001\u677F\u6C47\u62A5\u4E00\u6B21\uFF1A\u6709\u591A\u6761\u5C31\u5408\u5E76\u6210\u4E00\u6761\u8BF4\u6E05\u695A\uFF0C\u522B\u4E00\u6761\u4E8B\u4EF6\u56DE\u4E00\u53E5\u3001\u628A\u540C\u4E00\u4EF6\u4E8B\u91CD\u590D\u53D1\u7ED9\u8001\u677F\u3002`,
51831
+ `\u5982\u679C\u7ED3\u679C\u8BF4\u660E\u4E8B\u60C5\u8FD8\u6CA1\u505A\u5B8C\u6216\u5361\u4F4F\u4E86\uFF0C\u5C31\u5982\u5B9E\u8FD9\u4E48\u8BB2\uFF0C\u800C\u4E0D\u662F\u542B\u7CCA\u5730\u201C\u7A0D\u540E\u540C\u6B65\u201D\u3002`
51832
+ ].join("\n") : "";
51833
+ const hasManagerMailboxMessage = events.some((event) => event.type === "manager.mailbox_message");
51834
+ const managerMailboxInstruction = hasManagerMailboxMessage ? [
51835
+ ``,
51836
+ `\u5176\u4E2D type=manager.mailbox_message \u7684\u4E8B\u4EF6\uFF0C\u662F\u56E2\u961F\u53D1\u7ED9 CEO \u7684\u5185\u90E8\u8FDB\u5C55\u3001\u8865\u5145\u6216\u963B\u585E\u72B6\u6001\u3002`,
51837
+ `\u8FD9\u7C7B\u4E8B\u4EF6\u53EA\u4EE3\u8868\u4F60\u770B\u5230\u4E86\u56E2\u961F\u6D88\u606F\uFF0C\u4E0D\u4EE3\u8868\u7CFB\u7EDF\u8981\u6C42\u4F60\u9010\u6761\u8F6C\u53D1\u3002\u8BF7\u50CF CEO \u4E00\u6837\u5224\u65AD\uFF1A\u5982\u679C\u7528\u6237\u9700\u8981\u77E5\u9053\u3001\u9700\u8981\u884C\u52A8\u3001\u6216\u6B63\u5728\u7B49\u5F85\u5173\u952E\u72B6\u6001\uFF0C\u5C31\u7528 send_message \u7B80\u660E\u8F6C\u8FBE\uFF1B\u5982\u679C\u53EA\u662F\u666E\u901A\u5185\u90E8\u8FDB\u5C55\u6216\u4F60\u4F1A\u7EE7\u7EED\u534F\u8C03\u3001\u4E0D\u9700\u8981\u6253\u6270\u7528\u6237\uFF0C\u5C31\u8C03\u7528 internal_event_decision(event_id, decision, reason) \u660E\u786E\u5173\u95ED\u8FD9\u6761\u5185\u90E8\u4E8B\u4EF6\u3002`
51838
+ ].join("\n") : "";
51839
+ return `<system-reminder>
51840
+ \u672C\u8F6E\u6709 ${events.length} \u6761\u5185\u90E8\u4E8B\u4EF6\u53EF\u7528\uFF1A
51841
+ ${lines}
51842
+
51843
+ \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 mailbox_list \u67E5\u770B\u961F\u5217\uFF0C\u5E76\u5728\u9700\u8981\u65F6\u7528 mailbox_get(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
51844
+ ${ceoFollowupInstruction}
51845
+ ${managerMailboxInstruction}
51846
+ </system-reminder>`;
51847
+ };
51760
51848
 
51761
51849
  // src/tools/tools/InternalEventDecision.ts
51762
51850
  var DESCRIPTION13 = `
@@ -51817,6 +51905,25 @@ var internalEventDecision = {
51817
51905
  }
51818
51906
  };
51819
51907
 
51908
+ // src/files/fileType.ts
51909
+ var EXT_TO_FILE_TYPE = {
51910
+ ".opus": "opus",
51911
+ ".mp4": "mp4",
51912
+ ".pdf": "pdf",
51913
+ ".doc": "doc",
51914
+ ".docx": "doc",
51915
+ ".xls": "xls",
51916
+ ".xlsx": "xls",
51917
+ ".ppt": "ppt",
51918
+ ".pptx": "ppt"
51919
+ };
51920
+ var inferFileType = (fileName) => {
51921
+ const dotIndex = fileName.lastIndexOf(".");
51922
+ if (dotIndex < 0) return "stream";
51923
+ const ext = fileName.slice(dotIndex).toLowerCase();
51924
+ return EXT_TO_FILE_TYPE[ext] || "stream";
51925
+ };
51926
+
51820
51927
  // src/tools/tools/SendFile.ts
51821
51928
  var DESCRIPTION14 = `
51822
51929
  \u53D1\u9001\u6587\u4EF6\u7ED9\u7528\u6237\u3002\u652F\u6301\u4E24\u79CD\u65B9\u5F0F\uFF1A
@@ -52084,160 +52191,6 @@ var cronDelete = {
52084
52191
  // src/cron/cron.ts
52085
52192
  var import_node_cron = __toESM(require_node_cron());
52086
52193
 
52087
- // src/storage/utils.ts
52088
- var searchTopicIndex = async (topicStorage, userId, query, date, limit = 8) => {
52089
- const key = `topics:${userId}`;
52090
- const data = await topicStorage.get(key) || [];
52091
- let candidates = date ? data.filter((e) => e.d === date) : data;
52092
- const tokens = query.toLowerCase().split(/[\s,,。!?!?、::]+/).filter((t) => t.length > 0);
52093
- const scored = candidates.map((entry) => {
52094
- const text2 = entry.s.toLowerCase();
52095
- const score = tokens.reduce((acc, token) => acc + (text2.includes(token) ? 1 : 0), 0);
52096
- return { entry, score };
52097
- }).filter((s) => s.score > 0);
52098
- scored.sort((a, b) => b.score - a.score || data.indexOf(b.entry) - data.indexOf(a.entry));
52099
- return {
52100
- entries: scored.slice(0, Math.min(limit, 15)).map((s) => s.entry),
52101
- total: data.length
52102
- };
52103
- };
52104
- var searchChatHistory = async (messageStorage, topicStorage, userId, query, date, limit = 8, contextRadius = 2) => {
52105
- const { entries: matches, total } = await searchTopicIndex(
52106
- topicStorage,
52107
- userId,
52108
- query,
52109
- date,
52110
- limit
52111
- );
52112
- if (matches.length === 0) {
52113
- return { matches: [], total, matchCount: 0 };
52114
- }
52115
- const keyCache = /* @__PURE__ */ new Map();
52116
- const buildKey2 = (d, c) => {
52117
- let k = `mem:${userId}:${d}`;
52118
- if (c) k += `:${c}`;
52119
- return k;
52120
- };
52121
- const loadMessages = async (d, c) => {
52122
- const k = buildKey2(d, c);
52123
- if (keyCache.has(k)) return keyCache.get(k);
52124
- const msgs = await messageStorage.get(k);
52125
- keyCache.set(k, msgs);
52126
- return msgs;
52127
- };
52128
- const results = [];
52129
- for (const match of matches) {
52130
- const messages = await loadMessages(match.d, match.c);
52131
- if (!messages) continue;
52132
- const from = Math.max(0, match.i - contextRadius);
52133
- const to = Math.min(messages.length - 1, match.i + contextRadius);
52134
- const snippets = [];
52135
- for (let j = from; j <= to; j++) {
52136
- const msg = messages[j];
52137
- if (!msg) continue;
52138
- const textContent = msg.content.filter((b) => b.type === "text").map((b) => b.text).join(" ").slice(0, 200);
52139
- if (textContent) {
52140
- snippets.push({
52141
- index: j,
52142
- role: msg.role,
52143
- text: textContent,
52144
- isMatch: j === match.i
52145
- });
52146
- }
52147
- }
52148
- if (snippets.length > 0) {
52149
- results.push({
52150
- date: match.d,
52151
- cronTitle: match.c,
52152
- snippets
52153
- });
52154
- }
52155
- }
52156
- return { matches: results, total, matchCount: matches.length };
52157
- };
52158
-
52159
- // src/agent/interruptRegistry.ts
52160
- var registry = /* @__PURE__ */ new Map();
52161
- var hasRunningAgent = (userId) => {
52162
- return registry.has(userId);
52163
- };
52164
- var queueInterrupt = (userId, message) => {
52165
- const entry = registry.get(userId);
52166
- if (!entry) return false;
52167
- const interruptMessage = typeof message === "string" ? { content: message } : message;
52168
- entry.messages.push(interruptMessage);
52169
- console.log(`[interrupt] \u7528\u6237 ${userId} \u65B0\u6D88\u606F\u5DF2\u5165\u961F\uFF0C\u5F53\u524D\u961F\u5217\u957F\u5EA6: ${entry.messages.length}`);
52170
- for (const listener of entry.listeners) {
52171
- try {
52172
- listener();
52173
- } catch (err) {
52174
- console.warn(`[interrupt] \u7528\u6237 ${userId} \u4E2D\u65AD\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25: ${err.message}`);
52175
- }
52176
- }
52177
- return true;
52178
- };
52179
-
52180
- // src/recall/recallIndex.ts
52181
- var buildRecallIndexKey = (userId) => `recall:index:${userId}`;
52182
- var normalize = (value) => value.toLowerCase();
52183
- var tokenizeRecallText = (value) => normalize(value).split(/[\s,,。!?!?、::;;()[\]{}<>'"`/\\|+=*_#@~-]+/).map((token) => token.trim()).filter((token) => token.length > 0);
52184
- var extractRecallKeywords = (value, limit = 12) => {
52185
- const seen = /* @__PURE__ */ new Set();
52186
- const keywords = [];
52187
- for (const token of tokenizeRecallText(value)) {
52188
- if (seen.has(token)) continue;
52189
- seen.add(token);
52190
- keywords.push(token);
52191
- if (keywords.length >= limit) break;
52192
- }
52193
- return keywords;
52194
- };
52195
- var upsertRecallIndexEntry = async (storage, entry) => {
52196
- const key = buildRecallIndexKey(entry.userId);
52197
- const entries = await storage.get(key) || [];
52198
- const index = entries.findIndex((item) => item.id === entry.id && item.type === entry.type);
52199
- if (index >= 0) {
52200
- entries[index] = entry;
52201
- } else {
52202
- entries.push(entry);
52203
- }
52204
- await storage.set(key, entries);
52205
- };
52206
- var removeRecallIndexEntry = async (storage, userId, type, id) => {
52207
- const key = buildRecallIndexKey(userId);
52208
- const entries = await storage.get(key) || [];
52209
- const next = entries.filter((entry) => !(entry.type === type && entry.id === id));
52210
- await storage.set(key, next);
52211
- };
52212
- var searchRecallIndex = async (storage, userId, query, date, limit = 8) => {
52213
- const entries = await storage.get(buildRecallIndexKey(userId)) || [];
52214
- const candidates = date ? entries.filter((entry) => entry.date === date) : entries;
52215
- const tokens = tokenizeRecallText(query);
52216
- const scored = candidates.map((entry) => {
52217
- const haystack = normalize([
52218
- entry.type,
52219
- entry.title,
52220
- entry.summary,
52221
- entry.keywords.join(" "),
52222
- entry.date
52223
- ].join("\n"));
52224
- const score = tokens.reduce((acc, token) => {
52225
- if (!token) return acc;
52226
- if (entry.keywords.some((keyword) => normalize(keyword) === token)) return acc + 3;
52227
- if (haystack.includes(token)) return acc + 1;
52228
- return acc;
52229
- }, 0);
52230
- return { entry, score };
52231
- }).filter((match) => match.score > 0);
52232
- scored.sort(
52233
- (a, b) => b.score - a.score || b.entry.createdAt - a.entry.createdAt
52234
- );
52235
- return {
52236
- matches: scored.slice(0, Math.min(limit, 15)),
52237
- total: entries.length
52238
- };
52239
- };
52240
-
52241
52194
  // src/tasks/goal.ts
52242
52195
  var import_dayjs2 = __toESM(require_dayjs_min());
52243
52196
  var import_utc2 = __toESM(require_utc());
@@ -52389,13 +52342,13 @@ var updateGoal = (id, goal) => {
52389
52342
  (t) => t.status === "pending" || t.status === "in_progress"
52390
52343
  );
52391
52344
  if (unfinished.length > 0) {
52392
- const preview = unfinished.slice(0, 5).map((t) => ` - [${t.status}] ${t.id} ${t.subject}`).join("\n");
52345
+ const preview2 = unfinished.slice(0, 5).map((t) => ` - [${t.status}] ${t.id} ${t.subject}`).join("\n");
52393
52346
  const more = unfinished.length > 5 ? `
52394
52347
  ... \u8FD8\u6709 ${unfinished.length - 5} \u4E2A\u672A\u5217\u51FA` : "";
52395
52348
  throw new GoalCompletionBlockedError(
52396
52349
  `[UpdateGoal] \u65E0\u6CD5\u5C06 goal=${id} \u7F6E\u4E3A completed\uFF1A\u4ECD\u6709 ${unfinished.length} \u4E2A\u5B50\u4EFB\u52A1\u5904\u4E8E pending/in_progress\u3002\u8BF7\u5148\u901A\u8FC7 task_update \u5C06\u5B83\u4EEC\u6807\u8BB0\u4E3A completed \u6216 failed\uFF0C\u518D\u5173\u95ED goal\u3002
52397
52350
  \u672A\u5B8C\u6210\u5B50\u4EFB\u52A1\uFF1A
52398
- ${preview}${more}`
52351
+ ${preview2}${more}`
52399
52352
  );
52400
52353
  }
52401
52354
  }
@@ -52822,6 +52775,58 @@ ${replies}`;
52822
52775
  // src/department/mailbox/mailbox.ts
52823
52776
  var import_node_crypto11 = require("node:crypto");
52824
52777
 
52778
+ // src/agent/interruptRegistry.ts
52779
+ var registry = /* @__PURE__ */ new Map();
52780
+ var markRunning = (userId) => {
52781
+ const current = registry.get(userId);
52782
+ if (current) {
52783
+ current.startedAt = Date.now();
52784
+ current.cancelled = false;
52785
+ return;
52786
+ }
52787
+ registry.set(userId, { messages: [], startedAt: Date.now(), cancelled: false, listeners: /* @__PURE__ */ new Set() });
52788
+ };
52789
+ var markDone = (userId) => {
52790
+ registry.delete(userId);
52791
+ };
52792
+ var hasRunningAgent = (userId) => {
52793
+ return registry.has(userId);
52794
+ };
52795
+ var isCancellationRequested = (userId) => {
52796
+ return registry.get(userId)?.cancelled === true;
52797
+ };
52798
+ var queueInterrupt = (userId, message) => {
52799
+ const entry = registry.get(userId);
52800
+ if (!entry) return false;
52801
+ const interruptMessage = typeof message === "string" ? { content: message } : message;
52802
+ entry.messages.push(interruptMessage);
52803
+ console.log(`[interrupt] \u7528\u6237 ${userId} \u65B0\u6D88\u606F\u5DF2\u5165\u961F\uFF0C\u5F53\u524D\u961F\u5217\u957F\u5EA6: ${entry.messages.length}`);
52804
+ for (const listener of entry.listeners) {
52805
+ try {
52806
+ listener();
52807
+ } catch (err) {
52808
+ console.warn(`[interrupt] \u7528\u6237 ${userId} \u4E2D\u65AD\u76D1\u542C\u5668\u6267\u884C\u5931\u8D25: ${err.message}`);
52809
+ }
52810
+ }
52811
+ return true;
52812
+ };
52813
+ var registerInterruptListener = (userId, listener) => {
52814
+ const entry = registry.get(userId);
52815
+ if (!entry) return () => void 0;
52816
+ entry.listeners.add(listener);
52817
+ return () => {
52818
+ entry.listeners.delete(listener);
52819
+ };
52820
+ };
52821
+ var drainInterrupts = (userId) => {
52822
+ const entry = registry.get(userId);
52823
+ if (!entry || entry.messages.length === 0) return [];
52824
+ const messages = [...entry.messages];
52825
+ entry.messages.length = 0;
52826
+ console.log(`[interrupt] \u7528\u6237 ${userId} drain ${messages.length} \u6761\u4E2D\u65AD\u6D88\u606F`);
52827
+ return messages;
52828
+ };
52829
+
52825
52830
  // src/department/mailbox/events.ts
52826
52831
  var import_node_crypto9 = require("node:crypto");
52827
52832
  var recordMailboxEvent = (input) => {
@@ -55000,36 +55005,405 @@ var createDuclawTools = (bg, options = []) => {
55000
55005
  };
55001
55006
  var createDefaultTools = createDuclawTools;
55002
55007
 
55003
- // src/tools/tools/RecallChatHistory.ts
55004
- var DESCRIPTION34 = `\u641C\u7D22\u7528\u6237\u7684\u5386\u53F2\u804A\u5929\u8BB0\u5F55\u3001compact \u6458\u8981\u3001dream \u957F\u671F\u8BB0\u5FC6\u548C\u663E\u5F0F\u957F\u671F memory\u3002\u5F53\u7528\u6237\u63D0\u5230\u8FC7\u53BB\u7684\u5BF9\u8BDD\u3001\u4E4B\u524D\u7684\u8BF7\u6C42\u3001\u4E0A\u6B21\u4EFB\u52A1\u3001\u6216\u4F60\u9700\u8981\u56DE\u5FC6\u65E9\u671F\u4EA4\u4E92\u5185\u5BB9\u65F6\u4F7F\u7528\u3002
55005
-
55006
- \u4F7F\u7528\u6307\u5357\uFF1A
55007
- - query \u5FC5\u987B\u5177\u4F53\uFF0C\u5305\u542B\u5173\u952E\u8BCD\uFF08\u5982\u6587\u4EF6\u540D\u3001\u529F\u80FD\u540D\u3001\u4E3B\u9898\u8BCD\uFF09
55008
- - \u901A\u5E38\u53EA\u9700\u8C03\u7528 1 \u6B21\u5373\u53EF\u627E\u5230\u76EE\u6807\uFF0C\u907F\u514D\u53CD\u590D\u8C03\u7528\u6D6A\u8D39\u4E0A\u4E0B\u6587
55009
- - \u5982\u679C\u77E5\u9053\u5927\u6982\u65E5\u671F\uFF0C\u8BF7\u63D0\u4F9B date \u53C2\u6570\u7F29\u5C0F\u8303\u56F4
55010
- - \u8FD4\u56DE\u7684\u662F\u5339\u914D\u6458\u8981\u548C\u4E0A\u4E0B\u6587\u7247\u6BB5\uFF0C\u4E0D\u662F\u5B8C\u6574\u5BF9\u8BDD
55011
- `;
55012
- var OUTPUT_LIMIT = 3e3;
55013
- var formatRecallResult = (result, indexResult) => {
55014
- const indexMatches = indexResult?.matches ?? [];
55015
- if (result.matchCount === 0 && indexMatches.length === 0) {
55016
- const indexTotal = indexResult?.total ?? 0;
55017
- return `\u672A\u627E\u5230\u5339\u914D\u7ED3\u679C\uFF08topic \u7D22\u5F15 ${result.total} \u6761\uFF0Csummary \u7D22\u5F15 ${indexTotal} \u6761\uFF09\u3002\u5C1D\u8BD5\u4F7F\u7528\u4E0D\u540C\u7684\u5173\u952E\u8BCD\u3002`;
55008
+ // src/storage/utils.ts
55009
+ var buildMessageKey = (userId, date, cronTitle) => {
55010
+ let key = `mem:${userId}`;
55011
+ if (date) {
55012
+ key = key + `:${date}`;
55013
+ }
55014
+ if (cronTitle) {
55015
+ key = key + `:${cronTitle}`;
55016
+ }
55017
+ return key;
55018
+ };
55019
+ var getMessages = async (storage, userId, limit = 300, date, cronTitle) => {
55020
+ const key = buildMessageKey(userId, date, cronTitle);
55021
+ const data = await storage.get(key);
55022
+ if (!data) return [];
55023
+ const repair = sanitizeMessagesWithReport(data, {
55024
+ mergeAdjacentNonProtocolMessages: false
55025
+ });
55026
+ const repairedData = repair.messages;
55027
+ if (repair.report.changed) {
55028
+ await storage.set(key, repairedData);
55029
+ logSanitizeRepair(repair.report);
55030
+ }
55031
+ if (repairedData.length === 0) return [];
55032
+ let start = Math.max(0, repairedData.length - limit);
55033
+ if (repairedData[start].role !== "user") {
55034
+ let earlier = start - 1;
55035
+ while (earlier >= 0 && repairedData[earlier].role !== "user") earlier--;
55036
+ if (earlier >= 0) {
55037
+ start = earlier;
55038
+ } else {
55039
+ let later = start + 1;
55040
+ while (later < repairedData.length && repairedData[later].role !== "user") later++;
55041
+ if (later >= repairedData.length) return [];
55042
+ start = later;
55043
+ }
55044
+ }
55045
+ return sanitizeMessages(repairedData.slice(start));
55046
+ };
55047
+ var isInjectedMemoryContextMessage = (msg) => {
55048
+ if (msg.role !== "user" || msg.content.length === 0) return false;
55049
+ if (!msg.content.every((block) => block.type === "text")) return false;
55050
+ const textContent2 = msg.content.map((block) => block.type === "text" ? block.text : "").join("\n").trim();
55051
+ return textContent2.startsWith("<memory-context>") && textContent2.endsWith("</memory-context>");
55052
+ };
55053
+ var hasProtocolBlock = (msg) => {
55054
+ return msg.content.some((block) => block.type === "tool_use" || block.type === "tool_result");
55055
+ };
55056
+ var createSanitizeReport = () => ({
55057
+ changed: false,
55058
+ removedToolUses: 0,
55059
+ removedToolResults: 0,
55060
+ removedEmptyMessages: 0,
55061
+ removedMemoryContextMessages: 0,
55062
+ droppedMessages: 0,
55063
+ shiftedLeadingMessages: 0,
55064
+ mergedAdjacentMessages: 0
55065
+ });
55066
+ var markSanitizeChanged = (report, index) => {
55067
+ report.changed = true;
55068
+ if (report.firstChangedIndex === void 0 || index < report.firstChangedIndex) {
55069
+ report.firstChangedIndex = index;
55070
+ }
55071
+ };
55072
+ var mergeSanitizeReport = (target, source) => {
55073
+ if (!source.changed) return;
55074
+ target.changed = true;
55075
+ if (source.firstChangedIndex !== void 0 && (target.firstChangedIndex === void 0 || source.firstChangedIndex < target.firstChangedIndex)) {
55076
+ target.firstChangedIndex = source.firstChangedIndex;
55077
+ }
55078
+ target.removedToolUses += source.removedToolUses;
55079
+ target.removedToolResults += source.removedToolResults;
55080
+ target.removedEmptyMessages += source.removedEmptyMessages;
55081
+ target.removedMemoryContextMessages += source.removedMemoryContextMessages;
55082
+ target.droppedMessages += source.droppedMessages;
55083
+ target.shiftedLeadingMessages += source.shiftedLeadingMessages;
55084
+ target.mergedAdjacentMessages += source.mergedAdjacentMessages;
55085
+ };
55086
+ var stripToolResultBlocks = (msg, report, index) => {
55087
+ const removed = msg.content.filter((block) => block.type === "tool_result").length;
55088
+ const content = msg.content.filter((block) => block.type !== "tool_result");
55089
+ if (report && removed > 0 && index !== void 0) {
55090
+ report.removedToolResults += removed;
55091
+ markSanitizeChanged(report, index);
55018
55092
  }
55019
- let output = `\u5339\u914D ${result.matchCount + indexMatches.length} \u6761\u7ED3\u679C\uFF08topic \u7D22\u5F15 ${result.total} \u6761\uFF0Csummary \u7D22\u5F15 ${indexResult?.total ?? 0} \u6761\uFF09:
55020
- `;
55021
- for (const match of indexMatches) {
55022
- if (output.length >= OUTPUT_LIMIT) {
55023
- output += `
55024
- ...(\u5DF2\u8FBE\u8F93\u51FA\u4E0A\u9650\uFF0C\u5269\u4F59\u7ED3\u679C\u7701\u7565)`;
55025
- break;
55026
- }
55027
- const entry = match.entry;
55028
- output += `
55029
- --- ${entry.type} ${entry.date} score=${match.score} ---
55030
- `;
55031
- output += `\u6807\u9898\uFF1A${entry.title}
55032
- `;
55093
+ if (content.length === 0) return null;
55094
+ if (content.every((b) => b.type === "text" && !b.text?.trim())) return null;
55095
+ return { ...msg, content };
55096
+ };
55097
+ var stripToolUseBlocks = (msg, report, index) => {
55098
+ const removed = msg.content.filter((block) => block.type === "tool_use").length;
55099
+ const content = msg.content.filter((block) => block.type !== "tool_use");
55100
+ if (report && removed > 0 && index !== void 0) {
55101
+ report.removedToolUses += removed;
55102
+ markSanitizeChanged(report, index);
55103
+ }
55104
+ if (content.length === 0) return null;
55105
+ if (content.every((b) => b.type === "text" && !b.text?.trim())) return null;
55106
+ return { ...msg, content };
55107
+ };
55108
+ var recordDroppedMessage = (report, index) => {
55109
+ report.droppedMessages++;
55110
+ markSanitizeChanged(report, index);
55111
+ };
55112
+ var logSanitizeRepair = (report) => {
55113
+ console.warn(
55114
+ `[sanitize] repaired message history removedToolUses=${report.removedToolUses} removedToolResults=${report.removedToolResults} droppedMessages=${report.droppedMessages} emptyMessages=${report.removedEmptyMessages} memoryContextMessages=${report.removedMemoryContextMessages} shiftedLeadingMessages=${report.shiftedLeadingMessages} firstIndex=${report.firstChangedIndex ?? -1}`
55115
+ );
55116
+ };
55117
+ var sanitizeMessagesWithReport = (messages, options = {}) => {
55118
+ const report = createSanitizeReport();
55119
+ const mergeAdjacentNonProtocolMessages2 = options.mergeAdjacentNonProtocolMessages ?? true;
55120
+ if (messages.length === 0) {
55121
+ return { messages, report };
55122
+ }
55123
+ const result = [];
55124
+ for (let i = 0; i < messages.length; i++) {
55125
+ const msg = messages[i];
55126
+ if (isInjectedMemoryContextMessage(msg)) {
55127
+ report.removedMemoryContextMessages++;
55128
+ recordDroppedMessage(report, i);
55129
+ continue;
55130
+ }
55131
+ if (!msg.content || msg.content.length === 0) {
55132
+ report.removedEmptyMessages++;
55133
+ recordDroppedMessage(report, i);
55134
+ continue;
55135
+ }
55136
+ if (msg.content.every((b) => b.type === "text" && !b.text?.trim())) {
55137
+ report.removedEmptyMessages++;
55138
+ recordDroppedMessage(report, i);
55139
+ continue;
55140
+ }
55141
+ let nextMsg = msg;
55142
+ if (msg.role === "assistant") {
55143
+ const toolUses = msg.content.filter((b) => b.type === "tool_use");
55144
+ if (toolUses.length > 0) {
55145
+ const next = messages[i + 1];
55146
+ if (!next || next.role !== "user") {
55147
+ nextMsg = stripToolUseBlocks(msg, report, i);
55148
+ if (!nextMsg) {
55149
+ recordDroppedMessage(report, i);
55150
+ continue;
55151
+ }
55152
+ } else {
55153
+ const resultIds = new Set(
55154
+ next.content.filter((b) => b.type === "tool_result").map((b) => b.tool_use_id)
55155
+ );
55156
+ const allMatched = toolUses.every((tu) => resultIds.has(tu.id));
55157
+ if (!allMatched) {
55158
+ nextMsg = stripToolUseBlocks(msg, report, i);
55159
+ if (!nextMsg) {
55160
+ recordDroppedMessage(report, i);
55161
+ continue;
55162
+ }
55163
+ }
55164
+ }
55165
+ }
55166
+ }
55167
+ if (nextMsg.role === "user") {
55168
+ const toolResults = nextMsg.content.filter((b) => b.type === "tool_result");
55169
+ if (toolResults.length > 0) {
55170
+ const prev2 = result[result.length - 1];
55171
+ const prevToolUseIds = new Set(
55172
+ prev2?.role === "assistant" ? prev2.content.filter((b) => b.type === "tool_use").map((b) => b.id) : []
55173
+ );
55174
+ const allResultsMatched = toolResults.every((tr) => prevToolUseIds.has(tr.tool_use_id));
55175
+ if (!prev2 || prev2.role !== "assistant" || prevToolUseIds.size === 0 || !allResultsMatched) {
55176
+ nextMsg = stripToolResultBlocks(nextMsg, report, i);
55177
+ if (!nextMsg) {
55178
+ recordDroppedMessage(report, i);
55179
+ continue;
55180
+ }
55181
+ }
55182
+ }
55183
+ }
55184
+ const prev = result[result.length - 1];
55185
+ if (mergeAdjacentNonProtocolMessages2 && prev && prev.role === nextMsg.role && !hasProtocolBlock(prev) && !hasProtocolBlock(nextMsg)) {
55186
+ prev.content = [...prev.content, ...nextMsg.content];
55187
+ report.mergedAdjacentMessages++;
55188
+ markSanitizeChanged(report, i);
55189
+ } else {
55190
+ result.push({ ...nextMsg, content: [...nextMsg.content] });
55191
+ }
55192
+ }
55193
+ while (result.length > 0 && result[0].role !== "user") {
55194
+ result.shift();
55195
+ report.shiftedLeadingMessages++;
55196
+ markSanitizeChanged(report, 0);
55197
+ }
55198
+ if (report.shiftedLeadingMessages > 0) {
55199
+ const revalidated = sanitizeMessagesWithReport(result, options);
55200
+ if (revalidated.report.changed) {
55201
+ mergeSanitizeReport(report, revalidated.report);
55202
+ return { messages: revalidated.messages, report };
55203
+ }
55204
+ }
55205
+ return { messages: result, report };
55206
+ };
55207
+ var sanitizeMessages = (messages) => {
55208
+ return sanitizeMessagesWithReport(messages).messages;
55209
+ };
55210
+ var addMessage = async (storage, userId, message, date, cronTitle) => {
55211
+ const key = buildMessageKey(userId, date, cronTitle);
55212
+ const data = await storage.get(key) || [];
55213
+ data.push(message);
55214
+ await storage.set(key, data);
55215
+ return data.length - 1;
55216
+ };
55217
+ var addTopicIndex = async (storage, userId, date, messageIndex, snippet, cronTitle) => {
55218
+ const key = `topics:${userId}`;
55219
+ const data = await storage.get(key) || [];
55220
+ data.push({
55221
+ d: date,
55222
+ i: messageIndex,
55223
+ s: snippet.slice(0, 80),
55224
+ ...cronTitle ? { c: cronTitle } : {}
55225
+ });
55226
+ await storage.set(key, data);
55227
+ };
55228
+ var updateTopicSummary = async (storage, userId, date, summary, cronTitle) => {
55229
+ const key = `topics:${userId}`;
55230
+ const data = await storage.get(key);
55231
+ if (!data || data.length === 0) return;
55232
+ for (let i = data.length - 1; i >= 0; i--) {
55233
+ const entry = data[i];
55234
+ if (entry.d === date && (entry.c || void 0) === (cronTitle || void 0)) {
55235
+ entry.s = summary.slice(0, 80);
55236
+ await storage.set(key, data);
55237
+ return;
55238
+ }
55239
+ }
55240
+ };
55241
+ var searchTopicIndex = async (topicStorage, userId, query, date, limit = 8) => {
55242
+ const key = `topics:${userId}`;
55243
+ const data = await topicStorage.get(key) || [];
55244
+ let candidates = date ? data.filter((e) => e.d === date) : data;
55245
+ const tokens = query.toLowerCase().split(/[\s,,。!?!?、::]+/).filter((t) => t.length > 0);
55246
+ const scored = candidates.map((entry) => {
55247
+ const text2 = entry.s.toLowerCase();
55248
+ const score = tokens.reduce((acc, token) => acc + (text2.includes(token) ? 1 : 0), 0);
55249
+ return { entry, score };
55250
+ }).filter((s) => s.score > 0);
55251
+ scored.sort((a, b) => b.score - a.score || data.indexOf(b.entry) - data.indexOf(a.entry));
55252
+ return {
55253
+ entries: scored.slice(0, Math.min(limit, 15)).map((s) => s.entry),
55254
+ total: data.length
55255
+ };
55256
+ };
55257
+ var searchChatHistory = async (messageStorage, topicStorage, userId, query, date, limit = 8, contextRadius = 2) => {
55258
+ const { entries: matches, total } = await searchTopicIndex(
55259
+ topicStorage,
55260
+ userId,
55261
+ query,
55262
+ date,
55263
+ limit
55264
+ );
55265
+ if (matches.length === 0) {
55266
+ return { matches: [], total, matchCount: 0 };
55267
+ }
55268
+ const keyCache = /* @__PURE__ */ new Map();
55269
+ const buildKey2 = (d, c) => {
55270
+ let k = `mem:${userId}:${d}`;
55271
+ if (c) k += `:${c}`;
55272
+ return k;
55273
+ };
55274
+ const loadMessages = async (d, c) => {
55275
+ const k = buildKey2(d, c);
55276
+ if (keyCache.has(k)) return keyCache.get(k);
55277
+ const msgs = await messageStorage.get(k);
55278
+ keyCache.set(k, msgs);
55279
+ return msgs;
55280
+ };
55281
+ const results = [];
55282
+ for (const match of matches) {
55283
+ const messages = await loadMessages(match.d, match.c);
55284
+ if (!messages) continue;
55285
+ const from = Math.max(0, match.i - contextRadius);
55286
+ const to = Math.min(messages.length - 1, match.i + contextRadius);
55287
+ const snippets = [];
55288
+ for (let j = from; j <= to; j++) {
55289
+ const msg = messages[j];
55290
+ if (!msg) continue;
55291
+ const textContent2 = msg.content.filter((b) => b.type === "text").map((b) => b.text).join(" ").slice(0, 200);
55292
+ if (textContent2) {
55293
+ snippets.push({
55294
+ index: j,
55295
+ role: msg.role,
55296
+ text: textContent2,
55297
+ isMatch: j === match.i
55298
+ });
55299
+ }
55300
+ }
55301
+ if (snippets.length > 0) {
55302
+ results.push({
55303
+ date: match.d,
55304
+ cronTitle: match.c,
55305
+ snippets
55306
+ });
55307
+ }
55308
+ }
55309
+ return { matches: results, total, matchCount: matches.length };
55310
+ };
55311
+ var clearMessages = async (storage, userId, date, cronTitle) => {
55312
+ const key = buildMessageKey(userId, date, cronTitle);
55313
+ await storage.del(key);
55314
+ };
55315
+
55316
+ // src/recall/recallIndex.ts
55317
+ var buildRecallIndexKey = (userId) => `recall:index:${userId}`;
55318
+ var normalize = (value) => value.toLowerCase();
55319
+ var tokenizeRecallText = (value) => normalize(value).split(/[\s,,。!?!?、::;;()[\]{}<>'"`/\\|+=*_#@~-]+/).map((token) => token.trim()).filter((token) => token.length > 0);
55320
+ var extractRecallKeywords = (value, limit = 12) => {
55321
+ const seen = /* @__PURE__ */ new Set();
55322
+ const keywords = [];
55323
+ for (const token of tokenizeRecallText(value)) {
55324
+ if (seen.has(token)) continue;
55325
+ seen.add(token);
55326
+ keywords.push(token);
55327
+ if (keywords.length >= limit) break;
55328
+ }
55329
+ return keywords;
55330
+ };
55331
+ var upsertRecallIndexEntry = async (storage, entry) => {
55332
+ const key = buildRecallIndexKey(entry.userId);
55333
+ const entries = await storage.get(key) || [];
55334
+ const index = entries.findIndex((item) => item.id === entry.id && item.type === entry.type);
55335
+ if (index >= 0) {
55336
+ entries[index] = entry;
55337
+ } else {
55338
+ entries.push(entry);
55339
+ }
55340
+ await storage.set(key, entries);
55341
+ };
55342
+ var removeRecallIndexEntry = async (storage, userId, type, id) => {
55343
+ const key = buildRecallIndexKey(userId);
55344
+ const entries = await storage.get(key) || [];
55345
+ const next = entries.filter((entry) => !(entry.type === type && entry.id === id));
55346
+ await storage.set(key, next);
55347
+ };
55348
+ var searchRecallIndex = async (storage, userId, query, date, limit = 8) => {
55349
+ const entries = await storage.get(buildRecallIndexKey(userId)) || [];
55350
+ const candidates = date ? entries.filter((entry) => entry.date === date) : entries;
55351
+ const tokens = tokenizeRecallText(query);
55352
+ const scored = candidates.map((entry) => {
55353
+ const haystack = normalize([
55354
+ entry.type,
55355
+ entry.title,
55356
+ entry.summary,
55357
+ entry.keywords.join(" "),
55358
+ entry.date
55359
+ ].join("\n"));
55360
+ const score = tokens.reduce((acc, token) => {
55361
+ if (!token) return acc;
55362
+ if (entry.keywords.some((keyword) => normalize(keyword) === token)) return acc + 3;
55363
+ if (haystack.includes(token)) return acc + 1;
55364
+ return acc;
55365
+ }, 0);
55366
+ return { entry, score };
55367
+ }).filter((match) => match.score > 0);
55368
+ scored.sort(
55369
+ (a, b) => b.score - a.score || b.entry.createdAt - a.entry.createdAt
55370
+ );
55371
+ return {
55372
+ matches: scored.slice(0, Math.min(limit, 15)),
55373
+ total: entries.length
55374
+ };
55375
+ };
55376
+
55377
+ // src/tools/tools/RecallChatHistory.ts
55378
+ var DESCRIPTION34 = `\u641C\u7D22\u7528\u6237\u7684\u5386\u53F2\u804A\u5929\u8BB0\u5F55\u3001compact \u6458\u8981\u3001dream \u957F\u671F\u8BB0\u5FC6\u548C\u663E\u5F0F\u957F\u671F memory\u3002\u5F53\u7528\u6237\u63D0\u5230\u8FC7\u53BB\u7684\u5BF9\u8BDD\u3001\u4E4B\u524D\u7684\u8BF7\u6C42\u3001\u4E0A\u6B21\u4EFB\u52A1\u3001\u6216\u4F60\u9700\u8981\u56DE\u5FC6\u65E9\u671F\u4EA4\u4E92\u5185\u5BB9\u65F6\u4F7F\u7528\u3002
55379
+
55380
+ \u4F7F\u7528\u6307\u5357\uFF1A
55381
+ - query \u5FC5\u987B\u5177\u4F53\uFF0C\u5305\u542B\u5173\u952E\u8BCD\uFF08\u5982\u6587\u4EF6\u540D\u3001\u529F\u80FD\u540D\u3001\u4E3B\u9898\u8BCD\uFF09
55382
+ - \u901A\u5E38\u53EA\u9700\u8C03\u7528 1 \u6B21\u5373\u53EF\u627E\u5230\u76EE\u6807\uFF0C\u907F\u514D\u53CD\u590D\u8C03\u7528\u6D6A\u8D39\u4E0A\u4E0B\u6587
55383
+ - \u5982\u679C\u77E5\u9053\u5927\u6982\u65E5\u671F\uFF0C\u8BF7\u63D0\u4F9B date \u53C2\u6570\u7F29\u5C0F\u8303\u56F4
55384
+ - \u8FD4\u56DE\u7684\u662F\u5339\u914D\u6458\u8981\u548C\u4E0A\u4E0B\u6587\u7247\u6BB5\uFF0C\u4E0D\u662F\u5B8C\u6574\u5BF9\u8BDD
55385
+ `;
55386
+ var OUTPUT_LIMIT = 3e3;
55387
+ var formatRecallResult = (result, indexResult) => {
55388
+ const indexMatches = indexResult?.matches ?? [];
55389
+ if (result.matchCount === 0 && indexMatches.length === 0) {
55390
+ const indexTotal = indexResult?.total ?? 0;
55391
+ return `\u672A\u627E\u5230\u5339\u914D\u7ED3\u679C\uFF08topic \u7D22\u5F15 ${result.total} \u6761\uFF0Csummary \u7D22\u5F15 ${indexTotal} \u6761\uFF09\u3002\u5C1D\u8BD5\u4F7F\u7528\u4E0D\u540C\u7684\u5173\u952E\u8BCD\u3002`;
55392
+ }
55393
+ let output = `\u5339\u914D ${result.matchCount + indexMatches.length} \u6761\u7ED3\u679C\uFF08topic \u7D22\u5F15 ${result.total} \u6761\uFF0Csummary \u7D22\u5F15 ${indexResult?.total ?? 0} \u6761\uFF09:
55394
+ `;
55395
+ for (const match of indexMatches) {
55396
+ if (output.length >= OUTPUT_LIMIT) {
55397
+ output += `
55398
+ ...(\u5DF2\u8FBE\u8F93\u51FA\u4E0A\u9650\uFF0C\u5269\u4F59\u7ED3\u679C\u7701\u7565)`;
55399
+ break;
55400
+ }
55401
+ const entry = match.entry;
55402
+ output += `
55403
+ --- ${entry.type} ${entry.date} score=${match.score} ---
55404
+ `;
55405
+ output += `\u6807\u9898\uFF1A${entry.title}
55406
+ `;
55033
55407
  output += `\u6458\u8981\uFF1A${entry.summary.slice(0, 800)}
55034
55408
  `;
55035
55409
  if (entry.keywords.length > 0) {
@@ -56881,11 +57255,1290 @@ var duclawPreset = () => {
56881
57255
  hooks: config2.hooks
56882
57256
  };
56883
57257
  };
57258
+
57259
+ // src/agent/createAgentCore.ts
57260
+ var import_node_crypto18 = require("node:crypto");
57261
+
57262
+ // src/compact/config.ts
57263
+ var readNumber = (name, fallback) => {
57264
+ const raw = process.env[name];
57265
+ if (!raw) return fallback;
57266
+ const parsed = Number(raw);
57267
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : fallback;
57268
+ };
57269
+ var readBoolean = (name, fallback) => {
57270
+ const raw = process.env[name];
57271
+ if (raw === void 0) return fallback;
57272
+ return !["0", "false", "no", "off"].includes(raw.trim().toLowerCase());
57273
+ };
57274
+ var getCompactConfig = () => ({
57275
+ enabled: readBoolean("COMPACT_ENABLED", true),
57276
+ contextWindowTokens: readNumber("COMPACT_CONTEXT_WINDOW_TOKENS", 2e5),
57277
+ outputReserveTokens: readNumber("COMPACT_OUTPUT_RESERVE_TOKENS", 2e4),
57278
+ bufferTokens: readNumber("COMPACT_BUFFER_TOKENS", 0),
57279
+ warningBufferTokens: readNumber("COMPACT_WARNING_BUFFER_TOKENS", 2e4),
57280
+ hotTailMessages: readNumber("COMPACT_HOT_TAIL_MESSAGES", 24),
57281
+ compactUserMessageMaxTokens: readNumber("COMPACT_USER_MESSAGE_MAX_TOKENS", 2e4),
57282
+ maxFailures: readNumber("COMPACT_MAX_FAILURES", 3),
57283
+ microCompactKeepToolResults: readNumber("MICRO_COMPACT_KEEP_TOOL_RESULTS", 5),
57284
+ microCompactToolResultChars: readNumber("MICRO_COMPACT_TOOL_RESULT_CHARS", 1200)
57285
+ });
57286
+ var getEffectiveContextWindow = (config2) => Math.max(1, config2.contextWindowTokens - config2.outputReserveTokens);
57287
+ var getCompactThreshold = (config2) => Math.max(1, getEffectiveContextWindow(config2) - config2.bufferTokens);
57288
+ var getWarningThreshold = (config2) => Math.max(1, getEffectiveContextWindow(config2) - config2.warningBufferTokens);
57289
+ var calculateCompactTokenState = (currentContextTokens, config2) => {
57290
+ const warningThreshold = getWarningThreshold(config2);
57291
+ const compactThreshold = getCompactThreshold(config2);
57292
+ return {
57293
+ currentContextTokens,
57294
+ warningThreshold,
57295
+ compactThreshold,
57296
+ isAboveWarningThreshold: currentContextTokens >= warningThreshold,
57297
+ isAboveCompactThreshold: currentContextTokens >= compactThreshold
57298
+ };
57299
+ };
57300
+
57301
+ // src/compact/errors.ts
57302
+ var PROMPT_TOO_LONG_PATTERNS = [
57303
+ "prompt_too_long",
57304
+ "context_length_exceeded",
57305
+ "context window",
57306
+ "context_window",
57307
+ "maximum context length",
57308
+ "max context length",
57309
+ "model_context_window_exceeded",
57310
+ "too many tokens",
57311
+ "input is too long"
57312
+ ];
57313
+ var collectErrorText = (error) => {
57314
+ const err = error;
57315
+ const parts = [
57316
+ err?.message,
57317
+ err?.status ? String(err.status) : "",
57318
+ err?.error ? JSON.stringify(err.error) : "",
57319
+ err?.response ? JSON.stringify(err.response) : ""
57320
+ ];
57321
+ return parts.filter(Boolean).join("\n").toLowerCase();
57322
+ };
57323
+ var isPromptTooLongError = (error) => {
57324
+ const text2 = collectErrorText(error);
57325
+ if (!text2) return false;
57326
+ return PROMPT_TOO_LONG_PATTERNS.some((pattern) => text2.includes(pattern));
57327
+ };
57328
+
57329
+ // src/compact/tokenEstimate.ts
57330
+ var IMAGE_MAX_TOKEN_SIZE = 2e3;
57331
+ var roughTokenEstimateText = (content, bytesPerToken = 4) => {
57332
+ if (!content) return 0;
57333
+ return Math.ceil(content.length / bytesPerToken);
57334
+ };
57335
+ var stringify = (value) => {
57336
+ try {
57337
+ return JSON.stringify(value);
57338
+ } catch {
57339
+ return "[unserializable]";
57340
+ }
57341
+ };
57342
+ var tokenCountFromUsage = (usage) => usage.inputTokens + usage.outputTokens + (usage.cacheCreationInputTokens ?? 0) + (usage.cacheReadInputTokens ?? 0);
57343
+ var roughTokenEstimateBlock = (block) => {
57344
+ switch (block.type) {
57345
+ case "text":
57346
+ return roughTokenEstimateText(block.text);
57347
+ case "tool_result":
57348
+ return roughTokenEstimateText(block.content);
57349
+ case "tool_use": {
57350
+ const toolUse = block;
57351
+ return roughTokenEstimateText(toolUse.name + stringify(toolUse.input ?? {}));
57352
+ }
57353
+ case "image":
57354
+ return IMAGE_MAX_TOKEN_SIZE;
57355
+ case "thinking":
57356
+ return roughTokenEstimateText(block.thinking);
57357
+ default:
57358
+ return roughTokenEstimateText(stringify(block));
57359
+ }
57360
+ };
57361
+ var roughTokenEstimateMessages = (messages) => {
57362
+ let total = 0;
57363
+ for (const message of messages) {
57364
+ for (const block of message.content) {
57365
+ total += roughTokenEstimateBlock(block);
57366
+ }
57367
+ }
57368
+ return Math.ceil(total * (4 / 3));
57369
+ };
57370
+ var findLastAssistantUsageAnchor = (messages) => {
57371
+ for (let i = messages.length - 1; i >= 0; i--) {
57372
+ const message = messages[i];
57373
+ if (message?.role === "assistant" && message.usage) {
57374
+ let anchorIndex = i;
57375
+ if (message.providerResponseId) {
57376
+ for (let j = i - 1; j >= 0; j--) {
57377
+ const prior = messages[j];
57378
+ if (prior?.role === "assistant" && prior.providerResponseId === message.providerResponseId) {
57379
+ anchorIndex = j;
57380
+ continue;
57381
+ }
57382
+ if (prior?.role === "assistant" && prior.providerResponseId && prior.providerResponseId !== message.providerResponseId) {
57383
+ break;
57384
+ }
57385
+ }
57386
+ }
57387
+ return { index: anchorIndex, usage: message.usage };
57388
+ }
57389
+ }
57390
+ return null;
57391
+ };
57392
+ var tokenCountWithEstimation = (messages, systemPrompt = "") => {
57393
+ const anchor = findLastAssistantUsageAnchor(messages);
57394
+ if (!anchor) {
57395
+ return {
57396
+ tokens: roughTokenEstimateMessages(messages) + roughTokenEstimateText(systemPrompt),
57397
+ source: "rough_fallback"
57398
+ };
57399
+ }
57400
+ return {
57401
+ tokens: tokenCountFromUsage(anchor.usage) + roughTokenEstimateMessages(messages.slice(anchor.index + 1)),
57402
+ source: "api_usage_plus_delta"
57403
+ };
57404
+ };
57405
+
57406
+ // src/compact/compactPrompt.ts
57407
+ var COMPACT_SUMMARIZATION_PROMPT = `You are performing a CONTEXT CHECKPOINT COMPACTION. Create a handoff summary for another LLM that will resume the task.
57408
+
57409
+ The summary must be concise, factual, and directly useful for continuing the work. Do not invent missing details. Clearly separate confirmed facts from assumptions or items that still need verification.
57410
+
57411
+ Use this exact schema:
57412
+
57413
+ <compact-summary>
57414
+ 1. \u7528\u6237\u6700\u65B0\u76EE\u6807:
57415
+ 2. \u7528\u6237\u786C\u6027\u7EA6\u675F:
57416
+ 3. \u5F53\u524D\u4E8B\u5B9E\u72B6\u6001:
57417
+ 4. \u5DF2\u5B8C\u6210\u52A8\u4F5C:
57418
+ 5. \u6587\u4EF6/\u547D\u4EE4/\u8BC1\u636E:
57419
+ 6. mailbox/department \u7EBF\u7A0B:
57420
+ 7. \u7528\u6237\u53EF\u89C1\u627F\u8BFA:
57421
+ 8. \u672A\u5B8C\u6210\u4E8B\u9879:
57422
+ 9. \u5F53\u524D\u963B\u585E\u4E0E\u7B49\u5F85\u5BF9\u8C61:
57423
+ 10. \u4E0B\u4E00\u6B65\u5FC5\u987B\u52A8\u4F5C:
57424
+ 11. \u4E0D\u786E\u5B9A/\u5F85\u786E\u8BA4:
57425
+ 12. \u5DF2\u4E22\u5F03\u4FE1\u606F:
57426
+ </compact-summary>
57427
+
57428
+ Field guidance:
57429
+ - \u7528\u6237\u6700\u65B0\u76EE\u6807: the latest user intent, not stale earlier goals.
57430
+ - \u7528\u6237\u786C\u6027\u7EA6\u675F: explicit user constraints, safety boundaries, deployment/data-persistence constraints, style preferences, or "do not" instructions.
57431
+ - \u5F53\u524D\u4E8B\u5B9E\u72B6\u6001: verified state only. Say "\u65E0" if there is no verified fact.
57432
+ - \u5DF2\u5B8C\u6210\u52A8\u4F5C: concrete actions already performed by the agent or team.
57433
+ - \u6587\u4EF6/\u547D\u4EE4/\u8BC1\u636E: important paths, commands, test results, errors, URLs, versions, sandbox IDs, mailbox IDs, and other evidence required to continue.
57434
+ - mailbox/department \u7EBF\u7A0B: responsible owner, mailbox thread/message IDs, CEO followups, department head/executor status, who owes a reply to whom, and whether the user-visible closure is complete.
57435
+ - \u7528\u6237\u53EF\u89C1\u627F\u8BFA: what the user has been told or promised, including pending follow-ups.
57436
+ - \u672A\u5B8C\u6210\u4E8B\u9879: work still not done.
57437
+ - \u5F53\u524D\u963B\u585E\u4E0E\u7B49\u5F85\u5BF9\u8C61: blockers, external waits, running commands, pending approvals, or a named agent/person/system being waited on.
57438
+ - \u4E0B\u4E00\u6B65\u5FC5\u987B\u52A8\u4F5C: the minimal next actions the next LLM should take, in order.
57439
+ - \u4E0D\u786E\u5B9A/\u5F85\u786E\u8BA4: assumptions, ambiguous facts, or things that must be re-checked.
57440
+ - \u5DF2\u4E22\u5F03\u4FE1\u606F: categories of old details intentionally omitted, such as long logs, obsolete failed attempts, or completed transient steps.
57441
+
57442
+ If a field does not apply, write "\u65E0".`;
57443
+ var COMPACT_SUMMARY_PREFIX = `Another language model started to solve this problem and produced a summary of its thinking process. You also have access to the state of the tools that were used by that language model. Use this to build on the work that has already been done and avoid duplicating work. Here is the summary produced by the other language model, use the information in this summary to assist with your own analysis:`;
57444
+ var COMPACT_SYSTEM_PROMPT = `You are Duclaw's context compaction worker. Produce only the requested handoff summary. Do not call tools and do not chat with the user.`;
57445
+ var buildCompactUserPrompt = (_messages, reason) => `${COMPACT_SUMMARIZATION_PROMPT}
57446
+
57447
+ Compaction trigger: ${reason}`;
57448
+
57449
+ // src/compact/CompactEngine.ts
57450
+ var buildCompactSummaryKey = (userId, date, cronTitle) => `compact:summary:${userId}:${date}${cronTitle ? `:${cronTitle}` : ""}`;
57451
+ var extractSummaryText = (message) => message.content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
57452
+ var stripAssistantUsage = (message) => {
57453
+ if (message.role !== "assistant") return { ...message, content: [...message.content] };
57454
+ return {
57455
+ role: "assistant",
57456
+ content: [...message.content]
57457
+ };
57458
+ };
57459
+ var textContent = (message) => message.content.filter((block) => block.type === "text").map((block) => block.text).join("\n").trim();
57460
+ var isSummaryUserMessage = (message) => message.role === "user" && textContent(message).startsWith(COMPACT_SUMMARY_PREFIX);
57461
+ var isRawTextUserMessage = (message) => message.role === "user" && message.content.length > 0 && message.content.every((block) => block.type === "text") && !isSummaryUserMessage(message);
57462
+ var collectRecentUserMessages = (messages, maxTokens) => {
57463
+ if (maxTokens <= 0) return [];
57464
+ const selected = [];
57465
+ let usedTokens = 0;
57466
+ for (let i = messages.length - 1; i >= 0; i--) {
57467
+ const message = messages[i];
57468
+ if (!message || !isRawTextUserMessage(message)) continue;
57469
+ const messageTokens = roughTokenEstimateText(textContent(message));
57470
+ if (selected.length > 0 && usedTokens + messageTokens > maxTokens) break;
57471
+ if (messageTokens > maxTokens && selected.length === 0) continue;
57472
+ selected.push({ role: "user", content: [...message.content] });
57473
+ usedTokens += messageTokens;
57474
+ }
57475
+ return selected.reverse();
57476
+ };
57477
+ var buildCompactionRequestMessages = (messages, reason) => sanitizeMessagesWithReport([
57478
+ ...messages.map(stripAssistantUsage),
57479
+ userMessage(text(buildCompactUserPrompt(messages, reason)))
57480
+ ], { mergeAdjacentNonProtocolMessages: false }).messages;
57481
+ var CompactEngine = class {
57482
+ storage;
57483
+ summaryStorage;
57484
+ recallIndexStorage;
57485
+ llm;
57486
+ config;
57487
+ constructor(options) {
57488
+ this.storage = options.storage;
57489
+ this.summaryStorage = options.summaryStorage;
57490
+ this.recallIndexStorage = options.recallIndexStorage;
57491
+ this.llm = options.llm;
57492
+ this.config = options.config;
57493
+ }
57494
+ async compact(input) {
57495
+ const sourceMessages = sanitizeMessages(input.messages);
57496
+ if (sourceMessages.length === 0) {
57497
+ throw new Error("[compact] \u6CA1\u6709\u53EF\u538B\u7F29\u7684\u6D88\u606F\u5386\u53F2");
57498
+ }
57499
+ const tokenCountBefore = tokenCountWithEstimation(sourceMessages, input.systemPrompt);
57500
+ const response = await this.llm.chat(
57501
+ buildCompactionRequestMessages(sourceMessages, input.reason),
57502
+ COMPACT_SYSTEM_PROMPT,
57503
+ []
57504
+ );
57505
+ const rawSummary = extractSummaryText(response);
57506
+ if (!rawSummary) {
57507
+ throw new Error("[compact] compact LLM \u6CA1\u6709\u8FD4\u56DE\u6458\u8981\u6587\u672C");
57508
+ }
57509
+ const summary = `${COMPACT_SUMMARY_PREFIX}
57510
+ ${rawSummary}`.trim();
57511
+ const recentUserMessages = collectRecentUserMessages(sourceMessages, this.config.compactUserMessageMaxTokens);
57512
+ const compactedMessages = sanitizeMessagesWithReport([
57513
+ ...recentUserMessages,
57514
+ userMessage(text(summary))
57515
+ ], { mergeAdjacentNonProtocolMessages: false }).messages;
57516
+ if (compactedMessages.length === 0) {
57517
+ throw new Error("[compact] compact \u540E\u6CA1\u6709\u53EF\u5199\u56DE\u7684\u5408\u6CD5\u6D88\u606F");
57518
+ }
57519
+ const record2 = {
57520
+ id: `compact_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`,
57521
+ userId: input.userId,
57522
+ date: input.date,
57523
+ ...input.cronTitle ? { cronTitle: input.cronTitle } : {},
57524
+ ...input.threadId ? { threadId: input.threadId } : {},
57525
+ summary,
57526
+ sourceMessageCount: sourceMessages.length,
57527
+ hotTailCount: recentUserMessages.length,
57528
+ contextTokensBefore: tokenCountBefore.tokens,
57529
+ contextTokensAfter: roughTokenEstimateMessages(compactedMessages),
57530
+ tokenCountSource: tokenCountBefore.source,
57531
+ reason: input.reason,
57532
+ createdAt: Date.now()
57533
+ };
57534
+ await this.storage.set(buildMessageKey(input.userId, input.date, input.cronTitle), compactedMessages);
57535
+ await this.appendSummaryRecord(record2);
57536
+ await this.upsertRecallIndex(record2);
57537
+ return {
57538
+ record: record2,
57539
+ messages: compactedMessages.length
57540
+ };
57541
+ }
57542
+ async upsertRecallIndex(record2) {
57543
+ if (!this.recallIndexStorage) return;
57544
+ await upsertRecallIndexEntry(this.recallIndexStorage, {
57545
+ id: record2.id,
57546
+ userId: record2.userId,
57547
+ type: "compact",
57548
+ title: `compact ${record2.date}${record2.cronTitle ? ` ${record2.cronTitle}` : ""}`,
57549
+ summary: record2.summary,
57550
+ keywords: extractRecallKeywords(record2.summary),
57551
+ date: record2.date,
57552
+ sourceKey: buildCompactSummaryKey(record2.userId, record2.date, record2.cronTitle),
57553
+ createdAt: record2.createdAt
57554
+ });
57555
+ }
57556
+ async appendSummaryRecord(record2) {
57557
+ if (!this.summaryStorage) return;
57558
+ const key = buildCompactSummaryKey(record2.userId, record2.date, record2.cronTitle);
57559
+ const records = await this.summaryStorage.get(key) || [];
57560
+ records.push(record2);
57561
+ await this.summaryStorage.set(key, records);
57562
+ }
57563
+ };
57564
+
57565
+ // src/compact/microCompact.ts
57566
+ var COMPACTED_MARKER = "[\u65E7\u5DE5\u5177\u7ED3\u679C\u5DF2\u538B\u7F29]";
57567
+ var stringify2 = (value) => {
57568
+ try {
57569
+ return JSON.stringify(value);
57570
+ } catch {
57571
+ return "[unserializable]";
57572
+ }
57573
+ };
57574
+ var preview = (content, maxChars) => {
57575
+ const trimmed = content.trim();
57576
+ if (trimmed.length <= maxChars) return trimmed;
57577
+ const half = Math.max(80, Math.floor(maxChars / 2));
57578
+ return `${trimmed.slice(0, half)}
57579
+ ...
57580
+ ${trimmed.slice(-half)}`;
57581
+ };
57582
+ var toolUseMapFromMessages = (messages) => {
57583
+ const map = /* @__PURE__ */ new Map();
57584
+ for (const message of messages) {
57585
+ if (message.role !== "assistant") continue;
57586
+ for (const block of message.content) {
57587
+ if (block.type === "tool_use") {
57588
+ map.set(block.id, block);
57589
+ }
57590
+ }
57591
+ }
57592
+ return map;
57593
+ };
57594
+ var collectToolResults = (messages) => {
57595
+ const locations = [];
57596
+ messages.forEach((message, messageIndex) => {
57597
+ if (message.role !== "user") return;
57598
+ message.content.forEach((block, blockIndex) => {
57599
+ if (block.type === "tool_result") {
57600
+ locations.push({ messageIndex, blockIndex, block });
57601
+ }
57602
+ });
57603
+ });
57604
+ return locations;
57605
+ };
57606
+ var stripAssistantUsage2 = (message) => {
57607
+ if (message.role !== "assistant") return message;
57608
+ return {
57609
+ role: "assistant",
57610
+ content: message.content
57611
+ };
57612
+ };
57613
+ var buildCompactedToolResultContent = (block, toolUse, maxChars) => {
57614
+ const toolName = toolUse?.name ?? "unknown";
57615
+ const toolInput = toolUse ? stringify2(toolUse.input) : "{}";
57616
+ const previewChars = Math.max(200, Math.floor(maxChars * 0.6));
57617
+ return `${COMPACTED_MARKER}
57618
+ \u5DE5\u5177: ${toolName}
57619
+ tool_use_id: ${block.tool_use_id}
57620
+ \u539F\u59CB\u957F\u5EA6: ${block.content.length} chars
57621
+ \u5DE5\u5177\u8F93\u5165: ${toolInput.slice(0, 300)}
57622
+ \u6458\u8981: ${preview(block.content, previewChars)}
57623
+ \u8BF4\u660E: \u5B8C\u6574\u65E7\u5DE5\u5177\u7ED3\u679C\u672A\u4FDD\u5B58\uFF1B\u5982\u9700\u7EC6\u8282\u8BF7\u91CD\u65B0\u8FD0\u884C\u5BF9\u5E94\u5DE5\u5177\u6216\u4F9D\u8D56\u540E\u7EED compact summary\u3002`;
57624
+ };
57625
+ var microCompactMessages = (messages, config2) => {
57626
+ const sanitized = sanitizeMessages(messages.map((message) => ({
57627
+ ...message,
57628
+ content: [...message.content]
57629
+ })));
57630
+ const toolResults = collectToolResults(sanitized);
57631
+ const keepFromIndex = Math.max(0, toolResults.length - config2.microCompactKeepToolResults);
57632
+ const toolUses = toolUseMapFromMessages(sanitized);
57633
+ let compactedToolResults = 0;
57634
+ let originalCharsRemoved = 0;
57635
+ const nextMessages = sanitized.map((message) => ({
57636
+ ...message,
57637
+ content: [...message.content]
57638
+ }));
57639
+ for (let i = 0; i < keepFromIndex; i++) {
57640
+ const location = toolResults[i];
57641
+ if (location.block.content.startsWith(COMPACTED_MARKER)) continue;
57642
+ if (location.block.content.length <= config2.microCompactToolResultChars) continue;
57643
+ const compactedContent = buildCompactedToolResultContent(
57644
+ location.block,
57645
+ toolUses.get(location.block.tool_use_id),
57646
+ config2.microCompactToolResultChars
57647
+ );
57648
+ const message = nextMessages[location.messageIndex];
57649
+ message.content[location.blockIndex] = {
57650
+ ...location.block,
57651
+ content: compactedContent
57652
+ };
57653
+ compactedToolResults++;
57654
+ originalCharsRemoved += Math.max(0, location.block.content.length - compactedContent.length);
57655
+ }
57656
+ if (compactedToolResults === 0) {
57657
+ return {
57658
+ messages: sanitized,
57659
+ changed: false,
57660
+ compactedToolResults,
57661
+ originalCharsRemoved
57662
+ };
57663
+ }
57664
+ return {
57665
+ messages: sanitizeMessages(nextMessages.map(stripAssistantUsage2)),
57666
+ changed: true,
57667
+ compactedToolResults,
57668
+ originalCharsRemoved
57669
+ };
57670
+ };
57671
+
57672
+ // src/agent/createAgentCore.ts
57673
+ var assistantMessageFromResponse = (response) => ({
57674
+ role: "assistant",
57675
+ content: response.content,
57676
+ ...response.usage ? { usage: response.usage } : {},
57677
+ ...response.providerResponseId ? { providerResponseId: response.providerResponseId } : {},
57678
+ ...response.model ? { model: response.model } : {}
57679
+ });
57680
+ var isAbortError2 = (error) => {
57681
+ if (!(error instanceof Error)) return false;
57682
+ return error.name === "AbortError" || error.message.includes("aborted") || error.message.includes("AbortError");
57683
+ };
57684
+ var llmRequestIdForTurn = (request, messages, system, tools) => {
57685
+ const hash = (0, import_node_crypto18.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);
57686
+ return `dreq_${hash}`;
57687
+ };
57688
+ var LLM_CREDIT_EXHAUSTED_MESSAGE = "Credit \u4F59\u989D\u4E0D\u8DB3\uFF0C\u6682\u65F6\u65E0\u6CD5\u7EE7\u7EED\u8C03\u7528\u4E3B\u6A21\u578B\u5904\u7406\u8FD9\u6761\u6D88\u606F\u3002\u8BF7\u5148\u5145\u503C\u6216\u4F7F\u7528\u6FC0\u6D3B\u7801\u589E\u52A0 Credit \u540E\u518D\u8BD5\u3002";
57689
+ var isLlmCreditExhaustedError = (error) => {
57690
+ const err = error;
57691
+ const message = [
57692
+ err?.message,
57693
+ err?.error?.type,
57694
+ err?.error?.message
57695
+ ].filter((value) => typeof value === "string").join("\n");
57696
+ return err?.status === 402 || err?.status === 403 && /预扣费额度失败|额度不足|剩余额度|pre_consume.*quota|insufficient.*quota/i.test(message) || /预扣费额度失败|用户剩余额度|Credit balance is insufficient|credit_exhausted/i.test(message);
57697
+ };
57698
+ var traceMetadataFromRequest = (request, internalOnly) => ({
57699
+ platform: request.platform,
57700
+ userId: request.userId,
57701
+ requestId: request.requestId,
57702
+ departmentAgentId: request.departmentAgentId,
57703
+ trigger: request.metadata?.trigger,
57704
+ internalOnly,
57705
+ jobTitle: request.job?.title,
57706
+ eventId: request.metadata?.eventId,
57707
+ agentEventIds: request.metadata?.agentEventIds,
57708
+ ceoFollowupId: request.metadata?.ceoFollowupId,
57709
+ ceoFollowupIds: request.metadata?.ceoFollowupIds,
57710
+ mailboxMessageId: request.metadata?.mailboxMessageId,
57711
+ threadId: request.metadata?.threadId,
57712
+ parentMessageId: request.metadata?.parentMessageId,
57713
+ workItemId: request.metadata?.workItemId
57714
+ });
57715
+ var genericTraceIdentity = (request) => {
57716
+ return {
57717
+ name: `Agent turn`,
57718
+ role: `agent`,
57719
+ mailboxId: request.departmentAgentId || void 0
57720
+ };
57721
+ };
57722
+ var createAgent2 = (config2) => {
57723
+ const { systemPrompt, llm, storage, topicStorage, compactSummaryStorage, recallIndexStorage, toolExecutor, tools, backgroundManager, maxIterations = 50, dreamEngine, skillForgeEngine, memoryEngine, onLlmRequestId, tracer } = config2;
57724
+ const signals = /* @__PURE__ */ new Map();
57725
+ return async (initialRequest) => {
57726
+ let request = initialRequest;
57727
+ if (config2.workspacePath && !request.defaultWorkDir) {
57728
+ request.defaultWorkDir = config2.workspacePath;
57729
+ }
57730
+ request = await config2.hooks?.beforeRun?.(request) ?? request;
57731
+ const { userId, job } = request;
57732
+ const content = await config2.hooks?.augmentUserContent?.({
57733
+ request,
57734
+ content: request.content
57735
+ }) ?? request.content;
57736
+ const internalOnly = request.metadata?.internalOnly === true;
57737
+ let rootTrace;
57738
+ let agentTrace;
57739
+ const requestForTrace = () => ({
57740
+ ...request,
57741
+ content,
57742
+ traceRun: request.traceRun ? { id: request.traceRun.id } : void 0
57743
+ });
57744
+ const finish = async (result) => {
57745
+ await agentTrace?.end({ outputs: result });
57746
+ await rootTrace?.end({ outputs: result });
57747
+ await config2.hooks?.afterRun?.({ request, result });
57748
+ return result;
57749
+ };
57750
+ const traceOutboundText = async (to, message, send) => {
57751
+ const outboundTrace = await agentTrace?.child({
57752
+ name: `Outbound message`,
57753
+ runType: `tool`,
57754
+ inputs: {
57755
+ to,
57756
+ text: message,
57757
+ metadata: request.metadata
57758
+ },
57759
+ metadata: traceMetadataFromRequest(request, internalOnly)
57760
+ });
57761
+ try {
57762
+ await send();
57763
+ await outboundTrace?.end({ outputs: { sent: true } });
57764
+ } catch (error) {
57765
+ await outboundTrace?.end({ error: error.message });
57766
+ throw error;
57767
+ }
57768
+ };
57769
+ const traceOutboundFile = async (to, fileName, fileType, file, send) => {
57770
+ const outboundTrace = await agentTrace?.child({
57771
+ name: `Outbound file`,
57772
+ runType: `tool`,
57773
+ inputs: {
57774
+ to,
57775
+ fileName,
57776
+ fileType,
57777
+ file
57778
+ },
57779
+ metadata: traceMetadataFromRequest(request, internalOnly)
57780
+ });
57781
+ try {
57782
+ await send();
57783
+ await outboundTrace?.end({ outputs: { sent: true } });
57784
+ } catch (error) {
57785
+ await outboundTrace?.end({ error: error.message });
57786
+ throw error;
57787
+ }
57788
+ };
57789
+ const injectedEventIds = /* @__PURE__ */ new Set();
57790
+ const managerMailboxEventIds = /* @__PURE__ */ new Set();
57791
+ const interruptQueuedEventIds = /* @__PURE__ */ new Set();
57792
+ let durableEventPoller;
57793
+ let activeTurnAbortController;
57794
+ let unregisterInterruptListener;
57795
+ const markInterruptEventIdsInjected = (metadata) => {
57796
+ const ids = Array.isArray(metadata?.agentEventIds) ? metadata.agentEventIds.filter((id) => typeof id === "string") : [];
57797
+ if (ids.length === 0) return;
57798
+ for (const id of ids) injectedEventIds.add(id);
57799
+ if (metadata?.trigger === "manager.mailbox_message") {
57800
+ for (const id of ids) managerMailboxEventIds.add(id);
57801
+ }
57802
+ markAgentEventsInjected(ids);
57803
+ };
57804
+ const autoHandledEventIds = (userVisibleSent) => {
57805
+ const ids = [...injectedEventIds];
57806
+ if (userVisibleSent) return ids;
57807
+ return ids.filter((id) => !managerMailboxEventIds.has(id));
57808
+ };
57809
+ const ceoFollowupIdsFromMetadata2 = (metadata) => {
57810
+ const ids = /* @__PURE__ */ new Set();
57811
+ if (typeof metadata?.ceoFollowupId === "string") ids.add(metadata.ceoFollowupId);
57812
+ if (Array.isArray(metadata?.ceoFollowupIds)) {
57813
+ for (const id of metadata.ceoFollowupIds) {
57814
+ if (typeof id === "string") ids.add(id);
57815
+ }
57816
+ }
57817
+ return Array.from(ids);
57818
+ };
57819
+ const rememberCeoFollowupIds = (ids) => {
57820
+ if (ids.length === 0) return;
57821
+ const current = ceoFollowupIdsFromMetadata2(request.metadata);
57822
+ request.metadata = {
57823
+ ...request.metadata ?? {},
57824
+ ceoFollowupIds: Array.from(/* @__PURE__ */ new Set([...current, ...ids]))
57825
+ };
57826
+ };
57827
+ const completeUserVisibleCeoFollowups = async () => {
57828
+ await config2.hooks?.completeUserVisibleDelivery?.({ request });
57829
+ };
57830
+ const claimOutboundText = async (text2, reason) => {
57831
+ return await config2.hooks?.claimOutboundText?.({ request, text: text2, reason }) ?? true;
57832
+ };
57833
+ const claimOutboundFile = async (fileName, file) => {
57834
+ return await config2.hooks?.claimOutboundFile?.({ request, fileName, file }) ?? true;
57835
+ };
57836
+ const queuePendingDurableEvents = () => {
57837
+ try {
57838
+ const events = listPendingAgentEvents(userId, 10).filter((event) => !injectedEventIds.has(event.id)).filter((event) => !interruptQueuedEventIds.has(event.id));
57839
+ if (events.length === 0) return;
57840
+ for (const event of events) interruptQueuedEventIds.add(event.id);
57841
+ queueInterrupt(userId, {
57842
+ content: renderAgentEventReminder(events),
57843
+ metadata: {
57844
+ trigger: "agent_events.pending",
57845
+ agentEventIds: events.map((event) => event.id)
57846
+ }
57847
+ });
57848
+ } catch (err) {
57849
+ console.warn(`[agent_events] durable event poll failed: ${err.message}`);
57850
+ }
57851
+ };
57852
+ const prev = signals.get(userId);
57853
+ if (prev) {
57854
+ prev.abort();
57855
+ }
57856
+ const signal = {
57857
+ aborted: false,
57858
+ abort() {
57859
+ this.aborted = true;
57860
+ }
57861
+ };
57862
+ signals.set(userId, signal);
57863
+ markRunning(userId);
57864
+ unregisterInterruptListener = registerInterruptListener(userId, () => {
57865
+ activeTurnAbortController?.abort();
57866
+ });
57867
+ durableEventPoller = setInterval(queuePendingDurableEvents, 1e3);
57868
+ try {
57869
+ const sessionTraceInput = {
57870
+ name: `Duclaw User Session`,
57871
+ runType: `chain`,
57872
+ inputs: {
57873
+ platform: request.platform,
57874
+ userId: request.userId,
57875
+ requestId: request.requestId,
57876
+ content,
57877
+ request: requestForTrace()
57878
+ },
57879
+ metadata: traceMetadataFromRequest(request, internalOnly)
57880
+ };
57881
+ rootTrace = request.traceRun ? await request.traceRun.child(sessionTraceInput) : await tracer?.startRun(sessionTraceInput);
57882
+ const traceIdentity = await config2.hooks?.traceIdentity?.(request) ?? genericTraceIdentity(request);
57883
+ agentTrace = await rootTrace?.child({
57884
+ name: traceIdentity.name,
57885
+ runType: `chain`,
57886
+ inputs: {
57887
+ request: requestForTrace(),
57888
+ content
57889
+ },
57890
+ metadata: {
57891
+ ...traceMetadataFromRequest(request, internalOnly),
57892
+ agentRole: traceIdentity.role,
57893
+ memberName: traceIdentity.memberName,
57894
+ mailboxId: traceIdentity.mailboxId
57895
+ }
57896
+ });
57897
+ if (dreamEngine) {
57898
+ try {
57899
+ await dreamEngine.checkAndDream(userId);
57900
+ } catch (err) {
57901
+ console.warn(`[agent] checkAndDream \u5931\u8D25\uFF1A${err.message}`);
57902
+ }
57903
+ }
57904
+ const now = /* @__PURE__ */ new Date();
57905
+ const beijingTime = now.toLocaleString("sv-SE", {
57906
+ timeZone: "Asia/Shanghai",
57907
+ year: "numeric",
57908
+ month: "2-digit",
57909
+ day: "2-digit"
57910
+ }).replace(/-/g, "");
57911
+ if (!internalOnly) {
57912
+ const msgIndex = await addMessage(storage, userId, userMessage(text(content)), beijingTime, job?.title);
57913
+ if (topicStorage) {
57914
+ await addTopicIndex(topicStorage, userId, beijingTime, msgIndex, content, job?.title);
57915
+ }
57916
+ }
57917
+ if (skillForgeEngine && !internalOnly) {
57918
+ try {
57919
+ const pending = await skillForgeEngine.listPending(userId);
57920
+ if (pending.length > 0) {
57921
+ const lines = pending.map(
57922
+ (p) => ` - id=${p.id} name=${p.skillName} :: ${p.description}`
57923
+ ).join("\n");
57924
+ await addMessage(storage, userId, userMessage(text(
57925
+ `<pending-skill-proposal>
57926
+ \u5F53\u524D\u6709 ${pending.length} \u4E2A\u5F85\u7528\u6237\u786E\u8BA4\u7684\u6280\u80FD\u8349\u7A3F\uFF1A
57927
+ ${lines}
57928
+ \u5982\u679C\u7528\u6237\u8FD9\u6761\u6D88\u606F\u662F\u5728\u56DE\u5E94"\u8981\u4E0D\u8981\u4FDD\u7559"\u8FD9\u4E2A\u95EE\u9898\uFF1A
57929
+ \u2022 \u80AF\u5B9A\u610F\u56FE \u2192 \u8C03\u7528 skill_forge_keep\uFF08\u53EA\u6709 1 \u6761 pending \u65F6 proposalId \u53EF\u7701\u7565\uFF09
57930
+ \u2022 \u5426\u5B9A\u610F\u56FE \u2192 \u8C03\u7528 skill_forge_drop
57931
+ \u2022 \u672A\u8868\u6001 \u2192 \u5FFD\u7565\u672C\u63D0\u793A\uFF0C\u6B63\u5E38\u5904\u7406\u7528\u6237\u6D88\u606F
57932
+ </pending-skill-proposal>`
57933
+ )), beijingTime, job?.title);
57934
+ }
57935
+ } catch (err) {
57936
+ console.warn(`[skillForge] \u8BFB\u53D6 pending \u5217\u8868\u5931\u8D25\uFF1A${err.message}`);
57937
+ }
57938
+ }
57939
+ let iterations = 0;
57940
+ let hasSentMessage = false;
57941
+ let sentMessageContent = "";
57942
+ let emptyRetries = 0;
57943
+ let contextRecoveryAttempts = 0;
57944
+ let maxIterationCompactions = 0;
57945
+ const compactConfig = getCompactConfig();
57946
+ const compactEngine = new CompactEngine({
57947
+ storage,
57948
+ summaryStorage: compactSummaryStorage,
57949
+ recallIndexStorage,
57950
+ llm,
57951
+ config: compactConfig
57952
+ });
57953
+ const fallbackToDreamRecovery = async (reason) => {
57954
+ contextRecoveryAttempts++;
57955
+ console.warn(`[agent] \u4E0A\u4E0B\u6587\u538B\u7F29\u964D\u7EA7\u89E6\u53D1 reason=${reason} attempt=${contextRecoveryAttempts}`);
57956
+ let overflowWarning = `<system-warning>\u4E0A\u4E0B\u6587\u6EA2\u51FA\uFF0C\u5386\u53F2\u5BF9\u8BDD\u5DF2\u88AB\u6E05\u7A7A\u3002\u7531\u4E8E\u5F53\u524D\u6CA1\u6709\u53EF\u7528\u68A6\u5883\u8BB0\u5FC6\uFF0C\u8BF7\u4E0D\u8981\u4F9D\u8D56\u66F4\u65E9\u4E0A\u4E0B\u6587\uFF0C\u53EA\u76F4\u63A5\u5904\u7406\u7528\u6237\u6700\u65B0\u7684\u6D88\u606F\u3002</system-warning>
57957
+ ${content}`;
57958
+ if (dreamEngine) {
57959
+ try {
57960
+ const result = await dreamEngine.dream(userId);
57961
+ console.log(`[agent] \u5F3A\u5236\u505A\u68A6\u5B8C\u6210\uFF0C\u68A6\u5883\u957F\u5EA6=${result?.dreamContent.length ?? 0}`);
57962
+ if (result?.dreamContent) {
57963
+ overflowWarning = `<system-warning>\u4E0A\u4E0B\u6587\u6EA2\u51FA\uFF0C\u5DF2\u901A\u8FC7\u505A\u68A6\u538B\u7F29\u5386\u53F2\u5BF9\u8BDD\u3002\u91CD\u8981\u8BB0\u5FC6\u5DF2\u4FDD\u7559\u81F3\u68A6\u5883\uFF08systemPrompt \u4E2D\u7684 memory-context\uFF09\u3002\u8BF7\u76F4\u63A5\u56DE\u590D\u7528\u6237\u6700\u65B0\u7684\u6D88\u606F\u3002</system-warning>
57964
+ ${content}`;
57965
+ } else {
57966
+ overflowWarning = `<system-warning>\u4E0A\u4E0B\u6587\u6EA2\u51FA\uFF0C\u5DF2\u5C1D\u8BD5\u505A\u68A6\u538B\u7F29\u5386\u53F2\u5BF9\u8BDD\uFF0C\u4F46\u672A\u751F\u6210\u53EF\u7528\u68A6\u5883\u3002\u5386\u53F2\u5BF9\u8BDD\u5DF2\u88AB\u6E05\u7A7A\uFF0C\u8BF7\u4E0D\u8981\u4F9D\u8D56\u66F4\u65E9\u4E0A\u4E0B\u6587\uFF0C\u53EA\u76F4\u63A5\u5904\u7406\u7528\u6237\u6700\u65B0\u7684\u6D88\u606F\u3002</system-warning>
57967
+ ${content}`;
57968
+ }
57969
+ } catch (err) {
57970
+ console.error(`[agent] \u5F3A\u5236\u505A\u68A6\u5931\u8D25\uFF1A${err.message}`);
57971
+ overflowWarning = `<system-warning>\u4E0A\u4E0B\u6587\u6EA2\u51FA\uFF0C\u5DF2\u5C1D\u8BD5\u505A\u68A6\u538B\u7F29\u5386\u53F2\u5BF9\u8BDD\uFF0C\u4F46\u505A\u68A6\u5931\u8D25\u3002\u5386\u53F2\u5BF9\u8BDD\u5DF2\u88AB\u6E05\u7A7A\uFF0C\u8BF7\u4E0D\u8981\u4F9D\u8D56\u66F4\u65E9\u4E0A\u4E0B\u6587\uFF0C\u53EA\u76F4\u63A5\u5904\u7406\u7528\u6237\u6700\u65B0\u7684\u6D88\u606F\u3002</system-warning>
57972
+ ${content}`;
57973
+ }
57974
+ }
57975
+ await clearMessages(storage, userId, beijingTime, job?.title);
57976
+ await addMessage(storage, userId, userMessage(text(overflowWarning)), beijingTime, job?.title);
57977
+ };
57978
+ const recoverFromContextOverflow = async (reason, messages, effectiveSystemPrompt) => {
57979
+ contextRecoveryAttempts++;
57980
+ try {
57981
+ const result = await compactEngine.compact({
57982
+ userId,
57983
+ date: beijingTime,
57984
+ cronTitle: job?.title,
57985
+ messages,
57986
+ systemPrompt: effectiveSystemPrompt,
57987
+ reason,
57988
+ threadId: request.departmentAgentId || void 0
57989
+ });
57990
+ console.warn(
57991
+ `[compact] \u5B8C\u6574 compact \u6210\u529F reason=${reason} before=${result.record.contextTokensBefore} after=${result.record.contextTokensAfter} messages=${result.messages}`
57992
+ );
57993
+ } catch (err) {
57994
+ console.error(`[compact] \u5B8C\u6574 compact \u5931\u8D25\uFF0C\u8FDB\u5165 dream \u964D\u7EA7\uFF1A${err.message}`);
57995
+ contextRecoveryAttempts--;
57996
+ await fallbackToDreamRecovery(reason);
57997
+ }
57998
+ };
57999
+ const buildEffectiveSystemPrompt = async () => {
58000
+ let memoryInjection = "";
58001
+ if (memoryEngine) {
58002
+ try {
58003
+ memoryInjection = await memoryEngine.buildContextBlock(userId, memoryEngine.ownerFromRequest(request));
58004
+ } catch (err) {
58005
+ console.warn(`[memory] \u6784\u5EFA\u8BB0\u5FC6\u4E0A\u4E0B\u6587\u5931\u8D25\uFF1A${err.message}`);
58006
+ }
58007
+ }
58008
+ const dreamInjection = dreamEngine ? await dreamEngine.injectDream(userId) : "";
58009
+ const systemContext = await config2.hooks?.buildSystemContext?.({ request }) ?? "";
58010
+ return systemPrompt + (systemContext ? `
58011
+
58012
+ ${systemContext}` : "") + (memoryInjection ? `
58013
+
58014
+ ${memoryInjection}` : "") + dreamInjection;
58015
+ };
58016
+ while (true) {
58017
+ if (iterations >= maxIterations) {
58018
+ if (compactConfig.enabled && maxIterationCompactions < 1 && contextRecoveryAttempts < compactConfig.maxFailures) {
58019
+ const messages2 = await getMessages(storage, userId, 300, beijingTime, job?.title);
58020
+ await recoverFromContextOverflow(
58021
+ `max_iterations:${maxIterations}`,
58022
+ messages2,
58023
+ await buildEffectiveSystemPrompt()
58024
+ );
58025
+ iterations = 0;
58026
+ emptyRetries = 0;
58027
+ maxIterationCompactions++;
58028
+ continue;
58029
+ }
58030
+ throw new Error(`\u8FBE\u5230\u6700\u5927\u8FED\u4EE3\u6B21\u6570:${maxIterations}`);
58031
+ }
58032
+ if (signal.aborted) throw new Error(`[\u667A\u80FD\u4F53\u4E2D\u65AD] \u53D7\u5230\u4E2D\u65AD\u4FE1\u53F7\u5DF2\u4E2D\u65AD`);
58033
+ if (isCancellationRequested(userId)) throw new Error(`\u7528\u6237\u5DF2\u505C\u6B62\u5F53\u524D\u6267\u884C`);
58034
+ iterations++;
58035
+ if (backgroundManager) {
58036
+ const notifs = backgroundManager.drain();
58037
+ if (notifs.length > 0) {
58038
+ const notifText = notifs.map((n2) => `[bg:${n2.taskId}] ${n2.result}`).join("\n");
58039
+ await addMessage(
58040
+ storage,
58041
+ userId,
58042
+ userMessage(text(`<background-results>
58043
+ ${notifText}
58044
+ </background-results>`)),
58045
+ beijingTime,
58046
+ job?.title
58047
+ );
58048
+ await addMessage(
58049
+ storage,
58050
+ userId,
58051
+ assistantMessage(text("\u6536\u5230\u540E\u53F0\u4EFB\u52A1\u7ED3\u679C\u3002")),
58052
+ beijingTime,
58053
+ job?.title
58054
+ );
58055
+ }
58056
+ }
58057
+ const interrupts = drainInterrupts(userId);
58058
+ if (interrupts.length > 0) {
58059
+ for (const interrupt of interrupts) {
58060
+ markInterruptEventIdsInjected(interrupt.metadata);
58061
+ rememberCeoFollowupIds(ceoFollowupIdsFromMetadata2(interrupt.metadata));
58062
+ const msg = interrupt.content;
58063
+ console.log(`[agent] \u6536\u5230\u4E2D\u65AD\u6D88\u606F\uFF0C\u6CE8\u5165\u5BF9\u8BDD: ${msg.slice(0, 80)}...`);
58064
+ if (interrupt.metadata) {
58065
+ request.metadata = {
58066
+ ...request.metadata ?? {},
58067
+ ...interrupt.metadata
58068
+ };
58069
+ }
58070
+ if (interrupt.metadata?.internalOnly === true) {
58071
+ continue;
58072
+ }
58073
+ const interruptContent = msg.includes("<system_reminder>") || msg.includes("<system-reminder>") ? msg : `<user-interrupt>\u7528\u6237\u53D1\u6765\u4E86\u65B0\u6D88\u606F\uFF0C\u8BF7\u7ACB\u5373\u91CD\u65B0\u8BC4\u4F30\u5F53\u524D\u5DE5\u4F5C\uFF0C\u65B0\u6D88\u606F\u53EF\u80FD\u4F1A\u6539\u53D8\u4F60\u7684\u4EFB\u52A1\u4F18\u5148\u7EA7\u6216\u65B9\u5411\u3002
58074
+ ${msg}</user-interrupt>`;
58075
+ await addMessage(storage, userId, userMessage(text(
58076
+ interruptContent
58077
+ )), beijingTime, job?.title);
58078
+ }
58079
+ }
58080
+ let messages = await getMessages(storage, userId, 300, beijingTime, job?.title);
58081
+ const pendingEvents = listPendingAgentEvents(userId, 10).filter((event) => !injectedEventIds.has(event.id));
58082
+ const eventReminder = renderAgentEventReminder(pendingEvents);
58083
+ if (pendingEvents.length > 0) {
58084
+ for (const event of pendingEvents) injectedEventIds.add(event.id);
58085
+ for (const event of pendingEvents) {
58086
+ if (event.type === "manager.mailbox_message") managerMailboxEventIds.add(event.id);
58087
+ }
58088
+ markAgentEventsInjected(pendingEvents.map((event) => event.id));
58089
+ rememberCeoFollowupIds(pendingEvents.filter((event) => event.type === "ceo.followup_required").map((event) => event.payload.ceoFollowupId).filter((id) => typeof id === "string"));
58090
+ }
58091
+ if (messages.length === 0 && internalOnly && eventReminder) {
58092
+ messages = [userMessage(text(eventReminder))];
58093
+ } else if (messages.length === 0) {
58094
+ console.warn(`[agent] \u6D88\u606F\u5386\u53F2\u6E05\u6D17\u540E\u4E3A\u7A7A\uFF0C\u4F7F\u7528\u5F53\u524D\u8BF7\u6C42\u91CD\u5EFA\u5BF9\u8BDD userId=${userId}`);
58095
+ await clearMessages(storage, userId, beijingTime, job?.title);
58096
+ await addMessage(storage, userId, userMessage(text(
58097
+ `<system-warning>\u5386\u53F2\u6D88\u606F\u56E0\u5DE5\u5177\u8C03\u7528\u534F\u8BAE\u635F\u574F\u5DF2\u88AB\u6E05\u7A7A\u3002\u8BF7\u4E0D\u8981\u4F9D\u8D56\u66F4\u65E9\u4E0A\u4E0B\u6587\uFF0C\u53EA\u76F4\u63A5\u5904\u7406\u4E0B\u9762\u8FD9\u6761\u6700\u65B0\u8BF7\u6C42\u3002</system-warning>
58098
+ ${content}`
58099
+ )), beijingTime, job?.title);
58100
+ messages = await getMessages(storage, userId, 300, beijingTime, job?.title);
58101
+ }
58102
+ if (eventReminder && !(messages.length === 1 && internalOnly)) {
58103
+ const last = messages[messages.length - 1];
58104
+ if (last?.role === "user" && !last.content.some((block) => block.type === "tool_result")) {
58105
+ messages = [
58106
+ ...messages.slice(0, -1),
58107
+ {
58108
+ ...last,
58109
+ content: [
58110
+ ...last.content,
58111
+ text(eventReminder)
58112
+ ]
58113
+ }
58114
+ ];
58115
+ } else {
58116
+ messages = [...messages, userMessage(text(eventReminder))];
58117
+ }
58118
+ }
58119
+ const systemContext = await config2.hooks?.buildSystemContext?.({ request }) ?? "";
58120
+ const effectiveSystemPrompt = await buildEffectiveSystemPrompt();
58121
+ if (compactConfig.enabled) {
58122
+ let tokenCount = tokenCountWithEstimation(messages, effectiveSystemPrompt);
58123
+ let tokenState = calculateCompactTokenState(tokenCount.tokens, compactConfig);
58124
+ if (tokenState.isAboveWarningThreshold) {
58125
+ console.warn(
58126
+ `[compact] contextTokens=${tokenState.currentContextTokens} warning=${tokenState.warningThreshold} compact=${tokenState.compactThreshold} source=${tokenCount.source}`
58127
+ );
58128
+ const historyKey = buildMessageKey(userId, beijingTime, job?.title);
58129
+ const fullHistory = await storage.get(historyKey) || [];
58130
+ const microResult = microCompactMessages(fullHistory, compactConfig);
58131
+ if (microResult.changed) {
58132
+ await storage.set(historyKey, microResult.messages);
58133
+ messages = await getMessages(storage, userId, 300, beijingTime, job?.title);
58134
+ tokenCount = tokenCountWithEstimation(messages, effectiveSystemPrompt);
58135
+ tokenState = calculateCompactTokenState(tokenCount.tokens, compactConfig);
58136
+ console.warn(
58137
+ `[micro-compact] compactedToolResults=${microResult.compactedToolResults} removedChars=${microResult.originalCharsRemoved} contextTokens=${tokenState.currentContextTokens} source=${tokenCount.source}`
58138
+ );
58139
+ }
58140
+ }
58141
+ if (tokenState.isAboveCompactThreshold) {
58142
+ if (contextRecoveryAttempts >= compactConfig.maxFailures) {
58143
+ throw new Error(`[compact] \u4E0A\u4E0B\u6587\u8D85\u8FC7\u9608\u503C\u4E14\u6062\u590D\u6B21\u6570\u5DF2\u8FBE\u4E0A\u9650 (${compactConfig.maxFailures})`);
58144
+ }
58145
+ await recoverFromContextOverflow(`preflight:${tokenState.currentContextTokens}/${tokenState.compactThreshold}`, messages, effectiveSystemPrompt);
58146
+ continue;
58147
+ }
58148
+ }
58149
+ let response;
58150
+ const turnAbortController = new AbortController();
58151
+ activeTurnAbortController = turnAbortController;
58152
+ try {
58153
+ const llmRequestId = llmRequestIdForTurn(request, messages, effectiveSystemPrompt, tools);
58154
+ onLlmRequestId?.(llmRequestId);
58155
+ const llmTrace = await agentTrace?.child({
58156
+ name: `LLM call`,
58157
+ runType: `llm`,
58158
+ inputs: {
58159
+ llmRequestId,
58160
+ systemPrompt: effectiveSystemPrompt,
58161
+ systemContext,
58162
+ messages,
58163
+ tools: tools.map((tool) => ({
58164
+ name: tool.name,
58165
+ description: tool.description,
58166
+ input_schema: tool.input_schema
58167
+ }))
58168
+ },
58169
+ metadata: {
58170
+ ...traceMetadataFromRequest(request, internalOnly),
58171
+ iteration: iterations,
58172
+ llmRequestId
58173
+ }
58174
+ });
58175
+ try {
58176
+ response = await llm.chat(
58177
+ messages,
58178
+ effectiveSystemPrompt,
58179
+ tools,
58180
+ {
58181
+ requestId: llmRequestId,
58182
+ signal: turnAbortController.signal
58183
+ }
58184
+ );
58185
+ await llmTrace?.end({
58186
+ outputs: {
58187
+ response,
58188
+ stopReason: response.stopReason,
58189
+ usage: response.usage,
58190
+ providerResponseId: response.providerResponseId,
58191
+ model: response.model
58192
+ }
58193
+ });
58194
+ } catch (error) {
58195
+ await llmTrace?.end({ error: error.message });
58196
+ throw error;
58197
+ }
58198
+ } catch (error) {
58199
+ if (isAbortError2(error)) {
58200
+ if (isCancellationRequested(userId)) {
58201
+ throw new Error(`\u7528\u6237\u5DF2\u505C\u6B62\u5F53\u524D\u6267\u884C`);
58202
+ }
58203
+ console.log(`[agent] \u5F53\u524D LLM \u8C03\u7528\u88AB\u4E2D\u65AD\uFF0C\u51C6\u5907\u6CE8\u5165 interrupt \u540E\u91CD\u65B0\u51B3\u7B56 userId=${userId}`);
58204
+ continue;
58205
+ }
58206
+ if (compactConfig.enabled && isPromptTooLongError(error) && contextRecoveryAttempts < compactConfig.maxFailures) {
58207
+ await recoverFromContextOverflow("prompt_too_long", messages, effectiveSystemPrompt);
58208
+ continue;
58209
+ }
58210
+ if (isLlmCreditExhaustedError(error)) {
58211
+ let alreadySent = false;
58212
+ if (config2.channelPlugin && !internalOnly) {
58213
+ if (await claimOutboundText(LLM_CREDIT_EXHAUSTED_MESSAGE, "llm_credit_exhausted")) {
58214
+ await traceOutboundText(
58215
+ request.userId,
58216
+ LLM_CREDIT_EXHAUSTED_MESSAGE,
58217
+ () => config2.channelPlugin.outbound.sendText({
58218
+ cfg: {},
58219
+ to: request.userId,
58220
+ text: LLM_CREDIT_EXHAUSTED_MESSAGE,
58221
+ accountId: request.requestId,
58222
+ metadata: request.metadata
58223
+ })
58224
+ );
58225
+ alreadySent = true;
58226
+ } else {
58227
+ console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${request.userId} \u7684\u8FD1\u91CD\u590D LLM \u989D\u5EA6\u4E0D\u8DB3\u63D0\u793A`);
58228
+ }
58229
+ }
58230
+ await addMessage(storage, userId, assistantMessage(text(LLM_CREDIT_EXHAUSTED_MESSAGE)), beijingTime, job?.title);
58231
+ markAgentEventsHandled(autoHandledEventIds(alreadySent), "ignored");
58232
+ return finish({
58233
+ content: LLM_CREDIT_EXHAUSTED_MESSAGE,
58234
+ alreadySent
58235
+ });
58236
+ }
58237
+ throw error;
58238
+ } finally {
58239
+ if (activeTurnAbortController === turnAbortController) {
58240
+ activeTurnAbortController = void 0;
58241
+ }
58242
+ }
58243
+ if (response.stopReason === "model_context_window_exceeded") {
58244
+ await recoverFromContextOverflow("model_context_window_exceeded", messages, effectiveSystemPrompt);
58245
+ continue;
58246
+ }
58247
+ if (response.stopReason === "max_tokens") {
58248
+ const toolUsesTruncated = response.content.filter(isToolUseBlock);
58249
+ if (toolUsesTruncated.length > 0) {
58250
+ await addMessage(storage, userId, assistantMessage(text(
58251
+ response.content.filter((b) => b.type === "text").map((b) => b.text).join("\n") || "(\u8F93\u51FA\u88AB\u622A\u65AD)"
58252
+ )), beijingTime, job?.title);
58253
+ await addMessage(storage, userId, userMessage(text(
58254
+ `<system-warning>\u4F60\u7684\u8F93\u51FA\u56E0 max_tokens \u9650\u5236\u88AB\u622A\u65AD\uFF0C\u5DE5\u5177\u8C03\u7528\u53C2\u6570\u4E0D\u5B8C\u6574\uFF0C\u5DF2\u8DF3\u8FC7\u6267\u884C\u3002\u8BF7\u51CF\u5C11\u5355\u6B21\u8F93\u51FA\u91CF\uFF1A\u5148\u8F93\u51FA\u6587\u672C\u8BF4\u660E\uFF0C\u518D\u5355\u72EC\u8C03\u7528\u5DE5\u5177\uFF1B\u5982\u679C\u6587\u4EF6\u5185\u5BB9\u8F83\u957F\uFF0C\u8BF7\u5206\u6BB5\u5199\u5165\u3002</system-warning>`
58255
+ )), beijingTime, job?.title);
58256
+ continue;
58257
+ }
58258
+ }
58259
+ const toolUses = response.content.filter(isToolUseBlock);
58260
+ if (toolUses.length > 0) {
58261
+ await addMessage(storage, userId, assistantMessageFromResponse(response), beijingTime, job?.title);
58262
+ if (toolExecutor) {
58263
+ const userRecoverableMessages = [];
58264
+ const toolResultPromises = toolUses.map(async (useBlock) => {
58265
+ if (signal.aborted) {
58266
+ return toolResult(useBlock.id, `\u5DE5\u5177\u6267\u884C\u88AB\u4E2D\u65AD`);
58267
+ }
58268
+ try {
58269
+ if (useBlock.name === `send_message`) {
58270
+ const answer = useBlock.input.content?.trim();
58271
+ if (answer) {
58272
+ if (config2.channelPlugin) {
58273
+ console.log(`channelPlugin: ${JSON.stringify(config2.channelPlugin)}`);
58274
+ const { userId: userId2 } = request;
58275
+ console.log(`request: ${JSON.stringify(request)}`);
58276
+ if (await claimOutboundText(answer, "send_message_tool")) {
58277
+ await traceOutboundText(
58278
+ userId2,
58279
+ answer,
58280
+ () => config2.channelPlugin.outbound.sendText({
58281
+ cfg: {},
58282
+ to: userId2,
58283
+ text: answer,
58284
+ accountId: request.requestId,
58285
+ metadata: request.metadata
58286
+ })
58287
+ );
58288
+ } else {
58289
+ console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${userId2} \u7684\u8FD1\u91CD\u590D\u53D1\u9001\uFF08\u5355\u4E00\u58F0\u97F3\u515C\u5E95\uFF09`);
58290
+ }
58291
+ }
58292
+ hasSentMessage = true;
58293
+ sentMessageContent = answer;
58294
+ await completeUserVisibleCeoFollowups();
58295
+ }
58296
+ }
58297
+ if (useBlock.name === `send_file`) {
58298
+ if (config2.channelPlugin?.outbound.sendFile) {
58299
+ const { filePath, url, fileName } = useBlock.input;
58300
+ const file = filePath || url || "";
58301
+ if (file) {
58302
+ const fileType = inferFileType(fileName);
58303
+ const sentFileMessage = `\u6587\u4EF6\u5DF2\u53D1\u9001: ${fileName}`;
58304
+ if (await claimOutboundFile(fileName, file)) {
58305
+ await traceOutboundFile(
58306
+ request.userId,
58307
+ fileName,
58308
+ fileType,
58309
+ file,
58310
+ () => config2.channelPlugin.outbound.sendFile({
58311
+ cfg: {},
58312
+ to: request.userId,
58313
+ accountId: request.requestId,
58314
+ fileName,
58315
+ fileType,
58316
+ file
58317
+ })
58318
+ );
58319
+ } else {
58320
+ console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${request.userId} \u7684\u8FD1\u91CD\u590D\u6587\u4EF6\u53D1\u9001: ${fileName}`);
58321
+ }
58322
+ hasSentMessage = true;
58323
+ sentMessageContent ||= sentFileMessage;
58324
+ await completeUserVisibleCeoFollowups();
58325
+ }
58326
+ }
58327
+ }
58328
+ const toolRequest = {
58329
+ ...request,
58330
+ traceRun: agentTrace,
58331
+ metadata: {
58332
+ ...request.metadata ?? {},
58333
+ toolCallId: useBlock.id
58334
+ }
58335
+ };
58336
+ const result = await toolExecutor.execute(useBlock.name, useBlock.input, toolRequest);
58337
+ return toolResult(useBlock.id, result);
58338
+ } catch (error) {
58339
+ const err = error;
58340
+ if (isUserRecoverableToolError(error)) {
58341
+ userRecoverableMessages.push(error.userMessage);
58342
+ return toolResult(useBlock.id, `${useBlock.name}\u5DE5\u5177\u9700\u8981\u7528\u6237\u8865\u5145\u8F93\u5165,reason: ${err.message}`);
58343
+ }
58344
+ return toolResult(useBlock.id, `${useBlock.name}\u5DE5\u5177\u6267\u884C\u9519\u8BEF,reason: ${err.message}`);
58345
+ }
58346
+ });
58347
+ const toolResults = await Promise.all(toolResultPromises);
58348
+ if (toolResults.length > 0) {
58349
+ await addMessage(storage, userId, { role: "user", content: toolResults }, beijingTime, job?.title);
58350
+ }
58351
+ const userRecoverableMessage = userRecoverableMessages[0]?.trim();
58352
+ if (userRecoverableMessage) {
58353
+ let recoverableMessageSent = false;
58354
+ if (config2.channelPlugin && !internalOnly) {
58355
+ if (await claimOutboundText(userRecoverableMessage, "user_recoverable_tool_error")) {
58356
+ await traceOutboundText(
58357
+ request.userId,
58358
+ userRecoverableMessage,
58359
+ () => config2.channelPlugin.outbound.sendText({
58360
+ cfg: {},
58361
+ to: request.userId,
58362
+ text: userRecoverableMessage,
58363
+ accountId: request.requestId,
58364
+ metadata: request.metadata
58365
+ })
58366
+ );
58367
+ recoverableMessageSent = true;
58368
+ } else {
58369
+ console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${request.userId} \u7684\u8FD1\u91CD\u590D\u53EF\u6062\u590D\u9519\u8BEF\u63D0\u793A`);
58370
+ }
58371
+ }
58372
+ await addMessage(storage, userId, assistantMessage(text(userRecoverableMessage)), beijingTime, job?.title);
58373
+ markAgentEventsHandled(autoHandledEventIds(recoverableMessageSent));
58374
+ return finish({
58375
+ content: userRecoverableMessage,
58376
+ alreadySent: recoverableMessageSent
58377
+ });
58378
+ }
58379
+ const visibleCeoFollowupIdsAfterTools = ceoFollowupIdsFromMetadata2(request.metadata);
58380
+ if (hasSentMessage && visibleCeoFollowupIdsAfterTools.length > 0) {
58381
+ if (topicStorage) {
58382
+ await updateTopicSummary(topicStorage, userId, beijingTime, sentMessageContent, job?.title);
58383
+ }
58384
+ await addMessage(storage, userId, assistantMessage(text(sentMessageContent)), beijingTime, job?.title);
58385
+ markAgentEventsHandled(autoHandledEventIds(true));
58386
+ return finish({
58387
+ content: sentMessageContent,
58388
+ alreadySent: true
58389
+ });
58390
+ }
58391
+ if (hasSentMessage) {
58392
+ if (topicStorage) {
58393
+ await updateTopicSummary(topicStorage, userId, beijingTime, sentMessageContent, job?.title);
58394
+ }
58395
+ await addMessage(storage, userId, assistantMessage(text(sentMessageContent)), beijingTime, job?.title);
58396
+ markAgentEventsHandled(autoHandledEventIds(true));
58397
+ return finish({
58398
+ content: sentMessageContent,
58399
+ alreadySent: true
58400
+ });
58401
+ }
58402
+ }
58403
+ continue;
58404
+ }
58405
+ ;
58406
+ const textBlocks = response.content.filter(
58407
+ (b) => b.type === "text"
58408
+ );
58409
+ const textContent2 = textBlocks.map((b) => b.text).join(`
58410
+ `).trim();
58411
+ if (textContent2) {
58412
+ await addMessage(storage, userId, assistantMessageFromResponse(response), beijingTime, job?.title);
58413
+ const lateInterrupts = drainInterrupts(userId);
58414
+ if (lateInterrupts.length > 0) {
58415
+ console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
58416
+ for (const interrupt of lateInterrupts) {
58417
+ markInterruptEventIdsInjected(interrupt.metadata);
58418
+ rememberCeoFollowupIds(ceoFollowupIdsFromMetadata2(interrupt.metadata));
58419
+ const msg = interrupt.content;
58420
+ if (interrupt.metadata) {
58421
+ request.metadata = {
58422
+ ...request.metadata ?? {},
58423
+ ...interrupt.metadata
58424
+ };
58425
+ }
58426
+ if (interrupt.metadata?.internalOnly === true) {
58427
+ continue;
58428
+ }
58429
+ await addMessage(storage, userId, userMessage(text(
58430
+ `<user-interrupt>\u7528\u6237\u53D1\u6765\u4E86\u65B0\u6D88\u606F\uFF0C\u8BF7\u7ACB\u5373\u91CD\u65B0\u8BC4\u4F30\u5F53\u524D\u5DE5\u4F5C\uFF0C\u65B0\u6D88\u606F\u53EF\u80FD\u4F1A\u6539\u53D8\u4F60\u7684\u4EFB\u52A1\u4F18\u5148\u7EA7\u6216\u65B9\u5411\u3002
58431
+ ${msg}</user-interrupt>`
58432
+ )), beijingTime, job?.title);
58433
+ }
58434
+ continue;
58435
+ }
58436
+ const visibleCeoFollowupIds = ceoFollowupIdsFromMetadata2(request.metadata);
58437
+ if (!hasSentMessage && visibleCeoFollowupIds.length > 0 && config2.channelPlugin) {
58438
+ if (await claimOutboundText(textContent2, "followup_fallback_text")) {
58439
+ await traceOutboundText(
58440
+ request.userId,
58441
+ textContent2,
58442
+ () => config2.channelPlugin.outbound.sendText({
58443
+ cfg: {},
58444
+ to: request.userId,
58445
+ text: textContent2,
58446
+ accountId: request.requestId,
58447
+ metadata: request.metadata
58448
+ })
58449
+ );
58450
+ } else {
58451
+ console.log(`[outbound-dedup] \u8DF3\u8FC7\u5BF9\u7528\u6237 ${request.userId} \u7684\u8FD1\u91CD\u590D\u515C\u5E95\u53D1\u9001`);
58452
+ }
58453
+ hasSentMessage = true;
58454
+ sentMessageContent = textContent2;
58455
+ await completeUserVisibleCeoFollowups();
58456
+ }
58457
+ if (topicStorage) {
58458
+ const topicSummary = hasSentMessage ? sentMessageContent : textContent2;
58459
+ await updateTopicSummary(topicStorage, userId, beijingTime, topicSummary, job?.title);
58460
+ }
58461
+ markAgentEventsHandled(autoHandledEventIds(hasSentMessage));
58462
+ return finish({
58463
+ content: hasSentMessage ? sentMessageContent : textContent2,
58464
+ alreadySent: hasSentMessage
58465
+ });
58466
+ }
58467
+ if (hasSentMessage) {
58468
+ const lateInterrupts = drainInterrupts(userId);
58469
+ if (lateInterrupts.length > 0) {
58470
+ console.log(`[agent] \u9000\u51FA\u524D\u53D1\u73B0 ${lateInterrupts.length} \u6761\u8FDF\u5230\u7684\u4E2D\u65AD\u6D88\u606F\uFF0C\u7EE7\u7EED\u5904\u7406`);
58471
+ for (const interrupt of lateInterrupts) {
58472
+ markInterruptEventIdsInjected(interrupt.metadata);
58473
+ rememberCeoFollowupIds(ceoFollowupIdsFromMetadata2(interrupt.metadata));
58474
+ const msg = interrupt.content;
58475
+ if (interrupt.metadata) {
58476
+ request.metadata = {
58477
+ ...request.metadata ?? {},
58478
+ ...interrupt.metadata
58479
+ };
58480
+ }
58481
+ if (interrupt.metadata?.internalOnly === true) {
58482
+ continue;
58483
+ }
58484
+ await addMessage(storage, userId, userMessage(text(
58485
+ `<user-interrupt>\u7528\u6237\u53D1\u6765\u4E86\u65B0\u6D88\u606F\uFF0C\u8BF7\u7ACB\u5373\u91CD\u65B0\u8BC4\u4F30\u5F53\u524D\u5DE5\u4F5C\uFF0C\u65B0\u6D88\u606F\u53EF\u80FD\u4F1A\u6539\u53D8\u4F60\u7684\u4EFB\u52A1\u4F18\u5148\u7EA7\u6216\u65B9\u5411\u3002
58486
+ ${msg}</user-interrupt>`
58487
+ )), beijingTime, job?.title);
58488
+ }
58489
+ continue;
58490
+ }
58491
+ if (topicStorage) {
58492
+ await updateTopicSummary(topicStorage, userId, beijingTime, sentMessageContent, job?.title);
58493
+ }
58494
+ await addMessage(storage, userId, assistantMessage(text(sentMessageContent)), beijingTime, job?.title);
58495
+ markAgentEventsHandled(autoHandledEventIds(true));
58496
+ return finish({
58497
+ content: sentMessageContent,
58498
+ alreadySent: true
58499
+ });
58500
+ }
58501
+ emptyRetries++;
58502
+ console.warn(`[agent] LLM \u8FD4\u56DE\u7A7A\u5185\u5BB9\uFF08\u7B2C${emptyRetries}\u6B21\uFF09\uFF0CstopReason=${response.stopReason}, content=${JSON.stringify(response.content)}`);
58503
+ if (emptyRetries >= 3) {
58504
+ console.error(`[agent] LLM \u8FDE\u7EED ${emptyRetries} \u6B21\u8FD4\u56DE\u7A7A\u5185\u5BB9\uFF0C\u653E\u5F03\u91CD\u8BD5`);
58505
+ const fallback = "\u62B1\u6B49\uFF0C\u6211\u6682\u65F6\u65E0\u6CD5\u56DE\u590D\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002";
58506
+ await addMessage(storage, userId, assistantMessage(text(fallback)), beijingTime, job?.title);
58507
+ markAgentEventsHandled(autoHandledEventIds(false), "ignored");
58508
+ return finish({ content: fallback, alreadySent: false });
58509
+ }
58510
+ await addMessage(storage, userId, assistantMessage(text("(\u601D\u8003\u4E2D...)")), beijingTime, job?.title);
58511
+ await addMessage(storage, userId, userMessage(text(
58512
+ "<system-warning>\u4F60\u7684\u4E0A\u4E00\u6761\u56DE\u590D\u5185\u5BB9\u4E3A\u7A7A\u3002\u8BF7\u91CD\u65B0\u7EC4\u7EC7\u56DE\u590D\uFF0C\u4F7F\u7528 send_message \u5DE5\u5177\u5411\u7528\u6237\u53D1\u9001\u6D88\u606F\u3002</system-warning>"
58513
+ )), beijingTime, job?.title);
58514
+ continue;
58515
+ }
58516
+ } catch (error) {
58517
+ const message = error.message;
58518
+ await agentTrace?.end({ error: message });
58519
+ await rootTrace?.end({ error: message });
58520
+ throw error;
58521
+ } finally {
58522
+ if (durableEventPoller) clearInterval(durableEventPoller);
58523
+ unregisterInterruptListener?.();
58524
+ activeTurnAbortController?.abort();
58525
+ markDone(userId);
58526
+ signals.delete(userId);
58527
+ }
58528
+ };
58529
+ };
58530
+
58531
+ // src/agent/createAgent.ts
58532
+ var createAgent = (config2 = getDefaultAgentConfig()) => {
58533
+ return createAgent2(config2);
58534
+ };
56884
58535
  // Annotate the CommonJS export names for ESM import in node:
56885
58536
  0 && (module.exports = {
58537
+ createAgent,
56886
58538
  createDefaultToolHookPlugins,
56887
58539
  createDefaultTools,
56888
58540
  createDuclawTools,
56889
58541
  duclawPreset,
56890
- getDefaultAgentConfig
58542
+ getDefaultAgentConfig,
58543
+ getDefaultDuclawAgentConfig
56891
58544
  });