@ai-agent-forge/plugin-memory 0.88.11 → 0.88.12

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.
@@ -8,6 +8,22 @@ import { resolveMemoryInferencePort } from "./inference-client.js";
8
8
  import { MEMORY_INFERENCE_DEFAULT_PORT, MEMORY_INFERENCE_PORT_ENV } from "./inference-protocol.js";
9
9
  /** enabling 加载/下载期间的周期性进度日志间隔。 */
10
10
  const ENABLING_PROGRESS_LOG_INTERVAL_MS = 15_000;
11
+ // 宿主先撤销 CapabilityAPI 再调用 disposer。清理诊断不得依赖已撤销的 logger,
12
+ // 也不得因诊断输出失败而中断其他资源释放或替换原始装配错误。
13
+ function reportCleanupFailure(resource, error) {
14
+ try {
15
+ console.error(`memory ${resource} close failed`, error);
16
+ }
17
+ catch {
18
+ // 诊断接收端不可用不改变资源生命周期。
19
+ }
20
+ }
21
+ function closeResource(resource, close) {
22
+ return Promise.resolve()
23
+ .then(close)
24
+ .then(() => undefined)
25
+ .catch((error) => reportCleanupFailure(resource, error));
26
+ }
11
27
  /** 两档共用精排模型 (POC 报告 §8: 官方 Xenova 转换版唯一实测可用)。 */
12
28
  export const VECTOR_RERANKER_MODEL_ID = "Xenova/bge-reranker-base";
13
29
  export const VECTOR_DB_DIRNAME = "vector";
@@ -52,6 +68,20 @@ export function createMemoryVectorChannel(deps) {
52
68
  enablingSettled?.();
53
69
  }
54
70
  const vectorEnabled = () => vectorState !== "failed" && vectorState !== "consent-required" && !consentDeclined;
71
+ // 尚未发布的本地资源也归本实例拥有;teardown 立即标记 provider 关闭。
72
+ let closeOwnedLocalResources;
73
+ const closeLocalChannel = async (channel) => {
74
+ const results = await Promise.allSettled([
75
+ Promise.resolve().then(() => channel.index.close()),
76
+ (async () => channel.embed.dispose?.())(),
77
+ (async () => channel.reranker?.dispose?.())(),
78
+ ]);
79
+ const resources = ["vector index", "embedding provider", "reranker"];
80
+ for (const [index, result] of results.entries()) {
81
+ if (result.status === "rejected")
82
+ reportCleanupFailure(resources[index], result.reason);
83
+ }
84
+ };
55
85
  // 征询话术 (AI 转述给用户; 会话语言由 AI 决定): 模型清单 + 体积下限 + 两个
56
86
  // 后续动作。consent-required 态下的 recall packet、auto-recall 注入块共用。
57
87
  const consentAskMessage = () => {
@@ -118,6 +148,12 @@ export function createMemoryVectorChannel(deps) {
118
148
  /** 服务模式持有的 IPC 客户端 (断连自愈检测用; 本地装配路径恒 undefined)。 */
119
149
  let inferenceClient;
120
150
  const vectorEnsure = () => {
151
+ if (capabilityDisposed) {
152
+ vectorState = "failed";
153
+ enablingFailure ??= { reason: "capability disposed during enabling", actions: [] };
154
+ enablingSettled?.();
155
+ return Promise.resolve(undefined);
156
+ }
121
157
  if (vectorState === "ready" || vectorState === "degraded") {
122
158
  // 服务模式断连自愈 (Slice B2): 缓存 channel 背后的 IPC 客户端死亡时
123
159
  // 清缓存重走装配 (重连 + 必要时重拉起服务), 而不是拿着死连接报错。
@@ -140,10 +176,11 @@ export function createMemoryVectorChannel(deps) {
140
176
  vectorState = "failed";
141
177
  enablingFailure = { reason, actions };
142
178
  vectorInitPromise = undefined;
143
- logger?.warn(`memory enabling failed: ${reason} — actions: ${enablingFailure.actions.join(" | ")}`, {
144
- mode: memoryMode,
145
- });
146
179
  enablingSettled?.();
180
+ if (!capabilityDisposed)
181
+ logger?.warn(`memory enabling failed: ${reason} — actions: ${enablingFailure.actions.join(" | ")}`, {
182
+ mode: memoryMode,
183
+ });
147
184
  return undefined;
148
185
  };
149
186
  // dispose 竞态守卫 (2026-10-06 复审遗留): teardown 与在途 enabling 竞态
@@ -155,12 +192,9 @@ export function createMemoryVectorChannel(deps) {
155
192
  vectorState = "failed";
156
193
  enablingFailure = { reason: "capability disposed during enabling", actions: [] };
157
194
  vectorInitPromise = undefined;
158
- // 与 failEnabling 同构落一行: dispose 竞态让位不再是排障不可见。
159
- logger?.warn(`memory enabling aborted: ${enablingFailure.reason}`);
160
- void closeAcquired.catch((error) => {
161
- logger?.warn(`memory channel close after capability dispose failed: ${error instanceof Error ? error.message : String(error)}`);
162
- });
163
195
  enablingSettled?.();
196
+ if (closeAcquired !== undefined)
197
+ void closeResource("inference client", closeAcquired);
164
198
  return undefined;
165
199
  };
166
200
  logger?.info(`memory enabling started (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);
@@ -235,17 +269,19 @@ export function createMemoryVectorChannel(deps) {
235
269
  port: servicePort,
236
270
  ...(inferenceServiceSpawnImpl === undefined ? {} : { spawnImpl: inferenceServiceSpawnImpl }),
237
271
  });
272
+ if (capabilityDisposed)
273
+ return failEnablingDisposed(() => client.close());
238
274
  // agentDir 身份校验 (2026-10-06 串线修复): 固定端口单例服务可能
239
275
  // 属于另一个 --agent-dir 的会话 (hello 此前只回报模型身份, 后连
240
276
  // 者握手/冒烟全过却把读写投影进对方的 LanceDB)。在冒烟与档位比
241
277
  // 对之前先核对身份 — 不一致或缺失都绝不触碰该服务。
242
278
  const helloAgentDir = client.hello.agentDir;
243
279
  if (helloAgentDir === undefined) {
244
- client.close().catch(() => undefined);
280
+ void closeResource("inference client", () => client.close());
245
281
  return failEnabling(`inference service on port ${servicePort} reports no agent-dir identity — the service was started by an older version; wait for its idle exit or stop it manually, then restart the session`, serviceFailureActionList(servicePort));
246
282
  }
247
283
  if (normalizeMemoryAgentDirIdentity(helloAgentDir) !== normalizeMemoryAgentDirIdentity(agentDir)) {
248
- client.close().catch(() => undefined);
284
+ void closeResource("inference client", () => client.close());
249
285
  return failEnabling(`inference service on port ${servicePort} belongs to agent-dir ${helloAgentDir}, this session runs in ${agentDir} — its memory projection lives in another agent-dir; wait for its idle exit or stop it manually, then restart the session`, serviceFailureActionList(servicePort));
250
286
  }
251
287
  const channel = {
@@ -257,19 +293,21 @@ export function createMemoryVectorChannel(deps) {
257
293
  };
258
294
  // 冒烟经 wire (服务端首次 embed 完成模型加载, 预算放宽)。
259
295
  await channel.embed.embed(["memory enabling smoke test"]);
296
+ if (capabilityDisposed)
297
+ return failEnablingDisposed(() => client.close());
260
298
  if (client.hello.embeddingModelId !== preset.embeddingModelId) {
261
- client.close().catch(() => undefined);
299
+ void closeResource("inference client", () => client.close());
262
300
  return failEnabling(`inference service runs embedding model ${client.hello.embeddingModelId}, session preset is ${preset.embeddingModelId} — the service was spawned for another memory tier; wait for its idle exit or stop it, then restart the session`, serviceFailureActionList(servicePort));
263
301
  }
264
302
  const storedModelId = await channel.index.getStoredModelId();
265
- if (storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {
303
+ if (!capabilityDisposed && storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {
266
304
  logger?.warn(`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`);
267
305
  }
268
306
  // dispose 竞态: teardown 已清引用 (capabilityDisposed) 时, 装配成功
269
307
  // 分支不得把新 IPC 连接赋回去——关闭它并落结构化失败, 让在途的
270
308
  // enablingOutcome() 等待者 (如 memory-preheat) 落定为失败而非悬挂。
271
309
  if (capabilityDisposed)
272
- return failEnablingDisposed(client.close());
310
+ return failEnablingDisposed(() => client.close());
273
311
  inferenceClient = client;
274
312
  vectorChannel = channel;
275
313
  vectorState = "ready";
@@ -280,7 +318,8 @@ export function createMemoryVectorChannel(deps) {
280
318
  catch (error) {
281
319
  // 连接已建立后的失败 (冒烟/档位比对/getStoredModelId) 必须关掉
282
320
  // 客户端: 悬挂连接会让服务端 connections>0, 空闲自杀永不触发。
283
- client?.close().catch(() => undefined);
321
+ if (client !== undefined)
322
+ void closeResource("inference client", () => client.close());
284
323
  return failEnabling(`inference service assembly failed (${error instanceof Error ? error.message : String(error)})`, serviceFailureActionList(servicePort));
285
324
  }
286
325
  }
@@ -291,26 +330,39 @@ export function createMemoryVectorChannel(deps) {
291
330
  // dispose 竞态 (本地装配路径, 第一道): 已 teardown 就不再打开 LanceDB/
292
331
  // 拉起重依赖; 装配完成点还有第二道检查兜住模型下载窗口。
293
332
  if (capabilityDisposed)
294
- return failEnablingDisposed(Promise.resolve());
333
+ return failEnablingDisposed();
295
334
  // 加载: transformers/lancedb 的动态 import 都在这些模块内部, 这里只做
296
335
  // 模块级懒加载, 保持未触发会话零重依赖。进度周期性落一行 (下载可达
297
336
  // 数百 MB), 完成后清除。
298
337
  const progressTimer = setInterval(() => {
299
- logger?.info("memory enabling still in progress (downloading/loading models)");
338
+ if (!capabilityDisposed)
339
+ logger?.info("memory enabling still in progress (downloading/loading models)");
300
340
  }, ENABLING_PROGRESS_LOG_INTERVAL_MS);
301
341
  if (typeof progressTimer === "object" && "unref" in progressTimer)
302
342
  progressTimer.unref();
343
+ let closeAcquired;
344
+ let published = false;
303
345
  try {
304
346
  const [vectorIndexModule, embeddingModule, rerankerModule] = await Promise.all([
305
347
  import("./vector-index.js"),
306
348
  import("./embedding-provider.js"),
307
349
  import("./embedding-reranker.js"),
308
350
  ]);
351
+ if (capabilityDisposed)
352
+ return failEnablingDisposed();
309
353
  const index = await vectorIndexModule.createMemoryVectorIndex({
310
354
  dbPath: join(agentDir, "memory", VECTOR_DB_DIRNAME),
311
355
  dimensions: preset.dimensions,
312
356
  ...(hostLancedbEntryPath === undefined ? {} : { moduleEntryPath: hostLancedbEntryPath }),
313
357
  });
358
+ let indexClosePromise;
359
+ closeAcquired = () => {
360
+ indexClosePromise ??= closeResource("vector index", () => index.close());
361
+ return indexClosePromise;
362
+ };
363
+ closeOwnedLocalResources = closeAcquired;
364
+ if (capabilityDisposed)
365
+ return failEnablingDisposed();
314
366
  const remoteHosts = remoteHostsForEnabling();
315
367
  const channel = {
316
368
  embed: embeddingModule.createTransformersEmbeddingProvider({
@@ -336,27 +388,38 @@ export function createMemoryVectorChannel(deps) {
336
388
  queryPrefix: preset.queryPrefix,
337
389
  embeddingModelId: preset.embeddingModelId,
338
390
  };
391
+ let channelClosePromise;
392
+ closeAcquired = () => {
393
+ channelClosePromise ??= closeLocalChannel(channel);
394
+ return channelClosePromise;
395
+ };
396
+ closeOwnedLocalResources = closeAcquired;
339
397
  // 冒烟: embed + rerank 各一条 (同时完成两个模型的下载与加载) +
340
398
  // 投影档位比对。rerank 冒烟 2026-10-06 live E2E 补齐: reranker
341
399
  // 懒加载, 只 embed 的冒烟会让 "ready" 携带未下载的精排权重 —
342
400
  // 共享推理服务 (两项文件均前置检查、永不自主下载) 对该会话拒启,
343
401
  // "fully usable" 的自述与服务前置条件必须一致。
344
402
  await channel.embed.embed(["memory enabling smoke test"]);
403
+ if (capabilityDisposed)
404
+ return failEnablingDisposed();
345
405
  if (channel.embed.modelId !== preset.embeddingModelId) {
346
406
  return failEnabling(`smoke check failed: embedding modelId ${channel.embed.modelId} does not match the ${memoryMode} preset ${preset.embeddingModelId}`);
347
407
  }
348
408
  if (channel.reranker !== undefined) {
349
409
  await channel.reranker.rerank("memory enabling smoke test", ["memory enabling smoke test"]);
410
+ if (capabilityDisposed)
411
+ return failEnablingDisposed();
350
412
  }
351
413
  const storedModelId = await channel.index.getStoredModelId();
352
- if (storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {
414
+ if (!capabilityDisposed && storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {
353
415
  logger?.warn(`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`);
354
416
  }
355
417
  // dispose 竞态 (本地装配路径, 第二道, 兜住模型下载窗口): 不把索引句柄
356
418
  // 赋回引用——关闭刚打开的 LanceDB 并落结构化失败。
357
419
  if (capabilityDisposed)
358
- return failEnablingDisposed(channel.index.close());
420
+ return failEnablingDisposed();
359
421
  vectorChannel = channel;
422
+ published = true;
360
423
  vectorState = "ready";
361
424
  logger?.info(`memory ready (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);
362
425
  enablingSettled?.();
@@ -367,6 +430,11 @@ export function createMemoryVectorChannel(deps) {
367
430
  }
368
431
  finally {
369
432
  clearInterval(progressTimer);
433
+ if (!published && closeAcquired !== undefined) {
434
+ await closeAcquired();
435
+ if (closeOwnedLocalResources === closeAcquired)
436
+ closeOwnedLocalResources = undefined;
437
+ }
370
438
  }
371
439
  })();
372
440
  return vectorInitPromise;
@@ -427,7 +495,7 @@ export function createMemoryVectorChannel(deps) {
427
495
  };
428
496
  // 会话切换重绑/插件卸载的共享资源释放 (TUI 每次会话切换都重走装配, 不释放
429
497
  // 即每次泄漏一条 IPC 连接: 服务端 connections>0 抑制空闲自杀, 嵌入方进程因
430
- // socket 未关无法自然退出)。清引用先行: close 的 reject 兜底 warn 一行, 且
498
+ // socket 未关无法自然退出)。清引用先行: close 的错误经独立 stderr 诊断, 且
431
499
  // 二次调用因引用已空自然 no-op。服务路径与本地路径互斥 (服务路径的 index
432
500
  // 归服务进程持有, 客户端只断连; 本地路径才关 LanceDB 句柄)。
433
501
  // capabilityDisposed 是 teardown 与在途 enabling 的竞态闩锁: teardown 之后
@@ -436,21 +504,24 @@ export function createMemoryVectorChannel(deps) {
436
504
  let capabilityDisposed = false;
437
505
  const capabilityTeardown = () => {
438
506
  capabilityDisposed = true;
507
+ if (closeOwnedLocalResources !== undefined) {
508
+ const close = closeOwnedLocalResources;
509
+ closeOwnedLocalResources = undefined;
510
+ vectorChannel = undefined;
511
+ void close();
512
+ return;
513
+ }
439
514
  if (inferenceClient !== undefined) {
440
515
  const client = inferenceClient;
441
516
  inferenceClient = undefined;
442
517
  vectorChannel = undefined;
443
- void client.close().catch((error) => {
444
- logger?.warn(`memory inference client close failed: ${error instanceof Error ? error.message : String(error)}`);
445
- });
518
+ void closeResource("inference client", () => client.close());
446
519
  return;
447
520
  }
448
521
  if (vectorChannel !== undefined) {
449
522
  const channel = vectorChannel;
450
523
  vectorChannel = undefined;
451
- void channel.index.close().catch((error) => {
452
- logger?.warn(`memory vector index close failed: ${error instanceof Error ? error.message : String(error)}`);
453
- });
524
+ void closeLocalChannel(channel);
454
525
  }
455
526
  };
456
527
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"vector-channel.js","sourceRoot":"","sources":["../../src/memory/vector-channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 向量通道状态机(capability 拆分战役 slice 3b):vectorEnsure 状态转换、装配分支(服务/本地/下载/征询门)、dispose 闩锁。共享闭包状态收拢为 channel 对象, 经 deps 显式注入; 降级/投影经 slice 3a 的 vector-projection 上报\n */\n\nimport { join } from \"node:path\";\nimport type {\n\tCapabilityAPI,\n\tMemoryEnablingOverrideV1,\n\tMemoryVectorComponentsOverrideV1,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tDISK_HEADROOM_MIN_BYTES,\n\tdiskHeadroomCheck,\n\tenablingActionList,\n\tMODEL_MIN_WEIGHT_BYTES,\n\tmissingHeavyDependencyModules,\n\tmodelFilesCheck,\n\tnativeBinaryCheck,\n\tnormalizeMemoryAgentDirIdentity,\n\tRERANKER_MIN_WEIGHT_BYTES,\n\tremoteHostsForEnabling,\n\tresolveHeavyDependencyEntryPath,\n\tvectorPresetForMode,\n\twriteMemoryConsentDeclined,\n} from \"./enabling.ts\";\nimport { ensureInferenceServiceChannel, serviceFailureActionList } from \"./inference-channel.ts\";\nimport { type MemoryInferenceClientV1, resolveMemoryInferencePort } from \"./inference-client.ts\";\nimport { MEMORY_INFERENCE_DEFAULT_PORT, MEMORY_INFERENCE_PORT_ENV } from \"./inference-protocol.ts\";\nimport type { ActiveVectorChannelV1 } from \"./vector-projection.ts\";\n\n/** enabling 加载/下载期间的周期性进度日志间隔。 */\nconst ENABLING_PROGRESS_LOG_INTERVAL_MS = 15_000;\n\n/** 两档共用精排模型 (POC 报告 §8: 官方 Xenova 转换版唯一实测可用)。 */\nexport const VECTOR_RERANKER_MODEL_ID = \"Xenova/bge-reranker-base\";\nexport const VECTOR_DB_DIRNAME = \"vector\";\nexport const VECTOR_MODEL_CACHE_DIRNAME = \"model-cache\";\n\n/** capability 级状态机 (设计 §3.2): off 只出现在模式关闭 (零注册, 不可观测)。 */\nexport type MemoryCapabilityStateV1 = \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\n/** enabling 失败的结构化结果: 原因 + 行动清单 (硬性要求, 设计 §3.2)。 */\nexport interface MemoryEnablingFailureV1 {\n\treadonly reason: string;\n\treadonly actions: readonly string[];\n}\n\n/**\n * 征询门待决信息 (2026-10-05 用户裁决「首次使用征询、拒绝即持久化关闭」):\n * 向量通道从未就绪且模式已启用时, 模型下载必须先经用户同意——检索不触发下载,\n * 由 AI 转述征询后经 memory_enable 工具面继续。\n */\nexport interface MemoryConsentNeededV1 {\n\treadonly models: readonly string[];\n\t/** 模型权重体积下限之和 (非精确体积; 实际下载量以镜像文件为准)。 */\n\treadonly approximateBytes: number;\n}\n\n/** 征询面 (consent-required 态的模型可见包): AI 转述话术 + 后续动作 + 注入块。 */\nexport interface MemoryConsentAskV1 {\n\treadonly message: string;\n\treadonly actions: readonly string[];\n\treadonly block: string;\n}\n\n/**\n * 向量通道对 capability 装配上下文的显式依赖视图 (slice 3b): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实, 不再经共享闭包隐式可达。\n */\nexport interface MemoryVectorChannelDepsV1 {\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 模型缓存/索引/征询持久化的路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** capability 日志面 (api.logger): 进度/失败/自愈日志。 */\n\treadonly logger: CapabilityAPI[\"logger\"];\n\t/** 宿主注入的 onnxruntime-node 入口 (MemoryCapabilityContext.hostOnnxRuntimeEntryPath)。 */\n\treadonly hostOnnxRuntimeEntryPath?: string;\n\t/** 宿主注入的 @lancedb/lancedb 入口 (MemoryCapabilityContext.hostLancedbEntryPath)。 */\n\treadonly hostLancedbEntryPath?: string;\n\t/** 宿主注入的 @huggingface/transformers 入口 (MemoryCapabilityContext.hostTransformersEntryPath)。 */\n\treadonly hostTransformersEntryPath?: string;\n\t/** 服务装配缝 (Slice B2): 测试端口直连 (MemoryCapabilityContext.inferenceService.port)。 */\n\treadonly inferenceServicePort?: number;\n\t/** 服务装配缝 (Slice B2): 替换进程拉起的测试缝 (inferenceService.spawnImpl)。 */\n\treadonly inferenceServiceSpawnImpl?: (\n\t\tagentDir: string,\n\t\tmode: \"light\" | \"full\",\n\t\tport: number,\n\t\t/** spawn 异步失败 (EACCES/ENOMEM 等) 的回调; 缺省实现经 child 'error' 事件馈入。 */\n\t\tonError?: (error: Error) => void,\n\t) => Promise<void>;\n\t/** 服务装配缝 (Slice B2): 声明模型在位, 文件检查与征询门让位 (inferenceService.modelsInPlace)。 */\n\treadonly inferenceServiceModelsInPlace?: boolean;\n\t/** enabling 测试缝 (loadImpl 重定向模型加载); undefined = 生产路径。 */\n\treadonly enablingOverride?: MemoryEnablingOverrideV1;\n\t/** 组件注入 (deterministic mock 门禁): 存在时通道直接 ready, 跳过真实装配。 */\n\treadonly injectedComponents?: MemoryVectorComponentsOverrideV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection.resetReconcile): downloadMemory 就绪后重臂启动对账。 */\n\treadonly resetReconcile: () => void;\n\t/** 写侧投影 (slice 3a 的 vectorProjection.reconcileOnce): downloadMemory 就绪后补跑对账。 */\n\treadonly reconcileOnce: () => void;\n}\n\nexport interface MemoryVectorChannelV1 {\n\t/** harness.vectorState 面: 征询拒绝时投影为 \"off\" (本实例按模式关闭对待)。 */\n\tstate(): \"off\" | MemoryCapabilityStateV1;\n\t/** vectorState 原值 (未做 declined 投影; recall/合并探测等内部消费)。 */\n\trawState(): MemoryCapabilityStateV1;\n\t/** vectorEnabled: failed/consent-required/declined 时 false (写侧埋点门)。 */\n\tenabled(): boolean;\n\t/** 已就绪通道的同步快照 (vectorChannel 只读; projection.readyChannel 面)。 */\n\treadyChannel(): ActiveVectorChannelV1 | undefined;\n\t/** dispose 闩锁只读视图 (capabilityDisposed; projection.isDisposed 面)。 */\n\tisDisposed(): boolean;\n\t/** 征询拒绝标记 (declineMemory 持久化后的本实例内存面)。 */\n\tdeclined(): boolean;\n\t/** 用户显式再启用 (/memory light|full、自动升档) 清除本实例拒绝标记。 */\n\tclearDeclined(): void;\n\t/** 征询一次性注入钉住标记 (auto-recall 每实例只注入一次)。 */\n\tconsentAsked(): boolean;\n\tmarkConsentAsked(): void;\n\t/** 无副作用征询探测 (auto-recall 首轮; 纯本地 stat, 绝不触发下载/加载)。 */\n\tprimeConsentGate(): void;\n\t/** 征询待决面 (consent-required 且待决信息就位时非 undefined; 纯只读, 不探测)。 */\n\tconsentAsk(): MemoryConsentAskV1 | undefined;\n\t/** warming 守卫 (recall 后台预热不阻塞读侧): 装配在途且未拒绝。 */\n\twarming(): boolean;\n\t/** enabling 失败结构化结果 (未失败 = undefined)。 */\n\tfailure(): MemoryEnablingFailureV1 | undefined;\n\t/** 运行期故障 → degraded (可自愈; recall 与投影对账共用)。 */\n\tmarkDegraded(): void;\n\t/** degraded → ready 的自愈转换 (仅从 degraded; 全通 recall 成功后调用)。 */\n\trecoverDegraded(): void;\n\t/** vectorEnsure: 惰性单飞装配 (recall/write/埋点/对账的公共入口)。 */\n\tensure(): Promise<ActiveVectorChannelV1 | undefined>;\n\t/** harness.enablingOutcome 面: 触发惰性 enabling 并等待落定 (ready 或结构化失败)。 */\n\tenablingOutcome(): Promise<\"ready\" | MemoryEnablingFailureV1>;\n\t/** declineMemory 核心: 持久化拒绝 + 本实例按模式关闭。 */\n\tdecline(): { status: \"completed\"; message: string };\n\t/** downloadMemory 核心: 置征询同意 + 装配 + 补跑启动对账。 */\n\tdownload(): Promise<\n\t\t| { status: \"completed\"; message: string }\n\t\t| { status: \"failed\"; message: string; actions?: readonly string[]; next?: string }\n\t>;\n\t/** capabilityTeardown 本体: 资源关闭 + 闩锁置位 (幂等)。 */\n\tdispose(): void;\n}\n\nexport function createMemoryVectorChannel(deps: MemoryVectorChannelDepsV1): MemoryVectorChannelV1 {\n\tconst {\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tlogger,\n\t\thostOnnxRuntimeEntryPath,\n\t\thostLancedbEntryPath,\n\t\thostTransformersEntryPath,\n\t\tinferenceServicePort,\n\t\tinferenceServiceSpawnImpl,\n\t\tinferenceServiceModelsInPlace,\n\t\tenablingOverride,\n\t\tinjectedComponents,\n\t\tresetReconcile,\n\t\treconcileOnce,\n\t} = deps;\n\t// ---- 语义召回通道 (2.4d6 S1/S2; 召回唯一检索路径) ----\n\t// 状态机 (设计 §3.2): enabling = 检查/加载进行中 (惰性触发: 首次向量操作\n\t// 时真正执行); ready = 可用; degraded = ready 后运行期故障 (可自愈回\n\t// ready); failed = enabling 失败, 本实例内终态 (mode 回退 off, 记忆工具\n\t// 返回携带行动清单的不可用 packet, 不再重试)。所有写侧操作经 vectorQueue\n\t// 串行化, 避免 reconcile 与写入埋点在 LanceDB 建表上竞态; recall 等待\n\t// enabling 单飞完成, 不与后台对账并发读索引。transformers/lancedb 的动态\n\t// import 只出现在 vectorEnsure 的装配分支里 (type-position 引类型), 未\n\t// 触发时不加载任何重依赖。\n\tlet vectorState: MemoryCapabilityStateV1 = \"enabling\";\n\tlet vectorChannel: ActiveVectorChannelV1 | undefined;\n\tlet enablingFailure: MemoryEnablingFailureV1 | undefined;\n\tlet enablingSettled: (() => void) | undefined;\n\t// 征询门 (2026-10-05 用户裁决「首次使用征询、拒绝即持久化关闭」): 模型文件\n\t// 缺失时下载必须先经用户同意——consentGranted 只由 memory_enable 工具面置位;\n\t// consentDeclined = 本实例内用户拒绝/跳过 (同时持久化, 见\n\t// writeMemoryConsentDeclined), 之后本实例按模式关闭对待; consentAsked 钉住\n\t// 自动召回的一次性征询注入, 不随查询文本翻新。\n\tlet consentGranted = false;\n\tlet consentDeclined = false;\n\tlet consentAsked = false;\n\tlet consentNeededInfo: MemoryConsentNeededV1 | undefined;\n\tconst enablingSettledPromise = new Promise<\"ready\" | MemoryEnablingFailureV1>((resolve) => {\n\t\tenablingSettled = () => resolve(enablingFailure ?? \"ready\");\n\t});\n\tif (injectedComponents !== undefined) {\n\t\t// 测试注入: 直接 ready, 跳过真实装配与档位解析。\n\t\tvectorState = \"ready\";\n\t\tvectorChannel = {\n\t\t\tembed: injectedComponents.embedProvider,\n\t\t\treranker: injectedComponents.reranker,\n\t\t\tindex: injectedComponents.vectorIndex,\n\t\t\tqueryPrefix: injectedComponents.queryPrefix ?? \"\",\n\t\t\tembeddingModelId: injectedComponents.embedProvider.modelId,\n\t\t};\n\t\tenablingSettled?.();\n\t}\n\tconst vectorEnabled = (): boolean =>\n\t\tvectorState !== \"failed\" && vectorState !== \"consent-required\" && !consentDeclined;\n\t// 征询话术 (AI 转述给用户; 会话语言由 AI 决定): 模型清单 + 体积下限 + 两个\n\t// 后续动作。consent-required 态下的 recall packet、auto-recall 注入块共用。\n\tconst consentAskMessage = (): string => {\n\t\tconst info = consentNeededInfo;\n\t\tconst models = info === undefined ? \"embedding + reranker\" : info.models.join(\" + \");\n\t\tconst floorMb = Math.ceil(\n\t\t\t(info?.approximateBytes ?? MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES) / (1024 * 1024),\n\t\t);\n\t\treturn (\n\t\t\t`memory needs a one-time model download (${models}, at least ${floorMb} MB total; ` +\n\t\t\t\"actual sizes come from the mirror) into <agentDir>/memory/model-cache before recall can run — \" +\n\t\t\t\"nothing downloads without user consent\"\n\t\t);\n\t};\n\tconst consentAskActions = (): readonly string[] => [\n\t\t\"Ask the user whether to download the memory models now\",\n\t\t'With consent, call memory_enable with action \"download\"',\n\t\t'If the user declines, call memory_enable with action \"decline\" (persists memory off; set memory.mode in settings.json later to re-enable)',\n\t];\n\tconst consentAskBlock = (): string =>\n\t\t[\n\t\t\t\"<memory_setup>\",\n\t\t\tconsentAskMessage(),\n\t\t\t\"Ask the user (in the conversation language) whether to download now; relay that it is one-time and the size.\",\n\t\t\t...consentAskActions()\n\t\t\t\t.slice(1)\n\t\t\t\t.map((line) => `- ${line}`),\n\t\t\t\"</memory_setup>\",\n\t\t].join(\"\\n\");\n\t// 无副作用探测: 初始态是 enabling, 而征询态只在 vectorEnsure 探测后落定——\n\t// 自动召回钩子首轮就要给出征询注入, 这里只做模型文件存在性检查 (纯本地\n\t// stat), 缺失即落定 consent-required, 绝不触发下载/加载。\n\tconst primeConsentGate = (): void => {\n\t\tif (consentGranted || consentDeclined || vectorState !== \"enabling\") return;\n\t\tif (\n\t\t\tenablingOverride?.embeddingLoadImpl !== undefined ||\n\t\t\tenablingOverride?.rerankerLoadImpl !== undefined ||\n\t\t\t// 服务装配缝的模型声明 (Slice B2): 与 vectorEnsure 装配分支同一豁免 —\n\t\t\t// 声明在位时文件检查让位, 征询门不应被 auto-recall 钩子提前翻起。\n\t\t\tinferenceServiceModelsInPlace === true\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst preset = vectorPresetForMode(memoryMode);\n\t\tconst modelCacheDir = join(agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\t\tconst modelsMissing =\n\t\t\tmodelFilesCheck(modelCacheDir, preset.embeddingModelId, MODEL_MIN_WEIGHT_BYTES[memoryMode]) === \"missing\" ||\n\t\t\tmodelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES) === \"missing\";\n\t\tif (!modelsMissing) return;\n\t\tvectorState = \"consent-required\";\n\t\tconsentNeededInfo = {\n\t\t\tmodels: [\n\t\t\t\tpreset.embeddingModelId,\n\t\t\t\t...(modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES) === \"missing\"\n\t\t\t\t\t? [VECTOR_RERANKER_MODEL_ID]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t\tapproximateBytes: MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES,\n\t\t};\n\t};\n\tlet vectorInitPromise: Promise<ActiveVectorChannelV1 | undefined> | undefined;\n\n\t/**\n\t * 开启状态机 (设计 §3.2, 惰性单飞): 本地检查 (native .node 可解析 → 重依赖\n\t * 供给 (lancedb/transformers: 宿主入口路径或插件位置自解析) → 模型文件存在\n\t * 与大小 → 磁盘余量) → transformers 加载 (自带下载, 进度周期性\n\t * 落一行日志) → 冒烟 (embed 一条 + getStoredModelId 与档位比对) → ready。\n\t * 任一步失败 → failed (原因 + 五选一行动清单), mode 记录回退 off, 本实例\n\t * 不再重试。\n\t */\n\t/** 服务模式持有的 IPC 客户端 (断连自愈检测用; 本地装配路径恒 undefined)。 */\n\tlet inferenceClient: MemoryInferenceClientV1 | undefined;\n\n\tconst vectorEnsure = (): Promise<ActiveVectorChannelV1 | undefined> => {\n\t\tif (vectorState === \"ready\" || vectorState === \"degraded\") {\n\t\t\t// 服务模式断连自愈 (Slice B2): 缓存 channel 背后的 IPC 客户端死亡时\n\t\t\t// 清缓存重走装配 (重连 + 必要时重拉起服务), 而不是拿着死连接报错。\n\t\t\tif (inferenceClient === undefined || inferenceClient.isAlive()) return Promise.resolve(vectorChannel);\n\t\t\tlogger?.warn(\"memory inference service connection lost; reconnecting\");\n\t\t\tinferenceClient = undefined;\n\t\t\tvectorChannel = undefined;\n\t\t\tvectorState = \"enabling\";\n\t\t\tvectorInitPromise = undefined;\n\t\t}\n\t\tif (vectorState === \"failed\") return Promise.resolve(undefined);\n\t\tif (vectorInitPromise !== undefined) return vectorInitPromise;\n\t\tvectorInitPromise = (async (): Promise<ActiveVectorChannelV1 | undefined> => {\n\t\t\tconst preset = vectorPresetForMode(memoryMode);\n\t\t\tconst modelCacheDir = join(agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\t\t\tconst failEnabling = (\n\t\t\t\treason: string,\n\t\t\t\tactions: readonly string[] = enablingActionList(modelCacheDir, memoryMode),\n\t\t\t): undefined => {\n\t\t\t\tvectorState = \"failed\";\n\t\t\t\tenablingFailure = { reason, actions };\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\tlogger?.warn(`memory enabling failed: ${reason} — actions: ${enablingFailure.actions.join(\" | \")}`, {\n\t\t\t\t\tmode: memoryMode,\n\t\t\t\t});\n\t\t\t\tenablingSettled?.();\n\t\t\t\treturn undefined;\n\t\t\t};\n\t\t\t// dispose 竞态守卫 (2026-10-06 复审遗留): teardown 与在途 enabling 竞态\n\t\t\t// 时, 装配完成点必须让位——不得把新连接/索引句柄赋回已清空的引用 (那会\n\t\t\t// 复活一条无人关闭的连接: 服务端 connections>0 抑制空闲自杀、挂住嵌入\n\t\t\t// 进程事件循环), 也不得让 enablingOutcome() 等待者悬挂。改为关闭刚取得\n\t\t\t// 的资源并落结构化 failed (MemoryEnablingFailureV1 形状)。\n\t\t\tconst failEnablingDisposed = (closeAcquired: Promise<unknown>): undefined => {\n\t\t\t\tvectorState = \"failed\";\n\t\t\t\tenablingFailure = { reason: \"capability disposed during enabling\", actions: [] };\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\t// 与 failEnabling 同构落一行: dispose 竞态让位不再是排障不可见。\n\t\t\t\tlogger?.warn(`memory enabling aborted: ${enablingFailure.reason}`);\n\t\t\t\tvoid closeAcquired.catch((error: unknown) => {\n\t\t\t\t\tlogger?.warn(\n\t\t\t\t\t\t`memory channel close after capability dispose failed: ${\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t\t}`,\n\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t\tenablingSettled?.();\n\t\t\t\treturn undefined;\n\t\t\t};\n\t\t\tlogger?.info(`memory enabling started (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);\n\t\t\t// 检查 1: native .node sidecar (纯本地, 零网络)。宿主注入路径优先\n\t\t\t// (安装店副本自解析不可达, 见 MemoryCapabilityContext.hostOnnxRuntimeEntryPath)。\n\t\t\tconst nativeProblem = nativeBinaryCheck(hostOnnxRuntimeEntryPath);\n\t\t\tif (nativeProblem !== undefined) return failEnabling(nativeProblem);\n\t\t\t// 检查 1b: 重依赖供给。宿主入口路径优先; 未提供时插件位置自解析,\n\t\t\t// 两者都不可达 = 原本要到加载步才以 \"Cannot find module\" 泛化包装\n\t\t\t// 失败的根因, 前置到模型下载之前以 onnx 缺供分支同构的精准文案报告。\n\t\t\t// 路径已提供但包损坏的真实失败仍走加载步, 由泛化包装保留原始错误。\n\t\t\tconst missingHeavyDependencies = missingHeavyDependencyModules(\n\t\t\t\t{ lancedb: hostLancedbEntryPath, transformers: hostTransformersEntryPath },\n\t\t\t\tresolveHeavyDependencyEntryPath,\n\t\t\t);\n\t\t\tif (missingHeavyDependencies.length > 0) {\n\t\t\t\treturn failEnabling(\n\t\t\t\t\t`${missingHeavyDependencies.join(\", \")} are not provided by the host installation and could not be resolved from the plugin location; to enable memory features, install them in the host project (npm i ${missingHeavyDependencies.join(\" \")}) and restart the session`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// 检查 2: 模型文件 (缺失 = 进入下载; 存在但截断 = 失败提示手动导入)。\n\t\t\tconst embeddingProblem = modelFilesCheck(\n\t\t\t\tmodelCacheDir,\n\t\t\t\tpreset.embeddingModelId,\n\t\t\t\tMODEL_MIN_WEIGHT_BYTES[memoryMode],\n\t\t\t);\n\t\t\tconst rerankerProblem = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\t\tconst modelsMissing =\n\t\t\t\tembeddingProblem === \"missing\" || rerankerProblem === \"missing\"\n\t\t\t\t\t? `${preset.embeddingModelId}${rerankerProblem === \"missing\" ? ` + ${VECTOR_RERANKER_MODEL_ID}` : \"\"}`\n\t\t\t\t\t: undefined;\n\t\t\tif (embeddingProblem !== undefined && embeddingProblem !== \"missing\") return failEnabling(embeddingProblem);\n\t\t\tif (rerankerProblem !== undefined && rerankerProblem !== \"missing\") return failEnabling(rerankerProblem);\n\t\t\t// 征询门 (2026-10-05 用户裁决): 模型缺失且未经用户同意时不下载, 停在\n\t\t\t// consent-required 态等 memory_enable 工具面继续。注入 loadImpl 的测试\n\t\t\t// 缝绕过本门 (deterministic mock 门禁路径, 无网络语义)。截断文件不走\n\t\t\t// 征询 (文件在 = 曾有过一次下载意图), 仍走失败行动清单。\n\t\t\tconst hasEnablingTestSeam =\n\t\t\t\tenablingOverride?.embeddingLoadImpl !== undefined || enablingOverride?.rerankerLoadImpl !== undefined;\n\t\t\t// 服务装配缝的模型声明 (Slice B2): modelsInPlace = 测试声明模型已在位\n\t\t\t// (免写假权重文件), 文件检查与征询门相应让位; 生产路径缺省 false,\n\t\t\t// 真实文件检查与征询门语义不变。\n\t\t\tconst serviceModelsDeclared = inferenceServiceModelsInPlace === true;\n\t\t\tif (modelsMissing !== undefined && !consentGranted && !hasEnablingTestSeam && !serviceModelsDeclared) {\n\t\t\t\tvectorState = \"consent-required\";\n\t\t\t\tconsentNeededInfo = {\n\t\t\t\t\tmodels: modelsMissing.split(\" + \"),\n\t\t\t\t\tapproximateBytes: MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES,\n\t\t\t\t};\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\tenablingSettled?.();\n\t\t\t\tlogger?.info(\n\t\t\t\t\t`memory models missing (${modelsMissing}); download waits for user consent (memory_enable tool)`,\n\t\t\t\t);\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// 服务路径不下载 (模型归服务所有); 该日志只属于本地装配的下载分支。\n\t\t\tif (modelsMissing !== undefined && !serviceModelsDeclared) {\n\t\t\t\tlogger?.info(`memory enabling: model files missing (${modelsMissing}); downloading via configured mirrors`);\n\t\t\t}\n\t\t\t// 服务装配路径 (Slice B2, 裁决 C「根治」): 模型在位且无本地装配测试缝时,\n\t\t\t// 装配经共享推理服务 — 模型与索引全机一份 (主会话 + 全部 subagent 共享),\n\t\t\t// 本进程零重依赖加载。失败按 enabling failed 呈现 (裁决 A: 不回退本地\n\t\t\t// 装配 — 回退即重开多进程风险)。loadImpl 缝走下方本地装配路径 (既有语义)。\n\t\t\tconst useInferenceService = (modelsMissing === undefined || serviceModelsDeclared) && !hasEnablingTestSeam;\n\t\t\tif (useInferenceService) {\n\t\t\t\t// 端口解析也走结构化失败: 非法 env 值若在此裸抛, vectorInitPromise\n\t\t\t\t// 直接 reject 且 failEnabling 不运行 — 状态机被钉死在 enabling,\n\t\t\t\t// 写路径 (fire-and-forget) 还会丢成 unhandled rejection。\n\t\t\t\tlet servicePort: number;\n\t\t\t\ttry {\n\t\t\t\t\tservicePort = inferenceServicePort ?? resolveMemoryInferencePort(undefined, process.env);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`inference service assembly failed (invalid ${MEMORY_INFERENCE_PORT_ENV}: ${\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t\t})`,\n\t\t\t\t\t\tserviceFailureActionList(MEMORY_INFERENCE_DEFAULT_PORT),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlet client: MemoryInferenceClientV1 | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tclient = await ensureInferenceServiceChannel({\n\t\t\t\t\t\tagentDir,\n\t\t\t\t\t\tmemoryMode,\n\t\t\t\t\t\tport: servicePort,\n\t\t\t\t\t\t...(inferenceServiceSpawnImpl === undefined ? {} : { spawnImpl: inferenceServiceSpawnImpl }),\n\t\t\t\t\t});\n\t\t\t\t\t// agentDir 身份校验 (2026-10-06 串线修复): 固定端口单例服务可能\n\t\t\t\t\t// 属于另一个 --agent-dir 的会话 (hello 此前只回报模型身份, 后连\n\t\t\t\t\t// 者握手/冒烟全过却把读写投影进对方的 LanceDB)。在冒烟与档位比\n\t\t\t\t\t// 对之前先核对身份 — 不一致或缺失都绝不触碰该服务。\n\t\t\t\t\tconst helloAgentDir: string | undefined = client.hello.agentDir;\n\t\t\t\t\tif (helloAgentDir === undefined) {\n\t\t\t\t\t\tclient.close().catch(() => undefined);\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service on port ${servicePort} reports no agent-dir identity — the service was started by an older version; wait for its idle exit or stop it manually, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (normalizeMemoryAgentDirIdentity(helloAgentDir) !== normalizeMemoryAgentDirIdentity(agentDir)) {\n\t\t\t\t\t\tclient.close().catch(() => undefined);\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service on port ${servicePort} belongs to agent-dir ${helloAgentDir}, this session runs in ${agentDir} — its memory projection lives in another agent-dir; wait for its idle exit or stop it manually, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst channel: ActiveVectorChannelV1 = {\n\t\t\t\t\t\tembed: client.embedProvider,\n\t\t\t\t\t\treranker: client.reranker,\n\t\t\t\t\t\tindex: client.vectorIndex,\n\t\t\t\t\t\tqueryPrefix: preset.queryPrefix,\n\t\t\t\t\t\tembeddingModelId: client.hello.embeddingModelId,\n\t\t\t\t\t};\n\t\t\t\t\t// 冒烟经 wire (服务端首次 embed 完成模型加载, 预算放宽)。\n\t\t\t\t\tawait channel.embed.embed([\"memory enabling smoke test\"]);\n\t\t\t\t\tif (client.hello.embeddingModelId !== preset.embeddingModelId) {\n\t\t\t\t\t\tclient.close().catch(() => undefined);\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service runs embedding model ${client.hello.embeddingModelId}, session preset is ${preset.embeddingModelId} — the service was spawned for another memory tier; wait for its idle exit or stop it, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst storedModelId = await channel.index.getStoredModelId();\n\t\t\t\t\tif (storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {\n\t\t\t\t\t\tlogger?.warn(\n\t\t\t\t\t\t\t`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t// dispose 竞态: teardown 已清引用 (capabilityDisposed) 时, 装配成功\n\t\t\t\t\t// 分支不得把新 IPC 连接赋回去——关闭它并落结构化失败, 让在途的\n\t\t\t\t\t// enablingOutcome() 等待者 (如 memory-preheat) 落定为失败而非悬挂。\n\t\t\t\t\tif (capabilityDisposed) return failEnablingDisposed(client.close());\n\t\t\t\t\tinferenceClient = client;\n\t\t\t\t\tvectorChannel = channel;\n\t\t\t\t\tvectorState = \"ready\";\n\t\t\t\t\tlogger?.info(\n\t\t\t\t\t\t`memory ready via shared inference service (mode=${memoryMode}, embedding=${preset.embeddingModelId})`,\n\t\t\t\t\t);\n\t\t\t\t\tenablingSettled?.();\n\t\t\t\t\treturn channel;\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// 连接已建立后的失败 (冒烟/档位比对/getStoredModelId) 必须关掉\n\t\t\t\t\t// 客户端: 悬挂连接会让服务端 connections>0, 空闲自杀永不触发。\n\t\t\t\t\tclient?.close().catch(() => undefined);\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`inference service assembly failed (${error instanceof Error ? error.message : String(error)})`,\n\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 检查 3: 磁盘余量 (light ≥ 500MB / full ≥ 2GB)。服务装配路径不下载, 已在上面 return。\n\t\t\tconst diskProblem = await diskHeadroomCheck(agentDir, DISK_HEADROOM_MIN_BYTES[memoryMode]);\n\t\t\tif (diskProblem !== undefined) return failEnabling(diskProblem);\n\t\t\t// dispose 竞态 (本地装配路径, 第一道): 已 teardown 就不再打开 LanceDB/\n\t\t\t// 拉起重依赖; 装配完成点还有第二道检查兜住模型下载窗口。\n\t\t\tif (capabilityDisposed) return failEnablingDisposed(Promise.resolve());\n\t\t\t// 加载: transformers/lancedb 的动态 import 都在这些模块内部, 这里只做\n\t\t\t// 模块级懒加载, 保持未触发会话零重依赖。进度周期性落一行 (下载可达\n\t\t\t// 数百 MB), 完成后清除。\n\t\t\tconst progressTimer = setInterval(() => {\n\t\t\t\tlogger?.info(\"memory enabling still in progress (downloading/loading models)\");\n\t\t\t}, ENABLING_PROGRESS_LOG_INTERVAL_MS);\n\t\t\tif (typeof progressTimer === \"object\" && \"unref\" in progressTimer) progressTimer.unref();\n\t\t\ttry {\n\t\t\t\tconst [vectorIndexModule, embeddingModule, rerankerModule] = await Promise.all([\n\t\t\t\t\timport(\"./vector-index.ts\"),\n\t\t\t\t\timport(\"./embedding-provider.ts\"),\n\t\t\t\t\timport(\"./embedding-reranker.ts\"),\n\t\t\t\t]);\n\t\t\t\tconst index = await vectorIndexModule.createMemoryVectorIndex({\n\t\t\t\t\tdbPath: join(agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\t\t\tdimensions: preset.dimensions,\n\t\t\t\t\t...(hostLancedbEntryPath === undefined ? {} : { moduleEntryPath: hostLancedbEntryPath }),\n\t\t\t\t});\n\t\t\t\tconst remoteHosts = remoteHostsForEnabling();\n\t\t\t\tconst channel: ActiveVectorChannelV1 = {\n\t\t\t\t\tembed: embeddingModule.createTransformersEmbeddingProvider({\n\t\t\t\t\t\tmodelId: preset.embeddingModelId,\n\t\t\t\t\t\tdimensions: preset.dimensions,\n\t\t\t\t\t\tcacheDir: modelCacheDir,\n\t\t\t\t\t\tremoteHosts,\n\t\t\t\t\t\t...(hostTransformersEntryPath === undefined ? {} : { moduleEntryPath: hostTransformersEntryPath }),\n\t\t\t\t\t\t...(enablingOverride?.embeddingLoadImpl === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { loadImpl: enablingOverride.embeddingLoadImpl }),\n\t\t\t\t\t}),\n\t\t\t\t\treranker: rerankerModule.createTransformersReranker({\n\t\t\t\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\t\t\t\tcacheDir: modelCacheDir,\n\t\t\t\t\t\tremoteHosts,\n\t\t\t\t\t\t...(hostTransformersEntryPath === undefined ? {} : { moduleEntryPath: hostTransformersEntryPath }),\n\t\t\t\t\t\t...(enablingOverride?.rerankerLoadImpl === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { loadImpl: enablingOverride.rerankerLoadImpl }),\n\t\t\t\t\t}),\n\t\t\t\t\tindex,\n\t\t\t\t\tqueryPrefix: preset.queryPrefix,\n\t\t\t\t\tembeddingModelId: preset.embeddingModelId,\n\t\t\t\t};\n\t\t\t\t// 冒烟: embed + rerank 各一条 (同时完成两个模型的下载与加载) +\n\t\t\t\t// 投影档位比对。rerank 冒烟 2026-10-06 live E2E 补齐: reranker\n\t\t\t\t// 懒加载, 只 embed 的冒烟会让 \"ready\" 携带未下载的精排权重 —\n\t\t\t\t// 共享推理服务 (两项文件均前置检查、永不自主下载) 对该会话拒启,\n\t\t\t\t// \"fully usable\" 的自述与服务前置条件必须一致。\n\t\t\t\tawait channel.embed.embed([\"memory enabling smoke test\"]);\n\t\t\t\tif (channel.embed.modelId !== preset.embeddingModelId) {\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`smoke check failed: embedding modelId ${channel.embed.modelId} does not match the ${memoryMode} preset ${preset.embeddingModelId}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (channel.reranker !== undefined) {\n\t\t\t\t\tawait channel.reranker.rerank(\"memory enabling smoke test\", [\"memory enabling smoke test\"]);\n\t\t\t\t}\n\t\t\t\tconst storedModelId = await channel.index.getStoredModelId();\n\t\t\t\tif (storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {\n\t\t\t\t\tlogger?.warn(\n\t\t\t\t\t\t`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// dispose 竞态 (本地装配路径, 第二道, 兜住模型下载窗口): 不把索引句柄\n\t\t\t\t// 赋回引用——关闭刚打开的 LanceDB 并落结构化失败。\n\t\t\t\tif (capabilityDisposed) return failEnablingDisposed(channel.index.close());\n\t\t\t\tvectorChannel = channel;\n\t\t\t\tvectorState = \"ready\";\n\t\t\t\tlogger?.info(`memory ready (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);\n\t\t\t\tenablingSettled?.();\n\t\t\t\treturn channel;\n\t\t\t} catch (error) {\n\t\t\t\treturn failEnabling(\n\t\t\t\t\t`model load or smoke check failed (${error instanceof Error ? error.message : String(error)})`,\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tclearInterval(progressTimer);\n\t\t\t}\n\t\t})();\n\t\treturn vectorInitPromise;\n\t};\n\n\t// ---- 征询门执行面 (2026-10-05 用户裁决「首次使用征询、拒绝/失败可跳过」) ----\n\t// memory_enable 是 consent-required / failed 态的唯一下载入口: consentGranted\n\t// 只在这里置位, recall/auto-recall 永不触发下载。decline 同时持久化\n\t// (writeMemoryConsentDeclined), 只抑制默认档——用户显式设置 memory.mode 后\n\t// 下次启用会在首次使用时再次走到征询门。\n\t// ---- 记忆模型下载控制面 (2026-10-05 流程裁决「后台预热、不阻塞提问」) ----\n\t// 生产入口 (交互模式会话绑定后) 经公共工具面调用 memory_enable download\n\t// 触发后台预热; 命令面 /memory off|retry 是用户的直接出口。两处共用同一对\n\t// 闭包; decline 持久化只抑制默认档。\n\tconst declineMemory = (): { status: \"completed\"; message: string } => {\n\t\t// 总是落盘 (幂等写): 升降档会清理文件里的拒绝标记, 之后再次 off 必须\n\t\t// 重新写入——不能用内存 flag 跳过持久化。\n\t\tconst firstDecline = !consentDeclined;\n\t\tconsentDeclined = true;\n\t\twriteMemoryConsentDeclined(agentDir);\n\t\tif (firstDecline) {\n\t\t\tlogger?.info(\"memory disabled by user decision (persisted to the memory agent-dir config)\");\n\t\t}\n\t\treturn {\n\t\t\tstatus: \"completed\",\n\t\t\tmessage:\n\t\t\t\t\"memory disabled for this machine (persisted). Set memory.mode (light|full) in settings.json and restart the session to re-enable\",\n\t\t};\n\t};\n\tconst downloadMemory = async (): Promise<\n\t\t| { status: \"completed\"; message: string }\n\t\t| { status: \"failed\"; message: string; actions?: readonly string[]; next?: string }\n\t> => {\n\t\tif (consentDeclined) {\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"memory was declined on this machine — set memory.mode (light|full) in settings.json and restart the session to re-enable\",\n\t\t\t};\n\t\t}\n\t\tconsentGranted = true;\n\t\tif (vectorState === \"failed\" || vectorState === \"consent-required\") {\n\t\t\tvectorState = \"enabling\";\n\t\t\tenablingFailure = undefined;\n\t\t\tvectorInitPromise = undefined;\n\t\t}\n\t\tconst channel = await vectorEnsure();\n\t\tif (channel === undefined) {\n\t\t\tconst failure = enablingFailure ?? {\n\t\t\t\treason: `memory enabling did not complete (state=${vectorState})`,\n\t\t\t\tactions: [] as const,\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `memory enabling failed: ${failure.reason}`,\n\t\t\t\tactions: failure.actions,\n\t\t\t\tnext: 'Tell the user the download failed and ask whether to skip memory (call memory_enable with action \"decline\" or /memory off — both persist off) or fix the environment and retry (/memory retry)',\n\t\t\t};\n\t\t}\n\t\t// 就绪: 补跑启动对账, 把预热期间写入的 ledger 记忆补进向量投影。\n\t\tresetReconcile();\n\t\treconcileOnce();\n\t\treturn { status: \"completed\", message: \"memory models ready — the memory family is fully usable\" };\n\t};\n\n\t// 会话切换重绑/插件卸载的共享资源释放 (TUI 每次会话切换都重走装配, 不释放\n\t// 即每次泄漏一条 IPC 连接: 服务端 connections>0 抑制空闲自杀, 嵌入方进程因\n\t// socket 未关无法自然退出)。清引用先行: close 的 reject 兜底 warn 一行, 且\n\t// 二次调用因引用已空自然 no-op。服务路径与本地路径互斥 (服务路径的 index\n\t// 归服务进程持有, 客户端只断连; 本地路径才关 LanceDB 句柄)。\n\t// capabilityDisposed 是 teardown 与在途 enabling 的竞态闩锁: teardown 之后\n\t// 才完成的装配在成功分支让位 (见 vectorEnsure 的 failEnablingDisposed),\n\t// 不复活无人关闭的连接/句柄。\n\tlet capabilityDisposed = false;\n\tconst capabilityTeardown = (): void => {\n\t\tcapabilityDisposed = true;\n\t\tif (inferenceClient !== undefined) {\n\t\t\tconst client = inferenceClient;\n\t\t\tinferenceClient = undefined;\n\t\t\tvectorChannel = undefined;\n\t\t\tvoid client.close().catch((error: unknown) => {\n\t\t\t\tlogger?.warn(\n\t\t\t\t\t`memory inference client close failed: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\t\tif (vectorChannel !== undefined) {\n\t\t\tconst channel = vectorChannel;\n\t\t\tvectorChannel = undefined;\n\t\t\tvoid channel.index.close().catch((error: unknown) => {\n\t\t\t\tlogger?.warn(`memory vector index close failed: ${error instanceof Error ? error.message : String(error)}`);\n\t\t\t});\n\t\t}\n\t};\n\n\treturn {\n\t\tstate: (): \"off\" | MemoryCapabilityStateV1 => (consentDeclined ? \"off\" : vectorState),\n\t\trawState: (): MemoryCapabilityStateV1 => vectorState,\n\t\tenabled: vectorEnabled,\n\t\treadyChannel: (): ActiveVectorChannelV1 | undefined => vectorChannel,\n\t\tisDisposed: (): boolean => capabilityDisposed,\n\t\tdeclined: (): boolean => consentDeclined,\n\t\tclearDeclined: (): void => {\n\t\t\tconsentDeclined = false;\n\t\t},\n\t\tconsentAsked: (): boolean => consentAsked,\n\t\tmarkConsentAsked: (): void => {\n\t\t\tconsentAsked = true;\n\t\t},\n\t\tprimeConsentGate,\n\t\tconsentAsk: (): MemoryConsentAskV1 | undefined =>\n\t\t\tvectorState === \"consent-required\" && consentNeededInfo !== undefined\n\t\t\t\t? { message: consentAskMessage(), actions: consentAskActions(), block: consentAskBlock() }\n\t\t\t\t: undefined,\n\t\twarming: (): boolean => vectorState === \"enabling\" && vectorInitPromise !== undefined && !consentDeclined,\n\t\tfailure: (): MemoryEnablingFailureV1 | undefined => enablingFailure,\n\t\tmarkDegraded: (): void => {\n\t\t\tvectorState = \"degraded\";\n\t\t},\n\t\trecoverDegraded: (): void => {\n\t\t\tif (vectorState === \"degraded\") vectorState = \"ready\";\n\t\t},\n\t\tensure: vectorEnsure,\n\t\tenablingOutcome: async (): Promise<\"ready\" | MemoryEnablingFailureV1> => {\n\t\t\tif (vectorState === \"enabling\") void vectorEnsure();\n\t\t\tawait enablingSettledPromise;\n\t\t\treturn enablingFailure ?? \"ready\";\n\t\t},\n\t\tdecline: declineMemory,\n\t\tdownload: downloadMemory,\n\t\tdispose: capabilityTeardown,\n\t};\n}\n"]}
1
+ {"version":3,"file":"vector-channel.js","sourceRoot":"","sources":["../../src/memory/vector-channel.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 向量通道状态机(capability 拆分战役 slice 3b):vectorEnsure 状态转换、装配分支(服务/本地/下载/征询门)、dispose 闩锁。共享闭包状态收拢为 channel 对象, 经 deps 显式注入; 降级/投影经 slice 3a 的 vector-projection 上报\n */\n\nimport { join } from \"node:path\";\nimport type {\n\tCapabilityAPI,\n\tMemoryEnablingOverrideV1,\n\tMemoryVectorComponentsOverrideV1,\n} from \"@agent-forge/plugin-sdk\";\nimport {\n\tDISK_HEADROOM_MIN_BYTES,\n\tdiskHeadroomCheck,\n\tenablingActionList,\n\tMODEL_MIN_WEIGHT_BYTES,\n\tmissingHeavyDependencyModules,\n\tmodelFilesCheck,\n\tnativeBinaryCheck,\n\tnormalizeMemoryAgentDirIdentity,\n\tRERANKER_MIN_WEIGHT_BYTES,\n\tremoteHostsForEnabling,\n\tresolveHeavyDependencyEntryPath,\n\tvectorPresetForMode,\n\twriteMemoryConsentDeclined,\n} from \"./enabling.ts\";\nimport { ensureInferenceServiceChannel, serviceFailureActionList } from \"./inference-channel.ts\";\nimport { type MemoryInferenceClientV1, resolveMemoryInferencePort } from \"./inference-client.ts\";\nimport { MEMORY_INFERENCE_DEFAULT_PORT, MEMORY_INFERENCE_PORT_ENV } from \"./inference-protocol.ts\";\nimport type { ActiveVectorChannelV1 } from \"./vector-projection.ts\";\n\n/** enabling 加载/下载期间的周期性进度日志间隔。 */\nconst ENABLING_PROGRESS_LOG_INTERVAL_MS = 15_000;\n\n// 宿主先撤销 CapabilityAPI 再调用 disposer。清理诊断不得依赖已撤销的 logger,\n// 也不得因诊断输出失败而中断其他资源释放或替换原始装配错误。\nfunction reportCleanupFailure(resource: string, error: unknown): void {\n\ttry {\n\t\tconsole.error(`memory ${resource} close failed`, error);\n\t} catch {\n\t\t// 诊断接收端不可用不改变资源生命周期。\n\t}\n}\n\nfunction closeResource(resource: string, close: () => unknown): Promise<void> {\n\treturn Promise.resolve()\n\t\t.then(close)\n\t\t.then(() => undefined)\n\t\t.catch((error: unknown) => reportCleanupFailure(resource, error));\n}\n\n/** 两档共用精排模型 (POC 报告 §8: 官方 Xenova 转换版唯一实测可用)。 */\nexport const VECTOR_RERANKER_MODEL_ID = \"Xenova/bge-reranker-base\";\nexport const VECTOR_DB_DIRNAME = \"vector\";\nexport const VECTOR_MODEL_CACHE_DIRNAME = \"model-cache\";\n\n/** capability 级状态机 (设计 §3.2): off 只出现在模式关闭 (零注册, 不可观测)。 */\nexport type MemoryCapabilityStateV1 = \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\n/** enabling 失败的结构化结果: 原因 + 行动清单 (硬性要求, 设计 §3.2)。 */\nexport interface MemoryEnablingFailureV1 {\n\treadonly reason: string;\n\treadonly actions: readonly string[];\n}\n\n/**\n * 征询门待决信息 (2026-10-05 用户裁决「首次使用征询、拒绝即持久化关闭」):\n * 向量通道从未就绪且模式已启用时, 模型下载必须先经用户同意——检索不触发下载,\n * 由 AI 转述征询后经 memory_enable 工具面继续。\n */\nexport interface MemoryConsentNeededV1 {\n\treadonly models: readonly string[];\n\t/** 模型权重体积下限之和 (非精确体积; 实际下载量以镜像文件为准)。 */\n\treadonly approximateBytes: number;\n}\n\n/** 征询面 (consent-required 态的模型可见包): AI 转述话术 + 后续动作 + 注入块。 */\nexport interface MemoryConsentAskV1 {\n\treadonly message: string;\n\treadonly actions: readonly string[];\n\treadonly block: string;\n}\n\n/**\n * 向量通道对 capability 装配上下文的显式依赖视图 (slice 3b): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实, 不再经共享闭包隐式可达。\n */\nexport interface MemoryVectorChannelDepsV1 {\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 模型缓存/索引/征询持久化的路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** capability 日志面 (api.logger): 进度/失败/自愈日志。 */\n\treadonly logger: CapabilityAPI[\"logger\"];\n\t/** 宿主注入的 onnxruntime-node 入口 (MemoryCapabilityContext.hostOnnxRuntimeEntryPath)。 */\n\treadonly hostOnnxRuntimeEntryPath?: string;\n\t/** 宿主注入的 @lancedb/lancedb 入口 (MemoryCapabilityContext.hostLancedbEntryPath)。 */\n\treadonly hostLancedbEntryPath?: string;\n\t/** 宿主注入的 @huggingface/transformers 入口 (MemoryCapabilityContext.hostTransformersEntryPath)。 */\n\treadonly hostTransformersEntryPath?: string;\n\t/** 服务装配缝 (Slice B2): 测试端口直连 (MemoryCapabilityContext.inferenceService.port)。 */\n\treadonly inferenceServicePort?: number;\n\t/** 服务装配缝 (Slice B2): 替换进程拉起的测试缝 (inferenceService.spawnImpl)。 */\n\treadonly inferenceServiceSpawnImpl?: (\n\t\tagentDir: string,\n\t\tmode: \"light\" | \"full\",\n\t\tport: number,\n\t\t/** spawn 异步失败 (EACCES/ENOMEM 等) 的回调; 缺省实现经 child 'error' 事件馈入。 */\n\t\tonError?: (error: Error) => void,\n\t) => Promise<void>;\n\t/** 服务装配缝 (Slice B2): 声明模型在位, 文件检查与征询门让位 (inferenceService.modelsInPlace)。 */\n\treadonly inferenceServiceModelsInPlace?: boolean;\n\t/** enabling 测试缝 (loadImpl 重定向模型加载); undefined = 生产路径。 */\n\treadonly enablingOverride?: MemoryEnablingOverrideV1;\n\t/** 组件注入 (deterministic mock 门禁): 存在时通道直接 ready, 跳过真实装配。 */\n\treadonly injectedComponents?: MemoryVectorComponentsOverrideV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection.resetReconcile): downloadMemory 就绪后重臂启动对账。 */\n\treadonly resetReconcile: () => void;\n\t/** 写侧投影 (slice 3a 的 vectorProjection.reconcileOnce): downloadMemory 就绪后补跑对账。 */\n\treadonly reconcileOnce: () => void;\n}\n\nexport interface MemoryVectorChannelV1 {\n\t/** harness.vectorState 面: 征询拒绝时投影为 \"off\" (本实例按模式关闭对待)。 */\n\tstate(): \"off\" | MemoryCapabilityStateV1;\n\t/** vectorState 原值 (未做 declined 投影; recall/合并探测等内部消费)。 */\n\trawState(): MemoryCapabilityStateV1;\n\t/** vectorEnabled: failed/consent-required/declined 时 false (写侧埋点门)。 */\n\tenabled(): boolean;\n\t/** 已就绪通道的同步快照 (vectorChannel 只读; projection.readyChannel 面)。 */\n\treadyChannel(): ActiveVectorChannelV1 | undefined;\n\t/** dispose 闩锁只读视图 (capabilityDisposed; projection.isDisposed 面)。 */\n\tisDisposed(): boolean;\n\t/** 征询拒绝标记 (declineMemory 持久化后的本实例内存面)。 */\n\tdeclined(): boolean;\n\t/** 用户显式再启用 (/memory light|full、自动升档) 清除本实例拒绝标记。 */\n\tclearDeclined(): void;\n\t/** 征询一次性注入钉住标记 (auto-recall 每实例只注入一次)。 */\n\tconsentAsked(): boolean;\n\tmarkConsentAsked(): void;\n\t/** 无副作用征询探测 (auto-recall 首轮; 纯本地 stat, 绝不触发下载/加载)。 */\n\tprimeConsentGate(): void;\n\t/** 征询待决面 (consent-required 且待决信息就位时非 undefined; 纯只读, 不探测)。 */\n\tconsentAsk(): MemoryConsentAskV1 | undefined;\n\t/** warming 守卫 (recall 后台预热不阻塞读侧): 装配在途且未拒绝。 */\n\twarming(): boolean;\n\t/** enabling 失败结构化结果 (未失败 = undefined)。 */\n\tfailure(): MemoryEnablingFailureV1 | undefined;\n\t/** 运行期故障 → degraded (可自愈; recall 与投影对账共用)。 */\n\tmarkDegraded(): void;\n\t/** degraded → ready 的自愈转换 (仅从 degraded; 全通 recall 成功后调用)。 */\n\trecoverDegraded(): void;\n\t/** vectorEnsure: 惰性单飞装配 (recall/write/埋点/对账的公共入口)。 */\n\tensure(): Promise<ActiveVectorChannelV1 | undefined>;\n\t/** harness.enablingOutcome 面: 触发惰性 enabling 并等待落定 (ready 或结构化失败)。 */\n\tenablingOutcome(): Promise<\"ready\" | MemoryEnablingFailureV1>;\n\t/** declineMemory 核心: 持久化拒绝 + 本实例按模式关闭。 */\n\tdecline(): { status: \"completed\"; message: string };\n\t/** downloadMemory 核心: 置征询同意 + 装配 + 补跑启动对账。 */\n\tdownload(): Promise<\n\t\t| { status: \"completed\"; message: string }\n\t\t| { status: \"failed\"; message: string; actions?: readonly string[]; next?: string }\n\t>;\n\t/** capabilityTeardown 本体: 资源关闭 + 闩锁置位 (幂等)。 */\n\tdispose(): void;\n}\n\nexport function createMemoryVectorChannel(deps: MemoryVectorChannelDepsV1): MemoryVectorChannelV1 {\n\tconst {\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tlogger,\n\t\thostOnnxRuntimeEntryPath,\n\t\thostLancedbEntryPath,\n\t\thostTransformersEntryPath,\n\t\tinferenceServicePort,\n\t\tinferenceServiceSpawnImpl,\n\t\tinferenceServiceModelsInPlace,\n\t\tenablingOverride,\n\t\tinjectedComponents,\n\t\tresetReconcile,\n\t\treconcileOnce,\n\t} = deps;\n\t// ---- 语义召回通道 (2.4d6 S1/S2; 召回唯一检索路径) ----\n\t// 状态机 (设计 §3.2): enabling = 检查/加载进行中 (惰性触发: 首次向量操作\n\t// 时真正执行); ready = 可用; degraded = ready 后运行期故障 (可自愈回\n\t// ready); failed = enabling 失败, 本实例内终态 (mode 回退 off, 记忆工具\n\t// 返回携带行动清单的不可用 packet, 不再重试)。所有写侧操作经 vectorQueue\n\t// 串行化, 避免 reconcile 与写入埋点在 LanceDB 建表上竞态; recall 等待\n\t// enabling 单飞完成, 不与后台对账并发读索引。transformers/lancedb 的动态\n\t// import 只出现在 vectorEnsure 的装配分支里 (type-position 引类型), 未\n\t// 触发时不加载任何重依赖。\n\tlet vectorState: MemoryCapabilityStateV1 = \"enabling\";\n\tlet vectorChannel: ActiveVectorChannelV1 | undefined;\n\tlet enablingFailure: MemoryEnablingFailureV1 | undefined;\n\tlet enablingSettled: (() => void) | undefined;\n\t// 征询门 (2026-10-05 用户裁决「首次使用征询、拒绝即持久化关闭」): 模型文件\n\t// 缺失时下载必须先经用户同意——consentGranted 只由 memory_enable 工具面置位;\n\t// consentDeclined = 本实例内用户拒绝/跳过 (同时持久化, 见\n\t// writeMemoryConsentDeclined), 之后本实例按模式关闭对待; consentAsked 钉住\n\t// 自动召回的一次性征询注入, 不随查询文本翻新。\n\tlet consentGranted = false;\n\tlet consentDeclined = false;\n\tlet consentAsked = false;\n\tlet consentNeededInfo: MemoryConsentNeededV1 | undefined;\n\tconst enablingSettledPromise = new Promise<\"ready\" | MemoryEnablingFailureV1>((resolve) => {\n\t\tenablingSettled = () => resolve(enablingFailure ?? \"ready\");\n\t});\n\tif (injectedComponents !== undefined) {\n\t\t// 测试注入: 直接 ready, 跳过真实装配与档位解析。\n\t\tvectorState = \"ready\";\n\t\tvectorChannel = {\n\t\t\tembed: injectedComponents.embedProvider,\n\t\t\treranker: injectedComponents.reranker,\n\t\t\tindex: injectedComponents.vectorIndex,\n\t\t\tqueryPrefix: injectedComponents.queryPrefix ?? \"\",\n\t\t\tembeddingModelId: injectedComponents.embedProvider.modelId,\n\t\t};\n\t\tenablingSettled?.();\n\t}\n\tconst vectorEnabled = (): boolean =>\n\t\tvectorState !== \"failed\" && vectorState !== \"consent-required\" && !consentDeclined;\n\t// 尚未发布的本地资源也归本实例拥有;teardown 立即标记 provider 关闭。\n\tlet closeOwnedLocalResources: (() => Promise<void>) | undefined;\n\tconst closeLocalChannel = async (channel: ActiveVectorChannelV1): Promise<void> => {\n\t\tconst results = await Promise.allSettled([\n\t\t\tPromise.resolve().then(() => channel.index.close()),\n\t\t\t(async () => channel.embed.dispose?.())(),\n\t\t\t(async () => channel.reranker?.dispose?.())(),\n\t\t]);\n\t\tconst resources = [\"vector index\", \"embedding provider\", \"reranker\"];\n\t\tfor (const [index, result] of results.entries()) {\n\t\t\tif (result.status === \"rejected\") reportCleanupFailure(resources[index]!, result.reason);\n\t\t}\n\t};\n\t// 征询话术 (AI 转述给用户; 会话语言由 AI 决定): 模型清单 + 体积下限 + 两个\n\t// 后续动作。consent-required 态下的 recall packet、auto-recall 注入块共用。\n\tconst consentAskMessage = (): string => {\n\t\tconst info = consentNeededInfo;\n\t\tconst models = info === undefined ? \"embedding + reranker\" : info.models.join(\" + \");\n\t\tconst floorMb = Math.ceil(\n\t\t\t(info?.approximateBytes ?? MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES) / (1024 * 1024),\n\t\t);\n\t\treturn (\n\t\t\t`memory needs a one-time model download (${models}, at least ${floorMb} MB total; ` +\n\t\t\t\"actual sizes come from the mirror) into <agentDir>/memory/model-cache before recall can run — \" +\n\t\t\t\"nothing downloads without user consent\"\n\t\t);\n\t};\n\tconst consentAskActions = (): readonly string[] => [\n\t\t\"Ask the user whether to download the memory models now\",\n\t\t'With consent, call memory_enable with action \"download\"',\n\t\t'If the user declines, call memory_enable with action \"decline\" (persists memory off; set memory.mode in settings.json later to re-enable)',\n\t];\n\tconst consentAskBlock = (): string =>\n\t\t[\n\t\t\t\"<memory_setup>\",\n\t\t\tconsentAskMessage(),\n\t\t\t\"Ask the user (in the conversation language) whether to download now; relay that it is one-time and the size.\",\n\t\t\t...consentAskActions()\n\t\t\t\t.slice(1)\n\t\t\t\t.map((line) => `- ${line}`),\n\t\t\t\"</memory_setup>\",\n\t\t].join(\"\\n\");\n\t// 无副作用探测: 初始态是 enabling, 而征询态只在 vectorEnsure 探测后落定——\n\t// 自动召回钩子首轮就要给出征询注入, 这里只做模型文件存在性检查 (纯本地\n\t// stat), 缺失即落定 consent-required, 绝不触发下载/加载。\n\tconst primeConsentGate = (): void => {\n\t\tif (consentGranted || consentDeclined || vectorState !== \"enabling\") return;\n\t\tif (\n\t\t\tenablingOverride?.embeddingLoadImpl !== undefined ||\n\t\t\tenablingOverride?.rerankerLoadImpl !== undefined ||\n\t\t\t// 服务装配缝的模型声明 (Slice B2): 与 vectorEnsure 装配分支同一豁免 —\n\t\t\t// 声明在位时文件检查让位, 征询门不应被 auto-recall 钩子提前翻起。\n\t\t\tinferenceServiceModelsInPlace === true\n\t\t) {\n\t\t\treturn;\n\t\t}\n\t\tconst preset = vectorPresetForMode(memoryMode);\n\t\tconst modelCacheDir = join(agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\t\tconst modelsMissing =\n\t\t\tmodelFilesCheck(modelCacheDir, preset.embeddingModelId, MODEL_MIN_WEIGHT_BYTES[memoryMode]) === \"missing\" ||\n\t\t\tmodelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES) === \"missing\";\n\t\tif (!modelsMissing) return;\n\t\tvectorState = \"consent-required\";\n\t\tconsentNeededInfo = {\n\t\t\tmodels: [\n\t\t\t\tpreset.embeddingModelId,\n\t\t\t\t...(modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES) === \"missing\"\n\t\t\t\t\t? [VECTOR_RERANKER_MODEL_ID]\n\t\t\t\t\t: []),\n\t\t\t],\n\t\t\tapproximateBytes: MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES,\n\t\t};\n\t};\n\tlet vectorInitPromise: Promise<ActiveVectorChannelV1 | undefined> | undefined;\n\n\t/**\n\t * 开启状态机 (设计 §3.2, 惰性单飞): 本地检查 (native .node 可解析 → 重依赖\n\t * 供给 (lancedb/transformers: 宿主入口路径或插件位置自解析) → 模型文件存在\n\t * 与大小 → 磁盘余量) → transformers 加载 (自带下载, 进度周期性\n\t * 落一行日志) → 冒烟 (embed 一条 + getStoredModelId 与档位比对) → ready。\n\t * 任一步失败 → failed (原因 + 五选一行动清单), mode 记录回退 off, 本实例\n\t * 不再重试。\n\t */\n\t/** 服务模式持有的 IPC 客户端 (断连自愈检测用; 本地装配路径恒 undefined)。 */\n\tlet inferenceClient: MemoryInferenceClientV1 | undefined;\n\n\tconst vectorEnsure = (): Promise<ActiveVectorChannelV1 | undefined> => {\n\t\tif (capabilityDisposed) {\n\t\t\tvectorState = \"failed\";\n\t\t\tenablingFailure ??= { reason: \"capability disposed during enabling\", actions: [] };\n\t\t\tenablingSettled?.();\n\t\t\treturn Promise.resolve(undefined);\n\t\t}\n\t\tif (vectorState === \"ready\" || vectorState === \"degraded\") {\n\t\t\t// 服务模式断连自愈 (Slice B2): 缓存 channel 背后的 IPC 客户端死亡时\n\t\t\t// 清缓存重走装配 (重连 + 必要时重拉起服务), 而不是拿着死连接报错。\n\t\t\tif (inferenceClient === undefined || inferenceClient.isAlive()) return Promise.resolve(vectorChannel);\n\t\t\tlogger?.warn(\"memory inference service connection lost; reconnecting\");\n\t\t\tinferenceClient = undefined;\n\t\t\tvectorChannel = undefined;\n\t\t\tvectorState = \"enabling\";\n\t\t\tvectorInitPromise = undefined;\n\t\t}\n\t\tif (vectorState === \"failed\") return Promise.resolve(undefined);\n\t\tif (vectorInitPromise !== undefined) return vectorInitPromise;\n\t\tvectorInitPromise = (async (): Promise<ActiveVectorChannelV1 | undefined> => {\n\t\t\tconst preset = vectorPresetForMode(memoryMode);\n\t\t\tconst modelCacheDir = join(agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\t\t\tconst failEnabling = (\n\t\t\t\treason: string,\n\t\t\t\tactions: readonly string[] = enablingActionList(modelCacheDir, memoryMode),\n\t\t\t): undefined => {\n\t\t\t\tvectorState = \"failed\";\n\t\t\t\tenablingFailure = { reason, actions };\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\tenablingSettled?.();\n\t\t\t\tif (!capabilityDisposed)\n\t\t\t\t\tlogger?.warn(`memory enabling failed: ${reason} — actions: ${enablingFailure.actions.join(\" | \")}`, {\n\t\t\t\t\t\tmode: memoryMode,\n\t\t\t\t\t});\n\t\t\t\treturn undefined;\n\t\t\t};\n\t\t\t// dispose 竞态守卫 (2026-10-06 复审遗留): teardown 与在途 enabling 竞态\n\t\t\t// 时, 装配完成点必须让位——不得把新连接/索引句柄赋回已清空的引用 (那会\n\t\t\t// 复活一条无人关闭的连接: 服务端 connections>0 抑制空闲自杀、挂住嵌入\n\t\t\t// 进程事件循环), 也不得让 enablingOutcome() 等待者悬挂。改为关闭刚取得\n\t\t\t// 的资源并落结构化 failed (MemoryEnablingFailureV1 形状)。\n\t\t\tconst failEnablingDisposed = (closeAcquired?: () => Promise<unknown>): undefined => {\n\t\t\t\tvectorState = \"failed\";\n\t\t\t\tenablingFailure = { reason: \"capability disposed during enabling\", actions: [] };\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\tenablingSettled?.();\n\t\t\t\tif (closeAcquired !== undefined) void closeResource(\"inference client\", closeAcquired);\n\t\t\t\treturn undefined;\n\t\t\t};\n\t\t\tlogger?.info(`memory enabling started (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);\n\t\t\t// 检查 1: native .node sidecar (纯本地, 零网络)。宿主注入路径优先\n\t\t\t// (安装店副本自解析不可达, 见 MemoryCapabilityContext.hostOnnxRuntimeEntryPath)。\n\t\t\tconst nativeProblem = nativeBinaryCheck(hostOnnxRuntimeEntryPath);\n\t\t\tif (nativeProblem !== undefined) return failEnabling(nativeProblem);\n\t\t\t// 检查 1b: 重依赖供给。宿主入口路径优先; 未提供时插件位置自解析,\n\t\t\t// 两者都不可达 = 原本要到加载步才以 \"Cannot find module\" 泛化包装\n\t\t\t// 失败的根因, 前置到模型下载之前以 onnx 缺供分支同构的精准文案报告。\n\t\t\t// 路径已提供但包损坏的真实失败仍走加载步, 由泛化包装保留原始错误。\n\t\t\tconst missingHeavyDependencies = missingHeavyDependencyModules(\n\t\t\t\t{ lancedb: hostLancedbEntryPath, transformers: hostTransformersEntryPath },\n\t\t\t\tresolveHeavyDependencyEntryPath,\n\t\t\t);\n\t\t\tif (missingHeavyDependencies.length > 0) {\n\t\t\t\treturn failEnabling(\n\t\t\t\t\t`${missingHeavyDependencies.join(\", \")} are not provided by the host installation and could not be resolved from the plugin location; to enable memory features, install them in the host project (npm i ${missingHeavyDependencies.join(\" \")}) and restart the session`,\n\t\t\t\t);\n\t\t\t}\n\t\t\t// 检查 2: 模型文件 (缺失 = 进入下载; 存在但截断 = 失败提示手动导入)。\n\t\t\tconst embeddingProblem = modelFilesCheck(\n\t\t\t\tmodelCacheDir,\n\t\t\t\tpreset.embeddingModelId,\n\t\t\t\tMODEL_MIN_WEIGHT_BYTES[memoryMode],\n\t\t\t);\n\t\t\tconst rerankerProblem = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\t\tconst modelsMissing =\n\t\t\t\tembeddingProblem === \"missing\" || rerankerProblem === \"missing\"\n\t\t\t\t\t? `${preset.embeddingModelId}${rerankerProblem === \"missing\" ? ` + ${VECTOR_RERANKER_MODEL_ID}` : \"\"}`\n\t\t\t\t\t: undefined;\n\t\t\tif (embeddingProblem !== undefined && embeddingProblem !== \"missing\") return failEnabling(embeddingProblem);\n\t\t\tif (rerankerProblem !== undefined && rerankerProblem !== \"missing\") return failEnabling(rerankerProblem);\n\t\t\t// 征询门 (2026-10-05 用户裁决): 模型缺失且未经用户同意时不下载, 停在\n\t\t\t// consent-required 态等 memory_enable 工具面继续。注入 loadImpl 的测试\n\t\t\t// 缝绕过本门 (deterministic mock 门禁路径, 无网络语义)。截断文件不走\n\t\t\t// 征询 (文件在 = 曾有过一次下载意图), 仍走失败行动清单。\n\t\t\tconst hasEnablingTestSeam =\n\t\t\t\tenablingOverride?.embeddingLoadImpl !== undefined || enablingOverride?.rerankerLoadImpl !== undefined;\n\t\t\t// 服务装配缝的模型声明 (Slice B2): modelsInPlace = 测试声明模型已在位\n\t\t\t// (免写假权重文件), 文件检查与征询门相应让位; 生产路径缺省 false,\n\t\t\t// 真实文件检查与征询门语义不变。\n\t\t\tconst serviceModelsDeclared = inferenceServiceModelsInPlace === true;\n\t\t\tif (modelsMissing !== undefined && !consentGranted && !hasEnablingTestSeam && !serviceModelsDeclared) {\n\t\t\t\tvectorState = \"consent-required\";\n\t\t\t\tconsentNeededInfo = {\n\t\t\t\t\tmodels: modelsMissing.split(\" + \"),\n\t\t\t\t\tapproximateBytes: MODEL_MIN_WEIGHT_BYTES[memoryMode] + RERANKER_MIN_WEIGHT_BYTES,\n\t\t\t\t};\n\t\t\t\tvectorInitPromise = undefined;\n\t\t\t\tenablingSettled?.();\n\t\t\t\tlogger?.info(\n\t\t\t\t\t`memory models missing (${modelsMissing}); download waits for user consent (memory_enable tool)`,\n\t\t\t\t);\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\t// 服务路径不下载 (模型归服务所有); 该日志只属于本地装配的下载分支。\n\t\t\tif (modelsMissing !== undefined && !serviceModelsDeclared) {\n\t\t\t\tlogger?.info(`memory enabling: model files missing (${modelsMissing}); downloading via configured mirrors`);\n\t\t\t}\n\t\t\t// 服务装配路径 (Slice B2, 裁决 C「根治」): 模型在位且无本地装配测试缝时,\n\t\t\t// 装配经共享推理服务 — 模型与索引全机一份 (主会话 + 全部 subagent 共享),\n\t\t\t// 本进程零重依赖加载。失败按 enabling failed 呈现 (裁决 A: 不回退本地\n\t\t\t// 装配 — 回退即重开多进程风险)。loadImpl 缝走下方本地装配路径 (既有语义)。\n\t\t\tconst useInferenceService = (modelsMissing === undefined || serviceModelsDeclared) && !hasEnablingTestSeam;\n\t\t\tif (useInferenceService) {\n\t\t\t\t// 端口解析也走结构化失败: 非法 env 值若在此裸抛, vectorInitPromise\n\t\t\t\t// 直接 reject 且 failEnabling 不运行 — 状态机被钉死在 enabling,\n\t\t\t\t// 写路径 (fire-and-forget) 还会丢成 unhandled rejection。\n\t\t\t\tlet servicePort: number;\n\t\t\t\ttry {\n\t\t\t\t\tservicePort = inferenceServicePort ?? resolveMemoryInferencePort(undefined, process.env);\n\t\t\t\t} catch (error) {\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`inference service assembly failed (invalid ${MEMORY_INFERENCE_PORT_ENV}: ${\n\t\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t\t})`,\n\t\t\t\t\t\tserviceFailureActionList(MEMORY_INFERENCE_DEFAULT_PORT),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tlet client: MemoryInferenceClientV1 | undefined;\n\t\t\t\ttry {\n\t\t\t\t\tclient = await ensureInferenceServiceChannel({\n\t\t\t\t\t\tagentDir,\n\t\t\t\t\t\tmemoryMode,\n\t\t\t\t\t\tport: servicePort,\n\t\t\t\t\t\t...(inferenceServiceSpawnImpl === undefined ? {} : { spawnImpl: inferenceServiceSpawnImpl }),\n\t\t\t\t\t});\n\t\t\t\t\tif (capabilityDisposed) return failEnablingDisposed(() => client!.close());\n\t\t\t\t\t// agentDir 身份校验 (2026-10-06 串线修复): 固定端口单例服务可能\n\t\t\t\t\t// 属于另一个 --agent-dir 的会话 (hello 此前只回报模型身份, 后连\n\t\t\t\t\t// 者握手/冒烟全过却把读写投影进对方的 LanceDB)。在冒烟与档位比\n\t\t\t\t\t// 对之前先核对身份 — 不一致或缺失都绝不触碰该服务。\n\t\t\t\t\tconst helloAgentDir: string | undefined = client.hello.agentDir;\n\t\t\t\t\tif (helloAgentDir === undefined) {\n\t\t\t\t\t\tvoid closeResource(\"inference client\", () => client!.close());\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service on port ${servicePort} reports no agent-dir identity — the service was started by an older version; wait for its idle exit or stop it manually, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (normalizeMemoryAgentDirIdentity(helloAgentDir) !== normalizeMemoryAgentDirIdentity(agentDir)) {\n\t\t\t\t\t\tvoid closeResource(\"inference client\", () => client!.close());\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service on port ${servicePort} belongs to agent-dir ${helloAgentDir}, this session runs in ${agentDir} — its memory projection lives in another agent-dir; wait for its idle exit or stop it manually, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst channel: ActiveVectorChannelV1 = {\n\t\t\t\t\t\tembed: client.embedProvider,\n\t\t\t\t\t\treranker: client.reranker,\n\t\t\t\t\t\tindex: client.vectorIndex,\n\t\t\t\t\t\tqueryPrefix: preset.queryPrefix,\n\t\t\t\t\t\tembeddingModelId: client.hello.embeddingModelId,\n\t\t\t\t\t};\n\t\t\t\t\t// 冒烟经 wire (服务端首次 embed 完成模型加载, 预算放宽)。\n\t\t\t\t\tawait channel.embed.embed([\"memory enabling smoke test\"]);\n\t\t\t\t\tif (capabilityDisposed) return failEnablingDisposed(() => client!.close());\n\t\t\t\t\tif (client.hello.embeddingModelId !== preset.embeddingModelId) {\n\t\t\t\t\t\tvoid closeResource(\"inference client\", () => client!.close());\n\t\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t\t`inference service runs embedding model ${client.hello.embeddingModelId}, session preset is ${preset.embeddingModelId} — the service was spawned for another memory tier; wait for its idle exit or stop it, then restart the session`,\n\t\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst storedModelId = await channel.index.getStoredModelId();\n\t\t\t\t\tif (!capabilityDisposed && storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {\n\t\t\t\t\t\tlogger?.warn(\n\t\t\t\t\t\t\t`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\t// dispose 竞态: teardown 已清引用 (capabilityDisposed) 时, 装配成功\n\t\t\t\t\t// 分支不得把新 IPC 连接赋回去——关闭它并落结构化失败, 让在途的\n\t\t\t\t\t// enablingOutcome() 等待者 (如 memory-preheat) 落定为失败而非悬挂。\n\t\t\t\t\tif (capabilityDisposed) return failEnablingDisposed(() => client!.close());\n\t\t\t\t\tinferenceClient = client;\n\t\t\t\t\tvectorChannel = channel;\n\t\t\t\t\tvectorState = \"ready\";\n\t\t\t\t\tlogger?.info(\n\t\t\t\t\t\t`memory ready via shared inference service (mode=${memoryMode}, embedding=${preset.embeddingModelId})`,\n\t\t\t\t\t);\n\t\t\t\t\tenablingSettled?.();\n\t\t\t\t\treturn channel;\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// 连接已建立后的失败 (冒烟/档位比对/getStoredModelId) 必须关掉\n\t\t\t\t\t// 客户端: 悬挂连接会让服务端 connections>0, 空闲自杀永不触发。\n\t\t\t\t\tif (client !== undefined) void closeResource(\"inference client\", () => client!.close());\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`inference service assembly failed (${error instanceof Error ? error.message : String(error)})`,\n\t\t\t\t\t\tserviceFailureActionList(servicePort),\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\t// 检查 3: 磁盘余量 (light ≥ 500MB / full ≥ 2GB)。服务装配路径不下载, 已在上面 return。\n\t\t\tconst diskProblem = await diskHeadroomCheck(agentDir, DISK_HEADROOM_MIN_BYTES[memoryMode]);\n\t\t\tif (diskProblem !== undefined) return failEnabling(diskProblem);\n\t\t\t// dispose 竞态 (本地装配路径, 第一道): 已 teardown 就不再打开 LanceDB/\n\t\t\t// 拉起重依赖; 装配完成点还有第二道检查兜住模型下载窗口。\n\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t// 加载: transformers/lancedb 的动态 import 都在这些模块内部, 这里只做\n\t\t\t// 模块级懒加载, 保持未触发会话零重依赖。进度周期性落一行 (下载可达\n\t\t\t// 数百 MB), 完成后清除。\n\t\t\tconst progressTimer = setInterval(() => {\n\t\t\t\tif (!capabilityDisposed) logger?.info(\"memory enabling still in progress (downloading/loading models)\");\n\t\t\t}, ENABLING_PROGRESS_LOG_INTERVAL_MS);\n\t\t\tif (typeof progressTimer === \"object\" && \"unref\" in progressTimer) progressTimer.unref();\n\t\t\tlet closeAcquired: (() => Promise<void>) | undefined;\n\t\t\tlet published = false;\n\t\t\ttry {\n\t\t\t\tconst [vectorIndexModule, embeddingModule, rerankerModule] = await Promise.all([\n\t\t\t\t\timport(\"./vector-index.ts\"),\n\t\t\t\t\timport(\"./embedding-provider.ts\"),\n\t\t\t\t\timport(\"./embedding-reranker.ts\"),\n\t\t\t\t]);\n\t\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t\tconst index = await vectorIndexModule.createMemoryVectorIndex({\n\t\t\t\t\tdbPath: join(agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\t\t\tdimensions: preset.dimensions,\n\t\t\t\t\t...(hostLancedbEntryPath === undefined ? {} : { moduleEntryPath: hostLancedbEntryPath }),\n\t\t\t\t});\n\t\t\t\tlet indexClosePromise: Promise<void> | undefined;\n\t\t\t\tcloseAcquired = () => {\n\t\t\t\t\tindexClosePromise ??= closeResource(\"vector index\", () => index.close());\n\t\t\t\t\treturn indexClosePromise;\n\t\t\t\t};\n\t\t\t\tcloseOwnedLocalResources = closeAcquired;\n\t\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t\tconst remoteHosts = remoteHostsForEnabling();\n\t\t\t\tconst channel: ActiveVectorChannelV1 = {\n\t\t\t\t\tembed: embeddingModule.createTransformersEmbeddingProvider({\n\t\t\t\t\t\tmodelId: preset.embeddingModelId,\n\t\t\t\t\t\tdimensions: preset.dimensions,\n\t\t\t\t\t\tcacheDir: modelCacheDir,\n\t\t\t\t\t\tremoteHosts,\n\t\t\t\t\t\t...(hostTransformersEntryPath === undefined ? {} : { moduleEntryPath: hostTransformersEntryPath }),\n\t\t\t\t\t\t...(enablingOverride?.embeddingLoadImpl === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { loadImpl: enablingOverride.embeddingLoadImpl }),\n\t\t\t\t\t}),\n\t\t\t\t\treranker: rerankerModule.createTransformersReranker({\n\t\t\t\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\t\t\t\tcacheDir: modelCacheDir,\n\t\t\t\t\t\tremoteHosts,\n\t\t\t\t\t\t...(hostTransformersEntryPath === undefined ? {} : { moduleEntryPath: hostTransformersEntryPath }),\n\t\t\t\t\t\t...(enablingOverride?.rerankerLoadImpl === undefined\n\t\t\t\t\t\t\t? {}\n\t\t\t\t\t\t\t: { loadImpl: enablingOverride.rerankerLoadImpl }),\n\t\t\t\t\t}),\n\t\t\t\t\tindex,\n\t\t\t\t\tqueryPrefix: preset.queryPrefix,\n\t\t\t\t\tembeddingModelId: preset.embeddingModelId,\n\t\t\t\t};\n\t\t\t\tlet channelClosePromise: Promise<void> | undefined;\n\t\t\t\tcloseAcquired = () => {\n\t\t\t\t\tchannelClosePromise ??= closeLocalChannel(channel);\n\t\t\t\t\treturn channelClosePromise;\n\t\t\t\t};\n\t\t\t\tcloseOwnedLocalResources = closeAcquired;\n\t\t\t\t// 冒烟: embed + rerank 各一条 (同时完成两个模型的下载与加载) +\n\t\t\t\t// 投影档位比对。rerank 冒烟 2026-10-06 live E2E 补齐: reranker\n\t\t\t\t// 懒加载, 只 embed 的冒烟会让 \"ready\" 携带未下载的精排权重 —\n\t\t\t\t// 共享推理服务 (两项文件均前置检查、永不自主下载) 对该会话拒启,\n\t\t\t\t// \"fully usable\" 的自述与服务前置条件必须一致。\n\t\t\t\tawait channel.embed.embed([\"memory enabling smoke test\"]);\n\t\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t\tif (channel.embed.modelId !== preset.embeddingModelId) {\n\t\t\t\t\treturn failEnabling(\n\t\t\t\t\t\t`smoke check failed: embedding modelId ${channel.embed.modelId} does not match the ${memoryMode} preset ${preset.embeddingModelId}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (channel.reranker !== undefined) {\n\t\t\t\t\tawait channel.reranker.rerank(\"memory enabling smoke test\", [\"memory enabling smoke test\"]);\n\t\t\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t\t}\n\t\t\t\tconst storedModelId = await channel.index.getStoredModelId();\n\t\t\t\tif (!capabilityDisposed && storedModelId !== undefined && storedModelId !== preset.embeddingModelId) {\n\t\t\t\t\tlogger?.warn(\n\t\t\t\t\t\t`memory projection was built for ${storedModelId}, preset is ${preset.embeddingModelId}; startup reconciliation will rebuild it`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\t// dispose 竞态 (本地装配路径, 第二道, 兜住模型下载窗口): 不把索引句柄\n\t\t\t\t// 赋回引用——关闭刚打开的 LanceDB 并落结构化失败。\n\t\t\t\tif (capabilityDisposed) return failEnablingDisposed();\n\t\t\t\tvectorChannel = channel;\n\t\t\t\tpublished = true;\n\t\t\t\tvectorState = \"ready\";\n\t\t\t\tlogger?.info(`memory ready (mode=${memoryMode}, embedding=${preset.embeddingModelId})`);\n\t\t\t\tenablingSettled?.();\n\t\t\t\treturn channel;\n\t\t\t} catch (error) {\n\t\t\t\treturn failEnabling(\n\t\t\t\t\t`model load or smoke check failed (${error instanceof Error ? error.message : String(error)})`,\n\t\t\t\t);\n\t\t\t} finally {\n\t\t\t\tclearInterval(progressTimer);\n\t\t\t\tif (!published && closeAcquired !== undefined) {\n\t\t\t\t\tawait closeAcquired();\n\t\t\t\t\tif (closeOwnedLocalResources === closeAcquired) closeOwnedLocalResources = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t})();\n\t\treturn vectorInitPromise;\n\t};\n\n\t// ---- 征询门执行面 (2026-10-05 用户裁决「首次使用征询、拒绝/失败可跳过」) ----\n\t// memory_enable 是 consent-required / failed 态的唯一下载入口: consentGranted\n\t// 只在这里置位, recall/auto-recall 永不触发下载。decline 同时持久化\n\t// (writeMemoryConsentDeclined), 只抑制默认档——用户显式设置 memory.mode 后\n\t// 下次启用会在首次使用时再次走到征询门。\n\t// ---- 记忆模型下载控制面 (2026-10-05 流程裁决「后台预热、不阻塞提问」) ----\n\t// 生产入口 (交互模式会话绑定后) 经公共工具面调用 memory_enable download\n\t// 触发后台预热; 命令面 /memory off|retry 是用户的直接出口。两处共用同一对\n\t// 闭包; decline 持久化只抑制默认档。\n\tconst declineMemory = (): { status: \"completed\"; message: string } => {\n\t\t// 总是落盘 (幂等写): 升降档会清理文件里的拒绝标记, 之后再次 off 必须\n\t\t// 重新写入——不能用内存 flag 跳过持久化。\n\t\tconst firstDecline = !consentDeclined;\n\t\tconsentDeclined = true;\n\t\twriteMemoryConsentDeclined(agentDir);\n\t\tif (firstDecline) {\n\t\t\tlogger?.info(\"memory disabled by user decision (persisted to the memory agent-dir config)\");\n\t\t}\n\t\treturn {\n\t\t\tstatus: \"completed\",\n\t\t\tmessage:\n\t\t\t\t\"memory disabled for this machine (persisted). Set memory.mode (light|full) in settings.json and restart the session to re-enable\",\n\t\t};\n\t};\n\tconst downloadMemory = async (): Promise<\n\t\t| { status: \"completed\"; message: string }\n\t\t| { status: \"failed\"; message: string; actions?: readonly string[]; next?: string }\n\t> => {\n\t\tif (consentDeclined) {\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage:\n\t\t\t\t\t\"memory was declined on this machine — set memory.mode (light|full) in settings.json and restart the session to re-enable\",\n\t\t\t};\n\t\t}\n\t\tconsentGranted = true;\n\t\tif (vectorState === \"failed\" || vectorState === \"consent-required\") {\n\t\t\tvectorState = \"enabling\";\n\t\t\tenablingFailure = undefined;\n\t\t\tvectorInitPromise = undefined;\n\t\t}\n\t\tconst channel = await vectorEnsure();\n\t\tif (channel === undefined) {\n\t\t\tconst failure = enablingFailure ?? {\n\t\t\t\treason: `memory enabling did not complete (state=${vectorState})`,\n\t\t\t\tactions: [] as const,\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tstatus: \"failed\",\n\t\t\t\tmessage: `memory enabling failed: ${failure.reason}`,\n\t\t\t\tactions: failure.actions,\n\t\t\t\tnext: 'Tell the user the download failed and ask whether to skip memory (call memory_enable with action \"decline\" or /memory off — both persist off) or fix the environment and retry (/memory retry)',\n\t\t\t};\n\t\t}\n\t\t// 就绪: 补跑启动对账, 把预热期间写入的 ledger 记忆补进向量投影。\n\t\tresetReconcile();\n\t\treconcileOnce();\n\t\treturn { status: \"completed\", message: \"memory models ready — the memory family is fully usable\" };\n\t};\n\n\t// 会话切换重绑/插件卸载的共享资源释放 (TUI 每次会话切换都重走装配, 不释放\n\t// 即每次泄漏一条 IPC 连接: 服务端 connections>0 抑制空闲自杀, 嵌入方进程因\n\t// socket 未关无法自然退出)。清引用先行: close 的错误经独立 stderr 诊断, 且\n\t// 二次调用因引用已空自然 no-op。服务路径与本地路径互斥 (服务路径的 index\n\t// 归服务进程持有, 客户端只断连; 本地路径才关 LanceDB 句柄)。\n\t// capabilityDisposed 是 teardown 与在途 enabling 的竞态闩锁: teardown 之后\n\t// 才完成的装配在成功分支让位 (见 vectorEnsure 的 failEnablingDisposed),\n\t// 不复活无人关闭的连接/句柄。\n\tlet capabilityDisposed = false;\n\tconst capabilityTeardown = (): void => {\n\t\tcapabilityDisposed = true;\n\t\tif (closeOwnedLocalResources !== undefined) {\n\t\t\tconst close = closeOwnedLocalResources;\n\t\t\tcloseOwnedLocalResources = undefined;\n\t\t\tvectorChannel = undefined;\n\t\t\tvoid close();\n\t\t\treturn;\n\t\t}\n\t\tif (inferenceClient !== undefined) {\n\t\t\tconst client = inferenceClient;\n\t\t\tinferenceClient = undefined;\n\t\t\tvectorChannel = undefined;\n\t\t\tvoid closeResource(\"inference client\", () => client.close());\n\t\t\treturn;\n\t\t}\n\t\tif (vectorChannel !== undefined) {\n\t\t\tconst channel = vectorChannel;\n\t\t\tvectorChannel = undefined;\n\t\t\tvoid closeLocalChannel(channel);\n\t\t}\n\t};\n\n\treturn {\n\t\tstate: (): \"off\" | MemoryCapabilityStateV1 => (consentDeclined ? \"off\" : vectorState),\n\t\trawState: (): MemoryCapabilityStateV1 => vectorState,\n\t\tenabled: vectorEnabled,\n\t\treadyChannel: (): ActiveVectorChannelV1 | undefined => vectorChannel,\n\t\tisDisposed: (): boolean => capabilityDisposed,\n\t\tdeclined: (): boolean => consentDeclined,\n\t\tclearDeclined: (): void => {\n\t\t\tconsentDeclined = false;\n\t\t},\n\t\tconsentAsked: (): boolean => consentAsked,\n\t\tmarkConsentAsked: (): void => {\n\t\t\tconsentAsked = true;\n\t\t},\n\t\tprimeConsentGate,\n\t\tconsentAsk: (): MemoryConsentAskV1 | undefined =>\n\t\t\tvectorState === \"consent-required\" && consentNeededInfo !== undefined\n\t\t\t\t? { message: consentAskMessage(), actions: consentAskActions(), block: consentAskBlock() }\n\t\t\t\t: undefined,\n\t\twarming: (): boolean => vectorState === \"enabling\" && vectorInitPromise !== undefined && !consentDeclined,\n\t\tfailure: (): MemoryEnablingFailureV1 | undefined => enablingFailure,\n\t\tmarkDegraded: (): void => {\n\t\t\tvectorState = \"degraded\";\n\t\t},\n\t\trecoverDegraded: (): void => {\n\t\t\tif (vectorState === \"degraded\") vectorState = \"ready\";\n\t\t},\n\t\tensure: vectorEnsure,\n\t\tenablingOutcome: async (): Promise<\"ready\" | MemoryEnablingFailureV1> => {\n\t\t\tif (vectorState === \"enabling\") void vectorEnsure();\n\t\t\tawait enablingSettledPromise;\n\t\t\treturn enablingFailure ?? \"ready\";\n\t\t},\n\t\tdecline: declineMemory,\n\t\tdownload: downloadMemory,\n\t\tdispose: capabilityTeardown,\n\t};\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"vector-index.d.ts","sourceRoot":"","sources":["../../src/memory/vector-index.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,MAAM,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;IAC5G,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;IACpG,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwI/B","sourcesContent":["/**\n * Memory vector index for hybrid retrieval (混合检索 · LanceDB 适配层).\n *\n * POC-verified (2026-09) against @lancedb/lancedb 0.39.0 on a 100k corpus:\n * vector column must be named `vector` (number[] auto-maps to\n * fixed-size-list<float32>), FTS with `Index.fts({ baseTokenizer: \"icu\" })`\n * covers Chinese text, flat-scan KNN on 100k rows takes ~600ms (预期内).\n *\n * Deliberately NOT implemented (POC 结论, 留二期): IVF_PQ ANN index — flat\n * scan is acceptable at current scale; fused hybrid query via\n * `fullTextQuery()` — that chain does not exist in 0.39.0, the caller composes\n * KNN + FTS itself and fuses with RRF (k=60), which is why this adapter's FTS\n * scores use `1/(60 + rank + 1)`.\n *\n * 边界行为 (POC 观察): 空 table 上建 FTS 索引/查询可能抛错 — 空表查询返回\n * 空数组; 建索引包 try/catch 忽略 (注释见 createBodyFtsIndex)。LanceDB 其他\n * 失败原样抛出, 不吞错、不静默降级。\n *\n * Runtime dep @lancedb/lancedb is lazy-loaded via `await import` (惯例参考\n * packages/agent-forge/src/utils/photon.ts); type positions use type-only\n * imports.\n */\nimport type { Connection, Table as LanceDbTable, Query, VectorQuery } from \"@lancedb/lancedb\";\nimport { importHostOrBareModule } from \"./host-module-import.ts\";\n\n/** Stored row shape: 5 columns; `body` is the FTS text (statement + tags). */\ntype MemoryVectorRecord = {\n\tmemoryId: string;\n\towner: string;\n\tmodelId: string;\n\tbody: string;\n\tvector: number[];\n};\n\ninterface MemoryVectorHitRow {\n\tmemoryId: string;\n\t_distance: number;\n}\n\nconst TABLE_NAME = \"memories\";\n/** RRF 常量, 与调用方融合层一致 (queryFts 注释说明口径)。 */\nconst RRF_K = 60;\n\nfunction escapeSqlLiteral(value: string): string {\n\treturn value.replace(/'/g, \"''\");\n}\n\nexport interface MemoryVectorIndexEntryV1 {\n\treadonly memoryId: string;\n\treadonly owner: string;\n\treadonly modelId: string;\n\treadonly statement: string;\n\treadonly tags: readonly string[];\n\treadonly vector: readonly number[];\n}\n\nexport interface MemoryVectorIndexQueryV1 {\n\treadonly owner: string;\n\treadonly limit: number;\n}\n\nexport interface MemoryVectorHitV1 {\n\treadonly memoryId: string;\n\treadonly score: number;\n}\n\nexport interface MemoryVectorIndexV1 {\n\treadonly replicaId: \"memory-vector-index\";\n\tupsert(entries: readonly MemoryVectorIndexEntryV1[]): Promise<void>;\n\tremove(memoryIds: readonly string[]): Promise<void>;\n\tqueryKnn(vector: readonly number[], query: MemoryVectorIndexQueryV1): Promise<readonly MemoryVectorHitV1[]>;\n\tqueryFts(queryText: string, query: MemoryVectorIndexQueryV1): Promise<readonly MemoryVectorHitV1[]>;\n\tlistMemoryIds(): Promise<ReadonlySet<string>>;\n\tcount(): Promise<number>;\n\tgetStoredModelId(): Promise<string | undefined>;\n\tclose(): Promise<void>;\n}\n\n/**\n * Open (lazily) / create the LanceDB-backed memory vector index at `dbPath`.\n * Table creation is deferred to the first upsert; queries against a\n * not-yet-created table return empty results instead of throwing.\n */\nexport async function createMemoryVectorIndex(options: {\n\treadonly dbPath: string;\n\treadonly dimensions: number;\n\t/** Host-resolved lancedb entry path (install-store visibility); undefined = bare import. */\n\treadonly moduleEntryPath?: string;\n}): Promise<MemoryVectorIndexV1> {\n\tconst dimensions = options.dimensions;\n\tconst lancedb = await importHostOrBareModule<typeof import(\"@lancedb/lancedb\")>(\n\t\toptions.moduleEntryPath ?? \"@lancedb/lancedb\",\n\t);\n\tconst db: Connection = await lancedb.connect(options.dbPath);\n\tlet table: LanceDbTable | null = null;\n\n\tconst ensureTable = async (): Promise<LanceDbTable | null> => {\n\t\tif (table) {\n\t\t\treturn table;\n\t\t}\n\t\tconst names = await db.tableNames();\n\t\tif (!names.includes(TABLE_NAME)) {\n\t\t\treturn null;\n\t\t}\n\t\ttable = await db.openTable(TABLE_NAME);\n\t\treturn table;\n\t};\n\n\t// 空表建 FTS 索引在 LanceDB 0.39 会抛错 (POC 观察); 本适配器仅在首次建表\n\t// (带非空数据) 后建索引, 但仍按契约包 try/catch 容错。忽略建索引失败意味着\n\t// FTS 通道暂不可用 (queryFts 会显式报错), KNN 通道不受影响。\n\tconst createBodyFtsIndex = async (target: LanceDbTable): Promise<void> => {\n\t\ttry {\n\t\t\tawait target.createIndex(\"body\", { config: lancedb.Index.fts({ baseTokenizer: \"icu\" }), replace: true });\n\t\t} catch {\n\t\t\t// 空表/重复建索引等边界忽略; 二期 IVF_PQ 落地时统一补索引管理。\n\t\t}\n\t};\n\n\treturn {\n\t\treplicaId: \"memory-vector-index\",\n\n\t\tupsert: async (entries) => {\n\t\t\tif (entries.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tfor (const entry of entries) {\n\t\t\t\tif (entry.vector.length !== dimensions) {\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`memory vector dimension mismatch for ${entry.memoryId}: got ${entry.vector.length}, index declares ${dimensions}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst rows: MemoryVectorRecord[] = entries.map((entry) => ({\n\t\t\t\tmemoryId: entry.memoryId,\n\t\t\t\towner: entry.owner,\n\t\t\t\tmodelId: entry.modelId,\n\t\t\t\tbody: `${entry.statement} ${entry.tags.join(\" \")}`,\n\t\t\t\tvector: Array.from(entry.vector),\n\t\t\t}));\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\t// mode \"create\" (非 POC 的 \"overwrite\"): 表不存在才建; 并发竞态下\n\t\t\t\t// 若表已被他人创建则显式抛错, 而不是静默清空重写。\n\t\t\t\ttable = await db.createTable(TABLE_NAME, rows, { mode: \"create\" });\n\t\t\t\tawait createBodyFtsIndex(table);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\t// mergeInsert upsert: 同 memoryId 幂等更新, 新 id 插入。\n\t\t\tawait current.mergeInsert(\"memoryId\").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows);\n\t\t},\n\n\t\tremove: async (memoryIds) => {\n\t\t\tif (memoryIds.length === 0) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tconst predicate = `memoryId IN (${memoryIds.map((id) => `'${escapeSqlLiteral(id)}'`).join(\",\")})`;\n\t\t\tawait current.delete(predicate);\n\t\t},\n\n\t\tqueryKnn: async (vector, query) => {\n\t\t\tif (vector.length !== dimensions) {\n\t\t\t\tthrow new Error(`query vector dimension mismatch: got ${vector.length}, index declares ${dimensions}`);\n\t\t\t}\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst rows: MemoryVectorHitRow[] = await (current.search(Array.from(vector)) as VectorQuery)\n\t\t\t\t.where(`owner = '${escapeSqlLiteral(query.owner)}'`)\n\t\t\t\t.limit(query.limit)\n\t\t\t\t.toArray();\n\t\t\t// 分数口径: 1/(1 + _distance), L2 距离越小分越高, 与 FTS 通道分数同域可融合。\n\t\t\treturn rows.map((row) => ({ memoryId: row.memoryId, score: 1 / (1 + row._distance) }));\n\t\t},\n\n\t\tqueryFts: async (queryText, query) => {\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn [];\n\t\t\t}\n\t\t\tconst rows: MemoryVectorHitRow[] = await (current.search(queryText) as Query)\n\t\t\t\t.where(`owner = '${escapeSqlLiteral(query.owner)}'`)\n\t\t\t\t.limit(query.limit)\n\t\t\t\t.toArray();\n\t\t\t// FTS 无距离分: 按返回序 1/(RRF_K + rank + 1) 打分, RRF_K=60 与调用方\n\t\t\t// 融合层 (RRF k=60) 一致, 保证 KNN/FTS 两通道分数可融合。\n\t\t\treturn rows.map((row, rank) => ({ memoryId: row.memoryId, score: 1 / (RRF_K + rank + 1) }));\n\t\t},\n\n\t\tlistMemoryIds: async () => {\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn new Set<string>();\n\t\t\t}\n\t\t\tconst rows: { memoryId: string }[] = await current.query().select([\"memoryId\"]).toArray();\n\t\t\treturn new Set(rows.map((row) => row.memoryId));\n\t\t},\n\n\t\tcount: async () => {\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn 0;\n\t\t\t}\n\t\t\treturn current.countRows();\n\t\t},\n\n\t\tgetStoredModelId: async () => {\n\t\t\tconst current = await ensureTable();\n\t\t\tif (!current) {\n\t\t\t\treturn undefined;\n\t\t\t}\n\t\t\tconst rows: { modelId: string }[] = await current.query().select([\"modelId\"]).limit(1).toArray();\n\t\t\treturn rows[0]?.modelId;\n\t\t},\n\n\t\tclose: async () => {\n\t\t\tdb.close();\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"vector-index.d.ts","sourceRoot":"","sources":["../../src/memory/vector-index.ts"],"names":[],"mappings":"AA+CA,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,wBAAwB;IACxC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IACjC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IACnC,QAAQ,CAAC,SAAS,EAAE,qBAAqB,CAAC;IAC1C,MAAM,CAAC,OAAO,EAAE,SAAS,wBAAwB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpE,MAAM,CAAC,SAAS,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;IAC5G,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,wBAAwB,GAAG,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CAAC;IACpG,aAAa,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9C,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IACzB,gBAAgB,IAAI,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAChD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,uBAAuB,CAAC,OAAO,EAAE;IACtD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,4FAA4F;IAC5F,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;CAClC,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAiK/B","sourcesContent":["/**\n * Memory vector index for hybrid retrieval (混合检索 · LanceDB 适配层).\n *\n * POC-verified (2026-09) against @lancedb/lancedb 0.39.0 on a 100k corpus:\n * vector column must be named `vector` (number[] auto-maps to\n * fixed-size-list<float32>), FTS with `Index.fts({ baseTokenizer: \"icu\" })`\n * covers Chinese text, flat-scan KNN on 100k rows takes ~600ms (预期内).\n *\n * Deliberately NOT implemented (POC 结论, 留二期): IVF_PQ ANN index — flat\n * scan is acceptable at current scale; fused hybrid query via\n * `fullTextQuery()` — that chain does not exist in 0.39.0, the caller composes\n * KNN + FTS itself and fuses with RRF (k=60), which is why this adapter's FTS\n * scores use `1/(60 + rank + 1)`.\n *\n * 边界行为 (POC 观察): 空 table 上建 FTS 索引/查询可能抛错 — 空表查询返回\n * 空数组; 建索引包 try/catch 忽略 (注释见 createBodyFtsIndex)。LanceDB 其他\n * 失败原样抛出, 不吞错、不静默降级。\n *\n * Runtime dep @lancedb/lancedb is lazy-loaded via `await import` (惯例参考\n * packages/agent-forge/src/utils/photon.ts); type positions use type-only\n * imports.\n */\nimport type { Connection, Table as LanceDbTable, Query, VectorQuery } from \"@lancedb/lancedb\";\nimport { importHostOrBareModule } from \"./host-module-import.ts\";\n\n/** Stored row shape: 5 columns; `body` is the FTS text (statement + tags). */\ntype MemoryVectorRecord = {\n\tmemoryId: string;\n\towner: string;\n\tmodelId: string;\n\tbody: string;\n\tvector: number[];\n};\n\ninterface MemoryVectorHitRow {\n\tmemoryId: string;\n\t_distance: number;\n}\n\nconst TABLE_NAME = \"memories\";\n/** RRF 常量, 与调用方融合层一致 (queryFts 注释说明口径)。 */\nconst RRF_K = 60;\n\nfunction escapeSqlLiteral(value: string): string {\n\treturn value.replace(/'/g, \"''\");\n}\n\nexport interface MemoryVectorIndexEntryV1 {\n\treadonly memoryId: string;\n\treadonly owner: string;\n\treadonly modelId: string;\n\treadonly statement: string;\n\treadonly tags: readonly string[];\n\treadonly vector: readonly number[];\n}\n\nexport interface MemoryVectorIndexQueryV1 {\n\treadonly owner: string;\n\treadonly limit: number;\n}\n\nexport interface MemoryVectorHitV1 {\n\treadonly memoryId: string;\n\treadonly score: number;\n}\n\nexport interface MemoryVectorIndexV1 {\n\treadonly replicaId: \"memory-vector-index\";\n\tupsert(entries: readonly MemoryVectorIndexEntryV1[]): Promise<void>;\n\tremove(memoryIds: readonly string[]): Promise<void>;\n\tqueryKnn(vector: readonly number[], query: MemoryVectorIndexQueryV1): Promise<readonly MemoryVectorHitV1[]>;\n\tqueryFts(queryText: string, query: MemoryVectorIndexQueryV1): Promise<readonly MemoryVectorHitV1[]>;\n\tlistMemoryIds(): Promise<ReadonlySet<string>>;\n\tcount(): Promise<number>;\n\tgetStoredModelId(): Promise<string | undefined>;\n\tclose(): Promise<void>;\n}\n\n/**\n * Open (lazily) / create the LanceDB-backed memory vector index at `dbPath`.\n * Table creation is deferred to the first upsert; queries against a\n * not-yet-created table return empty results instead of throwing.\n */\nexport async function createMemoryVectorIndex(options: {\n\treadonly dbPath: string;\n\treadonly dimensions: number;\n\t/** Host-resolved lancedb entry path (install-store visibility); undefined = bare import. */\n\treadonly moduleEntryPath?: string;\n}): Promise<MemoryVectorIndexV1> {\n\tconst dimensions = options.dimensions;\n\tconst lancedb = await importHostOrBareModule<typeof import(\"@lancedb/lancedb\")>(\n\t\toptions.moduleEntryPath ?? \"@lancedb/lancedb\",\n\t);\n\tconst db: Connection = await lancedb.connect(options.dbPath);\n\tlet table: LanceDbTable | null = null;\n\tlet closed = false;\n\tlet closePromise: Promise<void> | undefined;\n\tconst activeCalls = new Set<Promise<unknown>>();\n\tconst withOpenIndex = <T>(operation: () => Promise<T>): Promise<T> => {\n\t\tif (closed) return Promise.reject(new Error(\"memory vector index is closed\"));\n\t\tconst call = operation();\n\t\tactiveCalls.add(call);\n\t\tvoid call.then(\n\t\t\t() => activeCalls.delete(call),\n\t\t\t() => activeCalls.delete(call),\n\t\t);\n\t\treturn call;\n\t};\n\n\tconst ensureTable = async (): Promise<LanceDbTable | null> => {\n\t\tif (table) {\n\t\t\treturn table;\n\t\t}\n\t\tconst names = await db.tableNames();\n\t\tif (!names.includes(TABLE_NAME)) {\n\t\t\treturn null;\n\t\t}\n\t\ttable = await db.openTable(TABLE_NAME);\n\t\treturn table;\n\t};\n\n\t// 空表建 FTS 索引在 LanceDB 0.39 会抛错 (POC 观察); 本适配器仅在首次建表\n\t// (带非空数据) 后建索引, 但仍按契约包 try/catch 容错。忽略建索引失败意味着\n\t// FTS 通道暂不可用 (queryFts 会显式报错), KNN 通道不受影响。\n\tconst createBodyFtsIndex = async (target: LanceDbTable): Promise<void> => {\n\t\ttry {\n\t\t\tawait target.createIndex(\"body\", { config: lancedb.Index.fts({ baseTokenizer: \"icu\" }), replace: true });\n\t\t} catch {\n\t\t\t// 空表/重复建索引等边界忽略; 二期 IVF_PQ 落地时统一补索引管理。\n\t\t}\n\t};\n\n\treturn {\n\t\treplicaId: \"memory-vector-index\",\n\n\t\tupsert: (entries) =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tif (entries.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tfor (const entry of entries) {\n\t\t\t\t\tif (entry.vector.length !== dimensions) {\n\t\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t\t`memory vector dimension mismatch for ${entry.memoryId}: got ${entry.vector.length}, index declares ${dimensions}`,\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tconst rows: MemoryVectorRecord[] = entries.map((entry) => ({\n\t\t\t\t\tmemoryId: entry.memoryId,\n\t\t\t\t\towner: entry.owner,\n\t\t\t\t\tmodelId: entry.modelId,\n\t\t\t\t\tbody: `${entry.statement} ${entry.tags.join(\" \")}`,\n\t\t\t\t\tvector: Array.from(entry.vector),\n\t\t\t\t}));\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\t// mode \"create\" (非 POC 的 \"overwrite\"): 表不存在才建; 并发竞态下\n\t\t\t\t\t// 若表已被他人创建则显式抛错, 而不是静默清空重写。\n\t\t\t\t\ttable = await db.createTable(TABLE_NAME, rows, { mode: \"create\" });\n\t\t\t\t\tawait createBodyFtsIndex(table);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\t// mergeInsert upsert: 同 memoryId 幂等更新, 新 id 插入。\n\t\t\t\tawait current.mergeInsert(\"memoryId\").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows);\n\t\t\t}),\n\n\t\tremove: (memoryIds) =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tif (memoryIds.length === 0) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tconst predicate = `memoryId IN (${memoryIds.map((id) => `'${escapeSqlLiteral(id)}'`).join(\",\")})`;\n\t\t\t\tawait current.delete(predicate);\n\t\t\t}),\n\n\t\tqueryKnn: (vector, query) =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tif (vector.length !== dimensions) {\n\t\t\t\t\tthrow new Error(`query vector dimension mismatch: got ${vector.length}, index declares ${dimensions}`);\n\t\t\t\t}\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\tconst rows: MemoryVectorHitRow[] = await (current.search(Array.from(vector)) as VectorQuery)\n\t\t\t\t\t.where(`owner = '${escapeSqlLiteral(query.owner)}'`)\n\t\t\t\t\t.limit(query.limit)\n\t\t\t\t\t.toArray();\n\t\t\t\t// 分数口径: 1/(1 + _distance), L2 距离越小分越高, 与 FTS 通道分数同域可融合。\n\t\t\t\treturn rows.map((row) => ({ memoryId: row.memoryId, score: 1 / (1 + row._distance) }));\n\t\t\t}),\n\n\t\tqueryFts: (queryText, query) =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn [];\n\t\t\t\t}\n\t\t\t\tconst rows: MemoryVectorHitRow[] = await (current.search(queryText) as Query)\n\t\t\t\t\t.where(`owner = '${escapeSqlLiteral(query.owner)}'`)\n\t\t\t\t\t.limit(query.limit)\n\t\t\t\t\t.toArray();\n\t\t\t\t// FTS 无距离分: 按返回序 1/(RRF_K + rank + 1) 打分, RRF_K=60 与调用方\n\t\t\t\t// 融合层 (RRF k=60) 一致, 保证 KNN/FTS 两通道分数可融合。\n\t\t\t\treturn rows.map((row, rank) => ({ memoryId: row.memoryId, score: 1 / (RRF_K + rank + 1) }));\n\t\t\t}),\n\n\t\tlistMemoryIds: () =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn new Set<string>();\n\t\t\t\t}\n\t\t\t\tconst rows: { memoryId: string }[] = await current.query().select([\"memoryId\"]).toArray();\n\t\t\t\treturn new Set(rows.map((row) => row.memoryId));\n\t\t\t}),\n\n\t\tcount: () =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\t\t\t\treturn current.countRows();\n\t\t\t}),\n\n\t\tgetStoredModelId: () =>\n\t\t\twithOpenIndex(async () => {\n\t\t\t\tconst current = await ensureTable();\n\t\t\t\tif (!current) {\n\t\t\t\t\treturn undefined;\n\t\t\t\t}\n\t\t\t\tconst rows: { modelId: string }[] = await current.query().select([\"modelId\"]).limit(1).toArray();\n\t\t\t\treturn rows[0]?.modelId;\n\t\t\t}),\n\n\t\tclose: () => {\n\t\t\tclosed = true;\n\t\t\tclosePromise ??= (async () => {\n\t\t\t\tawait Promise.allSettled([...activeCalls]);\n\t\t\t\tdb.close();\n\t\t\t})();\n\t\t\treturn closePromise;\n\t\t},\n\t};\n}\n"]}