shipmyagent 1.0.167 → 1.0.187
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/bin/core/context/Compact.d.ts.map +1 -0
- package/bin/core/context/Compact.js +170 -0
- package/bin/core/context/Compact.js.map +1 -0
- package/bin/core/context/ContextAgent.d.ts.map +1 -1
- package/bin/core/context/ContextAgent.js +164 -149
- package/bin/core/context/ContextAgent.js.map +1 -1
- package/bin/core/context/ContextManager.d.ts.map +1 -1
- package/bin/core/context/ContextManager.js +29 -20
- package/bin/core/context/ContextManager.js.map +1 -1
- package/bin/core/context/ContextStore.d.ts.map +1 -1
- package/bin/core/context/ContextStore.js +43 -161
- package/bin/core/context/ContextStore.js.map +1 -1
- package/bin/core/llm/CreateModel.d.ts.map +1 -1
- package/bin/core/llm/CreateModel.js +5 -4
- package/bin/core/llm/CreateModel.js.map +1 -1
- package/bin/core/prompts/System.d.ts.map +1 -1
- package/bin/core/prompts/System.js +23 -14
- package/bin/core/prompts/System.js.map +1 -1
- package/bin/core/prompts/prompt.txt +1 -44
- package/bin/core/shell/ShellHelpers.d.ts.map +1 -1
- package/bin/core/shell/ShellHelpers.js +6 -5
- package/bin/core/shell/ShellHelpers.js.map +1 -1
- package/bin/core/types/Agent.d.ts.map +1 -1
- package/bin/core/types/AgentSystem.d.ts.map +1 -0
- package/bin/core/types/AgentSystem.js +9 -0
- package/bin/core/types/AgentSystem.js.map +1 -0
- package/bin/core/types/ContextMessage.d.ts.map +1 -1
- package/bin/core/types/ContextStore.d.ts.map +1 -0
- package/bin/core/types/ContextStore.js +9 -0
- package/bin/core/types/ContextStore.js.map +1 -0
- package/bin/main/commands/Index.js +8 -7
- package/bin/main/commands/Index.js.map +1 -1
- package/bin/main/commands/Init.d.ts.map +1 -1
- package/bin/main/commands/Init.js +46 -40
- package/bin/main/commands/Init.js.map +1 -1
- package/bin/main/commands/Run.d.ts.map +1 -1
- package/bin/main/commands/Run.js +13 -9
- package/bin/main/commands/Run.js.map +1 -1
- package/bin/main/commands/Services.d.ts.map +1 -1
- package/bin/main/commands/Services.js +1 -0
- package/bin/main/commands/Services.js.map +1 -1
- package/bin/main/constants/Ship.js +4 -4
- package/bin/main/constants/Ship.js.map +1 -1
- package/bin/main/constants/ShipSchema.js +4 -4
- package/bin/main/constants/ShipSchema.js.map +1 -1
- package/bin/main/runtime/AgentServer.d.ts.map +1 -1
- package/bin/main/runtime/AgentServer.js +10 -5
- package/bin/main/runtime/AgentServer.js.map +1 -1
- package/bin/main/runtime/CliArgs.js +4 -4
- package/bin/main/runtime/CliArgs.js.map +1 -1
- package/bin/main/runtime/RuntimeState.d.ts.map +1 -1
- package/bin/main/runtime/RuntimeState.js +93 -94
- package/bin/main/runtime/RuntimeState.js.map +1 -1
- package/bin/main/runtime/TuiApi.d.ts.map +1 -0
- package/bin/main/runtime/TuiApi.js +516 -0
- package/bin/main/runtime/TuiApi.js.map +1 -0
- package/bin/main/service/Manager.d.ts.map +1 -0
- package/bin/main/service/{Registry.js → Manager.js} +2 -2
- package/bin/main/service/Manager.js.map +1 -0
- package/bin/main/service/PROMPT.txt +36 -0
- package/bin/main/service/RequestContext.d.ts.map +1 -1
- package/bin/main/service/RequestContext.js +10 -1
- package/bin/main/service/RequestContext.js.map +1 -1
- package/bin/main/service/ServiceManager.d.ts.map +1 -0
- package/bin/main/service/{ServiceRegistry.js → ServiceManager.js} +1 -1
- package/bin/main/service/ServiceManager.js.map +1 -0
- package/bin/main/service/ServiceRuntime.d.ts.map +1 -1
- package/bin/main/service/Services.d.ts.map +1 -1
- package/bin/main/service/Services.js +4 -4
- package/bin/main/service/Services.js.map +1 -1
- package/bin/main/types/ShipConfig.d.ts.map +1 -1
- package/bin/main/types/Start.d.ts.map +1 -1
- package/bin/main/types/Start.js +2 -2
- package/bin/main/ui/WebUIClient.d.ts.map +1 -1
- package/bin/main/ui/WebUIClient.js +7 -6
- package/bin/main/ui/WebUIClient.js.map +1 -1
- package/bin/main/utils/Id.d.ts.map +1 -1
- package/bin/main/utils/Id.js +5 -7
- package/bin/main/utils/Id.js.map +1 -1
- package/bin/services/chat/Action.d.ts.map +1 -0
- package/bin/services/chat/{Service.js → Action.js} +3 -5
- package/bin/services/chat/Action.js.map +1 -0
- package/bin/services/chat/Index.d.ts.map +1 -0
- package/bin/services/chat/Index.js +491 -0
- package/bin/services/chat/Index.js.map +1 -0
- package/bin/services/chat/PROMPT.txt +56 -0
- package/bin/services/chat/channels/BaseChatChannel.d.ts.map +1 -0
- package/bin/services/chat/{adapters/BaseChatAdapter.js → channels/BaseChatChannel.js} +76 -11
- package/bin/services/chat/channels/BaseChatChannel.js.map +1 -0
- package/bin/services/chat/{adapters → channels}/feishu/Feishu.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/feishu/Feishu.js +2 -2
- package/bin/services/chat/{adapters → channels}/feishu/Feishu.js.map +1 -1
- package/bin/services/chat/channels/feishu/PROMPT.txt +10 -0
- package/bin/services/chat/channels/qq/PROMPT.txt +10 -0
- package/bin/services/chat/{adapters → channels}/qq/QQ.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/qq/QQ.js +2 -2
- package/bin/services/chat/{adapters → channels}/qq/QQ.js.map +1 -1
- package/bin/services/chat/{adapters → channels}/qq/QQInboundDedupe.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/qq/QQInboundDedupe.js.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/Access.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/Access.js.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/ApiClient.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/ApiClient.js.map +1 -1
- package/bin/services/chat/channels/telegram/Bot.d.ts.map +1 -0
- package/bin/services/chat/{adapters → channels}/telegram/Bot.js +56 -3
- package/bin/services/chat/channels/telegram/Bot.js.map +1 -0
- package/bin/services/chat/{adapters → channels}/telegram/Handlers.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/Handlers.js.map +1 -1
- package/bin/services/chat/channels/telegram/PROMPT.txt +14 -0
- package/bin/services/chat/{adapters → channels}/telegram/Shared.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/Shared.js.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/StateStore.d.ts.map +1 -1
- package/bin/services/chat/{adapters → channels}/telegram/StateStore.js.map +1 -1
- package/bin/services/chat/runtime/ChatHistoryStore.d.ts.map +1 -1
- package/bin/services/chat/runtime/ChatHistoryStore.js +145 -2
- package/bin/services/chat/runtime/ChatHistoryStore.js.map +1 -1
- package/bin/services/chat/runtime/ChatQueueWorker.d.ts.map +1 -1
- package/bin/services/chat/runtime/ChatQueueWorker.js +0 -3
- package/bin/services/chat/runtime/ChatQueueWorker.js.map +1 -1
- package/bin/services/chat/runtime/ChatkeySend.d.ts.map +1 -1
- package/bin/services/chat/runtime/ChatkeySend.js +6 -2
- package/bin/services/chat/runtime/ChatkeySend.js.map +1 -1
- package/bin/services/chat/runtime/UIMessageTransformer.d.ts.map +1 -1
- package/bin/services/chat/runtime/UIMessageTransformer.js.map +1 -1
- package/bin/services/chat/runtime/UserVisibleText.d.ts.map +1 -1
- package/bin/services/chat/runtime/UserVisibleText.js.map +1 -1
- package/bin/services/chat/types/ChatCommand.d.ts.map +1 -1
- package/bin/services/chat/types/ChatHistory.d.ts.map +1 -1
- package/bin/services/chat/types/ChatHistory.js +1 -1
- package/bin/services/memory/runtime/SystemProvider.d.ts.map +1 -1
- package/bin/services/memory/runtime/SystemProvider.js +26 -31
- package/bin/services/memory/runtime/SystemProvider.js.map +1 -1
- package/bin/services/skills/Action.d.ts.map +1 -0
- package/bin/services/skills/{Service.js → Action.js} +1 -1
- package/bin/services/skills/Action.js.map +1 -0
- package/bin/services/skills/Index.d.ts.map +1 -0
- package/bin/services/skills/{ServiceEntry.js → Index.js} +25 -6
- package/bin/services/skills/Index.js.map +1 -0
- package/bin/services/skills/PROMPT.txt +28 -0
- package/bin/services/skills/runtime/ActiveSkillsPrompt.d.ts.map +1 -1
- package/bin/services/skills/runtime/ActiveSkillsPrompt.js +6 -24
- package/bin/services/skills/runtime/ActiveSkillsPrompt.js.map +1 -1
- package/bin/services/skills/runtime/SystemProvider.d.ts.map +1 -1
- package/bin/services/skills/runtime/SystemProvider.js +29 -55
- package/bin/services/skills/runtime/SystemProvider.js.map +1 -1
- package/bin/services/task/Action.d.ts.map +1 -0
- package/bin/services/task/{Service.js → Action.js} +51 -4
- package/bin/services/task/Action.js.map +1 -0
- package/bin/services/task/Index.d.ts.map +1 -0
- package/bin/services/task/{ServiceEntry.js → Index.js} +127 -8
- package/bin/services/task/Index.js.map +1 -0
- package/bin/services/task/PROMPT.txt +182 -0
- package/bin/services/task/Scheduler.d.ts.map +1 -1
- package/bin/services/task/Scheduler.js +150 -16
- package/bin/services/task/Scheduler.js.map +1 -1
- package/bin/services/task/TASK.prompt.txt +15 -0
- package/bin/services/task/runtime/Model.d.ts.map +1 -1
- package/bin/services/task/runtime/Model.js +55 -2
- package/bin/services/task/runtime/Model.js.map +1 -1
- package/bin/services/task/runtime/Runner.d.ts.map +1 -1
- package/bin/services/task/runtime/Runner.js +296 -150
- package/bin/services/task/runtime/Runner.js.map +1 -1
- package/bin/services/task/runtime/Store.d.ts.map +1 -1
- package/bin/services/task/runtime/Store.js +22 -0
- package/bin/services/task/runtime/Store.js.map +1 -1
- package/bin/services/task/runtime/TaskPrompt.d.ts.map +1 -0
- package/bin/services/task/runtime/TaskPrompt.js +23 -0
- package/bin/services/task/runtime/TaskPrompt.js.map +1 -0
- package/bin/services/task/types/Task.d.ts.map +1 -1
- package/bin/services/task/types/TaskCommand.d.ts.map +1 -1
- package/bin/utils/Id.d.ts.map +1 -0
- package/bin/utils/Id.js +12 -0
- package/bin/utils/Id.js.map +1 -0
- package/bin/utils/logger/Fetch.d.ts.map +1 -1
- package/bin/utils/logger/Fetch.js +4 -3
- package/bin/utils/logger/Fetch.js.map +1 -1
- package/bin/utils/logger/Format.d.ts.map +1 -1
- package/bin/utils/logger/Format.js +166 -30
- package/bin/utils/logger/Format.js.map +1 -1
- package/bin/utils/logger/Logger.d.ts.map +1 -1
- package/bin/utils/logger/Logger.js +50 -5
- package/bin/utils/logger/Logger.js.map +1 -1
- package/package.json +4 -1
- package/public/app.js +576 -421
- package/public/index.html +72 -107
- package/public/styles.css +342 -602
- package/scripts/copy-prompt-assets.mjs +45 -16
- package/src/core/README.md +3 -4
- package/src/core/prompts/prompt.txt +1 -44
- package/src/main/README.md +4 -4
- package/src/main/service/PROMPT.txt +36 -0
- package/src/main/service/README.md +8 -4
- package/src/services/README.md +1 -1
- package/src/services/chat/PROMPT.txt +56 -0
- package/src/services/chat/channels/feishu/PROMPT.txt +10 -0
- package/src/services/chat/channels/qq/PROMPT.txt +10 -0
- package/src/services/chat/channels/telegram/PROMPT.txt +14 -0
- package/src/services/skills/PROMPT.txt +28 -0
- package/src/services/task/PROMPT.txt +182 -0
- package/src/services/task/TASK.prompt.txt +15 -0
- package/src/utils/README.md +5 -7
- package/test/logger/format.test.mjs +76 -0
- package/test/model/create-model.test.mjs +135 -0
- package/test/test-model.mjs +343 -0
- package/bin/core/prompts/SystemProvider.d.ts.map +0 -1
- package/bin/core/prompts/SystemProvider.js +0 -154
- package/bin/core/prompts/SystemProvider.js.map +0 -1
- package/bin/core/types/SystemPromptProvider.d.ts.map +0 -1
- package/bin/core/types/SystemPromptProvider.js +0 -2
- package/bin/core/types/SystemPromptProvider.js.map +0 -1
- package/bin/main/service/Registry.d.ts.map +0 -1
- package/bin/main/service/Registry.js.map +0 -1
- package/bin/main/service/ServiceRegistry.d.ts.map +0 -1
- package/bin/main/service/ServiceRegistry.js.map +0 -1
- package/bin/services/chat/Service.d.ts.map +0 -1
- package/bin/services/chat/Service.js.map +0 -1
- package/bin/services/chat/ServiceEntry.d.ts.map +0 -1
- package/bin/services/chat/ServiceEntry.js +0 -290
- package/bin/services/chat/ServiceEntry.js.map +0 -1
- package/bin/services/chat/adapters/BaseChatAdapter.d.ts.map +0 -1
- package/bin/services/chat/adapters/BaseChatAdapter.js.map +0 -1
- package/bin/services/chat/adapters/PlatformAdapter.d.ts.map +0 -1
- package/bin/services/chat/adapters/PlatformAdapter.js +0 -81
- package/bin/services/chat/adapters/PlatformAdapter.js.map +0 -1
- package/bin/services/chat/adapters/telegram/Bot.d.ts.map +0 -1
- package/bin/services/chat/adapters/telegram/Bot.js.map +0 -1
- package/bin/services/chat/runtime/EgressIdempotency.d.ts.map +0 -1
- package/bin/services/chat/runtime/EgressIdempotency.js +0 -85
- package/bin/services/chat/runtime/EgressIdempotency.js.map +0 -1
- package/bin/services/skills/Service.d.ts.map +0 -1
- package/bin/services/skills/Service.js.map +0 -1
- package/bin/services/skills/ServiceEntry.d.ts.map +0 -1
- package/bin/services/skills/ServiceEntry.js.map +0 -1
- package/bin/services/task/Service.d.ts.map +0 -1
- package/bin/services/task/Service.js.map +0 -1
- package/bin/services/task/ServiceEntry.d.ts.map +0 -1
- package/bin/services/task/ServiceEntry.js.map +0 -1
- package/bin/utils/logger/Context.d.ts.map +0 -1
- package/bin/utils/logger/Context.js +0 -6
- package/bin/utils/logger/Context.js.map +0 -1
- /package/bin/services/chat/{adapters → channels}/qq/QQInboundDedupe.js +0 -0
- /package/bin/services/chat/{adapters → channels}/telegram/Access.js +0 -0
- /package/bin/services/chat/{adapters → channels}/telegram/ApiClient.js +0 -0
- /package/bin/services/chat/{adapters → channels}/telegram/Handlers.js +0 -0
- /package/bin/services/chat/{adapters → channels}/telegram/Shared.js +0 -0
- /package/bin/services/chat/{adapters → channels}/telegram/StateStore.js +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Compact.d.ts","sourceRoot":"","sources":["../../../src/core/context/Compact.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,EAGL,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACxB,MAAM,IAAI,CAAC;AAGZ,OAAO,KAAK,EACV,gBAAgB,EAChB,iBAAiB,EAClB,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,oCAAoC,CAAC;AAEpF,MAAM,MAAM,oBAAoB,GAAG;IACjC,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,KAAK,CAAC,kBAAkB,CAAC,CAAC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;CAC3B,CAAC;AAEF,KAAK,kBAAkB,GAAG;IACxB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;IACvD,OAAO,EAAE,MAAM,OAAO,CAAC,gBAAgB,EAAE,CAAC,CAAC;IAC3C,oBAAoB,EAAE,CAAC,MAAM,EAAE;QAC7B,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,iBAAiB,CAAC,aAAa,CAAC,CAAC;KAChD,KAAK,gBAAgB,CAAC;IACvB,iBAAiB,EAAE,MAAM,MAAM,CAAC;IAChC,mBAAmB,EAAE,MAAM,MAAM,CAAC;IAClC,cAAc,EAAE,MAAM,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACzD,eAAe,EAAE,CAAC,IAAI,EAAE,yBAAyB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrE,CAAC;AAEF;;;;;;GAMG;AACH,wBAAsB,6BAA6B,CACjD,IAAI,EAAE,kBAAkB,EACxB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0IlD"}
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Context 压缩模块。
|
|
3
|
+
*
|
|
4
|
+
* 关键职责(中文)
|
|
5
|
+
* - 评估当前消息是否超出输入预算。
|
|
6
|
+
* - 在锁外生成“更早历史摘要”,降低锁持有时间。
|
|
7
|
+
* - 在锁内完成归档与 messages.jsonl 重写,保证并发安全。
|
|
8
|
+
*/
|
|
9
|
+
import fs from "fs-extra";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { generateText, isTextUIPart, } from "ai";
|
|
12
|
+
import { generateId } from "../../utils/Id.js";
|
|
13
|
+
import { getLogger } from "../../utils/logger/Logger.js";
|
|
14
|
+
/**
|
|
15
|
+
* 对当前 context messages 做一次 best-effort compact(必要时)。
|
|
16
|
+
*
|
|
17
|
+
* 注意(中文)
|
|
18
|
+
* - compact 会 rewrite `messages.jsonl`(不是纯 append-only),因此必须防并发覆盖
|
|
19
|
+
* - 这里做两阶段锁:先 snapshot 再生成摘要,最后再锁定写入,降低锁持有时间
|
|
20
|
+
*/
|
|
21
|
+
export async function compactContextMessageIfNeeded(deps, params) {
|
|
22
|
+
const logger = getLogger(deps.rootPath, "info");
|
|
23
|
+
// 算法阶段(中文)
|
|
24
|
+
// phase 1:snapshot(短锁)
|
|
25
|
+
// - 仅负责拿一致性快照,不做耗时的模型调用。
|
|
26
|
+
// - 目的是把锁持有时间降到最低。
|
|
27
|
+
let snapshot = [];
|
|
28
|
+
let snapshotTailId = "";
|
|
29
|
+
await deps.withWriteLock(async () => {
|
|
30
|
+
snapshot = await deps.loadAll();
|
|
31
|
+
snapshotTailId =
|
|
32
|
+
snapshot.length > 0
|
|
33
|
+
? String(snapshot[snapshot.length - 1].id || "")
|
|
34
|
+
: "";
|
|
35
|
+
});
|
|
36
|
+
if (snapshot.length <= params.keepLastMessages + 2) {
|
|
37
|
+
return { compacted: false, reason: "small_messages" };
|
|
38
|
+
}
|
|
39
|
+
const systemText = (params.system || [])
|
|
40
|
+
.map((m) => String(m.content ?? ""))
|
|
41
|
+
.join("\n\n");
|
|
42
|
+
// 关键点(中文):context messages 现在可能包含 tool parts/output,必须把它们计入预算估算,否则会低估 token。
|
|
43
|
+
let messagesJson = "";
|
|
44
|
+
try {
|
|
45
|
+
messagesJson = JSON.stringify(snapshot);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
messagesJson = "";
|
|
49
|
+
}
|
|
50
|
+
const est = estimateTokensApproxFromText(systemText + "\n\n" + messagesJson);
|
|
51
|
+
if (est <= params.maxInputTokensApprox) {
|
|
52
|
+
return { compacted: false, reason: "under_budget" };
|
|
53
|
+
}
|
|
54
|
+
const keepLast = Math.max(6, Math.min(2000, Math.floor(params.keepLastMessages)));
|
|
55
|
+
const older = snapshot.slice(0, Math.max(0, snapshot.length - keepLast));
|
|
56
|
+
if (older.length === 0)
|
|
57
|
+
return { compacted: false, reason: "nothing_to_compact" };
|
|
58
|
+
const olderTextAll = extractPlainTextFromMessages(older);
|
|
59
|
+
const maxOlderChars = 24_000;
|
|
60
|
+
const olderText = olderTextAll.length > maxOlderChars
|
|
61
|
+
? "(注意:更早历史过长,已截断保留末尾)\n" + olderTextAll.slice(-maxOlderChars)
|
|
62
|
+
: olderTextAll;
|
|
63
|
+
// phase 1.5:生成摘要(不持锁)
|
|
64
|
+
// - 这一步最耗时,必须在锁外执行,避免阻塞 append。
|
|
65
|
+
let summary = "";
|
|
66
|
+
try {
|
|
67
|
+
const r = await generateText({
|
|
68
|
+
model: params.model,
|
|
69
|
+
system: [
|
|
70
|
+
{
|
|
71
|
+
role: "system",
|
|
72
|
+
content: "你是对话压缩助手。请把更早的对话历史压缩成“可持续复用”的工作摘要。\n" +
|
|
73
|
+
"要求:\n" +
|
|
74
|
+
"- 输出中文\n" +
|
|
75
|
+
"- 不要复述无关细节,不要输出工具原始日志\n" +
|
|
76
|
+
"- 必须包含:已确认事实/用户偏好约束/已做决策/未完成事项\n" +
|
|
77
|
+
"- 使用 Markdown 列表,控制在 300~800 字",
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
prompt: `请压缩以下更早历史(按 user/assistant 交替记录):\n\n${olderText}`,
|
|
81
|
+
});
|
|
82
|
+
summary = String(r.text || "").trim();
|
|
83
|
+
}
|
|
84
|
+
catch (e) {
|
|
85
|
+
await logger.log("warn", "Context messages compact summary failed, fallback to lossy truncation", {
|
|
86
|
+
contextId: deps.contextId,
|
|
87
|
+
error: String(e),
|
|
88
|
+
});
|
|
89
|
+
summary = "(系统自动压缩:摘要生成失败,已丢弃更早历史,仅保留最近对话。)";
|
|
90
|
+
}
|
|
91
|
+
const fromId = String(older[0]?.id || "");
|
|
92
|
+
const toId = String(older[older.length - 1]?.id || "");
|
|
93
|
+
const summaryMsg = deps.createSummaryMessage({
|
|
94
|
+
text: summary,
|
|
95
|
+
sourceRange: fromId && toId ? { fromId, toId, count: older.length } : undefined,
|
|
96
|
+
});
|
|
97
|
+
const archiveId = `compact-${Date.now()}-${generateId()}`;
|
|
98
|
+
// phase 2:写入(短锁,且避免覆盖新追加)
|
|
99
|
+
// - 以“当前最新 context messages”为准重算 currentOlder/currentKept,避免覆盖并发新消息。
|
|
100
|
+
await deps.withWriteLock(async () => {
|
|
101
|
+
const current = await deps.loadAll();
|
|
102
|
+
if (!current.length)
|
|
103
|
+
return;
|
|
104
|
+
// 如果 tail 不同,说明期间有新消息追加;我们仍可安全 compact:按“当前”来保留最近 keepLast。
|
|
105
|
+
// snapshotTailId 用于 debug,不作为强一致性依赖。
|
|
106
|
+
void snapshotTailId;
|
|
107
|
+
const currentOlder = current.slice(0, Math.max(0, current.length - keepLast));
|
|
108
|
+
const currentKept = current.slice(Math.max(0, current.length - keepLast));
|
|
109
|
+
if (currentOlder.length === 0)
|
|
110
|
+
return;
|
|
111
|
+
if (params.archiveOnCompact) {
|
|
112
|
+
const archivePath = path.join(deps.getArchiveDirPath(), `${encodeURIComponent(String(archiveId || "").trim())}.json`);
|
|
113
|
+
await fs.writeJson(archivePath, {
|
|
114
|
+
v: 1,
|
|
115
|
+
contextId: deps.contextId,
|
|
116
|
+
archivedAt: Date.now(),
|
|
117
|
+
messages: currentOlder,
|
|
118
|
+
}, { spaces: 2 });
|
|
119
|
+
}
|
|
120
|
+
const next = [summaryMsg, ...currentKept];
|
|
121
|
+
const messagesPath = deps.getMessagesFilePath();
|
|
122
|
+
const tmp = messagesPath + ".tmp";
|
|
123
|
+
await fs.writeFile(tmp, next.map((m) => JSON.stringify(m)).join("\n") + "\n", "utf8");
|
|
124
|
+
await fs.move(tmp, messagesPath, { overwrite: true });
|
|
125
|
+
const prevMeta = await deps.readMetaUnsafe();
|
|
126
|
+
await deps.writeMetaUnsafe({
|
|
127
|
+
...prevMeta,
|
|
128
|
+
updatedAt: Date.now(),
|
|
129
|
+
lastArchiveId: params.archiveOnCompact ? archiveId : undefined,
|
|
130
|
+
keepLastMessages: keepLast,
|
|
131
|
+
maxInputTokensApprox: params.maxInputTokensApprox,
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
return { compacted: true };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* 近似 token 估算。
|
|
138
|
+
*
|
|
139
|
+
* 算法说明(中文)
|
|
140
|
+
* - 这里使用经验近似,不追求精确 tokenizer 一致性。
|
|
141
|
+
* - 目标是为 compact 提供保守预算,宁可略高估也不要低估。
|
|
142
|
+
*/
|
|
143
|
+
function estimateTokensApproxFromText(text) {
|
|
144
|
+
const t = String(text || "");
|
|
145
|
+
// 经验值:英文 ~4 chars/token;中文更接近 1-2 chars/token。这里用保守的 3 chars/token。
|
|
146
|
+
return Math.ceil(t.length / 3);
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* 从 UIMessage 提取可摘要的纯文本。
|
|
150
|
+
*
|
|
151
|
+
* 关键点(中文)
|
|
152
|
+
* - 统一把 user/assistant 内容线性化,作为 compact 摘要输入。
|
|
153
|
+
* - tool 原始结构不会原样输出,避免把噪声日志喂给摘要模型。
|
|
154
|
+
*/
|
|
155
|
+
function extractPlainTextFromMessages(messages) {
|
|
156
|
+
const lines = [];
|
|
157
|
+
for (const m of messages) {
|
|
158
|
+
if (!m || typeof m !== "object")
|
|
159
|
+
continue;
|
|
160
|
+
const role = m.role === "user" ? "user" : "assistant";
|
|
161
|
+
const parts = Array.isArray(m.parts) ? m.parts : [];
|
|
162
|
+
const textParts = parts.filter(isTextUIPart).map((p) => String(p.text ?? ""));
|
|
163
|
+
const text = textParts.join("\n").trim();
|
|
164
|
+
if (!text)
|
|
165
|
+
continue;
|
|
166
|
+
lines.push(`${role}: ${text}`);
|
|
167
|
+
}
|
|
168
|
+
return lines.join("\n");
|
|
169
|
+
}
|
|
170
|
+
//# sourceMappingURL=Compact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Compact.js","sourceRoot":"","sources":["../../../src/core/context/Compact.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ContextAgent.d.ts","sourceRoot":"","sources":["../../../src/core/context/ContextAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"ContextAgent.d.ts","sourceRoot":"","sources":["../../../src/core/context/ContextAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAKL,KAAK,aAAa,EAGnB,MAAM,IAAI,CAAC;AAOZ,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACvE,OAAO,KAAK,EACV,iBAAiB,EAElB,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAKtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAItD,MAAM,MAAM,wBAAwB,GAAG;IACrC,KAAK,EAAE,aAAa,CAAC;IACrB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,CAAC,CAAC,EACrB,GAAG,EAAE;QAAE,SAAS,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,EAC/C,EAAE,EAAE,MAAM,CAAC,KACR,CAAC,CAAC;IACP,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,YAAY,CAAC;IACrD,sBAAsB,EAAE,MAAM,MAAM,EAAE,CAAC;IACvC,uBAAuB,EAAE,CAAC,MAAM,CAAC,EAAE;QACjC,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;KACjC,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACxB,OAAO,CAAC,EAAE;QACR,gBAAgB,CAAC,EAAE,MAAM,CAAC;QAC1B,oBAAoB,CAAC,EAAE,MAAM,CAAC;QAC9B,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CACH,CAAC;AAEF,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA2B;IAChD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgB;IAEtC,OAAO,CAAC,KAAK,CAA4B;IACzC;;;;;;OAMG;IACH,OAAO,CAAC,MAAM,CAC6B;IAC3C;;;;;;OAMG;IACH,OAAO,CAAC,cAAc,CAAuB;gBAEjC,IAAI,EAAE,wBAAwB;IAM1C;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,yBAAyB;IAOxC;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAsB7B;;OAEG;IACH,SAAS,IAAI,MAAM;IAInB;;;;;;OAMG;IACG,GAAG,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,WAAW,CAAC;IAkBrD;;OAEG;IACH,OAAO,CAAC,aAAa;IAarB;;;;;;;;OAQG;YACW,oBAAoB;IAkSlC;;OAEG;IACH,OAAO,CAAC,mCAAmC;IAa3C;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAkBlC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAWlC;;;;;;OAMG;IACH,OAAO,CAAC,6BAA6B;IAqCrC;;;;;;OAMG;IACH,OAAO,CAAC,oBAAoB;IA+C5B;;;;;OAKG;IACH,SAAS,CAAC,MAAM,EAAE,iBAAiB,GAAG,IAAI;IAI1C;;OAEG;IACH,WAAW,IAAI,IAAI;CAGpB"}
|
|
@@ -2,26 +2,27 @@
|
|
|
2
2
|
* ContextAgentRunner:单会话 Agent 执行器。
|
|
3
3
|
*
|
|
4
4
|
* 关键职责(中文)
|
|
5
|
-
* - 组装 system prompt(运行时上下文 +
|
|
5
|
+
* - 组装 system prompt(运行时上下文 + 静态模板 + service system)。
|
|
6
6
|
* - 执行 tool-loop,并把 assistant/tool 调用结果回写 context 消息。
|
|
7
7
|
* - 在上下文超窗时按策略逐步收紧 compact 参数并重试。
|
|
8
8
|
*/
|
|
9
9
|
import { isTextUIPart, streamText, stepCountIs, } from "ai";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import { buildContextSystemPrompt, transformPromptsIntoSystemMessages, } from "../prompts/System.js";
|
|
13
|
-
import { createModel } from "../llm/CreateModel.js";
|
|
14
|
-
import { openai } from "@ai-sdk/openai";
|
|
15
|
-
import { getRuntimeState, getRuntimeStateBase, } from "../../main/runtime/RuntimeState.js";
|
|
16
|
-
import { collectSystemPromptProviderResult } from "../prompts/SystemProvider.js";
|
|
17
|
-
import { loadProjectDotenv } from "../../main/runtime/Config.js";
|
|
10
|
+
import { generateId } from "../../utils/Id.js";
|
|
11
|
+
import { buildContextSystemPrompt, DEFAULT_SHIP_PROMPTS, transformPromptsIntoSystemMessages, } from "../prompts/System.js";
|
|
18
12
|
import { shellTools } from "../shell/Tool.js";
|
|
13
|
+
import { compactContextMessageIfNeeded } from "./Compact.js";
|
|
19
14
|
export class ContextAgent {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
// 模型
|
|
23
|
-
model = openai("gpt-5.2");
|
|
15
|
+
deps;
|
|
16
|
+
model;
|
|
24
17
|
tools = {};
|
|
18
|
+
/**
|
|
19
|
+
* Agent system 配置(可由调用方覆盖)。
|
|
20
|
+
*
|
|
21
|
+
* 关键点(中文)
|
|
22
|
+
* - 默认按 chat 会话模式运行。
|
|
23
|
+
* - task 等非聊天场景可通过 `setSystem` 覆盖默认行为。
|
|
24
|
+
*/
|
|
25
|
+
system = ContextAgent.createDefaultSystemConfig();
|
|
25
26
|
/**
|
|
26
27
|
* contextId 绑定检查。
|
|
27
28
|
*
|
|
@@ -30,83 +31,65 @@ export class ContextAgent {
|
|
|
30
31
|
* - 本实例一旦首次 run 绑定到某个 contextId,后续必须一致,避免上下文串线
|
|
31
32
|
*/
|
|
32
33
|
boundContextId = null;
|
|
33
|
-
constructor() {
|
|
34
|
+
constructor(deps) {
|
|
35
|
+
this.deps = deps;
|
|
36
|
+
this.model = deps.model;
|
|
37
|
+
this.tools = { ...shellTools };
|
|
38
|
+
}
|
|
34
39
|
/**
|
|
35
|
-
*
|
|
40
|
+
* 创建默认 system 配置。
|
|
36
41
|
*/
|
|
37
|
-
|
|
38
|
-
return
|
|
42
|
+
static createDefaultSystemConfig() {
|
|
43
|
+
return {
|
|
44
|
+
mode: "chat",
|
|
45
|
+
disableServiceSystems: [],
|
|
46
|
+
};
|
|
39
47
|
}
|
|
40
48
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
* 流程(中文)
|
|
44
|
-
* 1) 构建工具集合
|
|
45
|
-
* 2) 根据 ship.json 创建模型实例
|
|
46
|
-
* 3) 标记 initialized=true
|
|
49
|
+
* 归一化外部传入的 system 配置。
|
|
47
50
|
*/
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
51
|
+
normalizeSystemConfig(input) {
|
|
52
|
+
const mode = input.mode === "task" ? "task" : "chat";
|
|
53
|
+
const replaceDefaultCorePrompt = String(input.replaceDefaultCorePrompt || "").trim();
|
|
54
|
+
const disableServiceSystems = Array.isArray(input.disableServiceSystems)
|
|
55
|
+
? [...new Set(input.disableServiceSystems
|
|
56
|
+
.map((item) => String(item || "").trim())
|
|
57
|
+
.filter(Boolean))]
|
|
58
|
+
: [];
|
|
59
|
+
return {
|
|
60
|
+
mode,
|
|
61
|
+
...(replaceDefaultCorePrompt ? { replaceDefaultCorePrompt } : {}),
|
|
62
|
+
disableServiceSystems,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* 获取运行时 logger。
|
|
67
|
+
*/
|
|
68
|
+
getLogger() {
|
|
69
|
+
return this.deps.logger;
|
|
65
70
|
}
|
|
66
71
|
/**
|
|
67
72
|
* run:对外统一入口。
|
|
68
73
|
*
|
|
69
74
|
* 流程(中文)
|
|
70
75
|
* 1) 记录 requestId 与日志
|
|
71
|
-
* 2)
|
|
72
|
-
* 3) 进入 tool-loop 主流程
|
|
76
|
+
* 2) 进入 tool-loop 主流程
|
|
73
77
|
*/
|
|
74
78
|
async run(input) {
|
|
75
79
|
const { query, contextId, onStepCallback } = input;
|
|
76
80
|
const startTime = Date.now();
|
|
77
81
|
const requestId = generateId();
|
|
78
82
|
const logger = this.getLogger();
|
|
79
|
-
await logger.log("debug", `ContextId: ${contextId}`);
|
|
80
83
|
await logger.log("info", "Agent request started", {
|
|
81
84
|
requestId,
|
|
82
85
|
contextId,
|
|
83
86
|
instructionsPreview: query?.slice(0, 200),
|
|
84
|
-
rootPath:
|
|
87
|
+
rootPath: this.deps.projectRoot,
|
|
88
|
+
});
|
|
89
|
+
return this.runWithToolLoopAgent(query, startTime, contextId, {
|
|
90
|
+
requestId,
|
|
91
|
+
onStepCallback,
|
|
85
92
|
});
|
|
86
|
-
if (this.initialized) {
|
|
87
|
-
return this.runWithToolLoopAgent(query, startTime, contextId, {
|
|
88
|
-
requestId,
|
|
89
|
-
onStepCallback,
|
|
90
|
-
});
|
|
91
|
-
}
|
|
92
|
-
let contextStore = null;
|
|
93
|
-
try {
|
|
94
|
-
contextStore =
|
|
95
|
-
getRuntimeState().contextManager.getContextStore(contextId);
|
|
96
|
-
}
|
|
97
|
-
catch {
|
|
98
|
-
contextStore = null;
|
|
99
|
-
}
|
|
100
|
-
return {
|
|
101
|
-
success: false,
|
|
102
|
-
assistantMessage: this.buildFallbackAssistantMessage({
|
|
103
|
-
contextId,
|
|
104
|
-
requestId,
|
|
105
|
-
contextStore,
|
|
106
|
-
text: "LLM is not configured (or runtime not initialized). Please configure `ship.json.llm` (model + apiKey) and restart.",
|
|
107
|
-
note: "agent_not_initialized",
|
|
108
|
-
}),
|
|
109
|
-
};
|
|
110
93
|
}
|
|
111
94
|
/**
|
|
112
95
|
* 绑定 contextId(单实例单会话约束)。
|
|
@@ -128,7 +111,7 @@ export class ContextAgent {
|
|
|
128
111
|
* 算法步骤(中文)
|
|
129
112
|
* - 绑定 contextId,防止一个实例跨会话串线。
|
|
130
113
|
* - 读取/补齐用户消息到 context store(防止入口未写入)。
|
|
131
|
-
* - 收集 system
|
|
114
|
+
* - 收集 service system 文本,和运行时/静态 system 一起拼装。
|
|
132
115
|
* - 执行模型调用;若超窗则按 compact policy 递进重试。
|
|
133
116
|
*/
|
|
134
117
|
async runWithToolLoopAgent(userText, startTime, contextId, opts) {
|
|
@@ -137,37 +120,49 @@ export class ContextAgent {
|
|
|
137
120
|
const requestId = opts?.requestId || "";
|
|
138
121
|
const onStepCallback = opts?.onStepCallback;
|
|
139
122
|
const logger = this.getLogger();
|
|
140
|
-
if (!this.initialized) {
|
|
141
|
-
throw new Error("Agent not initialized");
|
|
142
|
-
}
|
|
143
123
|
try {
|
|
144
124
|
this.bindContextId(contextId);
|
|
145
|
-
const runtime = getRuntimeState();
|
|
146
125
|
// phase 0(中文):装配 context store 与 runtime/system prompt 基础上下文。
|
|
147
|
-
contextStore =
|
|
126
|
+
contextStore = this.deps.getContextStore(contextId);
|
|
127
|
+
const activeContextStore = contextStore;
|
|
148
128
|
const runtimeSystemMessages = this.buildRuntimeSystemMessages({
|
|
149
|
-
projectRoot:
|
|
150
|
-
contextId,
|
|
151
|
-
requestId,
|
|
152
|
-
});
|
|
153
|
-
const staticSystemMessages = transformPromptsIntoSystemMessages([
|
|
154
|
-
...runtime.systems,
|
|
155
|
-
]);
|
|
156
|
-
let currentProviderResult = await collectSystemPromptProviderResult({
|
|
157
|
-
projectRoot: runtime.rootPath,
|
|
129
|
+
projectRoot: this.deps.projectRoot,
|
|
158
130
|
contextId,
|
|
159
131
|
requestId,
|
|
160
|
-
allToolNames: Object.keys(this.tools),
|
|
161
132
|
});
|
|
133
|
+
const staticSystemMessages = transformPromptsIntoSystemMessages(this.resolveStaticSystemPrompts({
|
|
134
|
+
systems: this.deps.getStaticSystemPrompts(),
|
|
135
|
+
}));
|
|
136
|
+
let serviceSystemMessages = transformPromptsIntoSystemMessages(await this.deps.getServiceSystemPrompts({
|
|
137
|
+
disabledServiceNames: this.system.disableServiceSystems,
|
|
138
|
+
}));
|
|
162
139
|
let currentBaseSystemMessages = [
|
|
163
140
|
...runtimeSystemMessages,
|
|
164
141
|
...staticSystemMessages,
|
|
165
|
-
...
|
|
142
|
+
...serviceSystemMessages,
|
|
166
143
|
];
|
|
167
144
|
const compactPolicy = this.resolveCompactPolicy(retryAttempts);
|
|
168
145
|
let compacted = false;
|
|
169
146
|
try {
|
|
170
|
-
const compactResult = await
|
|
147
|
+
const compactResult = await compactContextMessageIfNeeded({
|
|
148
|
+
rootPath: activeContextStore.rootPath,
|
|
149
|
+
contextId: activeContextStore.contextId,
|
|
150
|
+
withWriteLock: (fn) => activeContextStore.withWriteLock(fn),
|
|
151
|
+
loadAll: () => activeContextStore.loadAll(),
|
|
152
|
+
createSummaryMessage: ({ text, sourceRange }) => activeContextStore.createAssistantTextMessage({
|
|
153
|
+
text,
|
|
154
|
+
metadata: {
|
|
155
|
+
contextId: activeContextStore.contextId,
|
|
156
|
+
},
|
|
157
|
+
kind: "summary",
|
|
158
|
+
source: "compact",
|
|
159
|
+
...(sourceRange ? { sourceRange } : {}),
|
|
160
|
+
}),
|
|
161
|
+
getArchiveDirPath: () => activeContextStore.getArchiveDirPath(),
|
|
162
|
+
getMessagesFilePath: () => activeContextStore.getMessagesFilePath(),
|
|
163
|
+
readMetaUnsafe: () => activeContextStore.readMetaUnsafe(),
|
|
164
|
+
writeMetaUnsafe: (next) => activeContextStore.writeMetaUnsafe(next),
|
|
165
|
+
}, {
|
|
171
166
|
model: this.model,
|
|
172
167
|
system: currentBaseSystemMessages,
|
|
173
168
|
keepLastMessages: compactPolicy.keepLastMessages,
|
|
@@ -180,32 +175,22 @@ export class ContextAgent {
|
|
|
180
175
|
// ignore compact failure; fallback to un-compacted context messages
|
|
181
176
|
}
|
|
182
177
|
if (compacted) {
|
|
183
|
-
// 关键点(中文):compact
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
requestId,
|
|
188
|
-
allToolNames: Object.keys(this.tools),
|
|
189
|
-
});
|
|
178
|
+
// 关键点(中文):compact 后重新收集 service system,保证提示词与最新状态一致。
|
|
179
|
+
serviceSystemMessages = transformPromptsIntoSystemMessages(await this.deps.getServiceSystemPrompts({
|
|
180
|
+
disabledServiceNames: this.system.disableServiceSystems,
|
|
181
|
+
}));
|
|
190
182
|
currentBaseSystemMessages = [
|
|
191
183
|
...runtimeSystemMessages,
|
|
192
184
|
...staticSystemMessages,
|
|
193
|
-
...
|
|
185
|
+
...serviceSystemMessages,
|
|
194
186
|
];
|
|
195
187
|
}
|
|
196
|
-
let baseModelMessages = await
|
|
188
|
+
let baseModelMessages = await activeContextStore.toModelMessages({
|
|
197
189
|
tools: this.tools,
|
|
198
190
|
});
|
|
199
191
|
if (!Array.isArray(baseModelMessages) || baseModelMessages.length === 0) {
|
|
200
192
|
baseModelMessages = [{ role: "user", content: userText }];
|
|
201
193
|
}
|
|
202
|
-
await logger.log("debug", "Context selected", {
|
|
203
|
-
contextId,
|
|
204
|
-
historySource: "messages_jsonl",
|
|
205
|
-
modelMessages: baseModelMessages.length,
|
|
206
|
-
keepLastMessages: compactPolicy.keepLastMessages,
|
|
207
|
-
maxInputTokensApprox: compactPolicy.maxInputTokensApprox,
|
|
208
|
-
});
|
|
209
194
|
// 关键点(中文)
|
|
210
195
|
// - 在 step 边界尝试合并同 lane 的新增用户消息,保证当前 run 可见最新输入。
|
|
211
196
|
// - 保留 tool-loop 的 in-flight 后缀消息(工具调用链)。
|
|
@@ -235,51 +220,46 @@ export class ContextAgent {
|
|
|
235
220
|
return toAppend.length;
|
|
236
221
|
};
|
|
237
222
|
// phase 2(中文):进入 tool-loop。
|
|
238
|
-
const
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
lastAppliedBasePrefixLen = baseModelMessages.length;
|
|
257
|
-
void logger.log("debug", "Lane merged messages detected; appended queued user messages for next step", { contextId, requestId, added });
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
catch {
|
|
261
|
-
// ignore merge hook failures
|
|
223
|
+
const runStreamText = () => streamText({
|
|
224
|
+
model: this.model,
|
|
225
|
+
system: currentBaseSystemMessages,
|
|
226
|
+
prepareStep: async ({ messages }) => {
|
|
227
|
+
const incomingMessages = Array.isArray(messages)
|
|
228
|
+
? messages
|
|
229
|
+
: [];
|
|
230
|
+
const suffix = incomingMessages.length >= lastAppliedBasePrefixLen
|
|
231
|
+
? incomingMessages.slice(lastAppliedBasePrefixLen)
|
|
232
|
+
: [];
|
|
233
|
+
let outMessages;
|
|
234
|
+
if (typeof onStepCallback === "function") {
|
|
235
|
+
try {
|
|
236
|
+
const mergedMessages = await onStepCallback();
|
|
237
|
+
const added = appendMergedUserMessages(Array.isArray(mergedMessages) ? mergedMessages : []);
|
|
238
|
+
if (added > 0) {
|
|
239
|
+
outMessages = [...baseModelMessages, ...suffix];
|
|
240
|
+
lastAppliedBasePrefixLen = baseModelMessages.length;
|
|
262
241
|
}
|
|
263
242
|
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
};
|
|
267
|
-
if (Array.isArray(currentProviderResult.activeTools) &&
|
|
268
|
-
currentProviderResult.activeTools.length > 0) {
|
|
269
|
-
stepOverrides.activeTools = currentProviderResult.activeTools;
|
|
243
|
+
catch {
|
|
244
|
+
// ignore merge hook failures
|
|
270
245
|
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
246
|
+
}
|
|
247
|
+
const stepOverrides = {
|
|
248
|
+
system: currentBaseSystemMessages,
|
|
249
|
+
};
|
|
250
|
+
return {
|
|
251
|
+
...stepOverrides,
|
|
252
|
+
...(Array.isArray(outMessages) ? { messages: outMessages } : {}),
|
|
253
|
+
};
|
|
254
|
+
},
|
|
255
|
+
messages: baseModelMessages,
|
|
256
|
+
tools: this.tools,
|
|
257
|
+
providerOptions: this.buildOpenAIResponsesProviderOptions(),
|
|
258
|
+
stopWhen: [stepCountIs(30)],
|
|
282
259
|
});
|
|
260
|
+
const result = this.deps.withRequestContext
|
|
261
|
+
? await this.deps.withRequestContext({ contextId, requestId }, runStreamText)
|
|
262
|
+
: runStreamText();
|
|
283
263
|
// phase 3(中文):把 stream 结果固化为最终 assistant UIMessage。
|
|
284
264
|
// 关键点(中文):用 ai-sdk v6 的 UIMessage 流来生成最终 assistant UIMessage(包含 tool parts),避免手工拼装。
|
|
285
265
|
let finalAssistantUiMessage = null;
|
|
@@ -383,6 +363,17 @@ export class ContextAgent {
|
|
|
383
363
|
};
|
|
384
364
|
}
|
|
385
365
|
}
|
|
366
|
+
/**
|
|
367
|
+
* 构建 OpenAI Responses providerOptions。
|
|
368
|
+
*/
|
|
369
|
+
buildOpenAIResponsesProviderOptions() {
|
|
370
|
+
return {
|
|
371
|
+
openai: {
|
|
372
|
+
// 关键点(中文):Responses 走无状态模式,历史仅由本地 UIMessage 管理。
|
|
373
|
+
store: false,
|
|
374
|
+
},
|
|
375
|
+
};
|
|
376
|
+
}
|
|
386
377
|
/**
|
|
387
378
|
* 构建运行时 system message。
|
|
388
379
|
*
|
|
@@ -397,10 +388,26 @@ export class ContextAgent {
|
|
|
397
388
|
projectRoot: input.projectRoot,
|
|
398
389
|
contextId: input.contextId,
|
|
399
390
|
requestId: input.requestId,
|
|
391
|
+
mode: this.system.mode,
|
|
400
392
|
}),
|
|
401
393
|
},
|
|
402
394
|
];
|
|
403
395
|
}
|
|
396
|
+
/**
|
|
397
|
+
* 解析静态 system prompts。
|
|
398
|
+
*
|
|
399
|
+
* 关键点(中文)
|
|
400
|
+
* - task 执行上下文替换默认 core prompt(`DEFAULT_SHIP_PROMPTS`)为 task 专用提示词。
|
|
401
|
+
* - Agent.md 等其他静态系统提示保持不变。
|
|
402
|
+
*/
|
|
403
|
+
resolveStaticSystemPrompts(input) {
|
|
404
|
+
const base = Array.isArray(input.systems) ? [...input.systems] : [];
|
|
405
|
+
const replacement = String(this.system.replaceDefaultCorePrompt || "").trim();
|
|
406
|
+
if (!replacement)
|
|
407
|
+
return base;
|
|
408
|
+
const filtered = base.filter((item) => item !== DEFAULT_SHIP_PROMPTS);
|
|
409
|
+
return [...filtered, replacement];
|
|
410
|
+
}
|
|
404
411
|
/**
|
|
405
412
|
* 构造 fallback assistant 消息。
|
|
406
413
|
*
|
|
@@ -446,14 +453,13 @@ export class ContextAgent {
|
|
|
446
453
|
* - 目标是在不直接失败的前提下,尽量保留可用上下文。
|
|
447
454
|
*/
|
|
448
455
|
resolveCompactPolicy(retryAttempts) {
|
|
449
|
-
const
|
|
450
|
-
const contextMessagesConfig = runtime.config.context?.messages;
|
|
456
|
+
const contextMessagesConfig = this.deps.compact;
|
|
451
457
|
const baseKeepLastMessages = typeof contextMessagesConfig?.keepLastMessages === "number"
|
|
452
458
|
? Math.max(6, Math.min(5000, Math.floor(contextMessagesConfig.keepLastMessages)))
|
|
453
459
|
: 30;
|
|
454
460
|
const baseMaxInputTokensApprox = typeof contextMessagesConfig?.maxInputTokensApprox === "number"
|
|
455
461
|
? Math.max(2000, Math.min(200_000, Math.floor(contextMessagesConfig.maxInputTokensApprox)))
|
|
456
|
-
:
|
|
462
|
+
: 128000;
|
|
457
463
|
// 关键点(中文):当 provider 报错超窗时,会进入 retry;此时需要更激进的 compact。
|
|
458
464
|
const retryFactor = Math.max(1, Math.pow(2, retryAttempts));
|
|
459
465
|
const keepLastMessages = Math.max(6, Math.floor(baseKeepLastMessages / retryFactor));
|
|
@@ -468,10 +474,19 @@ export class ContextAgent {
|
|
|
468
474
|
};
|
|
469
475
|
}
|
|
470
476
|
/**
|
|
471
|
-
*
|
|
477
|
+
* 设置当前 Agent 的 system 配置。
|
|
478
|
+
*
|
|
479
|
+
* 关键点(中文)
|
|
480
|
+
* - 由上游调用方(如 task runner)按场景覆盖默认 chat system。
|
|
481
|
+
*/
|
|
482
|
+
setSystem(config) {
|
|
483
|
+
this.system = this.normalizeSystemConfig(config);
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* 重置为默认 chat system 配置。
|
|
472
487
|
*/
|
|
473
|
-
|
|
474
|
-
|
|
488
|
+
resetSystem() {
|
|
489
|
+
this.system = ContextAgent.createDefaultSystemConfig();
|
|
475
490
|
}
|
|
476
491
|
}
|
|
477
492
|
//# sourceMappingURL=ContextAgent.js.map
|