@zooique/memora 5.2.0 → 5.3.0
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/CHANGELOG.md +38 -0
- package/dist/agent/agent.d.ts +37 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +53 -0
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/assembler.d.ts.map +1 -1
- package/dist/agent/assembler.js +7 -0
- package/dist/agent/assembler.js.map +1 -1
- package/dist/agent/constants.d.ts +22 -0
- package/dist/agent/constants.d.ts.map +1 -1
- package/dist/agent/constants.js +22 -0
- package/dist/agent/constants.js.map +1 -1
- package/dist/agent/loop.d.ts +11 -4
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +37 -13
- package/dist/agent/loop.js.map +1 -1
- package/dist/agent/managers/toolCallHelpers.d.ts.map +1 -1
- package/dist/agent/managers/toolCallHelpers.js +3 -0
- package/dist/agent/managers/toolCallHelpers.js.map +1 -1
- package/dist/agent/messageHistory.d.ts +83 -16
- package/dist/agent/messageHistory.d.ts.map +1 -1
- package/dist/agent/messageHistory.js +189 -65
- package/dist/agent/messageHistory.js.map +1 -1
- package/dist/agent/seed/orchestrator.d.ts.map +1 -1
- package/dist/agent/seed/orchestrator.js +45 -14
- package/dist/agent/seed/orchestrator.js.map +1 -1
- package/dist/agent/types.d.ts +9 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -4
- package/dist/index.js.map +1 -1
- package/dist/memory/gcService.d.ts +8 -4
- package/dist/memory/gcService.d.ts.map +1 -1
- package/dist/memory/gcService.js.map +1 -1
- package/dist/memory/inMemoryRoundStore.d.ts +8 -3
- package/dist/memory/inMemoryRoundStore.d.ts.map +1 -1
- package/dist/memory/inMemoryRoundStore.js +19 -10
- package/dist/memory/inMemoryRoundStore.js.map +1 -1
- package/dist/memory/roundStore.d.ts +77 -11
- package/dist/memory/roundStore.d.ts.map +1 -1
- package/dist/memory/roundStore.js +18 -0
- package/dist/memory/roundStore.js.map +1 -1
- package/dist/utils/time.d.ts +24 -4
- package/dist/utils/time.d.ts.map +1 -1
- package/dist/utils/time.js +32 -4
- package/dist/utils/time.js.map +1 -1
- package/docs/memora-api-reference.md +1 -0
- package/package.json +3 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolCallHelpers.d.ts","sourceRoot":"","sources":["../../../src/agent/managers/toolCallHelpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAwB,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAClF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD,mDAAmD;AACnD,KAAK,WAAW,GAAG,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,CAAC;AAE9E;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,WAAW,GAAG,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"toolCallHelpers.d.ts","sourceRoot":"","sources":["../../../src/agent/managers/toolCallHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -27,8 +27,11 @@ export function parseAskCalls(askCalls) {
|
|
|
27
27
|
catch {
|
|
28
28
|
// 参数非法:降级为空问题(宿主渲染兜底,不阻断)
|
|
29
29
|
}
|
|
30
|
+
// ADR-043:题身份在此**单点填入**(工具调用 id 即题身份),下游一律透传不自造。
|
|
31
|
+
// 批内第 i 题 ↔ askCalls[i].id,与 AgentLoop.pendingAsk.toolCallIds 同序同源。
|
|
30
32
|
return {
|
|
31
33
|
slot: 'ask',
|
|
34
|
+
askCallId: tc.id,
|
|
32
35
|
question,
|
|
33
36
|
...(options && options.length > 0 ? { options } : {}),
|
|
34
37
|
...(allowCustom !== undefined ? { allowCustom } : {}),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"toolCallHelpers.js","sourceRoot":"","sources":["../../../src/agent/managers/toolCallHelpers.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"toolCallHelpers.js","sourceRoot":"","sources":["../../../src/agent/managers/toolCallHelpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -17,6 +17,19 @@ export interface ForkResult {
|
|
|
17
17
|
/** 新会话的 Round ID 列表(已复制的指针) */
|
|
18
18
|
roundIds: string[];
|
|
19
19
|
}
|
|
20
|
+
/** 交互输入落档草稿(appendUser opts.group 元素):逐题展开的最小描述,id/timestamp/role 由 buildInteractiveInputs 统一装配 */
|
|
21
|
+
interface InteractiveInputDraft {
|
|
22
|
+
content: string;
|
|
23
|
+
kind: InteractiveInputKind;
|
|
24
|
+
/**
|
|
25
|
+
* 题身份(ADR-043 单源):来自内核 `AskQuestion.askCallId`(发起提问的工具调用 id)。
|
|
26
|
+
* 有则**直接作为落盘 id**(运行时行与盘面行同一身份,去重可靠配对);
|
|
27
|
+
* 无(supplement / 历史数据 / 未带身份的收场转化)则回退轮内序号公式。
|
|
28
|
+
*/
|
|
29
|
+
id?: string;
|
|
30
|
+
question?: string;
|
|
31
|
+
options?: string[];
|
|
32
|
+
}
|
|
20
33
|
/** 消息历史类 */
|
|
21
34
|
export declare class MessageHistory {
|
|
22
35
|
/** 会话存储(可选);注入则持久化,否则仅在内存保存(AgentLoop.messages[]) */
|
|
@@ -80,26 +93,59 @@ export declare class MessageHistory {
|
|
|
80
93
|
/**
|
|
81
94
|
* 追加 user 消息到当前会话(持久化失败不抛出,不阻塞对话)。
|
|
82
95
|
*
|
|
83
|
-
* Round-based 路径:roundStore 注入且 roundId 存在时,创建 pending Round
|
|
84
|
-
*
|
|
85
|
-
*
|
|
96
|
+
* Round-based 路径:roundStore 注入且 roundId 存在时,创建 pending Round 并**立即**归属当前会话
|
|
97
|
+
* (refCount 1 + appendRoundId,ADR-044「建轮即入会话」)。存在性由**创建**决定、不由**收场**决定——
|
|
98
|
+
* 未收场的轮同样可见、可删、可续跑;崩溃残留的 pending 轮不再是「GC 可清孤儿」,而是用户可见的
|
|
99
|
+
* 未完成轮(GC 只回收「连归属都没写成功」的残留,判据仍是 `refCount === 0`)。
|
|
86
100
|
*
|
|
87
101
|
* 交互输入:opts.interactive 为真且 roundId 对应轮已存在(prepare 建 pending 或
|
|
88
102
|
* 暂停已完成轮)时,不再创建/覆盖新轮——按序追加到该轮 interactiveInputs,保问答闭环不分裂。
|
|
89
103
|
*
|
|
90
104
|
* @param content 用户输入内容
|
|
91
105
|
* @param roundId 闭环节点轮次 ID(可选,交互输入必须携带 = appendUser 的 head roundId)
|
|
92
|
-
* @param opts 交互输入选项(interactive=是否交互归属;kind
|
|
93
|
-
*
|
|
106
|
+
* @param opts 交互输入选项(interactive=是否交互归属;kind/question/options=单条形态的
|
|
107
|
+
* 折叠块类型与所对 ask_user 提问原文/候选选项;group=整组形态,ASK-MULTI-Q-1:
|
|
108
|
+
* 作答/超时多题批次逐题落档,与崩溃收场转化同宽——提供时按序展开为 N 条,
|
|
109
|
+
* 单条形态等价于 1 元素组,同时提供以 group 为准)
|
|
94
110
|
*/
|
|
95
111
|
appendUser(content: string, roundId?: string, opts?: {
|
|
96
112
|
interactive?: boolean;
|
|
97
113
|
kind?: InteractiveInputKind;
|
|
98
114
|
question?: string;
|
|
99
115
|
options?: string[];
|
|
116
|
+
/** 整组交互输入(多题批次逐题落档);元素结构见 InteractiveInputDraft */
|
|
117
|
+
group?: ReadonlyArray<InteractiveInputDraft>;
|
|
100
118
|
/** 图片附件(可选,多模态输入);须显式透传到 `userMessage` 白名单与 SessionMessage,否则重启 / 切会话后图静默消失(方案 §7 P0-12) */
|
|
101
119
|
attachments?: readonly ImageRef[];
|
|
102
120
|
}): Promise<void>;
|
|
121
|
+
/**
|
|
122
|
+
* 把轮登记进当前会话的 `roundIds`(**ADR-044 归属登记单点**)。
|
|
123
|
+
*
|
|
124
|
+
* 语义:**建轮即登记**,收场不再登记。失败只记日志、不抛出——不阻塞对话。
|
|
125
|
+
*
|
|
126
|
+
* ⚠️ 失败的后果(ADR-044 第四刀写清,勿再按旧口径理解「退回登记前行为」):
|
|
127
|
+
* 轮已按 `refCount: 1` 落盘、但会话 `roundIds` 里没有它 ⇒ **不可见且不会被 GC 回收**
|
|
128
|
+
* (孤儿判据是 `refCount === 0`,它不满足)——即「静默保留、用户看不见也删不掉」。
|
|
129
|
+
* 这是**有意的取舍**:宁可留一个看不见的文件,也不静默删掉用户刚输入的内容;
|
|
130
|
+
* 触发条件 = 会话存储写入抛错(已 warn 日志可查)。
|
|
131
|
+
*
|
|
132
|
+
* 调用面只有三处,判据各不相同(勿扩张):
|
|
133
|
+
* - `appendUser` 建轮后(新轮必登记);
|
|
134
|
+
* - `appendAssistant` 兜底分支(轮原本不存在,新建即归属);
|
|
135
|
+
* - `attachUnownedRound`(存量 `refCount 0` 轮补登记,见其注释)。
|
|
136
|
+
*/
|
|
137
|
+
private registerRoundInSession;
|
|
138
|
+
/**
|
|
139
|
+
* 归属兜底(ADR-044 兼容面):`refCount === 0` 的轮 = **ADR-044 之前**落盘的存量
|
|
140
|
+
* (当时建轮写 0、收场才 +1),收场时补到 1 并登记进会话。
|
|
141
|
+
*
|
|
142
|
+
* 为什么不能直接删掉收场侧登记:存量半截轮(pending + refCount 0)在升级后仍必须可见,
|
|
143
|
+
* 删掉登记会让它们**永久不可见**——比「被 GC 回收」更糟(用户连删都删不到)。
|
|
144
|
+
* 新数据建轮即 refCount 1,本方法是 no-op。
|
|
145
|
+
*
|
|
146
|
+
* @returns 需要落盘的 Round(refCount 可能被补到 1);调用方负责 save。
|
|
147
|
+
*/
|
|
148
|
+
private attachUnownedRound;
|
|
103
149
|
/**
|
|
104
150
|
* 追加裁决证据到在途 Round(悬案取证轨;持久化失败不抛出,不阻塞对话)。
|
|
105
151
|
*
|
|
@@ -112,13 +158,32 @@ export declare class MessageHistory {
|
|
|
112
158
|
* @param ev 裁决证据事件(空响应 / 台账替身回显个案证据)
|
|
113
159
|
*/
|
|
114
160
|
appendEvidence(roundId: string, ev: RoundEvidenceEvent): Promise<void>;
|
|
161
|
+
/**
|
|
162
|
+
* 登记在途提问到当前轮(E2E-ASK-LOSS-1 写点;持久化失败不抛出)。
|
|
163
|
+
*
|
|
164
|
+
* 调用时机 = 提问挂起(yield paused)**之前**(装配层经 loop.onPendingQuestion 接线),
|
|
165
|
+
* 保证「AI 已提问」这一事实先于挂起落盘——挂起后崩溃,问题文本仍可从盘上恢复,
|
|
166
|
+
* 不再只活在进程内存(loop.pendingAsk)。
|
|
167
|
+
*
|
|
168
|
+
* 形状收窄:入参直取内核 `AskQuestion`,落盘只留 `question/options` 两个重放必需面
|
|
169
|
+
* (见 `RoundPendingAsk`——slot/allowCustom 是交互期参数,历史重放不消费)。
|
|
170
|
+
* 轮缺失(异常兜底):warn 后丢弃——挂起轮由 appendUser 建出,缺失即更上游已异常,
|
|
171
|
+
* 此处不伪造第二轨道补写(与 appendEvidence 同款降级语义)。
|
|
172
|
+
*
|
|
173
|
+
* @param roundId 闭环节点轮次 ID(loop.getCurrentRoundId(),与 appendUser 同源同值)
|
|
174
|
+
* @param questions 本批挂起提问(ask_user 解析产物,可多题)
|
|
175
|
+
*/
|
|
176
|
+
markPendingAsk(roundId: string, questions: readonly {
|
|
177
|
+
question: string;
|
|
178
|
+
options?: string[];
|
|
179
|
+
}[]): Promise<void>;
|
|
115
180
|
/**
|
|
116
181
|
* 追加 assistant 消息到当前会话(持久化失败不抛出)。
|
|
117
182
|
*
|
|
118
|
-
* Round-based 路径:完成 pending Round
|
|
119
|
-
* incrementRef
|
|
120
|
-
* RoundStore 取回补全;Round 不存在(异常兜底)时创建独立
|
|
121
|
-
*
|
|
183
|
+
* Round-based 路径:完成 pending Round 时**只改状态**——归属已在建轮时登记(ADR-044),
|
|
184
|
+
* 此处不再 incrementRef / appendRoundId;`refCount === 0` 的存量轮由 attachUnownedRound 补登记。
|
|
185
|
+
* pending 缓存丢失(跨重启)时从 RoundStore 取回补全;Round 不存在(异常兜底)时创建独立
|
|
186
|
+
* complete Round 并登记,保证用户消息不丢失。
|
|
122
187
|
*
|
|
123
188
|
* 闭环节点续写:同一 roundId 已存在 assistantMessage(跨暂停-续跑:
|
|
124
189
|
* 暂停轮已把 ask_user 提问/中断半截落为 assistantMessage)时,旧段入 assistantLog,
|
|
@@ -129,10 +194,12 @@ export declare class MessageHistory {
|
|
|
129
194
|
/**
|
|
130
195
|
* 中断轮收场:把「未正常完成」的轮升级为正常 stop turn 并入会话。
|
|
131
196
|
*
|
|
132
|
-
* 语义定案(step-atomic-persistence.md
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
*
|
|
197
|
+
* 语义定案(step-atomic-persistence.md §一·五):崩溃残留轮 = 等同于用户点「停止」的正常 turn
|
|
198
|
+
* ——可删、入会话 roundIds、作后续上下文,**不是**半成品草稿/孤儿。
|
|
199
|
+
* ⚠️ ADR-044 起:新建轮**建轮即入会话**,故本方法的「入会话」动作只对**存量无归属轮**
|
|
200
|
+
* (`refCount === 0`,ADR-044 之前落盘或建轮时登记失败)生效,见 attachUnownedRound。
|
|
201
|
+
* 宿主经 `IRoundStore.listInterruptedRecent` 打捞后再调本方法完成收场,恢复为普通 turn
|
|
202
|
+
* 渲染无需特殊草稿卡。
|
|
136
203
|
*
|
|
137
204
|
* **两个调用时机**:
|
|
138
205
|
* 1. 崩溃/断电后重启——宿主 `chatPanel.upgradeInterruptedRounds` 打捞后调用;
|
|
@@ -141,9 +208,8 @@ export declare class MessageHistory {
|
|
|
141
208
|
* 留下 pending 孤儿轮、须等下次重启才打捞(LLM 4xx 中断的长任务轮即此类)。
|
|
142
209
|
* 依据 = `memory/roundStore.ts` RoundStatus 文档「运行时失败不翻状态机,一律按中断处理」。
|
|
143
210
|
*
|
|
144
|
-
* 收场约定与 appendAssistant 同一真理源(
|
|
145
|
-
*
|
|
146
|
-
* 存储格式不变;
|
|
211
|
+
* 收场约定与 appendAssistant 同一真理源(status interrupted + completedAt + 存量无归属轮补登记
|
|
212
|
+
* 同走 attachUnownedRound;「已收场即跳过」仍用 `isRoundSettled`),Round schema / 存储格式不变;
|
|
147
213
|
* **有意不直接复用 appendAssistant**,两处差异:
|
|
148
214
|
* - appendAssistant 顶层跳过空内容 → 无文本中断轮无法收场;本方法允许多段「即使无
|
|
149
215
|
* assistantMessage 总结也按 stop 语义收场」(§一·五验收口径)。
|
|
@@ -186,4 +252,5 @@ export declare class MessageHistory {
|
|
|
186
252
|
*/
|
|
187
253
|
awaitPendingArchives(timeoutMs?: number): Promise<boolean>;
|
|
188
254
|
}
|
|
255
|
+
export {};
|
|
189
256
|
//# sourceMappingURL=messageHistory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messageHistory.d.ts","sourceRoot":"","sources":["../../src/agent/messageHistory.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,cAAc,EAAe,MAAM,0BAA0B,CAAC;AAC3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,OAAO,KAAK,EACV,oBAAoB,EACpB,WAAW,EAEX,kBAAkB,
|
|
1
|
+
{"version":3,"file":"messageHistory.d.ts","sourceRoot":"","sources":["../../src/agent/messageHistory.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,25 @@ import { logger } from '../logging/logger.js';
|
|
|
4
4
|
import { configError } from '../utils/errors.js';
|
|
5
5
|
import { safeSetTimeout } from '../utils/safeTimer.js';
|
|
6
6
|
import { nowIso, todayDate } from '../utils/time.js';
|
|
7
|
+
/**
|
|
8
|
+
* 整组交互输入 → 逐题 RoundInteractiveInput(ASK-MULTI-Q-1 单点装配):
|
|
9
|
+
* id 公式 / role / timestamp / question-options 摊开条件**只在此一处**。
|
|
10
|
+
* appendUser 交互分支(作答/超时整组)与 appendInterrupted 收场转化(unanswered 整组)
|
|
11
|
+
* 共用同一装配,两条消费路径从源头同宽。
|
|
12
|
+
*/
|
|
13
|
+
function buildInteractiveInputs(roundId, existingCount, drafts, timestamp) {
|
|
14
|
+
return drafts.map((d, i) => ({
|
|
15
|
+
// ADR-043:题身份优先(内核 toolCallId,跨重启恒定 ⇒ 运行时与重放可配对);
|
|
16
|
+
// 缺省回退轮内序号(supplement 等无题身份来源的路径,行为与历史一致)。
|
|
17
|
+
id: d.id ?? `msg-${roundId}-input-${existingCount + i + 1}`,
|
|
18
|
+
role: 'user',
|
|
19
|
+
content: d.content,
|
|
20
|
+
timestamp,
|
|
21
|
+
kind: d.kind,
|
|
22
|
+
...(d.question ? { question: d.question } : {}),
|
|
23
|
+
...(d.options && d.options.length > 0 ? { options: d.options } : {}),
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
7
26
|
/** 消息历史类 */
|
|
8
27
|
export class MessageHistory {
|
|
9
28
|
sessionStore;
|
|
@@ -173,17 +192,20 @@ export class MessageHistory {
|
|
|
173
192
|
/**
|
|
174
193
|
* 追加 user 消息到当前会话(持久化失败不抛出,不阻塞对话)。
|
|
175
194
|
*
|
|
176
|
-
* Round-based 路径:roundStore 注入且 roundId 存在时,创建 pending Round
|
|
177
|
-
*
|
|
178
|
-
*
|
|
195
|
+
* Round-based 路径:roundStore 注入且 roundId 存在时,创建 pending Round 并**立即**归属当前会话
|
|
196
|
+
* (refCount 1 + appendRoundId,ADR-044「建轮即入会话」)。存在性由**创建**决定、不由**收场**决定——
|
|
197
|
+
* 未收场的轮同样可见、可删、可续跑;崩溃残留的 pending 轮不再是「GC 可清孤儿」,而是用户可见的
|
|
198
|
+
* 未完成轮(GC 只回收「连归属都没写成功」的残留,判据仍是 `refCount === 0`)。
|
|
179
199
|
*
|
|
180
200
|
* 交互输入:opts.interactive 为真且 roundId 对应轮已存在(prepare 建 pending 或
|
|
181
201
|
* 暂停已完成轮)时,不再创建/覆盖新轮——按序追加到该轮 interactiveInputs,保问答闭环不分裂。
|
|
182
202
|
*
|
|
183
203
|
* @param content 用户输入内容
|
|
184
204
|
* @param roundId 闭环节点轮次 ID(可选,交互输入必须携带 = appendUser 的 head roundId)
|
|
185
|
-
* @param opts 交互输入选项(interactive=是否交互归属;kind
|
|
186
|
-
*
|
|
205
|
+
* @param opts 交互输入选项(interactive=是否交互归属;kind/question/options=单条形态的
|
|
206
|
+
* 折叠块类型与所对 ask_user 提问原文/候选选项;group=整组形态,ASK-MULTI-Q-1:
|
|
207
|
+
* 作答/超时多题批次逐题落档,与崩溃收场转化同宽——提供时按序展开为 N 条,
|
|
208
|
+
* 单条形态等价于 1 元素组,同时提供以 group 为准)
|
|
187
209
|
*/
|
|
188
210
|
async appendUser(content, roundId, opts) {
|
|
189
211
|
const message = {
|
|
@@ -201,28 +223,42 @@ export class MessageHistory {
|
|
|
201
223
|
if (opts?.interactive) {
|
|
202
224
|
const existing = this.roundStore.getById(roundId) ?? this.pendingRounds.get(roundId);
|
|
203
225
|
if (existing) {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
226
|
+
// 单条形态 = 退化 1 元素组:一条装配路径承载两种入参(无分叉实现)
|
|
227
|
+
const drafts = opts.group ?? [
|
|
228
|
+
{
|
|
229
|
+
content,
|
|
230
|
+
kind: opts.kind ?? 'supplement',
|
|
231
|
+
...(opts.question ? { question: opts.question } : {}),
|
|
232
|
+
...(opts.options && opts.options.length > 0 ? { options: opts.options } : {}),
|
|
233
|
+
},
|
|
234
|
+
];
|
|
235
|
+
const inputs = buildInteractiveInputs(roundId, existing.interactiveInputs?.length ?? 0, drafts, message.timestamp);
|
|
236
|
+
// 作答/超时记录落盘的**同一次 save 内**原子清 pendingAsk(生命周期不变量的清除点,
|
|
237
|
+
// 见 RoundPendingAsk 注释):提问已被消费(回答回填或超时收场),残留即脏数据——
|
|
238
|
+
// 若留到收场才清,「已答 + 未答」双记录窗口会打开(appendInterrupted 会把残留
|
|
239
|
+
// pendingAsk 再转化成重复的 unanswered 条目)。supplement 与提问无关,不动该字段。
|
|
240
|
+
// 判据含 unanswered(ASK-MULTI-Q-1):批次内全跳过(逐题均 unanswered)同样代表
|
|
241
|
+
// 快照已被 takeAnsweredAsk 消费——不清则收场转化二次记账。
|
|
242
|
+
// ⚠️ 勿在此点之前另加「提前清盘」层:答案此刻**尚未落盘**(`AgentLoop.appendToolMessage`
|
|
243
|
+
// 只 push 进程内 `loop.messages`,`Round` 结构不承载 tool 消息),二者之间不存在
|
|
244
|
+
// 「答案已持久而 pendingAsk 未清」的中间态 ⇒ 提前清的唯一净效应是把崩溃后一条
|
|
245
|
+
// 诚实的 unanswered 记录换成「该题在盘面彻底消失」(2026-10-31 实测,据此回滚)。
|
|
246
|
+
const askConsumed = drafts.some((d) => d.kind === 'question-answer' || d.kind === 'timeout' || d.kind === 'unanswered');
|
|
214
247
|
const updated = {
|
|
215
248
|
...existing,
|
|
216
|
-
interactiveInputs: [...(existing.interactiveInputs ?? []),
|
|
249
|
+
interactiveInputs: [...(existing.interactiveInputs ?? []), ...inputs],
|
|
250
|
+
...(askConsumed ? { pendingAsk: undefined } : {}),
|
|
217
251
|
};
|
|
218
252
|
this.roundStore.save(updated);
|
|
219
253
|
this.pendingRounds.set(roundId, updated);
|
|
220
|
-
logger.debug({ roundId,
|
|
254
|
+
logger.debug({ roundId, count: inputs.length, firstKind: inputs[0]?.kind }, 'appendUser: 交互输入归属问答闭环');
|
|
221
255
|
return;
|
|
222
256
|
}
|
|
223
257
|
// 轮不存在(异常兜底):降级为普通 pending Round(内容不丢失,GC 兜底)
|
|
224
258
|
logger.warn({ roundId }, 'appendUser: 交互输入对应轮缺失,降级为新建 pending Round');
|
|
225
259
|
}
|
|
260
|
+
// 重复 appendUser 到同一 roundId(异常路径)不重复登记,防 roundIds 堆叠
|
|
261
|
+
const preexisting = this.roundStore.getById(roundId) ?? this.pendingRounds.get(roundId);
|
|
226
262
|
const pendingRound = {
|
|
227
263
|
id: roundId,
|
|
228
264
|
userMessage: {
|
|
@@ -234,12 +270,17 @@ export class MessageHistory {
|
|
|
234
270
|
},
|
|
235
271
|
status: 'pending',
|
|
236
272
|
createdAt: message.timestamp,
|
|
237
|
-
//
|
|
238
|
-
refCount
|
|
273
|
+
// 🔴 ADR-044 建轮即入会话:存在性由「创建」决定,不由「收场」决定。
|
|
274
|
+
// 创建它的会话立即持有引用(refCount 1)⇒ 会话视图立即可见、可删、可续跑。
|
|
275
|
+
// `save()` 会用 round.refCount 重建索引条目(workspaceRoundStore.save),故此处**不再**调
|
|
276
|
+
// incrementRef——那既二次落盘,又让「建轮」与「收场」两处并改写同一个计数(两个真相源)。
|
|
277
|
+
refCount: 1,
|
|
239
278
|
};
|
|
240
279
|
this.roundStore.save(pendingRound);
|
|
241
280
|
this.pendingRounds.set(roundId, pendingRound);
|
|
242
|
-
|
|
281
|
+
if (!preexisting)
|
|
282
|
+
this.registerRoundInSession(roundId);
|
|
283
|
+
logger.debug({ roundId }, 'appendUser: pending Round created(已归属当前会话)');
|
|
243
284
|
}
|
|
244
285
|
catch (err) {
|
|
245
286
|
logger.warn({ err, roundId }, 'appendUser: Round-based 写入失败');
|
|
@@ -247,6 +288,48 @@ export class MessageHistory {
|
|
|
247
288
|
}
|
|
248
289
|
logger.debug({ role: message.role, session: this.currentSessionName }, 'appendUser');
|
|
249
290
|
}
|
|
291
|
+
/**
|
|
292
|
+
* 把轮登记进当前会话的 `roundIds`(**ADR-044 归属登记单点**)。
|
|
293
|
+
*
|
|
294
|
+
* 语义:**建轮即登记**,收场不再登记。失败只记日志、不抛出——不阻塞对话。
|
|
295
|
+
*
|
|
296
|
+
* ⚠️ 失败的后果(ADR-044 第四刀写清,勿再按旧口径理解「退回登记前行为」):
|
|
297
|
+
* 轮已按 `refCount: 1` 落盘、但会话 `roundIds` 里没有它 ⇒ **不可见且不会被 GC 回收**
|
|
298
|
+
* (孤儿判据是 `refCount === 0`,它不满足)——即「静默保留、用户看不见也删不掉」。
|
|
299
|
+
* 这是**有意的取舍**:宁可留一个看不见的文件,也不静默删掉用户刚输入的内容;
|
|
300
|
+
* 触发条件 = 会话存储写入抛错(已 warn 日志可查)。
|
|
301
|
+
*
|
|
302
|
+
* 调用面只有三处,判据各不相同(勿扩张):
|
|
303
|
+
* - `appendUser` 建轮后(新轮必登记);
|
|
304
|
+
* - `appendAssistant` 兜底分支(轮原本不存在,新建即归属);
|
|
305
|
+
* - `attachUnownedRound`(存量 `refCount 0` 轮补登记,见其注释)。
|
|
306
|
+
*/
|
|
307
|
+
registerRoundInSession(roundId) {
|
|
308
|
+
const sessionId = this.currentSessionName;
|
|
309
|
+
try {
|
|
310
|
+
this.sessionStore?.appendRoundId(sessionId, roundId);
|
|
311
|
+
logger.debug({ roundId, sessionId }, 'appendRoundId: 轮已归属当前会话');
|
|
312
|
+
}
|
|
313
|
+
catch (err) {
|
|
314
|
+
logger.warn({ err, roundId, sessionId }, 'appendRoundId: 归属登记失败(轮不可见,不阻断)');
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* 归属兜底(ADR-044 兼容面):`refCount === 0` 的轮 = **ADR-044 之前**落盘的存量
|
|
319
|
+
* (当时建轮写 0、收场才 +1),收场时补到 1 并登记进会话。
|
|
320
|
+
*
|
|
321
|
+
* 为什么不能直接删掉收场侧登记:存量半截轮(pending + refCount 0)在升级后仍必须可见,
|
|
322
|
+
* 删掉登记会让它们**永久不可见**——比「被 GC 回收」更糟(用户连删都删不到)。
|
|
323
|
+
* 新数据建轮即 refCount 1,本方法是 no-op。
|
|
324
|
+
*
|
|
325
|
+
* @returns 需要落盘的 Round(refCount 可能被补到 1);调用方负责 save。
|
|
326
|
+
*/
|
|
327
|
+
attachUnownedRound(round) {
|
|
328
|
+
if (round.refCount > 0)
|
|
329
|
+
return round;
|
|
330
|
+
this.registerRoundInSession(round.id);
|
|
331
|
+
return { ...round, refCount: 1 };
|
|
332
|
+
}
|
|
250
333
|
/**
|
|
251
334
|
* 追加裁决证据到在途 Round(悬案取证轨;持久化失败不抛出,不阻塞对话)。
|
|
252
335
|
*
|
|
@@ -276,13 +359,50 @@ export class MessageHistory {
|
|
|
276
359
|
logger.warn({ err, roundId }, 'appendEvidence: 写入失败');
|
|
277
360
|
}
|
|
278
361
|
}
|
|
362
|
+
/**
|
|
363
|
+
* 登记在途提问到当前轮(E2E-ASK-LOSS-1 写点;持久化失败不抛出)。
|
|
364
|
+
*
|
|
365
|
+
* 调用时机 = 提问挂起(yield paused)**之前**(装配层经 loop.onPendingQuestion 接线),
|
|
366
|
+
* 保证「AI 已提问」这一事实先于挂起落盘——挂起后崩溃,问题文本仍可从盘上恢复,
|
|
367
|
+
* 不再只活在进程内存(loop.pendingAsk)。
|
|
368
|
+
*
|
|
369
|
+
* 形状收窄:入参直取内核 `AskQuestion`,落盘只留 `question/options` 两个重放必需面
|
|
370
|
+
* (见 `RoundPendingAsk`——slot/allowCustom 是交互期参数,历史重放不消费)。
|
|
371
|
+
* 轮缺失(异常兜底):warn 后丢弃——挂起轮由 appendUser 建出,缺失即更上游已异常,
|
|
372
|
+
* 此处不伪造第二轨道补写(与 appendEvidence 同款降级语义)。
|
|
373
|
+
*
|
|
374
|
+
* @param roundId 闭环节点轮次 ID(loop.getCurrentRoundId(),与 appendUser 同源同值)
|
|
375
|
+
* @param questions 本批挂起提问(ask_user 解析产物,可多题)
|
|
376
|
+
*/
|
|
377
|
+
async markPendingAsk(roundId, questions) {
|
|
378
|
+
if (!this.roundStore || !roundId || questions.length === 0)
|
|
379
|
+
return;
|
|
380
|
+
try {
|
|
381
|
+
const existing = this.roundStore.getById(roundId) ?? this.pendingRounds.get(roundId);
|
|
382
|
+
if (!existing) {
|
|
383
|
+
logger.warn({ roundId }, 'markPendingAsk: 对应轮缺失,在途提问不落盘');
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
const snapshot = questions.map((q) => ({
|
|
387
|
+
question: q.question,
|
|
388
|
+
...(q.options && q.options.length > 0 ? { options: [...q.options] } : {}),
|
|
389
|
+
}));
|
|
390
|
+
const updated = { ...existing, pendingAsk: snapshot };
|
|
391
|
+
this.roundStore.save(updated);
|
|
392
|
+
this.pendingRounds.set(roundId, updated);
|
|
393
|
+
logger.debug({ roundId, count: snapshot.length }, 'markPendingAsk: 在途提问已落盘');
|
|
394
|
+
}
|
|
395
|
+
catch (err) {
|
|
396
|
+
logger.warn({ err, roundId }, 'markPendingAsk: 写入失败');
|
|
397
|
+
}
|
|
398
|
+
}
|
|
279
399
|
/**
|
|
280
400
|
* 追加 assistant 消息到当前会话(持久化失败不抛出)。
|
|
281
401
|
*
|
|
282
|
-
* Round-based 路径:完成 pending Round
|
|
283
|
-
* incrementRef
|
|
284
|
-
* RoundStore 取回补全;Round 不存在(异常兜底)时创建独立
|
|
285
|
-
*
|
|
402
|
+
* Round-based 路径:完成 pending Round 时**只改状态**——归属已在建轮时登记(ADR-044),
|
|
403
|
+
* 此处不再 incrementRef / appendRoundId;`refCount === 0` 的存量轮由 attachUnownedRound 补登记。
|
|
404
|
+
* pending 缓存丢失(跨重启)时从 RoundStore 取回补全;Round 不存在(异常兜底)时创建独立
|
|
405
|
+
* complete Round 并登记,保证用户消息不丢失。
|
|
286
406
|
*
|
|
287
407
|
* 闭环节点续写:同一 roundId 已存在 assistantMessage(跨暂停-续跑:
|
|
288
408
|
* 暂停轮已把 ask_user 提问/中断半截落为 assistantMessage)时,旧段入 assistantLog,
|
|
@@ -326,6 +446,9 @@ export class MessageHistory {
|
|
|
326
446
|
assistantLog: assistantLog && assistantLog.length > 0 ? assistantLog : undefined,
|
|
327
447
|
status: 'complete',
|
|
328
448
|
completedAt: message.timestamp,
|
|
449
|
+
// 防御清残留(正常完成轮不该有在途提问):作答记录落盘时已原子清(appendUser
|
|
450
|
+
// 交互分支),此处清异常窗口残留;终态轮不携带 pendingAsk(RoundPendingAsk 生命周期不变量)
|
|
451
|
+
pendingAsk: undefined,
|
|
329
452
|
};
|
|
330
453
|
this.pendingRounds.delete(roundId);
|
|
331
454
|
}
|
|
@@ -333,25 +456,12 @@ export class MessageHistory {
|
|
|
333
456
|
logger.warn({ roundId }, 'appendAssistant: Round not found in RoundStore');
|
|
334
457
|
}
|
|
335
458
|
if (completed) {
|
|
336
|
-
|
|
337
|
-
//
|
|
338
|
-
//
|
|
339
|
-
//
|
|
340
|
-
//
|
|
341
|
-
|
|
342
|
-
if (!isReappend) {
|
|
343
|
-
this.roundStore.incrementRef(roundId);
|
|
344
|
-
const sessionId = this.currentSessionName;
|
|
345
|
-
try {
|
|
346
|
-
this.sessionStore?.appendRoundId(sessionId, roundId);
|
|
347
|
-
}
|
|
348
|
-
catch (err) {
|
|
349
|
-
logger.warn({ err, sessionId, roundId }, 'appendAssistant: appendRoundId 失败');
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
else {
|
|
353
|
-
logger.debug({ roundId, status: existing?.status }, 'appendAssistant: 闭环节点续写段但不重复登记会话引用');
|
|
354
|
-
}
|
|
459
|
+
// 🔴 ADR-044:归属已在**建轮**时登记(appendUser),收场只改状态——不再登记、不再加计数。
|
|
460
|
+
// 仅当轮是「存量无归属」(refCount 0,ADR-044 之前落盘)时由 attachUnownedRound 补登记;
|
|
461
|
+
// 直接删掉收场侧登记会让存量半截轮永久不可见,比「不可回收」更糟。
|
|
462
|
+
// 由此 `isRoundSettled` 不再承担「防重复登记」职责(收场已不登记),但保留给
|
|
463
|
+
// appendInterrupted 的「已收场即跳过」幂等判据——两处语义不同,勿合并。
|
|
464
|
+
this.roundStore.save(this.attachUnownedRound(completed));
|
|
355
465
|
logger.debug({ roundId }, 'appendAssistant: Round-based Round completed');
|
|
356
466
|
}
|
|
357
467
|
else {
|
|
@@ -376,12 +486,8 @@ export class MessageHistory {
|
|
|
376
486
|
refCount: 1,
|
|
377
487
|
};
|
|
378
488
|
this.roundStore.save(fallback);
|
|
379
|
-
try
|
|
380
|
-
|
|
381
|
-
}
|
|
382
|
-
catch (err) {
|
|
383
|
-
logger.warn({ err, roundId }, 'appendAssistant: 兜底 appendRoundId 失败');
|
|
384
|
-
}
|
|
489
|
+
// 兜底轮是「新建即归属」:走 ADR-044 单点(不再手写 try/catch 与 sessionStore 断言)。
|
|
490
|
+
this.registerRoundInSession(roundId);
|
|
385
491
|
}
|
|
386
492
|
}
|
|
387
493
|
logger.debug({ role: message.role, session: this.currentSessionName }, 'appendAssistant');
|
|
@@ -389,10 +495,12 @@ export class MessageHistory {
|
|
|
389
495
|
/**
|
|
390
496
|
* 中断轮收场:把「未正常完成」的轮升级为正常 stop turn 并入会话。
|
|
391
497
|
*
|
|
392
|
-
* 语义定案(step-atomic-persistence.md
|
|
393
|
-
*
|
|
394
|
-
*
|
|
395
|
-
*
|
|
498
|
+
* 语义定案(step-atomic-persistence.md §一·五):崩溃残留轮 = 等同于用户点「停止」的正常 turn
|
|
499
|
+
* ——可删、入会话 roundIds、作后续上下文,**不是**半成品草稿/孤儿。
|
|
500
|
+
* ⚠️ ADR-044 起:新建轮**建轮即入会话**,故本方法的「入会话」动作只对**存量无归属轮**
|
|
501
|
+
* (`refCount === 0`,ADR-044 之前落盘或建轮时登记失败)生效,见 attachUnownedRound。
|
|
502
|
+
* 宿主经 `IRoundStore.listInterruptedRecent` 打捞后再调本方法完成收场,恢复为普通 turn
|
|
503
|
+
* 渲染无需特殊草稿卡。
|
|
396
504
|
*
|
|
397
505
|
* **两个调用时机**:
|
|
398
506
|
* 1. 崩溃/断电后重启——宿主 `chatPanel.upgradeInterruptedRounds` 打捞后调用;
|
|
@@ -401,9 +509,8 @@ export class MessageHistory {
|
|
|
401
509
|
* 留下 pending 孤儿轮、须等下次重启才打捞(LLM 4xx 中断的长任务轮即此类)。
|
|
402
510
|
* 依据 = `memory/roundStore.ts` RoundStatus 文档「运行时失败不翻状态机,一律按中断处理」。
|
|
403
511
|
*
|
|
404
|
-
* 收场约定与 appendAssistant 同一真理源(
|
|
405
|
-
*
|
|
406
|
-
* 存储格式不变;
|
|
512
|
+
* 收场约定与 appendAssistant 同一真理源(status interrupted + completedAt + 存量无归属轮补登记
|
|
513
|
+
* 同走 attachUnownedRound;「已收场即跳过」仍用 `isRoundSettled`),Round schema / 存储格式不变;
|
|
407
514
|
* **有意不直接复用 appendAssistant**,两处差异:
|
|
408
515
|
* - appendAssistant 顶层跳过空内容 → 无文本中断轮无法收场;本方法允许多段「即使无
|
|
409
516
|
* assistantMessage 总结也按 stop 语义收场」(§一·五验收口径)。
|
|
@@ -437,6 +544,22 @@ export class MessageHistory {
|
|
|
437
544
|
}
|
|
438
545
|
// 有恢复文本才写 assistantMessage(§一·五:无 assistantMessage 总结也按 stop 语义收场)
|
|
439
546
|
const content = opts?.content?.trim() ?? '';
|
|
547
|
+
// 在途提问收场转化(E2E-ASK-LOSS-1):轮上残留 pendingAsk = 「问了但未答且作答记录
|
|
548
|
+
// 未落盘」的窗口仍开着——收场即窗口关闭,转化成 kind:'unanswered' 交互输入并清字段,
|
|
549
|
+
// 问题文本与候选选项从「进程内存」归位到「盘上重放面」(重放渲染复用 timeout 同型「未回答」行)。
|
|
550
|
+
// 消费点统一在本方法(打捞收场 / 运行期失败收场共用),宿主打捞链零改动。
|
|
551
|
+
const pendingAsk = existing.pendingAsk;
|
|
552
|
+
// 多题整组转化(每题一条 unanswered):pendingAsk 是整组快照,逐题保留 question/options——
|
|
553
|
+
// 崩溃轮的问题文本只在收场这一刻归档进 interactiveInputs,取首问即丢 Q2..N。
|
|
554
|
+
// 装配走 buildInteractiveInputs 单点(与 appendUser 作答/超时整组同宽,ASK-MULTI-Q-1)。
|
|
555
|
+
const unansweredInputs = pendingAsk?.length
|
|
556
|
+
? buildInteractiveInputs(roundId, existing.interactiveInputs?.length ?? 0, pendingAsk.map((q) => ({
|
|
557
|
+
content: LOOP_CONSTANTS.ASK_UNANSWERED_NOTICE,
|
|
558
|
+
kind: 'unanswered',
|
|
559
|
+
question: q.question,
|
|
560
|
+
options: q.options,
|
|
561
|
+
})), nowIso())
|
|
562
|
+
: [];
|
|
440
563
|
const completed = {
|
|
441
564
|
// 展开保留 userMessage / interactiveInputs / processEvents 等原字段
|
|
442
565
|
//(existing 取自 RoundStore 时含宿主检查点已落盘的 processEvents——store-first 优先保证)
|
|
@@ -451,20 +574,21 @@ export class MessageHistory {
|
|
|
451
574
|
},
|
|
452
575
|
}
|
|
453
576
|
: {}),
|
|
577
|
+
...(unansweredInputs.length
|
|
578
|
+
? {
|
|
579
|
+
interactiveInputs: [...(existing.interactiveInputs ?? []), ...unansweredInputs],
|
|
580
|
+
}
|
|
581
|
+
: {}),
|
|
454
582
|
status: 'interrupted',
|
|
455
583
|
completedAt: nowIso(),
|
|
584
|
+
// 生命周期不变量收口:转化后清字段(终态轮不残留 pendingAsk)
|
|
585
|
+
pendingAsk: undefined,
|
|
456
586
|
};
|
|
457
587
|
this.pendingRounds.delete(roundId);
|
|
458
|
-
|
|
459
|
-
//
|
|
460
|
-
this.roundStore.
|
|
588
|
+
// 🔴 ADR-044:归属已在建轮时登记,收场只改状态。**但存量无归属轮(refCount 0)必须补登记**——
|
|
589
|
+
// 跨重启打捞的残留轮正是这一类,省掉它会让打捞出来的轮在会话视图里看不见。
|
|
590
|
+
this.roundStore.save(this.attachUnownedRound(completed));
|
|
461
591
|
const sessionId = this.currentSessionName;
|
|
462
|
-
try {
|
|
463
|
-
this.sessionStore?.appendRoundId(sessionId, roundId);
|
|
464
|
-
}
|
|
465
|
-
catch (err) {
|
|
466
|
-
logger.warn({ err, sessionId, roundId }, 'appendInterrupted: appendRoundId 失败');
|
|
467
|
-
}
|
|
468
592
|
logger.info({ roundId, sessionId, hasAssistant: content.length > 0 }, 'appendInterrupted: 崩溃残留轮升级为正常 stop turn');
|
|
469
593
|
}
|
|
470
594
|
catch (err) {
|