@ai-agent-forge/plugin-memory 0.88.19 → 0.88.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/agent-forge.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "packageFormatVersion": 1,
3
3
  "id": "agent-forge.plugin.memory",
4
- "pluginVersion": "0.88.19",
4
+ "pluginVersion": "0.88.20",
5
5
  "apiVersion": "1",
6
6
  "minHostVersion": "0.84.4",
7
7
  "platform": {
@@ -2306,6 +2306,23 @@ var init_embedding_reranker = __esm({
2306
2306
  function escapeSqlLiteral(value) {
2307
2307
  return value.replace(/'/g, "''");
2308
2308
  }
2309
+ function partitionIdentitySafeWrites(rows, stored) {
2310
+ const accepted = [];
2311
+ const collisions = [];
2312
+ for (const row of rows) {
2313
+ const storedBody = stored.get(row.memoryId);
2314
+ if (storedBody === void 0) {
2315
+ accepted.push(row);
2316
+ continue;
2317
+ }
2318
+ if (storedBody === row.body) {
2319
+ accepted.push(row);
2320
+ continue;
2321
+ }
2322
+ collisions.push({ memoryId: row.memoryId, storedBody, incomingBody: row.body });
2323
+ }
2324
+ return { accepted, collisions };
2325
+ }
2309
2326
  async function createMemoryVectorIndex(options) {
2310
2327
  const dimensions = options.dimensions;
2311
2328
  const lancedb = await importHostOrBareModule(
@@ -2343,6 +2360,14 @@ async function createMemoryVectorIndex(options) {
2343
2360
  } catch {
2344
2361
  }
2345
2362
  };
2363
+ const storedBodiesFor = async (target, rows) => {
2364
+ const ids = [...new Set(rows.map((row) => row.memoryId))];
2365
+ if (ids.length === 0) return /* @__PURE__ */ new Map();
2366
+ const predicate = `memoryId IN (${ids.map((id) => `'${escapeSqlLiteral(id)}'`).join(",")})`;
2367
+ const found = await target.query().where(predicate).select(["memoryId", "body"]).toArray();
2368
+ return new Map(found.map((row) => [row.memoryId, row.body]));
2369
+ };
2370
+ const reportedCollisions = /* @__PURE__ */ new Set();
2346
2371
  return {
2347
2372
  replicaId: "memory-vector-index",
2348
2373
  upsert: (entries) => withOpenIndex(async () => {
@@ -2369,7 +2394,15 @@ async function createMemoryVectorIndex(options) {
2369
2394
  await createBodyFtsIndex(table);
2370
2395
  return;
2371
2396
  }
2372
- await current.mergeInsert("memoryId").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute(rows);
2397
+ const { accepted, collisions } = partitionIdentitySafeWrites(rows, await storedBodiesFor(current, rows));
2398
+ for (const collision of collisions) {
2399
+ const key = `${collision.memoryId}\0${collision.storedBody}`;
2400
+ if (reportedCollisions.has(key)) continue;
2401
+ reportedCollisions.add(key);
2402
+ options.onCollision?.(collision);
2403
+ }
2404
+ if (accepted.length === 0) return;
2405
+ await current.mergeInsert("memoryId").whenMatchedUpdateAll().whenNotMatchedInsertAll().execute([...accepted]);
2373
2406
  }),
2374
2407
  remove: (memoryIds) => withOpenIndex(async () => {
2375
2408
  if (memoryIds.length === 0) {
@@ -7154,14 +7187,30 @@ var recallSchema = typebox_exports.Object({
7154
7187
  description: "Natural-language query; recall fuses semantic (vector) and full-text (BM25) matching and reranks the result. An exact memoryId retrieves that memory directly"
7155
7188
  }),
7156
7189
  limit: typebox_exports.Optional(
7157
- typebox_exports.Integer({ description: "Maximum number of memories to return (1-100)", minimum: 1, maximum: 100 })
7190
+ typebox_exports.Integer({
7191
+ description: "Maximum number of memories to return (1-100, default 5)",
7192
+ minimum: 1,
7193
+ maximum: 100
7194
+ })
7158
7195
  ),
7159
7196
  context: typebox_exports.Optional(
7160
7197
  typebox_exports.Object(
7161
7198
  {
7162
- scenes: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String())),
7163
- projects: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String())),
7164
- tasks: typebox_exports.Optional(typebox_exports.Array(typebox_exports.String()))
7199
+ scenes: typebox_exports.Optional(
7200
+ typebox_exports.Array(typebox_exports.String(), {
7201
+ description: "Scene tags of the current task, used to resolve preferences by scope"
7202
+ })
7203
+ ),
7204
+ projects: typebox_exports.Optional(
7205
+ typebox_exports.Array(typebox_exports.String(), {
7206
+ description: "Project identifiers of the current task, used to resolve preferences by scope"
7207
+ })
7208
+ ),
7209
+ tasks: typebox_exports.Optional(
7210
+ typebox_exports.Array(typebox_exports.String(), {
7211
+ description: "Task or goal identifiers of the current task, used to resolve preferences by scope"
7212
+ })
7213
+ )
7165
7214
  },
7166
7215
  {
7167
7216
  description: "Current scope context; when present, recalled preferences are resolved against it (out-of-scope preferences drop, competing values resolve by scope specificity or surface as explicit conflicts)"
@@ -11519,7 +11568,7 @@ var writeSchema = typebox_exports.Object({
11519
11568
  // src/memory/command-face.ts
11520
11569
  var listSchema = typebox_exports.Object({
11521
11570
  limit: typebox_exports.Optional(
11522
- typebox_exports.Integer({ description: "Maximum number of entries to list (1-100)", minimum: 1, maximum: 100 })
11571
+ typebox_exports.Integer({ description: "Maximum number of entries to list (1-100, default 20)", minimum: 1, maximum: 100 })
11523
11572
  )
11524
11573
  });
11525
11574
  var forgetSchema = typebox_exports.Object({
@@ -11977,7 +12026,13 @@ async function runMemoryInferenceService(options) {
11977
12026
  const vectorIndex = await createMemoryVectorIndex({
11978
12027
  dbPath: join7(options.agentDir, "memory", VECTOR_DB_DIRNAME),
11979
12028
  dimensions: preset.dimensions,
11980
- ...options.moduleEntryPaths?.lancedb === void 0 ? {} : { moduleEntryPath: options.moduleEntryPaths.lancedb }
12029
+ ...options.moduleEntryPaths?.lancedb === void 0 ? {} : { moduleEntryPath: options.moduleEntryPaths.lancedb },
12030
+ // P5 残留守卫 (与本地通道同语义): 拒绝覆盖外来同 id 行, 服务进程日志留痕。
12031
+ onCollision: (collision) => {
12032
+ log2(
12033
+ "memory-inference: vector projection refused to overwrite a row whose memoryId belongs to a different atom (cross-domain id collision): " + collision.memoryId
12034
+ );
12035
+ }
11981
12036
  });
11982
12037
  backend = { embedProvider, reranker, vectorIndex };
11983
12038
  }
@@ -1 +1 @@
1
- {"version":3,"file":"command-face.d.ts","sourceRoot":"","sources":["../../src/memory/command-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 命令面(capability 拆分战役 slice 6):memory_list / memory_forget 工具、\n * /memory 与 /promote 命令、memory_enable 征询执行面与 memory.scheduler 能力\n * 声明。物理删除的授权引用构造在本面(用户命令链专用); decline/download 仍\n * 薄委托 vectorChannelCtl(slice 3b 先例, 经 deps 下的 channel 对象调用);\n * 搬移函数体逐字节保留。\n */\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { writeMemorySettingsMode } from \"./enabling.ts\";\nimport type { DurableMemoryLedgerV1 } from \"./ledger.ts\";\nimport { promotePreferenceToUserDefault } from \"./preference-promotion.ts\";\nimport type { MemoryPurgeGateV1 } from \"./purge.ts\";\nimport type { MemoryPurgeJournalV1 } from \"./purge-journal.ts\";\nimport type { MemoryStoreV1 } from \"./store.ts\";\nimport {\n\tforgetDomainMemory,\n\tlistDomainMemories,\n\ttype SuiteForgetAuthorizationRefV1,\n\ttype SuiteMemoryDomainV1,\n\ttype SuiteMemoryListEntryV1,\n} from \"./suite-memory.ts\";\nimport type { MemoryVectorChannelV1 } from \"./vector-channel.ts\";\nimport type { MemoryVectorProjectionV1 } from \"./vector-projection.ts\";\nimport { EVENT_TYPE } from \"./write-face.ts\";\n\nconst DEFAULT_LIST_LIMIT = 20;\n\nconst listSchema = Type.Object({\n\tlimit: Type.Optional(\n\t\tType.Integer({ description: \"Maximum number of entries to list (1-100)\", minimum: 1, maximum: 100 }),\n\t),\n});\n\nconst forgetSchema = Type.Object({\n\tmemoryId: Type.String({\n\t\tdescription: \"The memoryId of the memory to forget, as returned by memory_write or memory_list\",\n\t}),\n});\n\nconst enableSchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"download\"), Type.Literal(\"decline\"), Type.Literal(\"retry\")], {\n\t\tdescription:\n\t\t\t'\"download\" / \"retry\" run the one-time model download (retry re-runs after a failure); \"decline\" persists memory off for this machine',\n\t}),\n});\n\n/** Canonical memoryId of the promoted copy of one preference (promotePreferenceToUserDefault suffix). */\nconst userDefaultMemoryId = (memoryId: string): string => `${memoryId}-user-default`;\n\n/**\n * 命令面对 capability 闭包的显式依赖视图 (slice 6): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实。状态机 (vectorChannelCtl)、\n * 写侧投影 (vectorProjection) 与 purge 组件归 capability 装配所有, 本模块经\n * 对象只读消费; capability 模块级纯函数经 deps 注入避免双头定义。\n */\nexport interface MemoryCommandFaceDepsV1 {\n\t/** 工具注册面 (api.registerTool): memory_list/forget/enable 经同一公共通道注册。 */\n\treadonly registerTool: CapabilityAPI[\"registerTool\"];\n\t/** 命令注册面 (api.registerCommand): /memory 与 /promote。 */\n\treadonly registerCommand: CapabilityAPI[\"registerCommand\"];\n\t/** 事件发布面 (api.publish): memory.changed forgotten 事件。 */\n\treadonly publish: CapabilityAPI[\"publish\"];\n\t/** 能力声明面 (api.capabilities): memory.scheduler@1 provide。 */\n\treadonly capabilities: CapabilityAPI[\"capabilities\"];\n\t/** 检索行 owner (capability.BUILTIN_MEMORY_OWNER)。 */\n\treadonly owner: string;\n\t/** 会话 id (harness sessionId): forget 授权引用 confirmationRef 组成。 */\n\treadonly sessionId: string;\n\t/** capability 清单 (capabilityManifest): issuedBy / authorizedBy / 事件 correlationId 来源。 */\n\treadonly manifest: { readonly id: string };\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 档位持久化路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** 时钟 (harness now)。 */\n\treadonly now: () => number;\n\t/** canonical store (per-capability 单例): 列表/成员判定/晋升回查。 */\n\treadonly store: MemoryStoreV1;\n\t/** purge 门 (capability.purgeGate): 物理删除唯一生产入口的授权面。 */\n\treadonly purgeGate: MemoryPurgeGateV1;\n\t/** purge 日志 (capability.purgeJournal)。 */\n\treadonly purgeJournal: MemoryPurgeJournalV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection): forget 批次的 index 副本分派与晋升埋点。 */\n\treadonly vectorProjection: MemoryVectorProjectionV1;\n\t/** 向量通道 (slice 3b 的 vectorChannelCtl): 状态行与 decline/download 薄委托。 */\n\treadonly vectorChannelCtl: MemoryVectorChannelV1;\n\t/** 域解析 (capability.resolveDomain): 每次调用时惰性解析 (B1 语义)。 */\n\treadonly resolveDomain: () => {\n\t\treadonly domain: SuiteMemoryDomainV1;\n\t\treadonly domainName: string;\n\t\treadonly ledger: DurableMemoryLedgerV1;\n\t};\n\t// ---- capability 模块级纯函数 (留守方, 经 deps 注入避免双头定义) ----\n\treadonly assertNonEmptyString: (value: unknown, label: string) => asserts value is string;\n\treadonly memoryToolInput: (first: unknown, second: unknown) => Record<string, unknown>;\n\treadonly statementOf: (payload: unknown) => string;\n\treadonly unwrapEgressStatement: (statement: string) => string;\n\t// ---- 写入面闭包视图 (slice 5 的 writeFace): 升档声明状态归 write-face 所有 ----\n\t/** 升档声明只读视图 (/memory 状态行 pending 尾巴)。 */\n\treadonly tierUpgradePending: () => boolean;\n\t/** 用户显式档位表达取代本实例升档声明 (/memory light)。 */\n\treadonly clearTierUpgrade: () => void;\n}\n\n/** 命令面工厂产物: 注册项集合 (capability registrations 按既有顺序收集)。 */\nexport interface MemoryCommandFaceV1 {\n\t/** memory_list 工具注册项。 */\n\treadonly listTool: DisposableRegistration;\n\t/** memory_forget 工具注册项 (仅登记请求, 物理删除在 /memory forget)。 */\n\treadonly forgetTool: DisposableRegistration;\n\t/** memory_enable 工具注册项 (征询门执行面)。 */\n\treadonly enableTool: DisposableRegistration;\n\t/** /memory 命令注册项。 */\n\treadonly memoryCommand: DisposableRegistration;\n\t/** /promote 命令注册项。 */\n\treadonly promoteCommand: DisposableRegistration;\n\t/** memory.scheduler@1 plugin capability 声明注册项。 */\n\treadonly schedulerCapability: DisposableRegistration;\n}\n\nexport function createMemoryCommandFace(deps: MemoryCommandFaceDepsV1): MemoryCommandFaceV1 {\n\tconst {\n\t\tregisterTool,\n\t\tregisterCommand,\n\t\tpublish,\n\t\tcapabilities,\n\t\towner,\n\t\tsessionId,\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tnow,\n\t\tstore,\n\t\tpurgeGate,\n\t\tpurgeJournal,\n\t\tvectorProjection,\n\t\tvectorChannelCtl,\n\t\tresolveDomain,\n\t\tmemoryToolInput,\n\t\tstatementOf,\n\t\tunwrapEgressStatement,\n\t\ttierUpgradePending,\n\t\tclearTierUpgrade,\n\t} = deps;\n\tconst { manifest: capabilityManifest } = deps;\n\n\t/** Recency-first payload projection: unwraps the `{ statement }` payload convention. */\n\tfunction entryToToolEntry(entry: SuiteMemoryListEntryV1): Record<string, unknown> {\n\t\treturn {\n\t\t\tmemoryId: entry.memoryId,\n\t\t\tkind: entry.memoryKind,\n\t\t\tstatement: statementOf(entry.payload),\n\t\t\toccurredAt: entry.occurredAt,\n\t\t\t...(entry.preference === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpreference: {\n\t\t\t\t\t\t\tsubject: entry.preference.subject,\n\t\t\t\t\t\t\tkey: entry.preference.key,\n\t\t\t\t\t\t\tscopeLevel: entry.preference.scopeLevel,\n\t\t\t\t\t\t\tcrossSuiteVisible: entry.preference.crossSuiteVisible,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t};\n\t}\n\n\tconst listTool = registerTool({\n\t\tname: \"memory_list\",\n\t\tlabel: \"List memories\",\n\t\tdescription: \"List this suite's durable memories (the explicit management surface for personal data)\",\n\t\tparameters: listSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst rawLimit: unknown = input.limit;\n\t\t\tconst limit =\n\t\t\t\trawLimit === undefined\n\t\t\t\t\t? DEFAULT_LIST_LIMIT\n\t\t\t\t\t: ((): number => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof rawLimit !== \"number\" ||\n\t\t\t\t\t\t\t\t!Number.isSafeInteger(rawLimit) ||\n\t\t\t\t\t\t\t\trawLimit < 1 ||\n\t\t\t\t\t\t\t\trawLimit > 100\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow new Error(\"limit must be an integer between 1 and 100\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn rawLimit;\n\t\t\t\t\t\t})();\n\t\t\tconst { domain } = resolveDomain();\n\t\t\tconst page = listDomainMemories({ store }, { owner, domain });\n\t\t\treturn {\n\t\t\t\tdomain: page.domain,\n\t\t\t\tentries: page.entries.slice(0, limit).map(entryToToolEntry),\n\t\t\t\ttotal: page.entries.length,\n\t\t\t\tpreferenceCount: page.preferenceCount,\n\t\t\t\tfactCount: page.factCount,\n\t\t\t\tfilter: page.filter,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * 物理删除唯一生产入口 (诚实化设计 §2, 2026-10-05 裁决): 用户命令链\n\t * `/memory forget <id> confirm`。授权引用由命令分发构造 (structured\n\t * confirmationRef `memory-forget-command:<session>:<memoryId>:confirmed`),\n\t * 模型工具面不再签发 user-immediate 授权 (记忆系统设计 :997 — 授权不能由\n\t * 模型生成)。\n\t */\n\tconst purgeMemoryViaUserCommand = (memoryId: string) => {\n\t\tconst { domain, ledger } = resolveDomain();\n\t\tconst authorizationRef: SuiteForgetAuthorizationRefV1 = {\n\t\t\tmode: \"user-immediate\",\n\t\t\tissuedAt: now(),\n\t\t\tissuedBy: `${capabilityManifest.id}:/memory-forget-confirm`,\n\t\t\tconfirmationRef: `memory-forget-command:${sessionId}:${memoryId}:confirmed`,\n\t\t};\n\t\treturn forgetDomainMemory(\n\t\t\t{\n\t\t\t\tstore,\n\t\t\t\tpurgeGate,\n\t\t\t\tpurgeJournal,\n\t\t\t\t// index 副本分派 (混合检索工程化): canonical 走下方原回调, 向量投影由\n\t\t\t\t// suite-memory 的 executePurgeBatch 按副本路由到这里。\n\t\t\t\tpurgeIndexReplica: vectorProjection.purgeMemories,\n\t\t\t\tnow,\n\t\t\t},\n\t\t\t{\n\t\t\t\towner,\n\t\t\t\tdomain,\n\t\t\t\tmemoryId,\n\t\t\t\tauthorizedBy: `${capabilityManifest.id}:memory-forget-command`,\n\t\t\t\tauthorizationRef,\n\t\t\t},\n\t\t\t(memoryIds) => {\n\t\t\t\tconst purged = new Set(memoryIds);\n\t\t\t\t// Physical replica purge: rewrite the durable ledger without the\n\t\t\t\t// purged atoms, then evict them from the in-memory store so the\n\t\t\t\t// running process cannot recall them either (both idempotent for\n\t\t\t\t// purge_eligible retries).\n\t\t\t\tledger.rewrite(ledger.atomsSnapshot().filter((atom) => !purged.has(atom.memoryId)));\n\t\t\t\tfor (const id of memoryIds) store.evict(id);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst forgetTool = registerTool({\n\t\tname: \"memory_forget\",\n\t\tlabel: \"File a forget request\",\n\t\tdescription:\n\t\t\t\"File a request to forget one memory of this suite by memoryId. This tool never deletes anything — physical deletion is user-only: the user confirms via /memory forget <memoryId> confirm\",\n\t\tparameters: forgetSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tdeps.assertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\tconst unscoped = store.get(input.memoryId, { owner });\n\t\t\tif (unscoped === undefined) {\n\t\t\t\treturn { status: \"not_found\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 域成员判定与 forgetDomainMemory 同判据 (suiteId 匹配 / legacy 为\n\t\t\t// undefined): 请求面同样拒绝外域 id — 模型连\"请求遗忘\"都不能指向别的域。\n\t\t\tconst isMember =\n\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\tif (!isMember) {\n\t\t\t\treturn { status: \"foreign_domain\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 请求的登记价值由返回文本承载 (转告用户确认命令); 无进程内状态 —\n\t\t\t// 重复请求幂等 (同一提示再次返回)。\n\t\t\treturn {\n\t\t\t\tstatus: \"requested\" as const,\n\t\t\t\tmemoryId: input.memoryId,\n\t\t\t\trequest:\n\t\t\t\t\t`Forget request filed for \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\" in domain ${domainName}. ` +\n\t\t\t\t\t`Nothing is deleted yet — tell the user to confirm the deletion with: /memory forget ${input.memoryId} confirm`,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * /promote (偏好晋升触发, B2; 2026-10-05 诚实化裁决起两步确认): the production\n\t * caller of {@link promotePreferenceToUserDefault}. Promotes one of THIS\n\t * session's preferences to the user-default scope: the promoted canonical atom\n\t * is appended to the session domain's durable ledger and committed to the\n\t * store, so every suite's preference-card read (which applies the suite read\n\t * boundary across all of the owner's ledgers) sees it from now on. The\n\t * original atom is never rewritten. Promotion is an irreversible cross-suite\n\t * authorization face, so the first run only shows the target and asks the\n\t * user to re-run with `confirm`. Errors (unknown id, non-preference, already\n\t * promoted) surface as error results, never as thrown failures — a slash\n\t * command must not crash the host.\n\t */\n\tconst promoteCommand = registerCommand({\n\t\tname: \"promote\",\n\t\tdescription:\n\t\t\t\"Promote a memory preference to the user-default scope (visible in every suite; two-step — re-run with confirm)\",\n\t\targumentHint: \"<memoryId> [confirm]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst memoryId = tokens[0] ?? \"\";\n\t\t\tconst confirmed = tokens[1] === \"confirm\";\n\t\t\tif (memoryId === \"\" || tokens.length > 2 || (tokens[1] !== undefined && !confirmed)) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: \"Usage: /promote <memoryId> [confirm] — run memory_list for this suite's memory ids\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst record = store.get(memoryId, { owner });\n\t\t\tif (!record) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst atom = record.atom;\n\t\t\tif (atom.memoryKind !== \"preference\" || atom.preference === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `${memoryId} is a fact, not a preference; only preferences can be promoted`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (store.get(userDefaultMemoryId(memoryId), { owner }) !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `Preference ${memoryId} is already promoted to the user-default scope`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!confirmed) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Promotion target: \"${unwrapEgressStatement(statementOf(atom.payload))}\"\\n` +\n\t\t\t\t\t\t\"This makes the preference visible in EVERY suite (user-default scope, permanent). Nothing is promoted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t`/promote ${memoryId} confirm`,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst promoted = promotePreferenceToUserDefault({\n\t\t\t\t\tatom,\n\t\t\t\t\tauthorizedBy: \"user:/promote\",\n\t\t\t\t\tconfirmedAt: new Date(now()).toISOString(),\n\t\t\t\t});\n\t\t\t\tconst { domainName, ledger } = resolveDomain();\n\t\t\t\tledger.append(promoted);\n\t\t\t\tstore.commit(promoted);\n\t\t\t\t// 向量投影埋点: 与 memory_write 同一异步旁路 (失败不阻塞命令返回)。\n\t\t\t\tvectorProjection.upsertAtom(promoted);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage: `Promoted \"${unwrapEgressStatement(statementOf(promoted.payload))}\" to the user-default scope; it is now visible in every suite`,\n\t\t\t\t\tdata: { memoryId: promoted.memoryId, sourceMemoryId: memoryId, domain: domainName },\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\" as const, message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\t// memory.scheduler@1 plugin capability (宪法 §3 显式声明面): a declarative\n\t// marker only — the scheduler enforcement itself (per-instance single\n\t// lease, acquired above) stays carried by the host builtin implementation.\n\t// The declaration anchors \"this suite's memory scheduling is provided by\n\t// this plugin\" so the code Profile assembly check (requiresMemoryScheduler)\n\t// and third-party replacement detection have an explicit surface:\n\t// list()-visible, a same-id double provide fails explicitly (no override\n\t// priority), and after dispose a replacement provider can take the id.\n\tconst schedulerCapability = capabilities.provide({ id: \"memory.scheduler\", version: 1, kind: \"service\" }, () =>\n\t\tObject.freeze({\n\t\t\tid: \"memory.scheduler\",\n\t\t\tversion: 1,\n\t\t\towner: \"agent-forge.builtin.memory\",\n\t\t\tleaseScope: \"per-agent-instance\",\n\t\t}),\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 是用户的直接出口。decline/download\n\t// 核心在 memory/vector-channel.ts (slice 3b), 工具与命令面经\n\t// vectorChannelCtl.decline()/download() 薄委托; decline 持久化只抑制默认档。\n\t/**\n\t * Structured status for host consoles (公共命令结果 data, additive):\n\t * the TUI `/memory` console reads mode/channel/domain without parsing the\n\t * human message. `channel` mirrors the vector state machine; decline is\n\t * reported as \"off\" (the line's existing semantics).\n\t */\n\tconst memoryStatusSnapshot = (): {\n\t\treadonly mode: \"light\" | \"full\";\n\t\treadonly channel: \"off\" | \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\t\treadonly declined: boolean;\n\t\treadonly pendingUpgrade: boolean;\n\t\treadonly failureReason?: string;\n\t} => {\n\t\t// pending 尾巴只对仍有效的升档声明 (declined 分支里档位键已被删除, 显示\n\t\t// pending 会失实 — 2026-10-06 复审 P2-1)。\n\t\tconst declined = vectorChannelCtl.declined();\n\t\tconst pendingUpgrade = tierUpgradePending() && !declined;\n\t\tconst failureReason = vectorChannelCtl.failure()?.reason;\n\t\treturn {\n\t\t\tmode: memoryMode,\n\t\t\tchannel: declined ? \"off\" : vectorChannelCtl.rawState(),\n\t\t\tdeclined,\n\t\t\tpendingUpgrade,\n\t\t\t...(failureReason === undefined ? {} : { failureReason }),\n\t\t};\n\t};\n\tconst memoryStatusLine = (status: ReturnType<typeof memoryStatusSnapshot>): string => {\n\t\tconst modeLine = `mode=${status.mode}${status.pendingUpgrade ? \", auto-upgrade to full pending (next session)\" : \"\"}`;\n\t\tif (status.declined) {\n\t\t\treturn `${modeLine}, off (declined on this machine). Set memory.mode (light|full) in settings.json and restart the session to re-enable`;\n\t\t}\n\t\tif (status.channel === \"ready\") return `${modeLine}, ready`;\n\t\tif (status.channel === \"degraded\") return `${modeLine}, ready (degraded)`;\n\t\tif (status.channel === \"failed\") return `${modeLine}, failed: ${status.failureReason ?? \"unknown reason\"}`;\n\t\tif (status.channel === \"consent-required\") {\n\t\t\treturn `${modeLine}, waiting for the model download decision (/memory retry to start it)`;\n\t\t}\n\t\treturn `${modeLine}, loading models in the background`;\n\t};\n\tconst enableTool = registerTool({\n\t\tname: \"memory_enable\",\n\t\tlabel: \"Enable memory\",\n\t\tdescription:\n\t\t\t'Run or decline the one-time memory model download. The host starts it in the background at session start; call it with \"retry\" after a failure, or with \"decline\" when the user chooses to keep memory off',\n\t\tparameters: enableSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst action: unknown = input.action;\n\t\t\tif (action !== \"download\" && action !== \"decline\" && action !== \"retry\") {\n\t\t\t\tthrow new Error('action must be \"download\", \"decline\", or \"retry\"');\n\t\t\t}\n\t\t\tif (action === \"decline\") return vectorChannelCtl.decline();\n\t\t\treturn vectorChannelCtl.download();\n\t\t},\n\t});\n\tconst memoryCommand = registerCommand({\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory controls: bare shows status; light|full switches the model preset (persisted, effective next session); off persists disable; retry re-runs the model download; forget <memoryId> [confirm] is the user-only physical delete (two-step)\",\n\t\targumentHint: \"[light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tif (tokens[0] === \"forget\") {\n\t\t\t\tconst memoryId = tokens[1] ?? \"\";\n\t\t\t\tconst confirmed = tokens[2] === \"confirm\";\n\t\t\t\tif (memoryId === \"\" || tokens.length > 3 || (tokens[2] !== undefined && !confirmed)) {\n\t\t\t\t\treturn { status: \"error\" as const, message: \"Usage: /memory forget <memoryId> [confirm]\" };\n\t\t\t\t}\n\t\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\t\tconst unscoped = store.get(memoryId, { owner });\n\t\t\t\tif (unscoped === undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst isMember =\n\t\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\t\tif (!isMember) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `${memoryId} belongs to another suite; each suite forgets only its own memories`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Forget target: \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\"\\n` +\n\t\t\t\t\t\t\t\"This permanently deletes the memory (irreversible, purge-gated). Nothing is deleted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t\t`/memory forget ${memoryId} confirm`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst result = purgeMemoryViaUserCommand(memoryId);\n\t\t\t\tif (result.status === \"completed\") {\n\t\t\t\t\tawait publish({\n\t\t\t\t\t\ttype: EVENT_TYPE,\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\tcorrelationId: capabilityManifest.id,\n\t\t\t\t\t\tdata: { action: \"forgotten\", memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage: `Forgot ${memoryId} (${domainName}): the memory is physically deleted`,\n\t\t\t\t\t\tdata: { memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { status: \"error\" as const, message: `forget failed: ${result.status}` };\n\t\t\t}\n\t\t\tconst sub = args.trim().toLowerCase();\n\t\t\tif (sub === \"\" || sub === \"status\") {\n\t\t\t\tconst snapshot = memoryStatusSnapshot();\n\t\t\t\tconst statusResult: CapabilityCommandResult = {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\tmessage: `memory: ${memoryStatusLine(snapshot)}`,\n\t\t\t\t\tdata: { memoryStatus: snapshot },\n\t\t\t\t};\n\t\t\t\treturn statusResult;\n\t\t\t}\n\t\t\tif (sub === \"light\" || sub === \"full\") {\n\t\t\t\t// 无\"已是该档\"早退: 持久化档位与会话内已解析档位是两回事——会话可能\n\t\t\t\t// 因默认档而运行 light, 用户降档仍需把持久化值落盘 (或覆盖旧档)。\n\t\t\t\twriteMemorySettingsMode(agentDir, sub);\n\t\t\t\t// 升/降档清了文件里的拒绝标记, 内存标记同步翻回: 用户最新的显式\n\t\t\t\t// 意图是启用——本会话恢复对当前预置的响应 (retry 可用), 新档与\n\t\t\t\t// 新模型下载在下一会话生效。\n\t\t\t\tvectorChannelCtl.clearDeclined();\n\t\t\t\t// 用户的显式档位表达取代本实例的自动升档声明: 降回 light 后 pending\n\t\t\t\t// 尾巴不再显示, 且显式 light 会让自动升档在后续写入中跳过 (复审 P2-1)。\n\t\t\t\tif (sub === \"light\") clearTierUpgrade();\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`memory: preset ${sub} persisted (capabilities/builtin.memory.json). It takes effect next session — ` +\n\t\t\t\t\t\t(sub === \"full\"\n\t\t\t\t\t\t\t? \"the larger embedding model (bge-m3, hundreds of MB) downloads in the background at the next start, disk headroom ≥2GB, and write-side semantic dedup turns on. \"\n\t\t\t\t\t\t\t: \"\") +\n\t\t\t\t\t\t\"Existing memories carry over: the projection rebuilds onto the new model automatically.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 命令面结果映射: 工具闭包的 completed/failed 面转 CapabilityCommandResult\n\t\t\t// 的 success/error; 行动清单/next 指引并入 message (命令结果无 actions 字段)。\n\t\t\tconst toCommandResult = (\n\t\t\t\tresult: Awaited<ReturnType<typeof vectorChannelCtl.download>>,\n\t\t\t): { status: \"success\" | \"error\"; message: string } => ({\n\t\t\t\tstatus: result.status === \"completed\" ? \"success\" : \"error\",\n\t\t\t\tmessage:\n\t\t\t\t\tresult.status === \"failed\"\n\t\t\t\t\t\t? [result.message, ...(result.actions ?? []), result.next].filter(Boolean).join(\" — \")\n\t\t\t\t\t\t: result.message,\n\t\t\t});\n\t\t\tif (sub === \"off\") return toCommandResult(vectorChannelCtl.decline());\n\t\t\tif (sub === \"retry\") return toCommandResult(await vectorChannelCtl.download());\n\t\t\treturn {\n\t\t\t\tstatus: \"error\" as const,\n\t\t\t\tmessage: \"Usage: /memory [light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\t\t};\n\t\t},\n\t});\n\n\treturn { listTool, forgetTool, enableTool, memoryCommand, promoteCommand, schedulerCapability };\n}\n"]}
1
+ {"version":3,"file":"command-face.d.ts","sourceRoot":"","sources":["../../src/memory/command-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 命令面(capability 拆分战役 slice 6):memory_list / memory_forget 工具、\n * /memory 与 /promote 命令、memory_enable 征询执行面与 memory.scheduler 能力\n * 声明。物理删除的授权引用构造在本面(用户命令链专用); decline/download 仍\n * 薄委托 vectorChannelCtl(slice 3b 先例, 经 deps 下的 channel 对象调用);\n * 搬移函数体逐字节保留。\n */\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { writeMemorySettingsMode } from \"./enabling.ts\";\nimport type { DurableMemoryLedgerV1 } from \"./ledger.ts\";\nimport { promotePreferenceToUserDefault } from \"./preference-promotion.ts\";\nimport type { MemoryPurgeGateV1 } from \"./purge.ts\";\nimport type { MemoryPurgeJournalV1 } from \"./purge-journal.ts\";\nimport type { MemoryStoreV1 } from \"./store.ts\";\nimport {\n\tforgetDomainMemory,\n\tlistDomainMemories,\n\ttype SuiteForgetAuthorizationRefV1,\n\ttype SuiteMemoryDomainV1,\n\ttype SuiteMemoryListEntryV1,\n} from \"./suite-memory.ts\";\nimport type { MemoryVectorChannelV1 } from \"./vector-channel.ts\";\nimport type { MemoryVectorProjectionV1 } from \"./vector-projection.ts\";\nimport { EVENT_TYPE } from \"./write-face.ts\";\n\nconst DEFAULT_LIST_LIMIT = 20;\n\nconst listSchema = Type.Object({\n\tlimit: Type.Optional(\n\t\tType.Integer({ description: \"Maximum number of entries to list (1-100, default 20)\", minimum: 1, maximum: 100 }),\n\t),\n});\n\nconst forgetSchema = Type.Object({\n\tmemoryId: Type.String({\n\t\tdescription: \"The memoryId of the memory to forget, as returned by memory_write or memory_list\",\n\t}),\n});\n\nconst enableSchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"download\"), Type.Literal(\"decline\"), Type.Literal(\"retry\")], {\n\t\tdescription:\n\t\t\t'\"download\" / \"retry\" run the one-time model download (retry re-runs after a failure); \"decline\" persists memory off for this machine',\n\t}),\n});\n\n/** Canonical memoryId of the promoted copy of one preference (promotePreferenceToUserDefault suffix). */\nconst userDefaultMemoryId = (memoryId: string): string => `${memoryId}-user-default`;\n\n/**\n * 命令面对 capability 闭包的显式依赖视图 (slice 6): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实。状态机 (vectorChannelCtl)、\n * 写侧投影 (vectorProjection) 与 purge 组件归 capability 装配所有, 本模块经\n * 对象只读消费; capability 模块级纯函数经 deps 注入避免双头定义。\n */\nexport interface MemoryCommandFaceDepsV1 {\n\t/** 工具注册面 (api.registerTool): memory_list/forget/enable 经同一公共通道注册。 */\n\treadonly registerTool: CapabilityAPI[\"registerTool\"];\n\t/** 命令注册面 (api.registerCommand): /memory 与 /promote。 */\n\treadonly registerCommand: CapabilityAPI[\"registerCommand\"];\n\t/** 事件发布面 (api.publish): memory.changed forgotten 事件。 */\n\treadonly publish: CapabilityAPI[\"publish\"];\n\t/** 能力声明面 (api.capabilities): memory.scheduler@1 provide。 */\n\treadonly capabilities: CapabilityAPI[\"capabilities\"];\n\t/** 检索行 owner (capability.BUILTIN_MEMORY_OWNER)。 */\n\treadonly owner: string;\n\t/** 会话 id (harness sessionId): forget 授权引用 confirmationRef 组成。 */\n\treadonly sessionId: string;\n\t/** capability 清单 (capabilityManifest): issuedBy / authorizedBy / 事件 correlationId 来源。 */\n\treadonly manifest: { readonly id: string };\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 档位持久化路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** 时钟 (harness now)。 */\n\treadonly now: () => number;\n\t/** canonical store (per-capability 单例): 列表/成员判定/晋升回查。 */\n\treadonly store: MemoryStoreV1;\n\t/** purge 门 (capability.purgeGate): 物理删除唯一生产入口的授权面。 */\n\treadonly purgeGate: MemoryPurgeGateV1;\n\t/** purge 日志 (capability.purgeJournal)。 */\n\treadonly purgeJournal: MemoryPurgeJournalV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection): forget 批次的 index 副本分派与晋升埋点。 */\n\treadonly vectorProjection: MemoryVectorProjectionV1;\n\t/** 向量通道 (slice 3b 的 vectorChannelCtl): 状态行与 decline/download 薄委托。 */\n\treadonly vectorChannelCtl: MemoryVectorChannelV1;\n\t/** 域解析 (capability.resolveDomain): 每次调用时惰性解析 (B1 语义)。 */\n\treadonly resolveDomain: () => {\n\t\treadonly domain: SuiteMemoryDomainV1;\n\t\treadonly domainName: string;\n\t\treadonly ledger: DurableMemoryLedgerV1;\n\t};\n\t// ---- capability 模块级纯函数 (留守方, 经 deps 注入避免双头定义) ----\n\treadonly assertNonEmptyString: (value: unknown, label: string) => asserts value is string;\n\treadonly memoryToolInput: (first: unknown, second: unknown) => Record<string, unknown>;\n\treadonly statementOf: (payload: unknown) => string;\n\treadonly unwrapEgressStatement: (statement: string) => string;\n\t// ---- 写入面闭包视图 (slice 5 的 writeFace): 升档声明状态归 write-face 所有 ----\n\t/** 升档声明只读视图 (/memory 状态行 pending 尾巴)。 */\n\treadonly tierUpgradePending: () => boolean;\n\t/** 用户显式档位表达取代本实例升档声明 (/memory light)。 */\n\treadonly clearTierUpgrade: () => void;\n}\n\n/** 命令面工厂产物: 注册项集合 (capability registrations 按既有顺序收集)。 */\nexport interface MemoryCommandFaceV1 {\n\t/** memory_list 工具注册项。 */\n\treadonly listTool: DisposableRegistration;\n\t/** memory_forget 工具注册项 (仅登记请求, 物理删除在 /memory forget)。 */\n\treadonly forgetTool: DisposableRegistration;\n\t/** memory_enable 工具注册项 (征询门执行面)。 */\n\treadonly enableTool: DisposableRegistration;\n\t/** /memory 命令注册项。 */\n\treadonly memoryCommand: DisposableRegistration;\n\t/** /promote 命令注册项。 */\n\treadonly promoteCommand: DisposableRegistration;\n\t/** memory.scheduler@1 plugin capability 声明注册项。 */\n\treadonly schedulerCapability: DisposableRegistration;\n}\n\nexport function createMemoryCommandFace(deps: MemoryCommandFaceDepsV1): MemoryCommandFaceV1 {\n\tconst {\n\t\tregisterTool,\n\t\tregisterCommand,\n\t\tpublish,\n\t\tcapabilities,\n\t\towner,\n\t\tsessionId,\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tnow,\n\t\tstore,\n\t\tpurgeGate,\n\t\tpurgeJournal,\n\t\tvectorProjection,\n\t\tvectorChannelCtl,\n\t\tresolveDomain,\n\t\tmemoryToolInput,\n\t\tstatementOf,\n\t\tunwrapEgressStatement,\n\t\ttierUpgradePending,\n\t\tclearTierUpgrade,\n\t} = deps;\n\tconst { manifest: capabilityManifest } = deps;\n\n\t/** Recency-first payload projection: unwraps the `{ statement }` payload convention. */\n\tfunction entryToToolEntry(entry: SuiteMemoryListEntryV1): Record<string, unknown> {\n\t\treturn {\n\t\t\tmemoryId: entry.memoryId,\n\t\t\tkind: entry.memoryKind,\n\t\t\tstatement: statementOf(entry.payload),\n\t\t\toccurredAt: entry.occurredAt,\n\t\t\t...(entry.preference === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpreference: {\n\t\t\t\t\t\t\tsubject: entry.preference.subject,\n\t\t\t\t\t\t\tkey: entry.preference.key,\n\t\t\t\t\t\t\tscopeLevel: entry.preference.scopeLevel,\n\t\t\t\t\t\t\tcrossSuiteVisible: entry.preference.crossSuiteVisible,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t};\n\t}\n\n\tconst listTool = registerTool({\n\t\tname: \"memory_list\",\n\t\tlabel: \"List memories\",\n\t\tdescription: \"List this suite's durable memories (the explicit management surface for personal data)\",\n\t\tparameters: listSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst rawLimit: unknown = input.limit;\n\t\t\tconst limit =\n\t\t\t\trawLimit === undefined\n\t\t\t\t\t? DEFAULT_LIST_LIMIT\n\t\t\t\t\t: ((): number => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof rawLimit !== \"number\" ||\n\t\t\t\t\t\t\t\t!Number.isSafeInteger(rawLimit) ||\n\t\t\t\t\t\t\t\trawLimit < 1 ||\n\t\t\t\t\t\t\t\trawLimit > 100\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow new Error(\"limit must be an integer between 1 and 100\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn rawLimit;\n\t\t\t\t\t\t})();\n\t\t\tconst { domain } = resolveDomain();\n\t\t\tconst page = listDomainMemories({ store }, { owner, domain });\n\t\t\treturn {\n\t\t\t\tdomain: page.domain,\n\t\t\t\tentries: page.entries.slice(0, limit).map(entryToToolEntry),\n\t\t\t\ttotal: page.entries.length,\n\t\t\t\tpreferenceCount: page.preferenceCount,\n\t\t\t\tfactCount: page.factCount,\n\t\t\t\tfilter: page.filter,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * 物理删除唯一生产入口 (诚实化设计 §2, 2026-10-05 裁决): 用户命令链\n\t * `/memory forget <id> confirm`。授权引用由命令分发构造 (structured\n\t * confirmationRef `memory-forget-command:<session>:<memoryId>:confirmed`),\n\t * 模型工具面不再签发 user-immediate 授权 (记忆系统设计 :997 — 授权不能由\n\t * 模型生成)。\n\t */\n\tconst purgeMemoryViaUserCommand = (memoryId: string) => {\n\t\tconst { domain, ledger } = resolveDomain();\n\t\tconst authorizationRef: SuiteForgetAuthorizationRefV1 = {\n\t\t\tmode: \"user-immediate\",\n\t\t\tissuedAt: now(),\n\t\t\tissuedBy: `${capabilityManifest.id}:/memory-forget-confirm`,\n\t\t\tconfirmationRef: `memory-forget-command:${sessionId}:${memoryId}:confirmed`,\n\t\t};\n\t\treturn forgetDomainMemory(\n\t\t\t{\n\t\t\t\tstore,\n\t\t\t\tpurgeGate,\n\t\t\t\tpurgeJournal,\n\t\t\t\t// index 副本分派 (混合检索工程化): canonical 走下方原回调, 向量投影由\n\t\t\t\t// suite-memory 的 executePurgeBatch 按副本路由到这里。\n\t\t\t\tpurgeIndexReplica: vectorProjection.purgeMemories,\n\t\t\t\tnow,\n\t\t\t},\n\t\t\t{\n\t\t\t\towner,\n\t\t\t\tdomain,\n\t\t\t\tmemoryId,\n\t\t\t\tauthorizedBy: `${capabilityManifest.id}:memory-forget-command`,\n\t\t\t\tauthorizationRef,\n\t\t\t},\n\t\t\t(memoryIds) => {\n\t\t\t\tconst purged = new Set(memoryIds);\n\t\t\t\t// Physical replica purge: rewrite the durable ledger without the\n\t\t\t\t// purged atoms, then evict them from the in-memory store so the\n\t\t\t\t// running process cannot recall them either (both idempotent for\n\t\t\t\t// purge_eligible retries).\n\t\t\t\tledger.rewrite(ledger.atomsSnapshot().filter((atom) => !purged.has(atom.memoryId)));\n\t\t\t\tfor (const id of memoryIds) store.evict(id);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst forgetTool = registerTool({\n\t\tname: \"memory_forget\",\n\t\tlabel: \"File a forget request\",\n\t\tdescription:\n\t\t\t\"File a request to forget one memory of this suite by memoryId. This tool never deletes anything — physical deletion is user-only: the user confirms via /memory forget <memoryId> confirm\",\n\t\tparameters: forgetSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tdeps.assertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\tconst unscoped = store.get(input.memoryId, { owner });\n\t\t\tif (unscoped === undefined) {\n\t\t\t\treturn { status: \"not_found\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 域成员判定与 forgetDomainMemory 同判据 (suiteId 匹配 / legacy 为\n\t\t\t// undefined): 请求面同样拒绝外域 id — 模型连\"请求遗忘\"都不能指向别的域。\n\t\t\tconst isMember =\n\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\tif (!isMember) {\n\t\t\t\treturn { status: \"foreign_domain\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 请求的登记价值由返回文本承载 (转告用户确认命令); 无进程内状态 —\n\t\t\t// 重复请求幂等 (同一提示再次返回)。\n\t\t\treturn {\n\t\t\t\tstatus: \"requested\" as const,\n\t\t\t\tmemoryId: input.memoryId,\n\t\t\t\trequest:\n\t\t\t\t\t`Forget request filed for \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\" in domain ${domainName}. ` +\n\t\t\t\t\t`Nothing is deleted yet — tell the user to confirm the deletion with: /memory forget ${input.memoryId} confirm`,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * /promote (偏好晋升触发, B2; 2026-10-05 诚实化裁决起两步确认): the production\n\t * caller of {@link promotePreferenceToUserDefault}. Promotes one of THIS\n\t * session's preferences to the user-default scope: the promoted canonical atom\n\t * is appended to the session domain's durable ledger and committed to the\n\t * store, so every suite's preference-card read (which applies the suite read\n\t * boundary across all of the owner's ledgers) sees it from now on. The\n\t * original atom is never rewritten. Promotion is an irreversible cross-suite\n\t * authorization face, so the first run only shows the target and asks the\n\t * user to re-run with `confirm`. Errors (unknown id, non-preference, already\n\t * promoted) surface as error results, never as thrown failures — a slash\n\t * command must not crash the host.\n\t */\n\tconst promoteCommand = registerCommand({\n\t\tname: \"promote\",\n\t\tdescription:\n\t\t\t\"Promote a memory preference to the user-default scope (visible in every suite; two-step — re-run with confirm)\",\n\t\targumentHint: \"<memoryId> [confirm]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst memoryId = tokens[0] ?? \"\";\n\t\t\tconst confirmed = tokens[1] === \"confirm\";\n\t\t\tif (memoryId === \"\" || tokens.length > 2 || (tokens[1] !== undefined && !confirmed)) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: \"Usage: /promote <memoryId> [confirm] — run memory_list for this suite's memory ids\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst record = store.get(memoryId, { owner });\n\t\t\tif (!record) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst atom = record.atom;\n\t\t\tif (atom.memoryKind !== \"preference\" || atom.preference === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `${memoryId} is a fact, not a preference; only preferences can be promoted`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (store.get(userDefaultMemoryId(memoryId), { owner }) !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `Preference ${memoryId} is already promoted to the user-default scope`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!confirmed) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Promotion target: \"${unwrapEgressStatement(statementOf(atom.payload))}\"\\n` +\n\t\t\t\t\t\t\"This makes the preference visible in EVERY suite (user-default scope, permanent). Nothing is promoted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t`/promote ${memoryId} confirm`,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst promoted = promotePreferenceToUserDefault({\n\t\t\t\t\tatom,\n\t\t\t\t\tauthorizedBy: \"user:/promote\",\n\t\t\t\t\tconfirmedAt: new Date(now()).toISOString(),\n\t\t\t\t});\n\t\t\t\tconst { domainName, ledger } = resolveDomain();\n\t\t\t\tledger.append(promoted);\n\t\t\t\tstore.commit(promoted);\n\t\t\t\t// 向量投影埋点: 与 memory_write 同一异步旁路 (失败不阻塞命令返回)。\n\t\t\t\tvectorProjection.upsertAtom(promoted);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage: `Promoted \"${unwrapEgressStatement(statementOf(promoted.payload))}\" to the user-default scope; it is now visible in every suite`,\n\t\t\t\t\tdata: { memoryId: promoted.memoryId, sourceMemoryId: memoryId, domain: domainName },\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\" as const, message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\t// memory.scheduler@1 plugin capability (宪法 §3 显式声明面): a declarative\n\t// marker only — the scheduler enforcement itself (per-instance single\n\t// lease, acquired above) stays carried by the host builtin implementation.\n\t// The declaration anchors \"this suite's memory scheduling is provided by\n\t// this plugin\" so the code Profile assembly check (requiresMemoryScheduler)\n\t// and third-party replacement detection have an explicit surface:\n\t// list()-visible, a same-id double provide fails explicitly (no override\n\t// priority), and after dispose a replacement provider can take the id.\n\tconst schedulerCapability = capabilities.provide({ id: \"memory.scheduler\", version: 1, kind: \"service\" }, () =>\n\t\tObject.freeze({\n\t\t\tid: \"memory.scheduler\",\n\t\t\tversion: 1,\n\t\t\towner: \"agent-forge.builtin.memory\",\n\t\t\tleaseScope: \"per-agent-instance\",\n\t\t}),\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 是用户的直接出口。decline/download\n\t// 核心在 memory/vector-channel.ts (slice 3b), 工具与命令面经\n\t// vectorChannelCtl.decline()/download() 薄委托; decline 持久化只抑制默认档。\n\t/**\n\t * Structured status for host consoles (公共命令结果 data, additive):\n\t * the TUI `/memory` console reads mode/channel/domain without parsing the\n\t * human message. `channel` mirrors the vector state machine; decline is\n\t * reported as \"off\" (the line's existing semantics).\n\t */\n\tconst memoryStatusSnapshot = (): {\n\t\treadonly mode: \"light\" | \"full\";\n\t\treadonly channel: \"off\" | \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\t\treadonly declined: boolean;\n\t\treadonly pendingUpgrade: boolean;\n\t\treadonly failureReason?: string;\n\t} => {\n\t\t// pending 尾巴只对仍有效的升档声明 (declined 分支里档位键已被删除, 显示\n\t\t// pending 会失实 — 2026-10-06 复审 P2-1)。\n\t\tconst declined = vectorChannelCtl.declined();\n\t\tconst pendingUpgrade = tierUpgradePending() && !declined;\n\t\tconst failureReason = vectorChannelCtl.failure()?.reason;\n\t\treturn {\n\t\t\tmode: memoryMode,\n\t\t\tchannel: declined ? \"off\" : vectorChannelCtl.rawState(),\n\t\t\tdeclined,\n\t\t\tpendingUpgrade,\n\t\t\t...(failureReason === undefined ? {} : { failureReason }),\n\t\t};\n\t};\n\tconst memoryStatusLine = (status: ReturnType<typeof memoryStatusSnapshot>): string => {\n\t\tconst modeLine = `mode=${status.mode}${status.pendingUpgrade ? \", auto-upgrade to full pending (next session)\" : \"\"}`;\n\t\tif (status.declined) {\n\t\t\treturn `${modeLine}, off (declined on this machine). Set memory.mode (light|full) in settings.json and restart the session to re-enable`;\n\t\t}\n\t\tif (status.channel === \"ready\") return `${modeLine}, ready`;\n\t\tif (status.channel === \"degraded\") return `${modeLine}, ready (degraded)`;\n\t\tif (status.channel === \"failed\") return `${modeLine}, failed: ${status.failureReason ?? \"unknown reason\"}`;\n\t\tif (status.channel === \"consent-required\") {\n\t\t\treturn `${modeLine}, waiting for the model download decision (/memory retry to start it)`;\n\t\t}\n\t\treturn `${modeLine}, loading models in the background`;\n\t};\n\tconst enableTool = registerTool({\n\t\tname: \"memory_enable\",\n\t\tlabel: \"Enable memory\",\n\t\tdescription:\n\t\t\t'Run or decline the one-time memory model download. The host starts it in the background at session start; call it with \"retry\" after a failure, or with \"decline\" when the user chooses to keep memory off',\n\t\tparameters: enableSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst action: unknown = input.action;\n\t\t\tif (action !== \"download\" && action !== \"decline\" && action !== \"retry\") {\n\t\t\t\tthrow new Error('action must be \"download\", \"decline\", or \"retry\"');\n\t\t\t}\n\t\t\tif (action === \"decline\") return vectorChannelCtl.decline();\n\t\t\treturn vectorChannelCtl.download();\n\t\t},\n\t});\n\tconst memoryCommand = registerCommand({\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory controls: bare shows status; light|full switches the model preset (persisted, effective next session); off persists disable; retry re-runs the model download; forget <memoryId> [confirm] is the user-only physical delete (two-step)\",\n\t\targumentHint: \"[light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tif (tokens[0] === \"forget\") {\n\t\t\t\tconst memoryId = tokens[1] ?? \"\";\n\t\t\t\tconst confirmed = tokens[2] === \"confirm\";\n\t\t\t\tif (memoryId === \"\" || tokens.length > 3 || (tokens[2] !== undefined && !confirmed)) {\n\t\t\t\t\treturn { status: \"error\" as const, message: \"Usage: /memory forget <memoryId> [confirm]\" };\n\t\t\t\t}\n\t\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\t\tconst unscoped = store.get(memoryId, { owner });\n\t\t\t\tif (unscoped === undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst isMember =\n\t\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\t\tif (!isMember) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `${memoryId} belongs to another suite; each suite forgets only its own memories`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Forget target: \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\"\\n` +\n\t\t\t\t\t\t\t\"This permanently deletes the memory (irreversible, purge-gated). Nothing is deleted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t\t`/memory forget ${memoryId} confirm`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst result = purgeMemoryViaUserCommand(memoryId);\n\t\t\t\tif (result.status === \"completed\") {\n\t\t\t\t\tawait publish({\n\t\t\t\t\t\ttype: EVENT_TYPE,\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\tcorrelationId: capabilityManifest.id,\n\t\t\t\t\t\tdata: { action: \"forgotten\", memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage: `Forgot ${memoryId} (${domainName}): the memory is physically deleted`,\n\t\t\t\t\t\tdata: { memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { status: \"error\" as const, message: `forget failed: ${result.status}` };\n\t\t\t}\n\t\t\tconst sub = args.trim().toLowerCase();\n\t\t\tif (sub === \"\" || sub === \"status\") {\n\t\t\t\tconst snapshot = memoryStatusSnapshot();\n\t\t\t\tconst statusResult: CapabilityCommandResult = {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\tmessage: `memory: ${memoryStatusLine(snapshot)}`,\n\t\t\t\t\tdata: { memoryStatus: snapshot },\n\t\t\t\t};\n\t\t\t\treturn statusResult;\n\t\t\t}\n\t\t\tif (sub === \"light\" || sub === \"full\") {\n\t\t\t\t// 无\"已是该档\"早退: 持久化档位与会话内已解析档位是两回事——会话可能\n\t\t\t\t// 因默认档而运行 light, 用户降档仍需把持久化值落盘 (或覆盖旧档)。\n\t\t\t\twriteMemorySettingsMode(agentDir, sub);\n\t\t\t\t// 升/降档清了文件里的拒绝标记, 内存标记同步翻回: 用户最新的显式\n\t\t\t\t// 意图是启用——本会话恢复对当前预置的响应 (retry 可用), 新档与\n\t\t\t\t// 新模型下载在下一会话生效。\n\t\t\t\tvectorChannelCtl.clearDeclined();\n\t\t\t\t// 用户的显式档位表达取代本实例的自动升档声明: 降回 light 后 pending\n\t\t\t\t// 尾巴不再显示, 且显式 light 会让自动升档在后续写入中跳过 (复审 P2-1)。\n\t\t\t\tif (sub === \"light\") clearTierUpgrade();\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`memory: preset ${sub} persisted (capabilities/builtin.memory.json). It takes effect next session — ` +\n\t\t\t\t\t\t(sub === \"full\"\n\t\t\t\t\t\t\t? \"the larger embedding model (bge-m3, hundreds of MB) downloads in the background at the next start, disk headroom ≥2GB, and write-side semantic dedup turns on. \"\n\t\t\t\t\t\t\t: \"\") +\n\t\t\t\t\t\t\"Existing memories carry over: the projection rebuilds onto the new model automatically.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 命令面结果映射: 工具闭包的 completed/failed 面转 CapabilityCommandResult\n\t\t\t// 的 success/error; 行动清单/next 指引并入 message (命令结果无 actions 字段)。\n\t\t\tconst toCommandResult = (\n\t\t\t\tresult: Awaited<ReturnType<typeof vectorChannelCtl.download>>,\n\t\t\t): { status: \"success\" | \"error\"; message: string } => ({\n\t\t\t\tstatus: result.status === \"completed\" ? \"success\" : \"error\",\n\t\t\t\tmessage:\n\t\t\t\t\tresult.status === \"failed\"\n\t\t\t\t\t\t? [result.message, ...(result.actions ?? []), result.next].filter(Boolean).join(\" — \")\n\t\t\t\t\t\t: result.message,\n\t\t\t});\n\t\t\tif (sub === \"off\") return toCommandResult(vectorChannelCtl.decline());\n\t\t\tif (sub === \"retry\") return toCommandResult(await vectorChannelCtl.download());\n\t\t\treturn {\n\t\t\t\tstatus: \"error\" as const,\n\t\t\t\tmessage: \"Usage: /memory [light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\t\t};\n\t\t},\n\t});\n\n\treturn { listTool, forgetTool, enableTool, memoryCommand, promoteCommand, schedulerCapability };\n}\n"]}
@@ -5,7 +5,7 @@ import { forgetDomainMemory, listDomainMemories, } from "./suite-memory.js";
5
5
  import { EVENT_TYPE } from "./write-face.js";
6
6
  const DEFAULT_LIST_LIMIT = 20;
7
7
  const listSchema = Type.Object({
8
- limit: Type.Optional(Type.Integer({ description: "Maximum number of entries to list (1-100)", minimum: 1, maximum: 100 })),
8
+ limit: Type.Optional(Type.Integer({ description: "Maximum number of entries to list (1-100, default 20)", minimum: 1, maximum: 100 })),
9
9
  });
10
10
  const forgetSchema = Type.Object({
11
11
  memoryId: Type.String({
@@ -1 +1 @@
1
- {"version":3,"file":"command-face.js","sourceRoot":"","sources":["../../src/memory/command-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 命令面(capability 拆分战役 slice 6):memory_list / memory_forget 工具、\n * /memory 与 /promote 命令、memory_enable 征询执行面与 memory.scheduler 能力\n * 声明。物理删除的授权引用构造在本面(用户命令链专用); decline/download 仍\n * 薄委托 vectorChannelCtl(slice 3b 先例, 经 deps 下的 channel 对象调用);\n * 搬移函数体逐字节保留。\n */\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { writeMemorySettingsMode } from \"./enabling.ts\";\nimport type { DurableMemoryLedgerV1 } from \"./ledger.ts\";\nimport { promotePreferenceToUserDefault } from \"./preference-promotion.ts\";\nimport type { MemoryPurgeGateV1 } from \"./purge.ts\";\nimport type { MemoryPurgeJournalV1 } from \"./purge-journal.ts\";\nimport type { MemoryStoreV1 } from \"./store.ts\";\nimport {\n\tforgetDomainMemory,\n\tlistDomainMemories,\n\ttype SuiteForgetAuthorizationRefV1,\n\ttype SuiteMemoryDomainV1,\n\ttype SuiteMemoryListEntryV1,\n} from \"./suite-memory.ts\";\nimport type { MemoryVectorChannelV1 } from \"./vector-channel.ts\";\nimport type { MemoryVectorProjectionV1 } from \"./vector-projection.ts\";\nimport { EVENT_TYPE } from \"./write-face.ts\";\n\nconst DEFAULT_LIST_LIMIT = 20;\n\nconst listSchema = Type.Object({\n\tlimit: Type.Optional(\n\t\tType.Integer({ description: \"Maximum number of entries to list (1-100)\", minimum: 1, maximum: 100 }),\n\t),\n});\n\nconst forgetSchema = Type.Object({\n\tmemoryId: Type.String({\n\t\tdescription: \"The memoryId of the memory to forget, as returned by memory_write or memory_list\",\n\t}),\n});\n\nconst enableSchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"download\"), Type.Literal(\"decline\"), Type.Literal(\"retry\")], {\n\t\tdescription:\n\t\t\t'\"download\" / \"retry\" run the one-time model download (retry re-runs after a failure); \"decline\" persists memory off for this machine',\n\t}),\n});\n\n/** Canonical memoryId of the promoted copy of one preference (promotePreferenceToUserDefault suffix). */\nconst userDefaultMemoryId = (memoryId: string): string => `${memoryId}-user-default`;\n\n/**\n * 命令面对 capability 闭包的显式依赖视图 (slice 6): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实。状态机 (vectorChannelCtl)、\n * 写侧投影 (vectorProjection) 与 purge 组件归 capability 装配所有, 本模块经\n * 对象只读消费; capability 模块级纯函数经 deps 注入避免双头定义。\n */\nexport interface MemoryCommandFaceDepsV1 {\n\t/** 工具注册面 (api.registerTool): memory_list/forget/enable 经同一公共通道注册。 */\n\treadonly registerTool: CapabilityAPI[\"registerTool\"];\n\t/** 命令注册面 (api.registerCommand): /memory 与 /promote。 */\n\treadonly registerCommand: CapabilityAPI[\"registerCommand\"];\n\t/** 事件发布面 (api.publish): memory.changed forgotten 事件。 */\n\treadonly publish: CapabilityAPI[\"publish\"];\n\t/** 能力声明面 (api.capabilities): memory.scheduler@1 provide。 */\n\treadonly capabilities: CapabilityAPI[\"capabilities\"];\n\t/** 检索行 owner (capability.BUILTIN_MEMORY_OWNER)。 */\n\treadonly owner: string;\n\t/** 会话 id (harness sessionId): forget 授权引用 confirmationRef 组成。 */\n\treadonly sessionId: string;\n\t/** capability 清单 (capabilityManifest): issuedBy / authorizedBy / 事件 correlationId 来源。 */\n\treadonly manifest: { readonly id: string };\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 档位持久化路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** 时钟 (harness now)。 */\n\treadonly now: () => number;\n\t/** canonical store (per-capability 单例): 列表/成员判定/晋升回查。 */\n\treadonly store: MemoryStoreV1;\n\t/** purge 门 (capability.purgeGate): 物理删除唯一生产入口的授权面。 */\n\treadonly purgeGate: MemoryPurgeGateV1;\n\t/** purge 日志 (capability.purgeJournal)。 */\n\treadonly purgeJournal: MemoryPurgeJournalV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection): forget 批次的 index 副本分派与晋升埋点。 */\n\treadonly vectorProjection: MemoryVectorProjectionV1;\n\t/** 向量通道 (slice 3b 的 vectorChannelCtl): 状态行与 decline/download 薄委托。 */\n\treadonly vectorChannelCtl: MemoryVectorChannelV1;\n\t/** 域解析 (capability.resolveDomain): 每次调用时惰性解析 (B1 语义)。 */\n\treadonly resolveDomain: () => {\n\t\treadonly domain: SuiteMemoryDomainV1;\n\t\treadonly domainName: string;\n\t\treadonly ledger: DurableMemoryLedgerV1;\n\t};\n\t// ---- capability 模块级纯函数 (留守方, 经 deps 注入避免双头定义) ----\n\treadonly assertNonEmptyString: (value: unknown, label: string) => asserts value is string;\n\treadonly memoryToolInput: (first: unknown, second: unknown) => Record<string, unknown>;\n\treadonly statementOf: (payload: unknown) => string;\n\treadonly unwrapEgressStatement: (statement: string) => string;\n\t// ---- 写入面闭包视图 (slice 5 的 writeFace): 升档声明状态归 write-face 所有 ----\n\t/** 升档声明只读视图 (/memory 状态行 pending 尾巴)。 */\n\treadonly tierUpgradePending: () => boolean;\n\t/** 用户显式档位表达取代本实例升档声明 (/memory light)。 */\n\treadonly clearTierUpgrade: () => void;\n}\n\n/** 命令面工厂产物: 注册项集合 (capability registrations 按既有顺序收集)。 */\nexport interface MemoryCommandFaceV1 {\n\t/** memory_list 工具注册项。 */\n\treadonly listTool: DisposableRegistration;\n\t/** memory_forget 工具注册项 (仅登记请求, 物理删除在 /memory forget)。 */\n\treadonly forgetTool: DisposableRegistration;\n\t/** memory_enable 工具注册项 (征询门执行面)。 */\n\treadonly enableTool: DisposableRegistration;\n\t/** /memory 命令注册项。 */\n\treadonly memoryCommand: DisposableRegistration;\n\t/** /promote 命令注册项。 */\n\treadonly promoteCommand: DisposableRegistration;\n\t/** memory.scheduler@1 plugin capability 声明注册项。 */\n\treadonly schedulerCapability: DisposableRegistration;\n}\n\nexport function createMemoryCommandFace(deps: MemoryCommandFaceDepsV1): MemoryCommandFaceV1 {\n\tconst {\n\t\tregisterTool,\n\t\tregisterCommand,\n\t\tpublish,\n\t\tcapabilities,\n\t\towner,\n\t\tsessionId,\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tnow,\n\t\tstore,\n\t\tpurgeGate,\n\t\tpurgeJournal,\n\t\tvectorProjection,\n\t\tvectorChannelCtl,\n\t\tresolveDomain,\n\t\tmemoryToolInput,\n\t\tstatementOf,\n\t\tunwrapEgressStatement,\n\t\ttierUpgradePending,\n\t\tclearTierUpgrade,\n\t} = deps;\n\tconst { manifest: capabilityManifest } = deps;\n\n\t/** Recency-first payload projection: unwraps the `{ statement }` payload convention. */\n\tfunction entryToToolEntry(entry: SuiteMemoryListEntryV1): Record<string, unknown> {\n\t\treturn {\n\t\t\tmemoryId: entry.memoryId,\n\t\t\tkind: entry.memoryKind,\n\t\t\tstatement: statementOf(entry.payload),\n\t\t\toccurredAt: entry.occurredAt,\n\t\t\t...(entry.preference === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpreference: {\n\t\t\t\t\t\t\tsubject: entry.preference.subject,\n\t\t\t\t\t\t\tkey: entry.preference.key,\n\t\t\t\t\t\t\tscopeLevel: entry.preference.scopeLevel,\n\t\t\t\t\t\t\tcrossSuiteVisible: entry.preference.crossSuiteVisible,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t};\n\t}\n\n\tconst listTool = registerTool({\n\t\tname: \"memory_list\",\n\t\tlabel: \"List memories\",\n\t\tdescription: \"List this suite's durable memories (the explicit management surface for personal data)\",\n\t\tparameters: listSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst rawLimit: unknown = input.limit;\n\t\t\tconst limit =\n\t\t\t\trawLimit === undefined\n\t\t\t\t\t? DEFAULT_LIST_LIMIT\n\t\t\t\t\t: ((): number => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof rawLimit !== \"number\" ||\n\t\t\t\t\t\t\t\t!Number.isSafeInteger(rawLimit) ||\n\t\t\t\t\t\t\t\trawLimit < 1 ||\n\t\t\t\t\t\t\t\trawLimit > 100\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow new Error(\"limit must be an integer between 1 and 100\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn rawLimit;\n\t\t\t\t\t\t})();\n\t\t\tconst { domain } = resolveDomain();\n\t\t\tconst page = listDomainMemories({ store }, { owner, domain });\n\t\t\treturn {\n\t\t\t\tdomain: page.domain,\n\t\t\t\tentries: page.entries.slice(0, limit).map(entryToToolEntry),\n\t\t\t\ttotal: page.entries.length,\n\t\t\t\tpreferenceCount: page.preferenceCount,\n\t\t\t\tfactCount: page.factCount,\n\t\t\t\tfilter: page.filter,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * 物理删除唯一生产入口 (诚实化设计 §2, 2026-10-05 裁决): 用户命令链\n\t * `/memory forget <id> confirm`。授权引用由命令分发构造 (structured\n\t * confirmationRef `memory-forget-command:<session>:<memoryId>:confirmed`),\n\t * 模型工具面不再签发 user-immediate 授权 (记忆系统设计 :997 — 授权不能由\n\t * 模型生成)。\n\t */\n\tconst purgeMemoryViaUserCommand = (memoryId: string) => {\n\t\tconst { domain, ledger } = resolveDomain();\n\t\tconst authorizationRef: SuiteForgetAuthorizationRefV1 = {\n\t\t\tmode: \"user-immediate\",\n\t\t\tissuedAt: now(),\n\t\t\tissuedBy: `${capabilityManifest.id}:/memory-forget-confirm`,\n\t\t\tconfirmationRef: `memory-forget-command:${sessionId}:${memoryId}:confirmed`,\n\t\t};\n\t\treturn forgetDomainMemory(\n\t\t\t{\n\t\t\t\tstore,\n\t\t\t\tpurgeGate,\n\t\t\t\tpurgeJournal,\n\t\t\t\t// index 副本分派 (混合检索工程化): canonical 走下方原回调, 向量投影由\n\t\t\t\t// suite-memory 的 executePurgeBatch 按副本路由到这里。\n\t\t\t\tpurgeIndexReplica: vectorProjection.purgeMemories,\n\t\t\t\tnow,\n\t\t\t},\n\t\t\t{\n\t\t\t\towner,\n\t\t\t\tdomain,\n\t\t\t\tmemoryId,\n\t\t\t\tauthorizedBy: `${capabilityManifest.id}:memory-forget-command`,\n\t\t\t\tauthorizationRef,\n\t\t\t},\n\t\t\t(memoryIds) => {\n\t\t\t\tconst purged = new Set(memoryIds);\n\t\t\t\t// Physical replica purge: rewrite the durable ledger without the\n\t\t\t\t// purged atoms, then evict them from the in-memory store so the\n\t\t\t\t// running process cannot recall them either (both idempotent for\n\t\t\t\t// purge_eligible retries).\n\t\t\t\tledger.rewrite(ledger.atomsSnapshot().filter((atom) => !purged.has(atom.memoryId)));\n\t\t\t\tfor (const id of memoryIds) store.evict(id);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst forgetTool = registerTool({\n\t\tname: \"memory_forget\",\n\t\tlabel: \"File a forget request\",\n\t\tdescription:\n\t\t\t\"File a request to forget one memory of this suite by memoryId. This tool never deletes anything — physical deletion is user-only: the user confirms via /memory forget <memoryId> confirm\",\n\t\tparameters: forgetSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tdeps.assertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\tconst unscoped = store.get(input.memoryId, { owner });\n\t\t\tif (unscoped === undefined) {\n\t\t\t\treturn { status: \"not_found\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 域成员判定与 forgetDomainMemory 同判据 (suiteId 匹配 / legacy 为\n\t\t\t// undefined): 请求面同样拒绝外域 id — 模型连\"请求遗忘\"都不能指向别的域。\n\t\t\tconst isMember =\n\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\tif (!isMember) {\n\t\t\t\treturn { status: \"foreign_domain\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 请求的登记价值由返回文本承载 (转告用户确认命令); 无进程内状态 —\n\t\t\t// 重复请求幂等 (同一提示再次返回)。\n\t\t\treturn {\n\t\t\t\tstatus: \"requested\" as const,\n\t\t\t\tmemoryId: input.memoryId,\n\t\t\t\trequest:\n\t\t\t\t\t`Forget request filed for \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\" in domain ${domainName}. ` +\n\t\t\t\t\t`Nothing is deleted yet — tell the user to confirm the deletion with: /memory forget ${input.memoryId} confirm`,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * /promote (偏好晋升触发, B2; 2026-10-05 诚实化裁决起两步确认): the production\n\t * caller of {@link promotePreferenceToUserDefault}. Promotes one of THIS\n\t * session's preferences to the user-default scope: the promoted canonical atom\n\t * is appended to the session domain's durable ledger and committed to the\n\t * store, so every suite's preference-card read (which applies the suite read\n\t * boundary across all of the owner's ledgers) sees it from now on. The\n\t * original atom is never rewritten. Promotion is an irreversible cross-suite\n\t * authorization face, so the first run only shows the target and asks the\n\t * user to re-run with `confirm`. Errors (unknown id, non-preference, already\n\t * promoted) surface as error results, never as thrown failures — a slash\n\t * command must not crash the host.\n\t */\n\tconst promoteCommand = registerCommand({\n\t\tname: \"promote\",\n\t\tdescription:\n\t\t\t\"Promote a memory preference to the user-default scope (visible in every suite; two-step — re-run with confirm)\",\n\t\targumentHint: \"<memoryId> [confirm]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst memoryId = tokens[0] ?? \"\";\n\t\t\tconst confirmed = tokens[1] === \"confirm\";\n\t\t\tif (memoryId === \"\" || tokens.length > 2 || (tokens[1] !== undefined && !confirmed)) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: \"Usage: /promote <memoryId> [confirm] — run memory_list for this suite's memory ids\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst record = store.get(memoryId, { owner });\n\t\t\tif (!record) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst atom = record.atom;\n\t\t\tif (atom.memoryKind !== \"preference\" || atom.preference === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `${memoryId} is a fact, not a preference; only preferences can be promoted`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (store.get(userDefaultMemoryId(memoryId), { owner }) !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `Preference ${memoryId} is already promoted to the user-default scope`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!confirmed) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Promotion target: \"${unwrapEgressStatement(statementOf(atom.payload))}\"\\n` +\n\t\t\t\t\t\t\"This makes the preference visible in EVERY suite (user-default scope, permanent). Nothing is promoted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t`/promote ${memoryId} confirm`,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst promoted = promotePreferenceToUserDefault({\n\t\t\t\t\tatom,\n\t\t\t\t\tauthorizedBy: \"user:/promote\",\n\t\t\t\t\tconfirmedAt: new Date(now()).toISOString(),\n\t\t\t\t});\n\t\t\t\tconst { domainName, ledger } = resolveDomain();\n\t\t\t\tledger.append(promoted);\n\t\t\t\tstore.commit(promoted);\n\t\t\t\t// 向量投影埋点: 与 memory_write 同一异步旁路 (失败不阻塞命令返回)。\n\t\t\t\tvectorProjection.upsertAtom(promoted);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage: `Promoted \"${unwrapEgressStatement(statementOf(promoted.payload))}\" to the user-default scope; it is now visible in every suite`,\n\t\t\t\t\tdata: { memoryId: promoted.memoryId, sourceMemoryId: memoryId, domain: domainName },\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\" as const, message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\t// memory.scheduler@1 plugin capability (宪法 §3 显式声明面): a declarative\n\t// marker only — the scheduler enforcement itself (per-instance single\n\t// lease, acquired above) stays carried by the host builtin implementation.\n\t// The declaration anchors \"this suite's memory scheduling is provided by\n\t// this plugin\" so the code Profile assembly check (requiresMemoryScheduler)\n\t// and third-party replacement detection have an explicit surface:\n\t// list()-visible, a same-id double provide fails explicitly (no override\n\t// priority), and after dispose a replacement provider can take the id.\n\tconst schedulerCapability = capabilities.provide({ id: \"memory.scheduler\", version: 1, kind: \"service\" }, () =>\n\t\tObject.freeze({\n\t\t\tid: \"memory.scheduler\",\n\t\t\tversion: 1,\n\t\t\towner: \"agent-forge.builtin.memory\",\n\t\t\tleaseScope: \"per-agent-instance\",\n\t\t}),\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 是用户的直接出口。decline/download\n\t// 核心在 memory/vector-channel.ts (slice 3b), 工具与命令面经\n\t// vectorChannelCtl.decline()/download() 薄委托; decline 持久化只抑制默认档。\n\t/**\n\t * Structured status for host consoles (公共命令结果 data, additive):\n\t * the TUI `/memory` console reads mode/channel/domain without parsing the\n\t * human message. `channel` mirrors the vector state machine; decline is\n\t * reported as \"off\" (the line's existing semantics).\n\t */\n\tconst memoryStatusSnapshot = (): {\n\t\treadonly mode: \"light\" | \"full\";\n\t\treadonly channel: \"off\" | \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\t\treadonly declined: boolean;\n\t\treadonly pendingUpgrade: boolean;\n\t\treadonly failureReason?: string;\n\t} => {\n\t\t// pending 尾巴只对仍有效的升档声明 (declined 分支里档位键已被删除, 显示\n\t\t// pending 会失实 — 2026-10-06 复审 P2-1)。\n\t\tconst declined = vectorChannelCtl.declined();\n\t\tconst pendingUpgrade = tierUpgradePending() && !declined;\n\t\tconst failureReason = vectorChannelCtl.failure()?.reason;\n\t\treturn {\n\t\t\tmode: memoryMode,\n\t\t\tchannel: declined ? \"off\" : vectorChannelCtl.rawState(),\n\t\t\tdeclined,\n\t\t\tpendingUpgrade,\n\t\t\t...(failureReason === undefined ? {} : { failureReason }),\n\t\t};\n\t};\n\tconst memoryStatusLine = (status: ReturnType<typeof memoryStatusSnapshot>): string => {\n\t\tconst modeLine = `mode=${status.mode}${status.pendingUpgrade ? \", auto-upgrade to full pending (next session)\" : \"\"}`;\n\t\tif (status.declined) {\n\t\t\treturn `${modeLine}, off (declined on this machine). Set memory.mode (light|full) in settings.json and restart the session to re-enable`;\n\t\t}\n\t\tif (status.channel === \"ready\") return `${modeLine}, ready`;\n\t\tif (status.channel === \"degraded\") return `${modeLine}, ready (degraded)`;\n\t\tif (status.channel === \"failed\") return `${modeLine}, failed: ${status.failureReason ?? \"unknown reason\"}`;\n\t\tif (status.channel === \"consent-required\") {\n\t\t\treturn `${modeLine}, waiting for the model download decision (/memory retry to start it)`;\n\t\t}\n\t\treturn `${modeLine}, loading models in the background`;\n\t};\n\tconst enableTool = registerTool({\n\t\tname: \"memory_enable\",\n\t\tlabel: \"Enable memory\",\n\t\tdescription:\n\t\t\t'Run or decline the one-time memory model download. The host starts it in the background at session start; call it with \"retry\" after a failure, or with \"decline\" when the user chooses to keep memory off',\n\t\tparameters: enableSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst action: unknown = input.action;\n\t\t\tif (action !== \"download\" && action !== \"decline\" && action !== \"retry\") {\n\t\t\t\tthrow new Error('action must be \"download\", \"decline\", or \"retry\"');\n\t\t\t}\n\t\t\tif (action === \"decline\") return vectorChannelCtl.decline();\n\t\t\treturn vectorChannelCtl.download();\n\t\t},\n\t});\n\tconst memoryCommand = registerCommand({\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory controls: bare shows status; light|full switches the model preset (persisted, effective next session); off persists disable; retry re-runs the model download; forget <memoryId> [confirm] is the user-only physical delete (two-step)\",\n\t\targumentHint: \"[light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tif (tokens[0] === \"forget\") {\n\t\t\t\tconst memoryId = tokens[1] ?? \"\";\n\t\t\t\tconst confirmed = tokens[2] === \"confirm\";\n\t\t\t\tif (memoryId === \"\" || tokens.length > 3 || (tokens[2] !== undefined && !confirmed)) {\n\t\t\t\t\treturn { status: \"error\" as const, message: \"Usage: /memory forget <memoryId> [confirm]\" };\n\t\t\t\t}\n\t\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\t\tconst unscoped = store.get(memoryId, { owner });\n\t\t\t\tif (unscoped === undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst isMember =\n\t\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\t\tif (!isMember) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `${memoryId} belongs to another suite; each suite forgets only its own memories`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Forget target: \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\"\\n` +\n\t\t\t\t\t\t\t\"This permanently deletes the memory (irreversible, purge-gated). Nothing is deleted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t\t`/memory forget ${memoryId} confirm`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst result = purgeMemoryViaUserCommand(memoryId);\n\t\t\t\tif (result.status === \"completed\") {\n\t\t\t\t\tawait publish({\n\t\t\t\t\t\ttype: EVENT_TYPE,\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\tcorrelationId: capabilityManifest.id,\n\t\t\t\t\t\tdata: { action: \"forgotten\", memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage: `Forgot ${memoryId} (${domainName}): the memory is physically deleted`,\n\t\t\t\t\t\tdata: { memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { status: \"error\" as const, message: `forget failed: ${result.status}` };\n\t\t\t}\n\t\t\tconst sub = args.trim().toLowerCase();\n\t\t\tif (sub === \"\" || sub === \"status\") {\n\t\t\t\tconst snapshot = memoryStatusSnapshot();\n\t\t\t\tconst statusResult: CapabilityCommandResult = {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\tmessage: `memory: ${memoryStatusLine(snapshot)}`,\n\t\t\t\t\tdata: { memoryStatus: snapshot },\n\t\t\t\t};\n\t\t\t\treturn statusResult;\n\t\t\t}\n\t\t\tif (sub === \"light\" || sub === \"full\") {\n\t\t\t\t// 无\"已是该档\"早退: 持久化档位与会话内已解析档位是两回事——会话可能\n\t\t\t\t// 因默认档而运行 light, 用户降档仍需把持久化值落盘 (或覆盖旧档)。\n\t\t\t\twriteMemorySettingsMode(agentDir, sub);\n\t\t\t\t// 升/降档清了文件里的拒绝标记, 内存标记同步翻回: 用户最新的显式\n\t\t\t\t// 意图是启用——本会话恢复对当前预置的响应 (retry 可用), 新档与\n\t\t\t\t// 新模型下载在下一会话生效。\n\t\t\t\tvectorChannelCtl.clearDeclined();\n\t\t\t\t// 用户的显式档位表达取代本实例的自动升档声明: 降回 light 后 pending\n\t\t\t\t// 尾巴不再显示, 且显式 light 会让自动升档在后续写入中跳过 (复审 P2-1)。\n\t\t\t\tif (sub === \"light\") clearTierUpgrade();\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`memory: preset ${sub} persisted (capabilities/builtin.memory.json). It takes effect next session — ` +\n\t\t\t\t\t\t(sub === \"full\"\n\t\t\t\t\t\t\t? \"the larger embedding model (bge-m3, hundreds of MB) downloads in the background at the next start, disk headroom ≥2GB, and write-side semantic dedup turns on. \"\n\t\t\t\t\t\t\t: \"\") +\n\t\t\t\t\t\t\"Existing memories carry over: the projection rebuilds onto the new model automatically.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 命令面结果映射: 工具闭包的 completed/failed 面转 CapabilityCommandResult\n\t\t\t// 的 success/error; 行动清单/next 指引并入 message (命令结果无 actions 字段)。\n\t\t\tconst toCommandResult = (\n\t\t\t\tresult: Awaited<ReturnType<typeof vectorChannelCtl.download>>,\n\t\t\t): { status: \"success\" | \"error\"; message: string } => ({\n\t\t\t\tstatus: result.status === \"completed\" ? \"success\" : \"error\",\n\t\t\t\tmessage:\n\t\t\t\t\tresult.status === \"failed\"\n\t\t\t\t\t\t? [result.message, ...(result.actions ?? []), result.next].filter(Boolean).join(\" — \")\n\t\t\t\t\t\t: result.message,\n\t\t\t});\n\t\t\tif (sub === \"off\") return toCommandResult(vectorChannelCtl.decline());\n\t\t\tif (sub === \"retry\") return toCommandResult(await vectorChannelCtl.download());\n\t\t\treturn {\n\t\t\t\tstatus: \"error\" as const,\n\t\t\t\tmessage: \"Usage: /memory [light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\t\t};\n\t\t},\n\t});\n\n\treturn { listTool, forgetTool, enableTool, memoryCommand, promoteCommand, schedulerCapability };\n}\n"]}
1
+ {"version":3,"file":"command-face.js","sourceRoot":"","sources":["../../src/memory/command-face.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 命令面(capability 拆分战役 slice 6):memory_list / memory_forget 工具、\n * /memory 与 /promote 命令、memory_enable 征询执行面与 memory.scheduler 能力\n * 声明。物理删除的授权引用构造在本面(用户命令链专用); decline/download 仍\n * 薄委托 vectorChannelCtl(slice 3b 先例, 经 deps 下的 channel 对象调用);\n * 搬移函数体逐字节保留。\n */\nimport type { CapabilityAPI, CapabilityCommandResult, DisposableRegistration } from \"@agent-forge/plugin-sdk\";\nimport { Type } from \"typebox\";\nimport { writeMemorySettingsMode } from \"./enabling.ts\";\nimport type { DurableMemoryLedgerV1 } from \"./ledger.ts\";\nimport { promotePreferenceToUserDefault } from \"./preference-promotion.ts\";\nimport type { MemoryPurgeGateV1 } from \"./purge.ts\";\nimport type { MemoryPurgeJournalV1 } from \"./purge-journal.ts\";\nimport type { MemoryStoreV1 } from \"./store.ts\";\nimport {\n\tforgetDomainMemory,\n\tlistDomainMemories,\n\ttype SuiteForgetAuthorizationRefV1,\n\ttype SuiteMemoryDomainV1,\n\ttype SuiteMemoryListEntryV1,\n} from \"./suite-memory.ts\";\nimport type { MemoryVectorChannelV1 } from \"./vector-channel.ts\";\nimport type { MemoryVectorProjectionV1 } from \"./vector-projection.ts\";\nimport { EVENT_TYPE } from \"./write-face.ts\";\n\nconst DEFAULT_LIST_LIMIT = 20;\n\nconst listSchema = Type.Object({\n\tlimit: Type.Optional(\n\t\tType.Integer({ description: \"Maximum number of entries to list (1-100, default 20)\", minimum: 1, maximum: 100 }),\n\t),\n});\n\nconst forgetSchema = Type.Object({\n\tmemoryId: Type.String({\n\t\tdescription: \"The memoryId of the memory to forget, as returned by memory_write or memory_list\",\n\t}),\n});\n\nconst enableSchema = Type.Object({\n\taction: Type.Union([Type.Literal(\"download\"), Type.Literal(\"decline\"), Type.Literal(\"retry\")], {\n\t\tdescription:\n\t\t\t'\"download\" / \"retry\" run the one-time model download (retry re-runs after a failure); \"decline\" persists memory off for this machine',\n\t}),\n});\n\n/** Canonical memoryId of the promoted copy of one preference (promotePreferenceToUserDefault suffix). */\nconst userDefaultMemoryId = (memoryId: string): string => `${memoryId}-user-default`;\n\n/**\n * 命令面对 capability 闭包的显式依赖视图 (slice 6): 逐项来自\n * createMemoryCapabilityHarness 的闭包捕获核实。状态机 (vectorChannelCtl)、\n * 写侧投影 (vectorProjection) 与 purge 组件归 capability 装配所有, 本模块经\n * 对象只读消费; capability 模块级纯函数经 deps 注入避免双头定义。\n */\nexport interface MemoryCommandFaceDepsV1 {\n\t/** 工具注册面 (api.registerTool): memory_list/forget/enable 经同一公共通道注册。 */\n\treadonly registerTool: CapabilityAPI[\"registerTool\"];\n\t/** 命令注册面 (api.registerCommand): /memory 与 /promote。 */\n\treadonly registerCommand: CapabilityAPI[\"registerCommand\"];\n\t/** 事件发布面 (api.publish): memory.changed forgotten 事件。 */\n\treadonly publish: CapabilityAPI[\"publish\"];\n\t/** 能力声明面 (api.capabilities): memory.scheduler@1 provide。 */\n\treadonly capabilities: CapabilityAPI[\"capabilities\"];\n\t/** 检索行 owner (capability.BUILTIN_MEMORY_OWNER)。 */\n\treadonly owner: string;\n\t/** 会话 id (harness sessionId): forget 授权引用 confirmationRef 组成。 */\n\treadonly sessionId: string;\n\t/** capability 清单 (capabilityManifest): issuedBy / authorizedBy / 事件 correlationId 来源。 */\n\treadonly manifest: { readonly id: string };\n\t/** agent 根目录 (MemoryCapabilityContext.agentDir): 档位持久化路径域。 */\n\treadonly agentDir: string;\n\t/** 已解析的全局档位 (harness memoryMode, off 已被工厂入口拦截)。 */\n\treadonly memoryMode: \"light\" | \"full\";\n\t/** 时钟 (harness now)。 */\n\treadonly now: () => number;\n\t/** canonical store (per-capability 单例): 列表/成员判定/晋升回查。 */\n\treadonly store: MemoryStoreV1;\n\t/** purge 门 (capability.purgeGate): 物理删除唯一生产入口的授权面。 */\n\treadonly purgeGate: MemoryPurgeGateV1;\n\t/** purge 日志 (capability.purgeJournal)。 */\n\treadonly purgeJournal: MemoryPurgeJournalV1;\n\t/** 写侧投影 (slice 3a 的 vectorProjection): forget 批次的 index 副本分派与晋升埋点。 */\n\treadonly vectorProjection: MemoryVectorProjectionV1;\n\t/** 向量通道 (slice 3b 的 vectorChannelCtl): 状态行与 decline/download 薄委托。 */\n\treadonly vectorChannelCtl: MemoryVectorChannelV1;\n\t/** 域解析 (capability.resolveDomain): 每次调用时惰性解析 (B1 语义)。 */\n\treadonly resolveDomain: () => {\n\t\treadonly domain: SuiteMemoryDomainV1;\n\t\treadonly domainName: string;\n\t\treadonly ledger: DurableMemoryLedgerV1;\n\t};\n\t// ---- capability 模块级纯函数 (留守方, 经 deps 注入避免双头定义) ----\n\treadonly assertNonEmptyString: (value: unknown, label: string) => asserts value is string;\n\treadonly memoryToolInput: (first: unknown, second: unknown) => Record<string, unknown>;\n\treadonly statementOf: (payload: unknown) => string;\n\treadonly unwrapEgressStatement: (statement: string) => string;\n\t// ---- 写入面闭包视图 (slice 5 的 writeFace): 升档声明状态归 write-face 所有 ----\n\t/** 升档声明只读视图 (/memory 状态行 pending 尾巴)。 */\n\treadonly tierUpgradePending: () => boolean;\n\t/** 用户显式档位表达取代本实例升档声明 (/memory light)。 */\n\treadonly clearTierUpgrade: () => void;\n}\n\n/** 命令面工厂产物: 注册项集合 (capability registrations 按既有顺序收集)。 */\nexport interface MemoryCommandFaceV1 {\n\t/** memory_list 工具注册项。 */\n\treadonly listTool: DisposableRegistration;\n\t/** memory_forget 工具注册项 (仅登记请求, 物理删除在 /memory forget)。 */\n\treadonly forgetTool: DisposableRegistration;\n\t/** memory_enable 工具注册项 (征询门执行面)。 */\n\treadonly enableTool: DisposableRegistration;\n\t/** /memory 命令注册项。 */\n\treadonly memoryCommand: DisposableRegistration;\n\t/** /promote 命令注册项。 */\n\treadonly promoteCommand: DisposableRegistration;\n\t/** memory.scheduler@1 plugin capability 声明注册项。 */\n\treadonly schedulerCapability: DisposableRegistration;\n}\n\nexport function createMemoryCommandFace(deps: MemoryCommandFaceDepsV1): MemoryCommandFaceV1 {\n\tconst {\n\t\tregisterTool,\n\t\tregisterCommand,\n\t\tpublish,\n\t\tcapabilities,\n\t\towner,\n\t\tsessionId,\n\t\tagentDir,\n\t\tmemoryMode,\n\t\tnow,\n\t\tstore,\n\t\tpurgeGate,\n\t\tpurgeJournal,\n\t\tvectorProjection,\n\t\tvectorChannelCtl,\n\t\tresolveDomain,\n\t\tmemoryToolInput,\n\t\tstatementOf,\n\t\tunwrapEgressStatement,\n\t\ttierUpgradePending,\n\t\tclearTierUpgrade,\n\t} = deps;\n\tconst { manifest: capabilityManifest } = deps;\n\n\t/** Recency-first payload projection: unwraps the `{ statement }` payload convention. */\n\tfunction entryToToolEntry(entry: SuiteMemoryListEntryV1): Record<string, unknown> {\n\t\treturn {\n\t\t\tmemoryId: entry.memoryId,\n\t\t\tkind: entry.memoryKind,\n\t\t\tstatement: statementOf(entry.payload),\n\t\t\toccurredAt: entry.occurredAt,\n\t\t\t...(entry.preference === undefined\n\t\t\t\t? {}\n\t\t\t\t: {\n\t\t\t\t\t\tpreference: {\n\t\t\t\t\t\t\tsubject: entry.preference.subject,\n\t\t\t\t\t\t\tkey: entry.preference.key,\n\t\t\t\t\t\t\tscopeLevel: entry.preference.scopeLevel,\n\t\t\t\t\t\t\tcrossSuiteVisible: entry.preference.crossSuiteVisible,\n\t\t\t\t\t\t},\n\t\t\t\t\t}),\n\t\t};\n\t}\n\n\tconst listTool = registerTool({\n\t\tname: \"memory_list\",\n\t\tlabel: \"List memories\",\n\t\tdescription: \"List this suite's durable memories (the explicit management surface for personal data)\",\n\t\tparameters: listSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst rawLimit: unknown = input.limit;\n\t\t\tconst limit =\n\t\t\t\trawLimit === undefined\n\t\t\t\t\t? DEFAULT_LIST_LIMIT\n\t\t\t\t\t: ((): number => {\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\ttypeof rawLimit !== \"number\" ||\n\t\t\t\t\t\t\t\t!Number.isSafeInteger(rawLimit) ||\n\t\t\t\t\t\t\t\trawLimit < 1 ||\n\t\t\t\t\t\t\t\trawLimit > 100\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tthrow new Error(\"limit must be an integer between 1 and 100\");\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn rawLimit;\n\t\t\t\t\t\t})();\n\t\t\tconst { domain } = resolveDomain();\n\t\t\tconst page = listDomainMemories({ store }, { owner, domain });\n\t\t\treturn {\n\t\t\t\tdomain: page.domain,\n\t\t\t\tentries: page.entries.slice(0, limit).map(entryToToolEntry),\n\t\t\t\ttotal: page.entries.length,\n\t\t\t\tpreferenceCount: page.preferenceCount,\n\t\t\t\tfactCount: page.factCount,\n\t\t\t\tfilter: page.filter,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * 物理删除唯一生产入口 (诚实化设计 §2, 2026-10-05 裁决): 用户命令链\n\t * `/memory forget <id> confirm`。授权引用由命令分发构造 (structured\n\t * confirmationRef `memory-forget-command:<session>:<memoryId>:confirmed`),\n\t * 模型工具面不再签发 user-immediate 授权 (记忆系统设计 :997 — 授权不能由\n\t * 模型生成)。\n\t */\n\tconst purgeMemoryViaUserCommand = (memoryId: string) => {\n\t\tconst { domain, ledger } = resolveDomain();\n\t\tconst authorizationRef: SuiteForgetAuthorizationRefV1 = {\n\t\t\tmode: \"user-immediate\",\n\t\t\tissuedAt: now(),\n\t\t\tissuedBy: `${capabilityManifest.id}:/memory-forget-confirm`,\n\t\t\tconfirmationRef: `memory-forget-command:${sessionId}:${memoryId}:confirmed`,\n\t\t};\n\t\treturn forgetDomainMemory(\n\t\t\t{\n\t\t\t\tstore,\n\t\t\t\tpurgeGate,\n\t\t\t\tpurgeJournal,\n\t\t\t\t// index 副本分派 (混合检索工程化): canonical 走下方原回调, 向量投影由\n\t\t\t\t// suite-memory 的 executePurgeBatch 按副本路由到这里。\n\t\t\t\tpurgeIndexReplica: vectorProjection.purgeMemories,\n\t\t\t\tnow,\n\t\t\t},\n\t\t\t{\n\t\t\t\towner,\n\t\t\t\tdomain,\n\t\t\t\tmemoryId,\n\t\t\t\tauthorizedBy: `${capabilityManifest.id}:memory-forget-command`,\n\t\t\t\tauthorizationRef,\n\t\t\t},\n\t\t\t(memoryIds) => {\n\t\t\t\tconst purged = new Set(memoryIds);\n\t\t\t\t// Physical replica purge: rewrite the durable ledger without the\n\t\t\t\t// purged atoms, then evict them from the in-memory store so the\n\t\t\t\t// running process cannot recall them either (both idempotent for\n\t\t\t\t// purge_eligible retries).\n\t\t\t\tledger.rewrite(ledger.atomsSnapshot().filter((atom) => !purged.has(atom.memoryId)));\n\t\t\t\tfor (const id of memoryIds) store.evict(id);\n\t\t\t},\n\t\t);\n\t};\n\n\tconst forgetTool = registerTool({\n\t\tname: \"memory_forget\",\n\t\tlabel: \"File a forget request\",\n\t\tdescription:\n\t\t\t\"File a request to forget one memory of this suite by memoryId. This tool never deletes anything — physical deletion is user-only: the user confirms via /memory forget <memoryId> confirm\",\n\t\tparameters: forgetSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tdeps.assertNonEmptyString(input.memoryId, \"memoryId\");\n\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\tconst unscoped = store.get(input.memoryId, { owner });\n\t\t\tif (unscoped === undefined) {\n\t\t\t\treturn { status: \"not_found\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 域成员判定与 forgetDomainMemory 同判据 (suiteId 匹配 / legacy 为\n\t\t\t// undefined): 请求面同样拒绝外域 id — 模型连\"请求遗忘\"都不能指向别的域。\n\t\t\tconst isMember =\n\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\tif (!isMember) {\n\t\t\t\treturn { status: \"foreign_domain\" as const, memoryId: input.memoryId };\n\t\t\t}\n\t\t\t// 请求的登记价值由返回文本承载 (转告用户确认命令); 无进程内状态 —\n\t\t\t// 重复请求幂等 (同一提示再次返回)。\n\t\t\treturn {\n\t\t\t\tstatus: \"requested\" as const,\n\t\t\t\tmemoryId: input.memoryId,\n\t\t\t\trequest:\n\t\t\t\t\t`Forget request filed for \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\" in domain ${domainName}. ` +\n\t\t\t\t\t`Nothing is deleted yet — tell the user to confirm the deletion with: /memory forget ${input.memoryId} confirm`,\n\t\t\t};\n\t\t},\n\t});\n\n\t/**\n\t * /promote (偏好晋升触发, B2; 2026-10-05 诚实化裁决起两步确认): the production\n\t * caller of {@link promotePreferenceToUserDefault}. Promotes one of THIS\n\t * session's preferences to the user-default scope: the promoted canonical atom\n\t * is appended to the session domain's durable ledger and committed to the\n\t * store, so every suite's preference-card read (which applies the suite read\n\t * boundary across all of the owner's ledgers) sees it from now on. The\n\t * original atom is never rewritten. Promotion is an irreversible cross-suite\n\t * authorization face, so the first run only shows the target and asks the\n\t * user to re-run with `confirm`. Errors (unknown id, non-preference, already\n\t * promoted) surface as error results, never as thrown failures — a slash\n\t * command must not crash the host.\n\t */\n\tconst promoteCommand = registerCommand({\n\t\tname: \"promote\",\n\t\tdescription:\n\t\t\t\"Promote a memory preference to the user-default scope (visible in every suite; two-step — re-run with confirm)\",\n\t\targumentHint: \"<memoryId> [confirm]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tconst memoryId = tokens[0] ?? \"\";\n\t\t\tconst confirmed = tokens[1] === \"confirm\";\n\t\t\tif (memoryId === \"\" || tokens.length > 2 || (tokens[1] !== undefined && !confirmed)) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: \"Usage: /promote <memoryId> [confirm] — run memory_list for this suite's memory ids\",\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst record = store.get(memoryId, { owner });\n\t\t\tif (!record) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tconst atom = record.atom;\n\t\t\tif (atom.memoryKind !== \"preference\" || atom.preference === undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `${memoryId} is a fact, not a preference; only preferences can be promoted`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (store.get(userDefaultMemoryId(memoryId), { owner }) !== undefined) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\tmessage: `Preference ${memoryId} is already promoted to the user-default scope`,\n\t\t\t\t};\n\t\t\t}\n\t\t\tif (!confirmed) {\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`Promotion target: \"${unwrapEgressStatement(statementOf(atom.payload))}\"\\n` +\n\t\t\t\t\t\t\"This makes the preference visible in EVERY suite (user-default scope, permanent). Nothing is promoted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t`/promote ${memoryId} confirm`,\n\t\t\t\t};\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst promoted = promotePreferenceToUserDefault({\n\t\t\t\t\tatom,\n\t\t\t\t\tauthorizedBy: \"user:/promote\",\n\t\t\t\t\tconfirmedAt: new Date(now()).toISOString(),\n\t\t\t\t});\n\t\t\t\tconst { domainName, ledger } = resolveDomain();\n\t\t\t\tledger.append(promoted);\n\t\t\t\tstore.commit(promoted);\n\t\t\t\t// 向量投影埋点: 与 memory_write 同一异步旁路 (失败不阻塞命令返回)。\n\t\t\t\tvectorProjection.upsertAtom(promoted);\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage: `Promoted \"${unwrapEgressStatement(statementOf(promoted.payload))}\" to the user-default scope; it is now visible in every suite`,\n\t\t\t\t\tdata: { memoryId: promoted.memoryId, sourceMemoryId: memoryId, domain: domainName },\n\t\t\t\t};\n\t\t\t} catch (error) {\n\t\t\t\treturn { status: \"error\" as const, message: error instanceof Error ? error.message : String(error) };\n\t\t\t}\n\t\t},\n\t});\n\n\t// memory.scheduler@1 plugin capability (宪法 §3 显式声明面): a declarative\n\t// marker only — the scheduler enforcement itself (per-instance single\n\t// lease, acquired above) stays carried by the host builtin implementation.\n\t// The declaration anchors \"this suite's memory scheduling is provided by\n\t// this plugin\" so the code Profile assembly check (requiresMemoryScheduler)\n\t// and third-party replacement detection have an explicit surface:\n\t// list()-visible, a same-id double provide fails explicitly (no override\n\t// priority), and after dispose a replacement provider can take the id.\n\tconst schedulerCapability = capabilities.provide({ id: \"memory.scheduler\", version: 1, kind: \"service\" }, () =>\n\t\tObject.freeze({\n\t\t\tid: \"memory.scheduler\",\n\t\t\tversion: 1,\n\t\t\towner: \"agent-forge.builtin.memory\",\n\t\t\tleaseScope: \"per-agent-instance\",\n\t\t}),\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 是用户的直接出口。decline/download\n\t// 核心在 memory/vector-channel.ts (slice 3b), 工具与命令面经\n\t// vectorChannelCtl.decline()/download() 薄委托; decline 持久化只抑制默认档。\n\t/**\n\t * Structured status for host consoles (公共命令结果 data, additive):\n\t * the TUI `/memory` console reads mode/channel/domain without parsing the\n\t * human message. `channel` mirrors the vector state machine; decline is\n\t * reported as \"off\" (the line's existing semantics).\n\t */\n\tconst memoryStatusSnapshot = (): {\n\t\treadonly mode: \"light\" | \"full\";\n\t\treadonly channel: \"off\" | \"consent-required\" | \"enabling\" | \"ready\" | \"degraded\" | \"failed\";\n\t\treadonly declined: boolean;\n\t\treadonly pendingUpgrade: boolean;\n\t\treadonly failureReason?: string;\n\t} => {\n\t\t// pending 尾巴只对仍有效的升档声明 (declined 分支里档位键已被删除, 显示\n\t\t// pending 会失实 — 2026-10-06 复审 P2-1)。\n\t\tconst declined = vectorChannelCtl.declined();\n\t\tconst pendingUpgrade = tierUpgradePending() && !declined;\n\t\tconst failureReason = vectorChannelCtl.failure()?.reason;\n\t\treturn {\n\t\t\tmode: memoryMode,\n\t\t\tchannel: declined ? \"off\" : vectorChannelCtl.rawState(),\n\t\t\tdeclined,\n\t\t\tpendingUpgrade,\n\t\t\t...(failureReason === undefined ? {} : { failureReason }),\n\t\t};\n\t};\n\tconst memoryStatusLine = (status: ReturnType<typeof memoryStatusSnapshot>): string => {\n\t\tconst modeLine = `mode=${status.mode}${status.pendingUpgrade ? \", auto-upgrade to full pending (next session)\" : \"\"}`;\n\t\tif (status.declined) {\n\t\t\treturn `${modeLine}, off (declined on this machine). Set memory.mode (light|full) in settings.json and restart the session to re-enable`;\n\t\t}\n\t\tif (status.channel === \"ready\") return `${modeLine}, ready`;\n\t\tif (status.channel === \"degraded\") return `${modeLine}, ready (degraded)`;\n\t\tif (status.channel === \"failed\") return `${modeLine}, failed: ${status.failureReason ?? \"unknown reason\"}`;\n\t\tif (status.channel === \"consent-required\") {\n\t\t\treturn `${modeLine}, waiting for the model download decision (/memory retry to start it)`;\n\t\t}\n\t\treturn `${modeLine}, loading models in the background`;\n\t};\n\tconst enableTool = registerTool({\n\t\tname: \"memory_enable\",\n\t\tlabel: \"Enable memory\",\n\t\tdescription:\n\t\t\t'Run or decline the one-time memory model download. The host starts it in the background at session start; call it with \"retry\" after a failure, or with \"decline\" when the user chooses to keep memory off',\n\t\tparameters: enableSchema,\n\t\texecute: async (first: unknown, second?: unknown) => {\n\t\t\tconst input = memoryToolInput(first, second);\n\t\t\tconst action: unknown = input.action;\n\t\t\tif (action !== \"download\" && action !== \"decline\" && action !== \"retry\") {\n\t\t\t\tthrow new Error('action must be \"download\", \"decline\", or \"retry\"');\n\t\t\t}\n\t\t\tif (action === \"decline\") return vectorChannelCtl.decline();\n\t\t\treturn vectorChannelCtl.download();\n\t\t},\n\t});\n\tconst memoryCommand = registerCommand({\n\t\tname: \"memory\",\n\t\tdescription:\n\t\t\t\"Memory controls: bare shows status; light|full switches the model preset (persisted, effective next session); off persists disable; retry re-runs the model download; forget <memoryId> [confirm] is the user-only physical delete (two-step)\",\n\t\targumentHint: \"[light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\texecute: async (args: string) => {\n\t\t\tconst tokens = args.trim().split(/\\s+/).filter(Boolean);\n\t\t\tif (tokens[0] === \"forget\") {\n\t\t\t\tconst memoryId = tokens[1] ?? \"\";\n\t\t\t\tconst confirmed = tokens[2] === \"confirm\";\n\t\t\t\tif (memoryId === \"\" || tokens.length > 3 || (tokens[2] !== undefined && !confirmed)) {\n\t\t\t\t\treturn { status: \"error\" as const, message: \"Usage: /memory forget <memoryId> [confirm]\" };\n\t\t\t\t}\n\t\t\t\tconst { domain, domainName } = resolveDomain();\n\t\t\t\tconst unscoped = store.get(memoryId, { owner });\n\t\t\t\tif (unscoped === undefined) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `No memory found with id ${memoryId}; run memory_list for this suite's memory ids`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst isMember =\n\t\t\t\t\tdomain.kind === \"suite\" ? unscoped.atom.suiteId === domain.suiteId : unscoped.atom.suiteId === undefined;\n\t\t\t\tif (!isMember) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"error\" as const,\n\t\t\t\t\t\tmessage: `${memoryId} belongs to another suite; each suite forgets only its own memories`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tif (!confirmed) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t`Forget target: \"${unwrapEgressStatement(statementOf(unscoped.atom.payload))}\"\\n` +\n\t\t\t\t\t\t\t\"This permanently deletes the memory (irreversible, purge-gated). Nothing is deleted yet — re-run to confirm:\\n\" +\n\t\t\t\t\t\t\t`/memory forget ${memoryId} confirm`,\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\tconst result = purgeMemoryViaUserCommand(memoryId);\n\t\t\t\tif (result.status === \"completed\") {\n\t\t\t\t\tawait publish({\n\t\t\t\t\t\ttype: EVENT_TYPE,\n\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\tcorrelationId: capabilityManifest.id,\n\t\t\t\t\t\tdata: { action: \"forgotten\", memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t});\n\t\t\t\t\treturn {\n\t\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\t\tmessage: `Forgot ${memoryId} (${domainName}): the memory is physically deleted`,\n\t\t\t\t\t\tdata: { memoryId, domain: domainName, batchId: result.batchId },\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t\treturn { status: \"error\" as const, message: `forget failed: ${result.status}` };\n\t\t\t}\n\t\t\tconst sub = args.trim().toLowerCase();\n\t\t\tif (sub === \"\" || sub === \"status\") {\n\t\t\t\tconst snapshot = memoryStatusSnapshot();\n\t\t\t\tconst statusResult: CapabilityCommandResult = {\n\t\t\t\t\tstatus: \"success\",\n\t\t\t\t\tmessage: `memory: ${memoryStatusLine(snapshot)}`,\n\t\t\t\t\tdata: { memoryStatus: snapshot },\n\t\t\t\t};\n\t\t\t\treturn statusResult;\n\t\t\t}\n\t\t\tif (sub === \"light\" || sub === \"full\") {\n\t\t\t\t// 无\"已是该档\"早退: 持久化档位与会话内已解析档位是两回事——会话可能\n\t\t\t\t// 因默认档而运行 light, 用户降档仍需把持久化值落盘 (或覆盖旧档)。\n\t\t\t\twriteMemorySettingsMode(agentDir, sub);\n\t\t\t\t// 升/降档清了文件里的拒绝标记, 内存标记同步翻回: 用户最新的显式\n\t\t\t\t// 意图是启用——本会话恢复对当前预置的响应 (retry 可用), 新档与\n\t\t\t\t// 新模型下载在下一会话生效。\n\t\t\t\tvectorChannelCtl.clearDeclined();\n\t\t\t\t// 用户的显式档位表达取代本实例的自动升档声明: 降回 light 后 pending\n\t\t\t\t// 尾巴不再显示, 且显式 light 会让自动升档在后续写入中跳过 (复审 P2-1)。\n\t\t\t\tif (sub === \"light\") clearTierUpgrade();\n\t\t\t\treturn {\n\t\t\t\t\tstatus: \"success\" as const,\n\t\t\t\t\tmessage:\n\t\t\t\t\t\t`memory: preset ${sub} persisted (capabilities/builtin.memory.json). It takes effect next session — ` +\n\t\t\t\t\t\t(sub === \"full\"\n\t\t\t\t\t\t\t? \"the larger embedding model (bge-m3, hundreds of MB) downloads in the background at the next start, disk headroom ≥2GB, and write-side semantic dedup turns on. \"\n\t\t\t\t\t\t\t: \"\") +\n\t\t\t\t\t\t\"Existing memories carry over: the projection rebuilds onto the new model automatically.\",\n\t\t\t\t};\n\t\t\t}\n\t\t\t// 命令面结果映射: 工具闭包的 completed/failed 面转 CapabilityCommandResult\n\t\t\t// 的 success/error; 行动清单/next 指引并入 message (命令结果无 actions 字段)。\n\t\t\tconst toCommandResult = (\n\t\t\t\tresult: Awaited<ReturnType<typeof vectorChannelCtl.download>>,\n\t\t\t): { status: \"success\" | \"error\"; message: string } => ({\n\t\t\t\tstatus: result.status === \"completed\" ? \"success\" : \"error\",\n\t\t\t\tmessage:\n\t\t\t\t\tresult.status === \"failed\"\n\t\t\t\t\t\t? [result.message, ...(result.actions ?? []), result.next].filter(Boolean).join(\" — \")\n\t\t\t\t\t\t: result.message,\n\t\t\t});\n\t\t\tif (sub === \"off\") return toCommandResult(vectorChannelCtl.decline());\n\t\t\tif (sub === \"retry\") return toCommandResult(await vectorChannelCtl.download());\n\t\t\treturn {\n\t\t\t\tstatus: \"error\" as const,\n\t\t\t\tmessage: \"Usage: /memory [light|full|off|retry|forget <memoryId> [confirm]]\",\n\t\t\t};\n\t\t},\n\t});\n\n\treturn { listTool, forgetTool, enableTool, memoryCommand, promoteCommand, schedulerCapability };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"inference-service-main.d.ts","sourceRoot":"","sources":["../../src/memory/inference-service-main.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,EAEN,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,MAAM,uBAAuB,CAAC;AAG/B,0FAAyC;AACzC,eAAO,MAAM,wCAAwC,QAAgB,CAAC;AAEtE,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC,+GAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAmD;IACnD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sFAAsC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE;QACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,6BAA6B,CAAC;QACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;KACjD,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,6BAA6B,GACpC,OAAO,CAAC,uBAAuB,CAAC,CAoElC","sourcesContent":["/**\n * 记忆共享推理服务 — 服务进程主函数 (记忆共享推理服务设计 §3.1/§3.6, Slice B1)。\n *\n * `agent-forge --memory-inference` 进程入口的执行体: 装配真实推理后端\n * (transformers embedding + reranker + LanceDB 向量索引 — 与会话进程本地装配\n * 完全同一组构件与模型缓存路径, 设计 §3.6「下载与装配只发生一次」的装配侧),\n * 然后以固定默认端口常驻服务 (设计 §3.5: 空闲自杀、信号优雅停机)。\n *\n * consent 链完整性 (设计 §3.6): 服务进程**不做 consent 判定、永不自主下载** —\n * 拉起方 (B2 接线: 会话侧在用户同意、模型经预热下载在位后) 才 spawn 本进程;\n * 启动时模型文件缺失即结构化退出 (拉起方把它当服务不可用, 按裁决 A 呈现)。\n * 下载只发生在会话进程的既有预热流程 (memory_enable download), 行为不变。\n *\n * 测试缝: `backend` 直接注入完整后端 (跳过真实装配); `loadImpls`/`moduleEntryPaths`\n * 透传给真实装配 (与 capability 的 enabling 缝同构)。\n */\nimport { join } from \"node:path\";\nimport { VECTOR_DB_DIRNAME, VECTOR_MODEL_CACHE_DIRNAME, VECTOR_RERANKER_MODEL_ID } from \"../capability.ts\";\nimport type { TransformersEmbeddingLoadImpl } from \"./embedding-provider.ts\";\nimport { createTransformersEmbeddingProvider } from \"./embedding-provider.ts\";\nimport type { TransformersRerankerLoadImpl } from \"./embedding-reranker.ts\";\nimport { createTransformersReranker } from \"./embedding-reranker.ts\";\nimport { MODEL_MIN_WEIGHT_BYTES, modelFilesCheck, RERANKER_MIN_WEIGHT_BYTES, vectorPresetForMode } from \"./enabling.ts\";\nimport {\n\tcreateMemoryInferenceServer,\n\ttype MemoryInferenceBackendV1,\n\ttype MemoryInferenceServerV1,\n} from \"./inference-server.ts\";\nimport { createMemoryVectorIndex } from \"./vector-index.ts\";\n\n/** 服务空闲自杀阈值出厂默认 (设计 §3.5; 登记产品默认值清单)。 */\nexport const MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface MemoryInferenceServiceOptions {\n\treadonly agentDir: string;\n\treadonly mode: \"light\" | \"full\";\n\t/** 缺省固定默认端口 (单例互斥); env 覆盖由 createMemoryInferenceServer 端口参数承担。 */\n\treadonly port?: number;\n\t/** 缺省 MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS。 */\n\treadonly idleTimeoutMs?: number;\n\treadonly signal?: AbortSignal;\n\t/** 测试缝: 直接给定后端, 跳过真实装配 (模型检查一并跳过)。 */\n\treadonly backend?: MemoryInferenceBackendV1;\n\treadonly moduleEntryPaths?: { readonly lancedb?: string; readonly transformers?: string };\n\treadonly loadImpls?: {\n\t\treadonly embedding?: TransformersEmbeddingLoadImpl;\n\t\treadonly reranker?: TransformersRerankerLoadImpl;\n\t};\n\treadonly log?: (line: string) => void;\n}\n\n/**\n * 装配并启动共享推理服务。真实装配路径的失败 (模型缺失) 抛结构化错误 —\n * 进程入口将其转为一行 stderr + 非零退出码; 已监听后返回 server 句柄。\n */\nexport async function runMemoryInferenceService(\n\toptions: MemoryInferenceServiceOptions,\n): Promise<MemoryInferenceServerV1> {\n\tconst log = options.log ?? (() => {});\n\tconst preset = vectorPresetForMode(options.mode);\n\tconst modelCacheDir = join(options.agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\n\tlet backend = options.backend;\n\tif (backend === undefined) {\n\t\t// consent 链守门: 模型缺失即退出, 服务进程绝不触发下载 (拉起方保证\n\t\t// \"已同意且已下载\"; 缺失说明拉起时机错误或缓存被清)。\n\t\tconst missingEmbedding = modelFilesCheck(\n\t\t\tmodelCacheDir,\n\t\t\tpreset.embeddingModelId,\n\t\t\tMODEL_MIN_WEIGHT_BYTES[options.mode],\n\t\t);\n\t\tconst missingReranker = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\tconst missing = missingEmbedding ?? missingReranker;\n\t\tif (missing !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`memory inference service refuses to start: ${missing} — the service never downloads models itself; ` +\n\t\t\t\t\t\"the spawner must start it after the session-side preheat has the models in place\",\n\t\t\t);\n\t\t}\n\t\t// remoteHosts 不传 (provider 缺省序列): 服务的前置条件是模型已在位,\n\t\t// 加载命中本地缓存、远端不可达也不影响; 显式空数组会被 provider 当\n\t\t// \"零镜像可用\", 首次加载直接报 no remote hosts (2026-10-06 live E2E)。\n\t\tconst embedProvider = createTransformersEmbeddingProvider({\n\t\t\tmodelId: preset.embeddingModelId,\n\t\t\tdimensions: preset.dimensions,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.embedding === undefined ? {} : { loadImpl: options.loadImpls.embedding }),\n\t\t});\n\t\tconst reranker = createTransformersReranker({\n\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.reranker === undefined ? {} : { loadImpl: options.loadImpls.reranker }),\n\t\t});\n\t\tconst vectorIndex = await createMemoryVectorIndex({\n\t\t\tdbPath: join(options.agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\tdimensions: preset.dimensions,\n\t\t\t...(options.moduleEntryPaths?.lancedb === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.lancedb }),\n\t\t});\n\t\tbackend = { embedProvider, reranker, vectorIndex };\n\t}\n\n\tconst server = await createMemoryInferenceServer({\n\t\tbackend,\n\t\t// agentDir 身份上报 (2026-10-06 串线修复): 服务进程的 agent-dir 由 spawn\n\t\t// env 解析而来, 经 hello 回报 — 会话装配据此拒绝跨 agent-dir 串线。\n\t\tagentDir: options.agentDir,\n\t\t...(options.port === undefined ? {} : { port: options.port }),\n\t\tidleTimeoutMs: options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS,\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t\tonError: (error, context) => {\n\t\t\tlog(`memory-inference: ${context}: ${error.message}`);\n\t\t},\n\t});\n\tlog(\n\t\t`memory-inference: serving on ${server.host}:${server.port} (mode=${options.mode}, idle-exit=${options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS}ms)`,\n\t);\n\treturn server;\n}\n"]}
1
+ {"version":3,"file":"inference-service-main.d.ts","sourceRoot":"","sources":["../../src/memory/inference-service-main.ts"],"names":[],"mappings":"AAkBA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAE7E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,EAEN,KAAK,wBAAwB,EAC7B,KAAK,uBAAuB,EAC5B,MAAM,uBAAuB,CAAC;AAG/B,0FAAyC;AACzC,eAAO,MAAM,wCAAwC,QAAgB,CAAC;AAEtE,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IAChC,+GAAmE;IACnE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,yDAAmD;IACnD,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;IAC9B,sFAAsC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,wBAAwB,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,CAAC,EAAE;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1F,QAAQ,CAAC,SAAS,CAAC,EAAE;QACpB,QAAQ,CAAC,SAAS,CAAC,EAAE,6BAA6B,CAAC;QACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,4BAA4B,CAAC;KACjD,CAAC;IACF,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAC9C,OAAO,EAAE,6BAA6B,GACpC,OAAO,CAAC,uBAAuB,CAAC,CA2ElC","sourcesContent":["/**\n * 记忆共享推理服务 — 服务进程主函数 (记忆共享推理服务设计 §3.1/§3.6, Slice B1)。\n *\n * `agent-forge --memory-inference` 进程入口的执行体: 装配真实推理后端\n * (transformers embedding + reranker + LanceDB 向量索引 — 与会话进程本地装配\n * 完全同一组构件与模型缓存路径, 设计 §3.6「下载与装配只发生一次」的装配侧),\n * 然后以固定默认端口常驻服务 (设计 §3.5: 空闲自杀、信号优雅停机)。\n *\n * consent 链完整性 (设计 §3.6): 服务进程**不做 consent 判定、永不自主下载** —\n * 拉起方 (B2 接线: 会话侧在用户同意、模型经预热下载在位后) 才 spawn 本进程;\n * 启动时模型文件缺失即结构化退出 (拉起方把它当服务不可用, 按裁决 A 呈现)。\n * 下载只发生在会话进程的既有预热流程 (memory_enable download), 行为不变。\n *\n * 测试缝: `backend` 直接注入完整后端 (跳过真实装配); `loadImpls`/`moduleEntryPaths`\n * 透传给真实装配 (与 capability 的 enabling 缝同构)。\n */\nimport { join } from \"node:path\";\nimport { VECTOR_DB_DIRNAME, VECTOR_MODEL_CACHE_DIRNAME, VECTOR_RERANKER_MODEL_ID } from \"../capability.ts\";\nimport type { TransformersEmbeddingLoadImpl } from \"./embedding-provider.ts\";\nimport { createTransformersEmbeddingProvider } from \"./embedding-provider.ts\";\nimport type { TransformersRerankerLoadImpl } from \"./embedding-reranker.ts\";\nimport { createTransformersReranker } from \"./embedding-reranker.ts\";\nimport { MODEL_MIN_WEIGHT_BYTES, modelFilesCheck, RERANKER_MIN_WEIGHT_BYTES, vectorPresetForMode } from \"./enabling.ts\";\nimport {\n\tcreateMemoryInferenceServer,\n\ttype MemoryInferenceBackendV1,\n\ttype MemoryInferenceServerV1,\n} from \"./inference-server.ts\";\nimport { createMemoryVectorIndex } from \"./vector-index.ts\";\n\n/** 服务空闲自杀阈值出厂默认 (设计 §3.5; 登记产品默认值清单)。 */\nexport const MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface MemoryInferenceServiceOptions {\n\treadonly agentDir: string;\n\treadonly mode: \"light\" | \"full\";\n\t/** 缺省固定默认端口 (单例互斥); env 覆盖由 createMemoryInferenceServer 端口参数承担。 */\n\treadonly port?: number;\n\t/** 缺省 MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS。 */\n\treadonly idleTimeoutMs?: number;\n\treadonly signal?: AbortSignal;\n\t/** 测试缝: 直接给定后端, 跳过真实装配 (模型检查一并跳过)。 */\n\treadonly backend?: MemoryInferenceBackendV1;\n\treadonly moduleEntryPaths?: { readonly lancedb?: string; readonly transformers?: string };\n\treadonly loadImpls?: {\n\t\treadonly embedding?: TransformersEmbeddingLoadImpl;\n\t\treadonly reranker?: TransformersRerankerLoadImpl;\n\t};\n\treadonly log?: (line: string) => void;\n}\n\n/**\n * 装配并启动共享推理服务。真实装配路径的失败 (模型缺失) 抛结构化错误 —\n * 进程入口将其转为一行 stderr + 非零退出码; 已监听后返回 server 句柄。\n */\nexport async function runMemoryInferenceService(\n\toptions: MemoryInferenceServiceOptions,\n): Promise<MemoryInferenceServerV1> {\n\tconst log = options.log ?? (() => {});\n\tconst preset = vectorPresetForMode(options.mode);\n\tconst modelCacheDir = join(options.agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\n\tlet backend = options.backend;\n\tif (backend === undefined) {\n\t\t// consent 链守门: 模型缺失即退出, 服务进程绝不触发下载 (拉起方保证\n\t\t// \"已同意且已下载\"; 缺失说明拉起时机错误或缓存被清)。\n\t\tconst missingEmbedding = modelFilesCheck(\n\t\t\tmodelCacheDir,\n\t\t\tpreset.embeddingModelId,\n\t\t\tMODEL_MIN_WEIGHT_BYTES[options.mode],\n\t\t);\n\t\tconst missingReranker = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\tconst missing = missingEmbedding ?? missingReranker;\n\t\tif (missing !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`memory inference service refuses to start: ${missing} — the service never downloads models itself; ` +\n\t\t\t\t\t\"the spawner must start it after the session-side preheat has the models in place\",\n\t\t\t);\n\t\t}\n\t\t// remoteHosts 不传 (provider 缺省序列): 服务的前置条件是模型已在位,\n\t\t// 加载命中本地缓存、远端不可达也不影响; 显式空数组会被 provider 当\n\t\t// \"零镜像可用\", 首次加载直接报 no remote hosts (2026-10-06 live E2E)。\n\t\tconst embedProvider = createTransformersEmbeddingProvider({\n\t\t\tmodelId: preset.embeddingModelId,\n\t\t\tdimensions: preset.dimensions,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.embedding === undefined ? {} : { loadImpl: options.loadImpls.embedding }),\n\t\t});\n\t\tconst reranker = createTransformersReranker({\n\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.reranker === undefined ? {} : { loadImpl: options.loadImpls.reranker }),\n\t\t});\n\t\tconst vectorIndex = await createMemoryVectorIndex({\n\t\t\tdbPath: join(options.agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\tdimensions: preset.dimensions,\n\t\t\t...(options.moduleEntryPaths?.lancedb === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.lancedb }),\n\t\t\t// P5 残留守卫 (与本地通道同语义): 拒绝覆盖外来同 id 行, 服务进程日志留痕。\n\t\t\tonCollision: (collision) => {\n\t\t\t\tlog(\n\t\t\t\t\t\"memory-inference: vector projection refused to overwrite a row whose memoryId belongs to a different atom (cross-domain id collision): \" +\n\t\t\t\t\t\tcollision.memoryId,\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\t\tbackend = { embedProvider, reranker, vectorIndex };\n\t}\n\n\tconst server = await createMemoryInferenceServer({\n\t\tbackend,\n\t\t// agentDir 身份上报 (2026-10-06 串线修复): 服务进程的 agent-dir 由 spawn\n\t\t// env 解析而来, 经 hello 回报 — 会话装配据此拒绝跨 agent-dir 串线。\n\t\tagentDir: options.agentDir,\n\t\t...(options.port === undefined ? {} : { port: options.port }),\n\t\tidleTimeoutMs: options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS,\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t\tonError: (error, context) => {\n\t\t\tlog(`memory-inference: ${context}: ${error.message}`);\n\t\t},\n\t});\n\tlog(\n\t\t`memory-inference: serving on ${server.host}:${server.port} (mode=${options.mode}, idle-exit=${options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS}ms)`,\n\t);\n\treturn server;\n}\n"]}
@@ -68,6 +68,11 @@ export async function runMemoryInferenceService(options) {
68
68
  ...(options.moduleEntryPaths?.lancedb === undefined
69
69
  ? {}
70
70
  : { moduleEntryPath: options.moduleEntryPaths.lancedb }),
71
+ // P5 残留守卫 (与本地通道同语义): 拒绝覆盖外来同 id 行, 服务进程日志留痕。
72
+ onCollision: (collision) => {
73
+ log("memory-inference: vector projection refused to overwrite a row whose memoryId belongs to a different atom (cross-domain id collision): " +
74
+ collision.memoryId);
75
+ },
71
76
  });
72
77
  backend = { embedProvider, reranker, vectorIndex };
73
78
  }
@@ -1 +1 @@
1
- {"version":3,"file":"inference-service-main.js","sourceRoot":"","sources":["../../src/memory/inference-service-main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 记忆共享推理服务 — 服务进程主函数 (记忆共享推理服务设计 §3.1/§3.6, Slice B1)。\n *\n * `agent-forge --memory-inference` 进程入口的执行体: 装配真实推理后端\n * (transformers embedding + reranker + LanceDB 向量索引 — 与会话进程本地装配\n * 完全同一组构件与模型缓存路径, 设计 §3.6「下载与装配只发生一次」的装配侧),\n * 然后以固定默认端口常驻服务 (设计 §3.5: 空闲自杀、信号优雅停机)。\n *\n * consent 链完整性 (设计 §3.6): 服务进程**不做 consent 判定、永不自主下载** —\n * 拉起方 (B2 接线: 会话侧在用户同意、模型经预热下载在位后) 才 spawn 本进程;\n * 启动时模型文件缺失即结构化退出 (拉起方把它当服务不可用, 按裁决 A 呈现)。\n * 下载只发生在会话进程的既有预热流程 (memory_enable download), 行为不变。\n *\n * 测试缝: `backend` 直接注入完整后端 (跳过真实装配); `loadImpls`/`moduleEntryPaths`\n * 透传给真实装配 (与 capability 的 enabling 缝同构)。\n */\nimport { join } from \"node:path\";\nimport { VECTOR_DB_DIRNAME, VECTOR_MODEL_CACHE_DIRNAME, VECTOR_RERANKER_MODEL_ID } from \"../capability.ts\";\nimport type { TransformersEmbeddingLoadImpl } from \"./embedding-provider.ts\";\nimport { createTransformersEmbeddingProvider } from \"./embedding-provider.ts\";\nimport type { TransformersRerankerLoadImpl } from \"./embedding-reranker.ts\";\nimport { createTransformersReranker } from \"./embedding-reranker.ts\";\nimport { MODEL_MIN_WEIGHT_BYTES, modelFilesCheck, RERANKER_MIN_WEIGHT_BYTES, vectorPresetForMode } from \"./enabling.ts\";\nimport {\n\tcreateMemoryInferenceServer,\n\ttype MemoryInferenceBackendV1,\n\ttype MemoryInferenceServerV1,\n} from \"./inference-server.ts\";\nimport { createMemoryVectorIndex } from \"./vector-index.ts\";\n\n/** 服务空闲自杀阈值出厂默认 (设计 §3.5; 登记产品默认值清单)。 */\nexport const MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface MemoryInferenceServiceOptions {\n\treadonly agentDir: string;\n\treadonly mode: \"light\" | \"full\";\n\t/** 缺省固定默认端口 (单例互斥); env 覆盖由 createMemoryInferenceServer 端口参数承担。 */\n\treadonly port?: number;\n\t/** 缺省 MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS。 */\n\treadonly idleTimeoutMs?: number;\n\treadonly signal?: AbortSignal;\n\t/** 测试缝: 直接给定后端, 跳过真实装配 (模型检查一并跳过)。 */\n\treadonly backend?: MemoryInferenceBackendV1;\n\treadonly moduleEntryPaths?: { readonly lancedb?: string; readonly transformers?: string };\n\treadonly loadImpls?: {\n\t\treadonly embedding?: TransformersEmbeddingLoadImpl;\n\t\treadonly reranker?: TransformersRerankerLoadImpl;\n\t};\n\treadonly log?: (line: string) => void;\n}\n\n/**\n * 装配并启动共享推理服务。真实装配路径的失败 (模型缺失) 抛结构化错误 —\n * 进程入口将其转为一行 stderr + 非零退出码; 已监听后返回 server 句柄。\n */\nexport async function runMemoryInferenceService(\n\toptions: MemoryInferenceServiceOptions,\n): Promise<MemoryInferenceServerV1> {\n\tconst log = options.log ?? (() => {});\n\tconst preset = vectorPresetForMode(options.mode);\n\tconst modelCacheDir = join(options.agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\n\tlet backend = options.backend;\n\tif (backend === undefined) {\n\t\t// consent 链守门: 模型缺失即退出, 服务进程绝不触发下载 (拉起方保证\n\t\t// \"已同意且已下载\"; 缺失说明拉起时机错误或缓存被清)。\n\t\tconst missingEmbedding = modelFilesCheck(\n\t\t\tmodelCacheDir,\n\t\t\tpreset.embeddingModelId,\n\t\t\tMODEL_MIN_WEIGHT_BYTES[options.mode],\n\t\t);\n\t\tconst missingReranker = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\tconst missing = missingEmbedding ?? missingReranker;\n\t\tif (missing !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`memory inference service refuses to start: ${missing} — the service never downloads models itself; ` +\n\t\t\t\t\t\"the spawner must start it after the session-side preheat has the models in place\",\n\t\t\t);\n\t\t}\n\t\t// remoteHosts 不传 (provider 缺省序列): 服务的前置条件是模型已在位,\n\t\t// 加载命中本地缓存、远端不可达也不影响; 显式空数组会被 provider 当\n\t\t// \"零镜像可用\", 首次加载直接报 no remote hosts (2026-10-06 live E2E)。\n\t\tconst embedProvider = createTransformersEmbeddingProvider({\n\t\t\tmodelId: preset.embeddingModelId,\n\t\t\tdimensions: preset.dimensions,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.embedding === undefined ? {} : { loadImpl: options.loadImpls.embedding }),\n\t\t});\n\t\tconst reranker = createTransformersReranker({\n\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.reranker === undefined ? {} : { loadImpl: options.loadImpls.reranker }),\n\t\t});\n\t\tconst vectorIndex = await createMemoryVectorIndex({\n\t\t\tdbPath: join(options.agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\tdimensions: preset.dimensions,\n\t\t\t...(options.moduleEntryPaths?.lancedb === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.lancedb }),\n\t\t});\n\t\tbackend = { embedProvider, reranker, vectorIndex };\n\t}\n\n\tconst server = await createMemoryInferenceServer({\n\t\tbackend,\n\t\t// agentDir 身份上报 (2026-10-06 串线修复): 服务进程的 agent-dir 由 spawn\n\t\t// env 解析而来, 经 hello 回报 — 会话装配据此拒绝跨 agent-dir 串线。\n\t\tagentDir: options.agentDir,\n\t\t...(options.port === undefined ? {} : { port: options.port }),\n\t\tidleTimeoutMs: options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS,\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t\tonError: (error, context) => {\n\t\t\tlog(`memory-inference: ${context}: ${error.message}`);\n\t\t},\n\t});\n\tlog(\n\t\t`memory-inference: serving on ${server.host}:${server.port} (mode=${options.mode}, idle-exit=${options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS}ms)`,\n\t);\n\treturn server;\n}\n"]}
1
+ {"version":3,"file":"inference-service-main.js","sourceRoot":"","sources":["../../src/memory/inference-service-main.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 记忆共享推理服务 — 服务进程主函数 (记忆共享推理服务设计 §3.1/§3.6, Slice B1)。\n *\n * `agent-forge --memory-inference` 进程入口的执行体: 装配真实推理后端\n * (transformers embedding + reranker + LanceDB 向量索引 — 与会话进程本地装配\n * 完全同一组构件与模型缓存路径, 设计 §3.6「下载与装配只发生一次」的装配侧),\n * 然后以固定默认端口常驻服务 (设计 §3.5: 空闲自杀、信号优雅停机)。\n *\n * consent 链完整性 (设计 §3.6): 服务进程**不做 consent 判定、永不自主下载** —\n * 拉起方 (B2 接线: 会话侧在用户同意、模型经预热下载在位后) 才 spawn 本进程;\n * 启动时模型文件缺失即结构化退出 (拉起方把它当服务不可用, 按裁决 A 呈现)。\n * 下载只发生在会话进程的既有预热流程 (memory_enable download), 行为不变。\n *\n * 测试缝: `backend` 直接注入完整后端 (跳过真实装配); `loadImpls`/`moduleEntryPaths`\n * 透传给真实装配 (与 capability 的 enabling 缝同构)。\n */\nimport { join } from \"node:path\";\nimport { VECTOR_DB_DIRNAME, VECTOR_MODEL_CACHE_DIRNAME, VECTOR_RERANKER_MODEL_ID } from \"../capability.ts\";\nimport type { TransformersEmbeddingLoadImpl } from \"./embedding-provider.ts\";\nimport { createTransformersEmbeddingProvider } from \"./embedding-provider.ts\";\nimport type { TransformersRerankerLoadImpl } from \"./embedding-reranker.ts\";\nimport { createTransformersReranker } from \"./embedding-reranker.ts\";\nimport { MODEL_MIN_WEIGHT_BYTES, modelFilesCheck, RERANKER_MIN_WEIGHT_BYTES, vectorPresetForMode } from \"./enabling.ts\";\nimport {\n\tcreateMemoryInferenceServer,\n\ttype MemoryInferenceBackendV1,\n\ttype MemoryInferenceServerV1,\n} from \"./inference-server.ts\";\nimport { createMemoryVectorIndex } from \"./vector-index.ts\";\n\n/** 服务空闲自杀阈值出厂默认 (设计 §3.5; 登记产品默认值清单)。 */\nexport const MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS = 5 * 60 * 1000;\n\nexport interface MemoryInferenceServiceOptions {\n\treadonly agentDir: string;\n\treadonly mode: \"light\" | \"full\";\n\t/** 缺省固定默认端口 (单例互斥); env 覆盖由 createMemoryInferenceServer 端口参数承担。 */\n\treadonly port?: number;\n\t/** 缺省 MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS。 */\n\treadonly idleTimeoutMs?: number;\n\treadonly signal?: AbortSignal;\n\t/** 测试缝: 直接给定后端, 跳过真实装配 (模型检查一并跳过)。 */\n\treadonly backend?: MemoryInferenceBackendV1;\n\treadonly moduleEntryPaths?: { readonly lancedb?: string; readonly transformers?: string };\n\treadonly loadImpls?: {\n\t\treadonly embedding?: TransformersEmbeddingLoadImpl;\n\t\treadonly reranker?: TransformersRerankerLoadImpl;\n\t};\n\treadonly log?: (line: string) => void;\n}\n\n/**\n * 装配并启动共享推理服务。真实装配路径的失败 (模型缺失) 抛结构化错误 —\n * 进程入口将其转为一行 stderr + 非零退出码; 已监听后返回 server 句柄。\n */\nexport async function runMemoryInferenceService(\n\toptions: MemoryInferenceServiceOptions,\n): Promise<MemoryInferenceServerV1> {\n\tconst log = options.log ?? (() => {});\n\tconst preset = vectorPresetForMode(options.mode);\n\tconst modelCacheDir = join(options.agentDir, \"memory\", VECTOR_MODEL_CACHE_DIRNAME);\n\n\tlet backend = options.backend;\n\tif (backend === undefined) {\n\t\t// consent 链守门: 模型缺失即退出, 服务进程绝不触发下载 (拉起方保证\n\t\t// \"已同意且已下载\"; 缺失说明拉起时机错误或缓存被清)。\n\t\tconst missingEmbedding = modelFilesCheck(\n\t\t\tmodelCacheDir,\n\t\t\tpreset.embeddingModelId,\n\t\t\tMODEL_MIN_WEIGHT_BYTES[options.mode],\n\t\t);\n\t\tconst missingReranker = modelFilesCheck(modelCacheDir, VECTOR_RERANKER_MODEL_ID, RERANKER_MIN_WEIGHT_BYTES);\n\t\tconst missing = missingEmbedding ?? missingReranker;\n\t\tif (missing !== undefined) {\n\t\t\tthrow new Error(\n\t\t\t\t`memory inference service refuses to start: ${missing} — the service never downloads models itself; ` +\n\t\t\t\t\t\"the spawner must start it after the session-side preheat has the models in place\",\n\t\t\t);\n\t\t}\n\t\t// remoteHosts 不传 (provider 缺省序列): 服务的前置条件是模型已在位,\n\t\t// 加载命中本地缓存、远端不可达也不影响; 显式空数组会被 provider 当\n\t\t// \"零镜像可用\", 首次加载直接报 no remote hosts (2026-10-06 live E2E)。\n\t\tconst embedProvider = createTransformersEmbeddingProvider({\n\t\t\tmodelId: preset.embeddingModelId,\n\t\t\tdimensions: preset.dimensions,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.embedding === undefined ? {} : { loadImpl: options.loadImpls.embedding }),\n\t\t});\n\t\tconst reranker = createTransformersReranker({\n\t\t\tmodelId: VECTOR_RERANKER_MODEL_ID,\n\t\t\tcacheDir: modelCacheDir,\n\t\t\t...(options.moduleEntryPaths?.transformers === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.transformers }),\n\t\t\t...(options.loadImpls?.reranker === undefined ? {} : { loadImpl: options.loadImpls.reranker }),\n\t\t});\n\t\tconst vectorIndex = await createMemoryVectorIndex({\n\t\t\tdbPath: join(options.agentDir, \"memory\", VECTOR_DB_DIRNAME),\n\t\t\tdimensions: preset.dimensions,\n\t\t\t...(options.moduleEntryPaths?.lancedb === undefined\n\t\t\t\t? {}\n\t\t\t\t: { moduleEntryPath: options.moduleEntryPaths.lancedb }),\n\t\t\t// P5 残留守卫 (与本地通道同语义): 拒绝覆盖外来同 id 行, 服务进程日志留痕。\n\t\t\tonCollision: (collision) => {\n\t\t\t\tlog(\n\t\t\t\t\t\"memory-inference: vector projection refused to overwrite a row whose memoryId belongs to a different atom (cross-domain id collision): \" +\n\t\t\t\t\t\tcollision.memoryId,\n\t\t\t\t);\n\t\t\t},\n\t\t});\n\t\tbackend = { embedProvider, reranker, vectorIndex };\n\t}\n\n\tconst server = await createMemoryInferenceServer({\n\t\tbackend,\n\t\t// agentDir 身份上报 (2026-10-06 串线修复): 服务进程的 agent-dir 由 spawn\n\t\t// env 解析而来, 经 hello 回报 — 会话装配据此拒绝跨 agent-dir 串线。\n\t\tagentDir: options.agentDir,\n\t\t...(options.port === undefined ? {} : { port: options.port }),\n\t\tidleTimeoutMs: options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS,\n\t\t...(options.signal === undefined ? {} : { signal: options.signal }),\n\t\tonError: (error, context) => {\n\t\t\tlog(`memory-inference: ${context}: ${error.message}`);\n\t\t},\n\t});\n\tlog(\n\t\t`memory-inference: serving on ${server.host}:${server.port} (mode=${options.mode}, idle-exit=${options.idleTimeoutMs ?? MEMORY_INFERENCE_SERVICE_IDLE_TIMEOUT_MS}ms)`,\n\t);\n\treturn server;\n}\n"]}