memory-eternal 0.8.0 → 0.9.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/README.en.md +37 -0
- package/README.md +21 -0
- package/index.js +173 -51
- package/lib/api.js +86 -15
- package/lib/capture.js +69 -1
- package/lib/client.js +6 -6
- package/lib/vault.js +132 -65
- package/lib/watchdog.js +28 -4
- package/lib/web.js +8 -3
- package/package.json +1 -1
- package/web/app.js +10 -10
package/lib/capture.js
CHANGED
|
@@ -230,12 +230,80 @@ export function extractLastTurn(events, _turn) {
|
|
|
230
230
|
return lines.join('\n').trim()
|
|
231
231
|
}
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* 读会话事件快照。
|
|
235
|
+
*
|
|
236
|
+
* 优先 `ownEvents()`(DSH 公开 API):只取本会话自身事件,恢复/分叉会话不会把
|
|
237
|
+
* 继承来的历史前缀重复沉淀;`snapshotEvents()` 次之,老结构里的 `events` 兜底。
|
|
238
|
+
* 三条路都取不到时返回空数组,而不是让监听器抛异常(抛异常 = 管线静默死亡,
|
|
239
|
+
* 页面只表现为「一直不写卡」)。
|
|
240
|
+
*/
|
|
241
|
+
export function sessionEvents(session) {
|
|
242
|
+
if (!session) return []
|
|
243
|
+
// 逐个试:某个取法报了错就换下一个,不要让监听器跟着挂掉。
|
|
244
|
+
for (const pick of ['ownEvents', 'snapshotEvents']) {
|
|
245
|
+
if (typeof session[pick] === 'function') {
|
|
246
|
+
try {
|
|
247
|
+
const out = session[pick]()
|
|
248
|
+
if (Array.isArray(out)) return out
|
|
249
|
+
} catch { /* 换下一个取法 */ }
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return Array.isArray(session.events) ? session.events : []
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* 自动沉淀健康状态(进程内)。
|
|
257
|
+
*
|
|
258
|
+
* 目的:任何一条失败路径都必须留下「坏消息」,供 systemPrompt 段和 UI 横幅提示用户——
|
|
259
|
+
* 沉淀是后台静默管线,坏了不能只写日志等人来看。`fail()` 记录当前故障与起始时间,
|
|
260
|
+
* `succeed()` 表示一次真实写卡成功(故障自动清除)。
|
|
261
|
+
*/
|
|
262
|
+
export function createCaptureHealth() {
|
|
263
|
+
let ok = true
|
|
264
|
+
let reason = ''
|
|
265
|
+
let since = 0
|
|
266
|
+
let lastOkAt = 0
|
|
267
|
+
let lastFailAt = 0
|
|
268
|
+
return {
|
|
269
|
+
fail(why) {
|
|
270
|
+
ok = false
|
|
271
|
+
reason = String(why || '未知原因').replace(/\s+/g, ' ').slice(0, 160)
|
|
272
|
+
since = Date.now()
|
|
273
|
+
lastFailAt = since
|
|
274
|
+
},
|
|
275
|
+
succeed() {
|
|
276
|
+
ok = true
|
|
277
|
+
reason = ''
|
|
278
|
+
since = 0
|
|
279
|
+
lastOkAt = Date.now()
|
|
280
|
+
},
|
|
281
|
+
snapshot() { return { ok, reason, since, lastOkAt, lastFailAt } },
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 探测会话对象认识哪种「取事件」方式,返回用到的成员名('' = 一个都不认识)。
|
|
287
|
+
*
|
|
288
|
+
* 这个返回值会写进自动沉淀日志:一旦 DSH 再改接口,日志第一行就会显示
|
|
289
|
+
* 「没有事件接口」,而不是继续静默无输出。
|
|
290
|
+
*/
|
|
291
|
+
export function sessionEventApi(session) {
|
|
292
|
+
if (!session) return ''
|
|
293
|
+
// 顺序即优先级:ownEvents() 只含本会话自身事件(恢复/分叉不会重复沉淀历史)。
|
|
294
|
+
for (const pick of ['ownEvents', 'snapshotEvents']) {
|
|
295
|
+
if (typeof session[pick] === 'function') return pick
|
|
296
|
+
}
|
|
297
|
+
return Array.isArray(session.events) ? 'events' : ''
|
|
298
|
+
}
|
|
299
|
+
|
|
233
300
|
/** 取增量事件:seq 大于 lastSeq 的 user/assistant 消息事件。 */
|
|
234
301
|
export function sliceNewEvents(events, lastSeq) {
|
|
235
302
|
const out = []
|
|
236
303
|
for (const event of events) {
|
|
237
304
|
const seq = event.seq
|
|
238
|
-
|
|
305
|
+
// 无 seq 的事件(非常规日志)也收,避免漏掉消息;有 seq 则按水位过滤。
|
|
306
|
+
if (typeof seq === 'number' && typeof lastSeq === 'number' && seq <= lastSeq) continue
|
|
239
307
|
const type = event.type
|
|
240
308
|
if (type === 'user/message' || type === 'assistant/message') out.push(event)
|
|
241
309
|
}
|