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.
- package/dist/bundle.js +6853 -6853
- package/dist/main.js +1 -1
- package/dist/sdk/duclaw.d.ts +8 -1
- package/dist/sdk/duclaw.d.ts.map +1 -1
- package/dist/sdk/duclaw.js +1840 -187
- package/dist/web/releases/macos/latest.json +8 -0
- package/dist/worker-main.js +1 -1
- package/package.json +2 -1
package/dist/sdk/duclaw.js
CHANGED
|
@@ -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
|
|
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
|
-
${
|
|
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/
|
|
55004
|
-
var
|
|
55005
|
-
|
|
55006
|
-
|
|
55007
|
-
|
|
55008
|
-
|
|
55009
|
-
|
|
55010
|
-
|
|
55011
|
-
|
|
55012
|
-
|
|
55013
|
-
|
|
55014
|
-
|
|
55015
|
-
|
|
55016
|
-
|
|
55017
|
-
|
|
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
|
-
|
|
55020
|
-
|
|
55021
|
-
|
|
55022
|
-
|
|
55023
|
-
|
|
55024
|
-
|
|
55025
|
-
|
|
55026
|
-
|
|
55027
|
-
|
|
55028
|
-
|
|
55029
|
-
|
|
55030
|
-
|
|
55031
|
-
|
|
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
|
});
|