@ai-agent-forge/plugin-memory 0.88.1 → 0.88.3

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.
Files changed (99) hide show
  1. package/README.md +10 -4
  2. package/agent-forge.json +1 -1
  3. package/bin/agent-forge-memory-inference.js +8 -0
  4. package/dist/capability.d.ts +42 -59
  5. package/dist/capability.d.ts.map +1 -1
  6. package/dist/capability.js +263 -2055
  7. package/dist/capability.js.map +1 -1
  8. package/dist/entry.d.ts +11 -0
  9. package/dist/entry.d.ts.map +1 -1
  10. package/dist/entry.js +38 -2
  11. package/dist/entry.js.map +1 -1
  12. package/dist/index.d.ts +5 -0
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +7 -0
  15. package/dist/index.js.map +1 -1
  16. package/dist/inference-bin.d.ts +21 -0
  17. package/dist/inference-bin.d.ts.map +1 -0
  18. package/dist/inference-bin.js +85 -0
  19. package/dist/inference-bin.js.map +1 -0
  20. package/dist/memory/command-face.d.ts +86 -0
  21. package/dist/memory/command-face.d.ts.map +1 -0
  22. package/dist/memory/command-face.js +377 -0
  23. package/dist/memory/command-face.js.map +1 -0
  24. package/dist/memory/embedding-provider.d.ts.map +1 -1
  25. package/dist/memory/embedding-provider.js +14 -2
  26. package/dist/memory/embedding-provider.js.map +1 -1
  27. package/dist/memory/embedding-reranker.d.ts.map +1 -1
  28. package/dist/memory/embedding-reranker.js +14 -2
  29. package/dist/memory/embedding-reranker.js.map +1 -1
  30. package/dist/memory/enabling.d.ts +104 -0
  31. package/dist/memory/enabling.d.ts.map +1 -0
  32. package/dist/memory/enabling.js +321 -0
  33. package/dist/memory/enabling.js.map +1 -0
  34. package/dist/memory/hooks.d.ts +110 -0
  35. package/dist/memory/hooks.d.ts.map +1 -0
  36. package/dist/memory/hooks.js +478 -0
  37. package/dist/memory/hooks.js.map +1 -0
  38. package/dist/memory/inference-channel.d.ts +33 -0
  39. package/dist/memory/inference-channel.d.ts.map +1 -0
  40. package/dist/memory/inference-channel.js +101 -0
  41. package/dist/memory/inference-channel.js.map +1 -0
  42. package/dist/memory/inference-client.d.ts +25 -0
  43. package/dist/memory/inference-client.d.ts.map +1 -0
  44. package/dist/memory/inference-client.js +216 -0
  45. package/dist/memory/inference-client.js.map +1 -0
  46. package/dist/memory/inference-protocol.d.ts +95 -0
  47. package/dist/memory/inference-protocol.d.ts.map +1 -0
  48. package/dist/memory/inference-protocol.js +27 -0
  49. package/dist/memory/inference-protocol.js.map +1 -0
  50. package/dist/memory/inference-server.d.ts +70 -0
  51. package/dist/memory/inference-server.d.ts.map +1 -0
  52. package/dist/memory/inference-server.js +395 -0
  53. package/dist/memory/inference-server.js.map +1 -0
  54. package/dist/memory/inference-service-main.d.ts +31 -0
  55. package/dist/memory/inference-service-main.d.ts.map +1 -0
  56. package/dist/memory/inference-service-main.js +89 -0
  57. package/dist/memory/inference-service-main.js.map +1 -0
  58. package/dist/memory/ledger.d.ts +15 -0
  59. package/dist/memory/ledger.d.ts.map +1 -1
  60. package/dist/memory/ledger.js +35 -2
  61. package/dist/memory/ledger.js.map +1 -1
  62. package/dist/memory/model-cache-hygiene.d.ts +10 -0
  63. package/dist/memory/model-cache-hygiene.d.ts.map +1 -1
  64. package/dist/memory/model-cache-hygiene.js +15 -0
  65. package/dist/memory/model-cache-hygiene.js.map +1 -1
  66. package/dist/memory/preference-promotion.d.ts +0 -14
  67. package/dist/memory/preference-promotion.d.ts.map +1 -1
  68. package/dist/memory/preference-promotion.js +17 -0
  69. package/dist/memory/preference-promotion.js.map +1 -1
  70. package/dist/memory/recall-pipeline.d.ts +85 -0
  71. package/dist/memory/recall-pipeline.d.ts.map +1 -0
  72. package/dist/memory/recall-pipeline.js +678 -0
  73. package/dist/memory/recall-pipeline.js.map +1 -0
  74. package/dist/memory/retention-sweep.d.ts +59 -0
  75. package/dist/memory/retention-sweep.d.ts.map +1 -0
  76. package/dist/memory/retention-sweep.js +103 -0
  77. package/dist/memory/retention-sweep.js.map +1 -0
  78. package/dist/memory/store.d.ts +17 -2
  79. package/dist/memory/store.d.ts.map +1 -1
  80. package/dist/memory/store.js +18 -2
  81. package/dist/memory/store.js.map +1 -1
  82. package/dist/memory/vector-channel.d.ts +120 -0
  83. package/dist/memory/vector-channel.d.ts.map +1 -0
  84. package/dist/memory/vector-channel.js +495 -0
  85. package/dist/memory/vector-channel.js.map +1 -0
  86. package/dist/memory/vector-projection.d.ts +87 -0
  87. package/dist/memory/vector-projection.d.ts.map +1 -0
  88. package/dist/memory/vector-projection.js +215 -0
  89. package/dist/memory/vector-projection.js.map +1 -0
  90. package/dist/memory/write-face.d.ts +128 -0
  91. package/dist/memory/write-face.d.ts.map +1 -0
  92. package/dist/memory/write-face.js +504 -0
  93. package/dist/memory/write-face.js.map +1 -0
  94. package/dist/testing/memory-testkit.d.ts +2 -0
  95. package/dist/testing/memory-testkit.d.ts.map +1 -1
  96. package/dist/testing/memory-testkit.js +1 -0
  97. package/dist/testing/memory-testkit.js.map +1 -1
  98. package/package.json +7 -3
  99. package/plugin.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory Foundation — three-scope store with revisions, TTL, and retention\n * inputs (1C.1b).\n *\n * Scope decides which partition a committed atom belongs to (session / cycle /\n * long-term); retention decides how long it stays recallable. Retention mode\n * IDs are opaque strings resolved through a versioned registry provided by the\n * Profile — the Foundation never hardcodes business durations. Expired records\n * lose recall eligibility but are NOT physically purged here (physical purge\n * is the controlled 1C.6d gate).\n */\n\nimport type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport type { MemoryAtomV1, MemoryScopeV1, MemorySuiteFilterStatsV1 } from \"./foundation.ts\";\nimport { memorySuiteVisibility, validateMemoryAtomV1 } from \"./foundation.ts\";\n\n/** One retention mode published by a Profile's retention-mode registry. */\nexport interface RetentionModeDefinitionV1 {\n\treadonly id: string;\n\t/** Recall duration in ms. Absent = no expiry (e.g. `permanent`). */\n\treadonly durationMs?: number;\n\treadonly autoPurge: boolean;\n}\n\n/** Versioned retention-mode registry snapshot. */\nexport interface RetentionModeRegistryV1 {\n\treadonly policyVersion: string;\n\treadonly modes: readonly RetentionModeDefinitionV1[];\n\tget(id: string): RetentionModeDefinitionV1 | undefined;\n}\n\n/** Validates a retention-mode registry: parseable, finite, non-negative, unique, traceable. */\nexport function validateRetentionModeRegistry(value: unknown): RetentionModeRegistryV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Retention mode registry must be a plain object\");\n\t}\n\tconst record = value as Record<string, unknown>;\n\tassertNonEmptyString(record.policyVersion, \"Retention mode registry.policyVersion\");\n\tif (!Array.isArray(record.modes) || record.modes.length === 0) {\n\t\tthrow new Error(\"Retention mode registry.modes must be a non-empty array\");\n\t}\n\tconst seen = new Set<string>();\n\tconst modes: RetentionModeDefinitionV1[] = record.modes.map((item, index) => {\n\t\tconst label = `Retention mode[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(`${label} must be a plain object`);\n\t\t}\n\t\tconst entry = item as Record<string, unknown>;\n\t\tassertNonEmptyString(entry.id, `${label}.id`);\n\t\tif (seen.has(entry.id)) throw new Error(`${label} duplicates id: ${entry.id}`);\n\t\tseen.add(entry.id);\n\t\tif (typeof entry.autoPurge !== \"boolean\") throw new Error(`${label}.autoPurge must be boolean`);\n\t\tif (entry.durationMs !== undefined) {\n\t\t\tif (typeof entry.durationMs !== \"number\" || !Number.isSafeInteger(entry.durationMs) || entry.durationMs <= 0) {\n\t\t\t\tthrow new Error(`${label}.durationMs must be a positive safe integer`);\n\t\t\t}\n\t\t}\n\t\treturn Object.freeze({\n\t\t\tid: entry.id,\n\t\t\t...(entry.durationMs === undefined ? {} : { durationMs: entry.durationMs }),\n\t\t\tautoPurge: entry.autoPurge,\n\t\t});\n\t});\n\treturn Object.freeze({\n\t\tpolicyVersion: record.policyVersion,\n\t\tmodes: Object.freeze(modes),\n\t\tget(id: string) {\n\t\t\treturn modes.find((mode) => mode.id === id);\n\t\t},\n\t});\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\n/** First-party default registry (short/standard/long/permanent). Durations live here, not in Foundation logic. */\nexport function createFirstPartyRetentionRegistry(): RetentionModeRegistryV1 {\n\tconst DAY = 24 * 60 * 60 * 1000;\n\treturn validateRetentionModeRegistry({\n\t\tpolicyVersion: \"retention@1\",\n\t\tmodes: [\n\t\t\t{ id: \"short\", durationMs: 7 * DAY, autoPurge: true },\n\t\t\t{ id: \"standard\", durationMs: 30 * DAY, autoPurge: true },\n\t\t\t{ id: \"long\", durationMs: 365 * DAY, autoPurge: true },\n\t\t\t{ id: \"permanent\", autoPurge: false },\n\t\t],\n\t});\n}\n\nexport interface MemoryStoreCommitOptions {\n\t/** Overrides the atom's retentionMode id at commit time (policy-selected). */\n\treadonly retentionModeId?: string;\n}\n\n/** A committed atom plus the store-assigned bookkeeping facts. */\nexport interface CommittedMemoryV1<TPayload extends JsonValue = JsonValue> {\n\treadonly atom: MemoryAtomV1<TPayload>;\n\t/** Monotonic across the whole store. */\n\treadonly storeRevision: number;\n\t/** Monotonic within the atom's scope partition. */\n\treadonly scopeRevision: number;\n\treadonly committedAt: number;\n\t/** Recall deadline computed from the retention registry. Absent = no expiry. */\n\treadonly purgeAt?: number;\n\treadonly retentionModeId: string;\n}\n\nexport interface MemoryStoreQuery {\n\treadonly owner: string;\n\t/**\n\t * Suite-scoped read boundary (方案系统设计 §6.1/§11). When set, only atoms\n\t * whose suiteId equals this value — plus explicitly promoted user-default\n\t * preferences — are visible; legacy (suiteId-less) atoms are skipped\n\t * fail-safe. When absent, no suite filtering happens (suite-unscoped read).\n\t */\n\treadonly suiteId?: string;\n}\n\nexport interface MemoryStoreStats {\n\treadonly active: number;\n\treadonly expired: number;\n\treadonly byScope: Readonly<Record<MemoryScopeV1, { active: number; expired: number }>>;\n}\n\n/** Result of {@link MemoryStoreV1.listForSuite}: visible records plus skip counters. */\nexport interface MemoryStoreSuitePageV1 {\n\treadonly records: readonly CommittedMemoryV1[];\n\t/** Excluded-record counters for the suite read boundary (设计 §11). */\n\treadonly filter: MemorySuiteFilterStatsV1;\n}\n\nexport interface MemoryStoreV1 {\n\tcommit(atom: MemoryAtomV1, options?: MemoryStoreCommitOptions): CommittedMemoryV1;\n\t/**\n\t * Returns the record only when unexpired, owned by `query.owner`, and —\n\t * when `query.suiteId` is set — visible in that suite (legacy atoms are\n\t * invisible to every suite).\n\t */\n\tget(memoryId: string, query: MemoryStoreQuery): CommittedMemoryV1 | undefined;\n\t/** Lists active records owned by `query.owner`, optionally narrowed to one scope. */\n\tlist(query: MemoryStoreQuery, scope?: MemoryScopeV1): readonly CommittedMemoryV1[];\n\t/**\n\t * Suite-scoped listing with skip diagnostics: returns the records visible\n\t * in `query.suiteId` plus how many legacy and foreign-suite records were\n\t * excluded (expired records are excluded before the suite filter and are\n\t * not counted here).\n\t */\n\tlistForSuite(query: MemoryStoreQuery & { readonly suiteId: string }, scope?: MemoryScopeV1): MemoryStoreSuitePageV1;\n\tstats(): MemoryStoreStats;\n\t/**\n\t * Physically removes one record from the canonical in-memory ledger — the\n\t * store-side arm of the controlled purge gate (设计 §3.3: only the purge\n\t * flow may destroy committed atoms). Call it exclusively from the purge\n\t * path (suite memory facade / scheduler purge); ordinary business code\n\t * never evicts. Returns true when the record existed. Expired-then-evicted\n\t * and unexpired records are removed alike; a restart replay cannot\n\t * resurrect an evicted atom once the durable replica is rewritten.\n\t */\n\tevict(memoryId: string): boolean;\n}\n\n/** Creates a deterministic three-scope Foundation store. Expired records lose recall but stay ledgered. */\nexport function createMemoryStore(options: {\n\treadonly retentionRegistry: RetentionModeRegistryV1;\n\treadonly now?: () => number;\n}): MemoryStoreV1 {\n\tconst registry = options.retentionRegistry;\n\tconst now = options.now ?? (() => Date.now());\n\tconst records = new Map<string, CommittedMemoryV1>();\n\tlet storeRevision = 0;\n\tconst scopeRevisions = new Map<MemoryScopeV1, number>();\n\n\tconst isExpired = (record: CommittedMemoryV1): boolean => record.purgeAt !== undefined && record.purgeAt <= now();\n\n\tconst requireOwner = (query: MemoryStoreQuery): string => {\n\t\tif (query === null || typeof query !== \"object\" || typeof query.owner !== \"string\" || query.owner.trim() === \"\") {\n\t\t\tthrow new Error(\"Memory store query requires an owner\");\n\t\t}\n\t\tif (query.suiteId !== undefined && (typeof query.suiteId !== \"string\" || query.suiteId.trim() === \"\")) {\n\t\t\tthrow new Error(\"Memory store query requires a non-empty suiteId when filtering by suite\");\n\t\t}\n\t\treturn query.owner;\n\t};\n\n\t/** Suite read boundary: `undefined` query.suiteId means no suite filtering. */\n\tconst isVisibleInSuite = (atom: MemoryAtomV1, suiteId: string | undefined): boolean =>\n\t\tsuiteId === undefined || memorySuiteVisibility(atom, suiteId) === \"visible\";\n\n\treturn {\n\t\tcommit(atom, commitOptions) {\n\t\t\tconst validated = validateMemoryAtomV1(atom);\n\t\t\t// Canonical atoms are immutable once committed (设计 §4): a second\n\t\t\t// commit with the same memoryId is a caller bug and must fail\n\t\t\t// explicitly instead of silently overwriting verified facts.\n\t\t\tif (records.has(validated.memoryId)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Memory already committed: ${validated.memoryId} (canonical atoms are immutable; use the candidate machine for dedupe)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst modeId = commitOptions?.retentionModeId ?? validated.retentionMode;\n\t\t\tconst mode = registry.get(modeId);\n\t\t\tif (!mode) throw new Error(`Retention mode is not registered: ${modeId}`);\n\t\t\tstoreRevision += 1;\n\t\t\tconst scopeRevision = (scopeRevisions.get(validated.scope) ?? 0) + 1;\n\t\t\tscopeRevisions.set(validated.scope, scopeRevision);\n\t\t\tconst committedAt = now();\n\t\t\tconst committed: CommittedMemoryV1 = Object.freeze({\n\t\t\t\tatom: validated,\n\t\t\t\tstoreRevision,\n\t\t\t\tscopeRevision,\n\t\t\t\tcommittedAt,\n\t\t\t\t...(mode.durationMs === undefined ? {} : { purgeAt: committedAt + mode.durationMs }),\n\t\t\t\tretentionModeId: mode.id,\n\t\t\t});\n\t\t\trecords.set(validated.memoryId, committed);\n\t\t\treturn committed;\n\t\t},\n\t\tget(memoryId, query) {\n\t\t\tconst owner = requireOwner(query);\n\t\t\tconst record = records.get(memoryId);\n\t\t\tif (!record) return undefined;\n\t\t\tif (record.atom.owner !== owner) return undefined;\n\t\t\tif (!isVisibleInSuite(record.atom, query.suiteId)) return undefined;\n\t\t\tif (isExpired(record)) return undefined;\n\t\t\treturn record;\n\t\t},\n\t\tlist(query, scope) {\n\t\t\tconst owner = requireOwner(query);\n\t\t\tconst results: CommittedMemoryV1[] = [];\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.atom.owner !== owner) continue;\n\t\t\t\tif (scope !== undefined && record.atom.scope !== scope) continue;\n\t\t\t\tif (!isVisibleInSuite(record.atom, query.suiteId)) continue;\n\t\t\t\tif (isExpired(record)) continue;\n\t\t\t\tresults.push(record);\n\t\t\t}\n\t\t\treturn Object.freeze(results.sort((left, right) => left.storeRevision - right.storeRevision));\n\t\t},\n\t\tlistForSuite(query, scope) {\n\t\t\trequireOwner(query);\n\t\t\tconst suiteId = query.suiteId;\n\t\t\tconst results: CommittedMemoryV1[] = [];\n\t\t\tlet legacySkipped = 0;\n\t\t\tlet foreignSuiteSkipped = 0;\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.atom.owner !== query.owner) continue;\n\t\t\t\tif (scope !== undefined && record.atom.scope !== scope) continue;\n\t\t\t\tif (isExpired(record)) continue;\n\t\t\t\tconst visibility = memorySuiteVisibility(record.atom, suiteId);\n\t\t\t\tif (visibility === \"legacy\") {\n\t\t\t\t\tlegacySkipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (visibility === \"foreign-suite\") {\n\t\t\t\t\tforeignSuiteSkipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresults.push(record);\n\t\t\t}\n\t\t\tresults.sort((left, right) => left.storeRevision - right.storeRevision);\n\t\t\treturn Object.freeze({\n\t\t\t\trecords: Object.freeze(results),\n\t\t\t\tfilter: Object.freeze({ legacySkipped, foreignSuiteSkipped }),\n\t\t\t});\n\t\t},\n\t\tstats() {\n\t\t\tconst bucket = () => ({ active: 0, expired: 0 });\n\t\t\tconst byScope: Record<MemoryScopeV1, { active: number; expired: number }> = {\n\t\t\t\tsession: bucket(),\n\t\t\t\tcycle: bucket(),\n\t\t\t\t\"long-term\": bucket(),\n\t\t\t};\n\t\t\tlet active = 0;\n\t\t\tlet expired = 0;\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tconst target = byScope[record.atom.scope];\n\t\t\t\tif (isExpired(record)) {\n\t\t\t\t\texpired += 1;\n\t\t\t\t\ttarget.expired += 1;\n\t\t\t\t} else {\n\t\t\t\t\tactive += 1;\n\t\t\t\t\ttarget.active += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { active, expired, byScope: Object.freeze(byScope) };\n\t\t},\n\t\tevict(memoryId) {\n\t\t\tif (typeof memoryId !== \"string\" || memoryId.trim() === \"\") {\n\t\t\t\tthrow new Error(\"Memory store evict requires a memoryId\");\n\t\t\t}\n\t\t\treturn records.delete(memoryId);\n\t\t},\n\t};\n}\n"]}
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Memory Foundation — three-scope store with revisions, TTL, and retention\n * inputs (1C.1b).\n *\n * Scope decides which partition a committed atom belongs to (session / cycle /\n * long-term); retention decides how long it stays recallable. Retention mode\n * IDs are opaque strings resolved through a versioned registry provided by the\n * Profile — the Foundation never hardcodes business durations. Expired records\n * lose recall eligibility but are NOT physically purged here — the store never\n * self-purges. The physical purge is the controlled gate driven by the\n * retention sweep (src/memory/retention-sweep.ts, 记忆系统设计 §3.3), which\n * enumerates expired records through {@link MemoryStoreV1.listExpired} and\n * destroys the replicas via the purge gate's injected callbacks (ledger\n * rewrite + vector row deletion + store evict).\n */\n\nimport type { JsonValue } from \"@agent-forge/plugin-sdk\";\nimport type { MemoryAtomV1, MemoryScopeV1, MemorySuiteFilterStatsV1 } from \"./foundation.ts\";\nimport { memorySuiteVisibility, validateMemoryAtomV1 } from \"./foundation.ts\";\n\n/** One retention mode published by a Profile's retention-mode registry. */\nexport interface RetentionModeDefinitionV1 {\n\treadonly id: string;\n\t/** Recall duration in ms. Absent = no expiry (e.g. `permanent`). */\n\treadonly durationMs?: number;\n\treadonly autoPurge: boolean;\n}\n\n/** Versioned retention-mode registry snapshot. */\nexport interface RetentionModeRegistryV1 {\n\treadonly policyVersion: string;\n\treadonly modes: readonly RetentionModeDefinitionV1[];\n\tget(id: string): RetentionModeDefinitionV1 | undefined;\n}\n\n/** Validates a retention-mode registry: parseable, finite, non-negative, unique, traceable. */\nexport function validateRetentionModeRegistry(value: unknown): RetentionModeRegistryV1 {\n\tif (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n\t\tthrow new Error(\"Retention mode registry must be a plain object\");\n\t}\n\tconst record = value as Record<string, unknown>;\n\tassertNonEmptyString(record.policyVersion, \"Retention mode registry.policyVersion\");\n\tif (!Array.isArray(record.modes) || record.modes.length === 0) {\n\t\tthrow new Error(\"Retention mode registry.modes must be a non-empty array\");\n\t}\n\tconst seen = new Set<string>();\n\tconst modes: RetentionModeDefinitionV1[] = record.modes.map((item, index) => {\n\t\tconst label = `Retention mode[${index}]`;\n\t\tif (item === null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\tthrow new Error(`${label} must be a plain object`);\n\t\t}\n\t\tconst entry = item as Record<string, unknown>;\n\t\tassertNonEmptyString(entry.id, `${label}.id`);\n\t\tif (seen.has(entry.id)) throw new Error(`${label} duplicates id: ${entry.id}`);\n\t\tseen.add(entry.id);\n\t\tif (typeof entry.autoPurge !== \"boolean\") throw new Error(`${label}.autoPurge must be boolean`);\n\t\tif (entry.durationMs !== undefined) {\n\t\t\tif (typeof entry.durationMs !== \"number\" || !Number.isSafeInteger(entry.durationMs) || entry.durationMs <= 0) {\n\t\t\t\tthrow new Error(`${label}.durationMs must be a positive safe integer`);\n\t\t\t}\n\t\t}\n\t\treturn Object.freeze({\n\t\t\tid: entry.id,\n\t\t\t...(entry.durationMs === undefined ? {} : { durationMs: entry.durationMs }),\n\t\t\tautoPurge: entry.autoPurge,\n\t\t});\n\t});\n\treturn Object.freeze({\n\t\tpolicyVersion: record.policyVersion,\n\t\tmodes: Object.freeze(modes),\n\t\tget(id: string) {\n\t\t\treturn modes.find((mode) => mode.id === id);\n\t\t},\n\t});\n}\n\nfunction assertNonEmptyString(value: unknown, label: string): asserts value is string {\n\tif (typeof value !== \"string\" || value.trim().length === 0) throw new Error(`${label} must be a non-empty string`);\n}\n\n/** First-party default registry (short/standard/long/permanent). Durations live here, not in Foundation logic. */\nexport function createFirstPartyRetentionRegistry(): RetentionModeRegistryV1 {\n\tconst DAY = 24 * 60 * 60 * 1000;\n\treturn validateRetentionModeRegistry({\n\t\tpolicyVersion: \"retention@1\",\n\t\tmodes: [\n\t\t\t{ id: \"short\", durationMs: 7 * DAY, autoPurge: true },\n\t\t\t{ id: \"standard\", durationMs: 30 * DAY, autoPurge: true },\n\t\t\t{ id: \"long\", durationMs: 365 * DAY, autoPurge: true },\n\t\t\t{ id: \"permanent\", autoPurge: false },\n\t\t],\n\t});\n}\n\nexport interface MemoryStoreCommitOptions {\n\t/** Overrides the atom's retentionMode id at commit time (policy-selected). */\n\treadonly retentionModeId?: string;\n}\n\n/** A committed atom plus the store-assigned bookkeeping facts. */\nexport interface CommittedMemoryV1<TPayload extends JsonValue = JsonValue> {\n\treadonly atom: MemoryAtomV1<TPayload>;\n\t/** Monotonic across the whole store. */\n\treadonly storeRevision: number;\n\t/** Monotonic within the atom's scope partition. */\n\treadonly scopeRevision: number;\n\treadonly committedAt: number;\n\t/** Recall deadline computed from the retention registry. Absent = no expiry. */\n\treadonly purgeAt?: number;\n\treadonly retentionModeId: string;\n}\n\nexport interface MemoryStoreQuery {\n\treadonly owner: string;\n\t/**\n\t * Suite-scoped read boundary (方案系统设计 §6.1/§11). When set, only atoms\n\t * whose suiteId equals this value — plus explicitly promoted user-default\n\t * preferences — are visible; legacy (suiteId-less) atoms are skipped\n\t * fail-safe. When absent, no suite filtering happens (suite-unscoped read).\n\t */\n\treadonly suiteId?: string;\n}\n\nexport interface MemoryStoreStats {\n\treadonly active: number;\n\treadonly expired: number;\n\treadonly byScope: Readonly<Record<MemoryScopeV1, { active: number; expired: number }>>;\n}\n\n/** Result of {@link MemoryStoreV1.listForSuite}: visible records plus skip counters. */\nexport interface MemoryStoreSuitePageV1 {\n\treadonly records: readonly CommittedMemoryV1[];\n\t/** Excluded-record counters for the suite read boundary (设计 §11). */\n\treadonly filter: MemorySuiteFilterStatsV1;\n}\n\nexport interface MemoryStoreV1 {\n\tcommit(atom: MemoryAtomV1, options?: MemoryStoreCommitOptions): CommittedMemoryV1;\n\t/**\n\t * Returns the record only when unexpired, owned by `query.owner`, and —\n\t * when `query.suiteId` is set — visible in that suite (legacy atoms are\n\t * invisible to every suite).\n\t */\n\tget(memoryId: string, query: MemoryStoreQuery): CommittedMemoryV1 | undefined;\n\t/** Lists active records owned by `query.owner`, optionally narrowed to one scope. */\n\tlist(query: MemoryStoreQuery, scope?: MemoryScopeV1): readonly CommittedMemoryV1[];\n\t/**\n\t * Lists EXPIRED records owned by `query.owner`, oldest first (store\n\t * revision ascending) — the read-only enumeration the retention sweep\n\t * batches from (the store's expiry predicate is the single authority; the\n\t * sweep never re-derives expiry). Expiry precedes the suite read boundary\n\t * (an expired record is expired in every suite); records without `purgeAt`\n\t * (`permanent`) never appear. Optional: replacement stores injected\n\t * through the SDK storage seam may omit it — the sweep then skips\n\t * explicitly instead of guessing.\n\t */\n\tlistExpired?(query: MemoryStoreQuery): readonly CommittedMemoryV1[];\n\t/**\n\t * Suite-scoped listing with skip diagnostics: returns the records visible\n\t * in `query.suiteId` plus how many legacy and foreign-suite records were\n\t * excluded (expired records are excluded before the suite filter and are\n\t * not counted here).\n\t */\n\tlistForSuite(query: MemoryStoreQuery & { readonly suiteId: string }, scope?: MemoryScopeV1): MemoryStoreSuitePageV1;\n\tstats(): MemoryStoreStats;\n\t/**\n\t * Physically removes one record from the canonical in-memory ledger — the\n\t * store-side arm of the controlled purge gate (设计 §3.3: only the purge\n\t * flow may destroy committed atoms). Call it exclusively from the purge\n\t * path (suite memory facade / scheduler purge); ordinary business code\n\t * never evicts. Returns true when the record existed. Expired-then-evicted\n\t * and unexpired records are removed alike; a restart replay cannot\n\t * resurrect an evicted atom once the durable replica is rewritten.\n\t */\n\tevict(memoryId: string): boolean;\n}\n\n/** Creates a deterministic three-scope Foundation store. Expired records lose recall but stay ledgered. */\nexport function createMemoryStore(options: {\n\treadonly retentionRegistry: RetentionModeRegistryV1;\n\treadonly now?: () => number;\n}): MemoryStoreV1 {\n\tconst registry = options.retentionRegistry;\n\tconst now = options.now ?? (() => Date.now());\n\tconst records = new Map<string, CommittedMemoryV1>();\n\tlet storeRevision = 0;\n\tconst scopeRevisions = new Map<MemoryScopeV1, number>();\n\n\tconst isExpired = (record: CommittedMemoryV1): boolean => record.purgeAt !== undefined && record.purgeAt <= now();\n\n\tconst requireOwner = (query: MemoryStoreQuery): string => {\n\t\tif (query === null || typeof query !== \"object\" || typeof query.owner !== \"string\" || query.owner.trim() === \"\") {\n\t\t\tthrow new Error(\"Memory store query requires an owner\");\n\t\t}\n\t\tif (query.suiteId !== undefined && (typeof query.suiteId !== \"string\" || query.suiteId.trim() === \"\")) {\n\t\t\tthrow new Error(\"Memory store query requires a non-empty suiteId when filtering by suite\");\n\t\t}\n\t\treturn query.owner;\n\t};\n\n\t/** Suite read boundary: `undefined` query.suiteId means no suite filtering. */\n\tconst isVisibleInSuite = (atom: MemoryAtomV1, suiteId: string | undefined): boolean =>\n\t\tsuiteId === undefined || memorySuiteVisibility(atom, suiteId) === \"visible\";\n\n\treturn {\n\t\tcommit(atom, commitOptions) {\n\t\t\tconst validated = validateMemoryAtomV1(atom);\n\t\t\t// Canonical atoms are immutable once committed (设计 §4): a second\n\t\t\t// commit with the same memoryId is a caller bug and must fail\n\t\t\t// explicitly instead of silently overwriting verified facts.\n\t\t\tif (records.has(validated.memoryId)) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Memory already committed: ${validated.memoryId} (canonical atoms are immutable; use the candidate machine for dedupe)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst modeId = commitOptions?.retentionModeId ?? validated.retentionMode;\n\t\t\tconst mode = registry.get(modeId);\n\t\t\tif (!mode) throw new Error(`Retention mode is not registered: ${modeId}`);\n\t\t\tstoreRevision += 1;\n\t\t\tconst scopeRevision = (scopeRevisions.get(validated.scope) ?? 0) + 1;\n\t\t\tscopeRevisions.set(validated.scope, scopeRevision);\n\t\t\tconst committedAt = now();\n\t\t\tconst committed: CommittedMemoryV1 = Object.freeze({\n\t\t\t\tatom: validated,\n\t\t\t\tstoreRevision,\n\t\t\t\tscopeRevision,\n\t\t\t\tcommittedAt,\n\t\t\t\t...(mode.durationMs === undefined ? {} : { purgeAt: committedAt + mode.durationMs }),\n\t\t\t\tretentionModeId: mode.id,\n\t\t\t});\n\t\t\trecords.set(validated.memoryId, committed);\n\t\t\treturn committed;\n\t\t},\n\t\tget(memoryId, query) {\n\t\t\tconst owner = requireOwner(query);\n\t\t\tconst record = records.get(memoryId);\n\t\t\tif (!record) return undefined;\n\t\t\tif (record.atom.owner !== owner) return undefined;\n\t\t\tif (!isVisibleInSuite(record.atom, query.suiteId)) return undefined;\n\t\t\tif (isExpired(record)) return undefined;\n\t\t\treturn record;\n\t\t},\n\t\tlist(query, scope) {\n\t\t\tconst owner = requireOwner(query);\n\t\t\tconst results: CommittedMemoryV1[] = [];\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.atom.owner !== owner) continue;\n\t\t\t\tif (scope !== undefined && record.atom.scope !== scope) continue;\n\t\t\t\tif (!isVisibleInSuite(record.atom, query.suiteId)) continue;\n\t\t\t\tif (isExpired(record)) continue;\n\t\t\t\tresults.push(record);\n\t\t\t}\n\t\t\treturn Object.freeze(results.sort((left, right) => left.storeRevision - right.storeRevision));\n\t\t},\n\t\tlistExpired(query) {\n\t\t\tconst owner = requireOwner(query);\n\t\t\tconst results: CommittedMemoryV1[] = [];\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.atom.owner !== owner) continue;\n\t\t\t\tif (!isExpired(record)) continue;\n\t\t\t\tresults.push(record);\n\t\t\t}\n\t\t\treturn Object.freeze(results.sort((left, right) => left.storeRevision - right.storeRevision));\n\t\t},\n\t\tlistForSuite(query, scope) {\n\t\t\trequireOwner(query);\n\t\t\tconst suiteId = query.suiteId;\n\t\t\tconst results: CommittedMemoryV1[] = [];\n\t\t\tlet legacySkipped = 0;\n\t\t\tlet foreignSuiteSkipped = 0;\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tif (record.atom.owner !== query.owner) continue;\n\t\t\t\tif (scope !== undefined && record.atom.scope !== scope) continue;\n\t\t\t\tif (isExpired(record)) continue;\n\t\t\t\tconst visibility = memorySuiteVisibility(record.atom, suiteId);\n\t\t\t\tif (visibility === \"legacy\") {\n\t\t\t\t\tlegacySkipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tif (visibility === \"foreign-suite\") {\n\t\t\t\t\tforeignSuiteSkipped += 1;\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tresults.push(record);\n\t\t\t}\n\t\t\tresults.sort((left, right) => left.storeRevision - right.storeRevision);\n\t\t\treturn Object.freeze({\n\t\t\t\trecords: Object.freeze(results),\n\t\t\t\tfilter: Object.freeze({ legacySkipped, foreignSuiteSkipped }),\n\t\t\t});\n\t\t},\n\t\tstats() {\n\t\t\tconst bucket = () => ({ active: 0, expired: 0 });\n\t\t\tconst byScope: Record<MemoryScopeV1, { active: number; expired: number }> = {\n\t\t\t\tsession: bucket(),\n\t\t\t\tcycle: bucket(),\n\t\t\t\t\"long-term\": bucket(),\n\t\t\t};\n\t\t\tlet active = 0;\n\t\t\tlet expired = 0;\n\t\t\tfor (const record of records.values()) {\n\t\t\t\tconst target = byScope[record.atom.scope];\n\t\t\t\tif (isExpired(record)) {\n\t\t\t\t\texpired += 1;\n\t\t\t\t\ttarget.expired += 1;\n\t\t\t\t} else {\n\t\t\t\t\tactive += 1;\n\t\t\t\t\ttarget.active += 1;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn { active, expired, byScope: Object.freeze(byScope) };\n\t\t},\n\t\tevict(memoryId) {\n\t\t\tif (typeof memoryId !== \"string\" || memoryId.trim() === \"\") {\n\t\t\t\tthrow new Error(\"Memory store evict requires a memoryId\");\n\t\t\t}\n\t\t\treturn records.delete(memoryId);\n\t\t},\n\t};\n}\n"]}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * 向量通道状态机(capability 拆分战役 slice 3b):vectorEnsure 状态转换、装配分支(服务/本地/下载/征询门)、dispose 闩锁。共享闭包状态收拢为 channel 对象, 经 deps 显式注入; 降级/投影经 slice 3a 的 vector-projection 上报
3
+ */
4
+ import type { CapabilityAPI, MemoryEnablingOverrideV1, MemoryVectorComponentsOverrideV1 } from "@agent-forge/plugin-sdk";
5
+ import type { ActiveVectorChannelV1 } from "./vector-projection.ts";
6
+ /** 两档共用精排模型 (POC 报告 §8: 官方 Xenova 转换版唯一实测可用)。 */
7
+ export declare const VECTOR_RERANKER_MODEL_ID = "Xenova/bge-reranker-base";
8
+ export declare const VECTOR_DB_DIRNAME = "vector";
9
+ export declare const VECTOR_MODEL_CACHE_DIRNAME = "model-cache";
10
+ /** capability 级状态机 (设计 §3.2): off 只出现在模式关闭 (零注册, 不可观测)。 */
11
+ export type MemoryCapabilityStateV1 = "consent-required" | "enabling" | "ready" | "degraded" | "failed";
12
+ /** enabling 失败的结构化结果: 原因 + 行动清单 (硬性要求, 设计 §3.2)。 */
13
+ export interface MemoryEnablingFailureV1 {
14
+ readonly reason: string;
15
+ readonly actions: readonly string[];
16
+ }
17
+ /**
18
+ * 征询门待决信息 (2026-10-05 用户裁决「首次使用征询、拒绝即持久化关闭」):
19
+ * 向量通道从未就绪且模式已启用时, 模型下载必须先经用户同意——检索不触发下载,
20
+ * 由 AI 转述征询后经 memory_enable 工具面继续。
21
+ */
22
+ export interface MemoryConsentNeededV1 {
23
+ readonly models: readonly string[];
24
+ /** 模型权重体积下限之和 (非精确体积; 实际下载量以镜像文件为准)。 */
25
+ readonly approximateBytes: number;
26
+ }
27
+ /** 征询面 (consent-required 态的模型可见包): AI 转述话术 + 后续动作 + 注入块。 */
28
+ export interface MemoryConsentAskV1 {
29
+ readonly message: string;
30
+ readonly actions: readonly string[];
31
+ readonly block: string;
32
+ }
33
+ /**
34
+ * 向量通道对 capability 装配上下文的显式依赖视图 (slice 3b): 逐项来自
35
+ * createMemoryCapabilityHarness 的闭包捕获核实, 不再经共享闭包隐式可达。
36
+ */
37
+ export interface MemoryVectorChannelDepsV1 {
38
+ /** agent 根目录 (MemoryCapabilityContext.agentDir): 模型缓存/索引/征询持久化的路径域。 */
39
+ readonly agentDir: string;
40
+ /** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */
41
+ readonly memoryMode: "light" | "full";
42
+ /** capability 日志面 (api.logger): 进度/失败/自愈日志。 */
43
+ readonly logger: CapabilityAPI["logger"];
44
+ /** 宿主注入的 onnxruntime-node 入口 (MemoryCapabilityContext.hostOnnxRuntimeEntryPath)。 */
45
+ readonly hostOnnxRuntimeEntryPath?: string;
46
+ /** 宿主注入的 @lancedb/lancedb 入口 (MemoryCapabilityContext.hostLancedbEntryPath)。 */
47
+ readonly hostLancedbEntryPath?: string;
48
+ /** 宿主注入的 @huggingface/transformers 入口 (MemoryCapabilityContext.hostTransformersEntryPath)。 */
49
+ readonly hostTransformersEntryPath?: string;
50
+ /** 服务装配缝 (Slice B2): 测试端口直连 (MemoryCapabilityContext.inferenceService.port)。 */
51
+ readonly inferenceServicePort?: number;
52
+ /** 服务装配缝 (Slice B2): 替换进程拉起的测试缝 (inferenceService.spawnImpl)。 */
53
+ readonly inferenceServiceSpawnImpl?: (agentDir: string, mode: "light" | "full", port: number,
54
+ /** spawn 异步失败 (EACCES/ENOMEM 等) 的回调; 缺省实现经 child 'error' 事件馈入。 */
55
+ onError?: (error: Error) => void) => Promise<void>;
56
+ /** 服务装配缝 (Slice B2): 声明模型在位, 文件检查与征询门让位 (inferenceService.modelsInPlace)。 */
57
+ readonly inferenceServiceModelsInPlace?: boolean;
58
+ /** enabling 测试缝 (loadImpl 重定向模型加载); undefined = 生产路径。 */
59
+ readonly enablingOverride?: MemoryEnablingOverrideV1;
60
+ /** 组件注入 (deterministic mock 门禁): 存在时通道直接 ready, 跳过真实装配。 */
61
+ readonly injectedComponents?: MemoryVectorComponentsOverrideV1;
62
+ /** 写侧投影 (slice 3a 的 vectorProjection.resetReconcile): downloadMemory 就绪后重臂启动对账。 */
63
+ readonly resetReconcile: () => void;
64
+ /** 写侧投影 (slice 3a 的 vectorProjection.reconcileOnce): downloadMemory 就绪后补跑对账。 */
65
+ readonly reconcileOnce: () => void;
66
+ }
67
+ export interface MemoryVectorChannelV1 {
68
+ /** harness.vectorState 面: 征询拒绝时投影为 "off" (本实例按模式关闭对待)。 */
69
+ state(): "off" | MemoryCapabilityStateV1;
70
+ /** vectorState 原值 (未做 declined 投影; recall/合并探测等内部消费)。 */
71
+ rawState(): MemoryCapabilityStateV1;
72
+ /** vectorEnabled: failed/consent-required/declined 时 false (写侧埋点门)。 */
73
+ enabled(): boolean;
74
+ /** 已就绪通道的同步快照 (vectorChannel 只读; projection.readyChannel 面)。 */
75
+ readyChannel(): ActiveVectorChannelV1 | undefined;
76
+ /** dispose 闩锁只读视图 (capabilityDisposed; projection.isDisposed 面)。 */
77
+ isDisposed(): boolean;
78
+ /** 征询拒绝标记 (declineMemory 持久化后的本实例内存面)。 */
79
+ declined(): boolean;
80
+ /** 用户显式再启用 (/memory light|full、自动升档) 清除本实例拒绝标记。 */
81
+ clearDeclined(): void;
82
+ /** 征询一次性注入钉住标记 (auto-recall 每实例只注入一次)。 */
83
+ consentAsked(): boolean;
84
+ markConsentAsked(): void;
85
+ /** 无副作用征询探测 (auto-recall 首轮; 纯本地 stat, 绝不触发下载/加载)。 */
86
+ primeConsentGate(): void;
87
+ /** 征询待决面 (consent-required 且待决信息就位时非 undefined; 纯只读, 不探测)。 */
88
+ consentAsk(): MemoryConsentAskV1 | undefined;
89
+ /** warming 守卫 (recall 后台预热不阻塞读侧): 装配在途且未拒绝。 */
90
+ warming(): boolean;
91
+ /** enabling 失败结构化结果 (未失败 = undefined)。 */
92
+ failure(): MemoryEnablingFailureV1 | undefined;
93
+ /** 运行期故障 → degraded (可自愈; recall 与投影对账共用)。 */
94
+ markDegraded(): void;
95
+ /** degraded → ready 的自愈转换 (仅从 degraded; 全通 recall 成功后调用)。 */
96
+ recoverDegraded(): void;
97
+ /** vectorEnsure: 惰性单飞装配 (recall/write/埋点/对账的公共入口)。 */
98
+ ensure(): Promise<ActiveVectorChannelV1 | undefined>;
99
+ /** harness.enablingOutcome 面: 触发惰性 enabling 并等待落定 (ready 或结构化失败)。 */
100
+ enablingOutcome(): Promise<"ready" | MemoryEnablingFailureV1>;
101
+ /** declineMemory 核心: 持久化拒绝 + 本实例按模式关闭。 */
102
+ decline(): {
103
+ status: "completed";
104
+ message: string;
105
+ };
106
+ /** downloadMemory 核心: 置征询同意 + 装配 + 补跑启动对账。 */
107
+ download(): Promise<{
108
+ status: "completed";
109
+ message: string;
110
+ } | {
111
+ status: "failed";
112
+ message: string;
113
+ actions?: readonly string[];
114
+ next?: string;
115
+ }>;
116
+ /** capabilityTeardown 本体: 资源关闭 + 闩锁置位 (幂等)。 */
117
+ dispose(): void;
118
+ }
119
+ export declare function createMemoryVectorChannel(deps: MemoryVectorChannelDepsV1): MemoryVectorChannelV1;
120
+ //# sourceMappingURL=vector-channel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vector-channel.d.ts","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"]}