@ai-agent-forge/plugin-memory 0.88.14 → 0.88.16

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.
@@ -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, 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\tconst memoryStatusLine = (): string => {\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 modeLine = `mode=${memoryMode}${pendingUpgrade ? \", auto-upgrade to full pending (next session)\" : \"\"}`;\n\t\tif (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\tconst channelState = vectorChannelCtl.rawState();\n\t\tif (channelState === \"ready\") return `${modeLine}, ready`;\n\t\tif (channelState === \"degraded\") return `${modeLine}, ready (degraded)`;\n\t\tif (channelState === \"failed\")\n\t\t\treturn `${modeLine}, failed: ${vectorChannelCtl.failure()?.reason ?? \"unknown reason\"}`;\n\t\tif (channelState === \"consent-required\")\n\t\t\treturn `${modeLine}, waiting for the model download decision (/memory retry to start it)`;\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\treturn { status: \"success\" as const, message: `memory: ${memoryStatusLine()}` };\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)\", 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"]}
@@ -0,0 +1,184 @@
1
+ import type { CapabilityAPI, DisposableRegistration, SessionArchiveHostV1, SessionEntryView } from "@agent-forge/plugin-sdk";
2
+ import { type MemoryAtomV1 } from "./foundation.ts";
3
+ import type { DurableMemoryLedgerV1 } from "./ledger.ts";
4
+ import type { MemoryStoreV1 } from "./store.ts";
5
+ import type { SuiteMemoryDomainV1 } from "./suite-memory.ts";
6
+ import type { MemoryVectorProjectionV1 } from "./vector-projection.ts";
7
+ /** 整理策略能力 id(记忆归档与整理设计 §7.2 冻结契约)。 */
8
+ export declare const MEMORY_CURATION_POLICY_CAPABILITY_ID = "memory.curation-policy";
9
+ /** 整理策略能力版本(exact version matching)。 */
10
+ export declare const MEMORY_CURATION_POLICY_VERSION = 1;
11
+ /** 每片最大条目数(有界切片,按条数)。 */
12
+ export declare const CURATION_SLICE_MAX_ENTRIES = 200;
13
+ /** 最多片数;超出截断并在 existingStatements 摘要里说明。 */
14
+ export declare const CURATION_MAX_SLICES = 20;
15
+ /** 传给策略的既有 statement 摘要条数上限(去重参考)。 */
16
+ export declare const CURATION_EXISTING_STATEMENTS_LIMIT = 100;
17
+ /** 既有 statement 摘要的每条截断长度(字符)。 */
18
+ export declare const CURATION_EXISTING_STATEMENT_PREFIX_CHARS = 200;
19
+ /** 单批 proposal 条数上限;超出部分丢弃并 warn。 */
20
+ export declare const CURATION_MAX_PROPOSALS = 20;
21
+ /** 单条 statement 上限(与 memory_write 内容契约同口径,UTF-16 单元)。 */
22
+ export declare const CURATION_STATEMENT_MAX_CHARS = 700;
23
+ /** 策略调用硬截止;超时按暂停处理(模型恢复后续跑)。 */
24
+ export declare const CURATION_POLICY_TIMEOUT_MS = 60000;
25
+ /**
26
+ * `session.archived@1`(宿主 lifecycle catalog)数据的结构化收窄——只取整理器
27
+ * 读的字段。订阅走 `{id, version}` 引用形式:定义归宿主 bootstrap lifecycle
28
+ * 插件所有,宿主未定义该事件时注册被结构性拒绝(D-028 插件装载失败,绝不会
29
+ * 变成会话失败)。
30
+ */
31
+ export declare const SESSION_ARCHIVED_EVENT_REFERENCE: {
32
+ readonly id: "session.archived";
33
+ readonly version: 1;
34
+ };
35
+ /** Structural narrowing of the host catalog's `SessionArchivedEventDataV1`. */
36
+ export interface MemorySessionArchivedEventDataV1 {
37
+ readonly version: 1;
38
+ readonly sessionId: string;
39
+ }
40
+ /** 策略 `propose` 输入(记忆归档与整理设计 §7.2 冻结形状)。 */
41
+ export interface CurationPolicyProposeInputV1 {
42
+ readonly op: "propose";
43
+ readonly sessionId: string;
44
+ /**
45
+ * 有界输入(§5.4):整理器逐片调用策略——每片一次 propose、每次恰好一片
46
+ * (≤ {@link CURATION_SLICE_MAX_ENTRIES} 条),保留数组形状以维持 §7.2
47
+ * 冻结契约;最多 {@link CURATION_MAX_SLICES} 片(超出截断并在
48
+ * existingStatements 附说明项)。
49
+ */
50
+ readonly slices: readonly (readonly SessionEntryView[])[];
51
+ /** 既有记忆 statement 前 200 字符列表(≤100 条,去重参考;截断时附说明项)。 */
52
+ readonly existingStatements: readonly string[];
53
+ }
54
+ /** 策略 `propose` 单条候选(原始形状,提交前由 memory 校验)。 */
55
+ export interface CurationProposalV1 {
56
+ readonly statement: string;
57
+ readonly facets?: readonly unknown[];
58
+ }
59
+ /** 策略 `propose` 结果(候选——提交与否由 memory 决定)。 */
60
+ export interface CurationPolicyProposeResultV1 {
61
+ readonly proposals: readonly CurationProposalV1[];
62
+ }
63
+ /** 校验后进入批次的候选:statement 合法,facets 已规范化。 */
64
+ export interface AcceptedCurationProposalV1 {
65
+ readonly statement: string;
66
+ readonly facets: readonly {
67
+ readonly key: string;
68
+ readonly value: string;
69
+ }[];
70
+ }
71
+ /** 单次 curateSession 的运行结论。 */
72
+ export type MemoryCurationRunResultV1 = {
73
+ readonly status: "curated";
74
+ readonly batchId: string;
75
+ /** 本次新提交的原子数。 */
76
+ readonly committed: number;
77
+ /** 同 batchId 重试时已存在而跳过的原子数。 */
78
+ readonly duplicates: number;
79
+ } | {
80
+ readonly status: "skipped";
81
+ readonly reason: "no-archive" | "policy-missing" | "already-curated" | "already-skipped";
82
+ } | {
83
+ readonly status: "paused";
84
+ readonly reason: "policy-error" | "policy-timeout" | "aborted" | "invalid-result";
85
+ };
86
+ /** journal open 行:批次的完整结果(§5.3 重试只读它,不再重新生成)。 */
87
+ export interface CurationJournalOpenEntryV1 {
88
+ readonly batchId: string;
89
+ readonly sessionId: string;
90
+ readonly at: string;
91
+ readonly status: "open";
92
+ readonly statements: readonly {
93
+ readonly statement: string;
94
+ readonly facets: readonly {
95
+ readonly key: string;
96
+ readonly value: string;
97
+ }[];
98
+ }[];
99
+ readonly digests: readonly string[];
100
+ }
101
+ /** journal committed 事实行:批次全部原子落库后的追加式收口(同 batchId 以文件末条为准)。 */
102
+ export interface CurationJournalCommittedEntryV1 {
103
+ readonly batchId: string;
104
+ readonly sessionId: string;
105
+ readonly at: string;
106
+ readonly status: "committed";
107
+ }
108
+ /** 整理批次 journal 行(冻结契约:不含会话原文;追加式,按 batchId 取末条)。 */
109
+ export type CurationJournalEntryV1 = CurationJournalOpenEntryV1 | CurationJournalCommittedEntryV1;
110
+ /** 批次凭据:batchId = sha256(sessionId + 各 statement digest 拼接)。 */
111
+ export declare function curationBatchIdOf(sessionId: string, statementDigests: readonly string[]): string;
112
+ /** 单条 statement 的 sha256 digest(journal 与 batchId 共用)。 */
113
+ export declare function curationStatementDigest(statement: string): string;
114
+ /**
115
+ * 确定性构造整理原子(记忆归档与整理设计 §5.2 冻结字段表)。不复用 buildWriteAtom——
116
+ * 那里 observationId 前缀写死 memory_write 会话序列。identityHash 由装配方
117
+ * 注入(capability.ts 的 FNV-1a,同一写入身份口径)。
118
+ */
119
+ export declare function buildCuratedAtom(input: {
120
+ readonly proposal: AcceptedCurationProposalV1;
121
+ readonly batchId: string;
122
+ readonly index: number;
123
+ readonly owner: string;
124
+ /** 提交域(当前会话的 suite 绑定解析结果):suite 域原子带 suiteId 读边界。 */
125
+ readonly domain: SuiteMemoryDomainV1;
126
+ readonly manifestId: string;
127
+ readonly now: () => number;
128
+ readonly identityHash: (value: string) => string;
129
+ }): MemoryAtomV1;
130
+ /** 整理器对 capability 闭包的显式依赖视图。 */
131
+ export interface MemoryCuratorDepsV1 {
132
+ /** capability API:logger / capabilities(策略 require)/ lifecycle / sessionAbortSignal。 */
133
+ readonly api: CapabilityAPI;
134
+ /** agent 根目录:journal 落在 `<agentDir>/archive/sessions/`。 */
135
+ readonly agentDir: string;
136
+ /** 检索行 owner(capability.BUILTIN_MEMORY_OWNER)。 */
137
+ readonly owner: string;
138
+ /** 时钟(harness now)。 */
139
+ readonly now: () => number;
140
+ /** capability 清单:profileId 与 writeReason `<manifest.id>/curation` 来源。 */
141
+ readonly manifest: {
142
+ readonly id: string;
143
+ };
144
+ /** canonical store(per-capability 单例):幂等回查 + 既有 statement 摘要来源。 */
145
+ readonly store: MemoryStoreV1;
146
+ /** 域解析(capability.resolveDomain):批次提交前解析一次,取 per-domain ledger。 */
147
+ readonly resolveDomain: () => {
148
+ readonly domain: SuiteMemoryDomainV1;
149
+ readonly domainName: string;
150
+ readonly ledger: DurableMemoryLedgerV1;
151
+ };
152
+ /** 写侧投影(slice 3a 的 vectorProjection):提交后埋点。 */
153
+ readonly vectorProjection: MemoryVectorProjectionV1;
154
+ /** 写入身份哈希(capability.ts FNV-1a,经 deps 注入避免双头定义)。 */
155
+ readonly identityHash: (value: string) => string;
156
+ /**
157
+ * 会话归档协调面(宿主服务,context/`api.host.sessionArchive` 已解析)。
158
+ * undefined = 宿主不开放归档:两个触发都不注册,记忆家族其余能力不受影响。
159
+ */
160
+ readonly sessionArchive: SessionArchiveHostV1 | undefined;
161
+ }
162
+ /** 整理器工厂产物:随 capability 注册/卸载的观察项(归档面缺席时为空)。 */
163
+ export interface MemoryCuratorV1 {
164
+ readonly registrations: readonly DisposableRegistration[];
165
+ }
166
+ /**
167
+ * 整理一个归档会话(记忆归档与整理设计 §5 批次协议):幂等状态回查 → journal
168
+ * open 批次重放(有则不调策略、不读会话,按持久化结果补齐提交并收口,§5.3.6/
169
+ * §5.3.7)→ 策略 require → 有界分页读 → 逐片策略 propose(每片一次调用;任一
170
+ * 片失败/超时/中止/非法结果即整批暂停,§5.4)→ 合并候选 → journal open 行落盘
171
+ * → 逐条幂等提交 → journal committed 收口 → 回写 curated。任何暂停/失败路径都
172
+ * 不写 curated、不留部分提交。
173
+ */
174
+ export declare function curateSession(deps: MemoryCuratorDepsV1, sessionId: string): Promise<MemoryCurationRunResultV1>;
175
+ /**
176
+ * 装配归档整理器(记忆归档与整理设计 §5-§7):
177
+ * - 启动 sweep:`sessionArchive.listArchived()` 找 curation 缺失的会话逐个整理;
178
+ * - `session.archived@1` 事件观察:归档即后台整理(handler 同步返回,整理在
179
+ * 后台跑,不阻塞事件投递)。
180
+ * 同一会话的整理经每会话一条 promise 链串行(sweep 与事件重投并发时天然去重)。
181
+ * 归档面缺席(testkit/老宿主)时两个触发都不注册,返回空注册列表。
182
+ */
183
+ export declare function createMemoryCurator(deps: MemoryCuratorDepsV1): MemoryCuratorV1;
184
+ //# sourceMappingURL=curator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"curator.d.ts","sourceRoot":"","sources":["../../src/memory/curator.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * 归档会话整理器(记忆归档与整理设计 §5-§7,2026-10-22 裁决落地):\n * 归档即后台整理。memory 插件负责调度、切片预算、批次协议、幂等提交与\n * 生命周期;\"从会话里提炼什么\"由经 `memory.curation-policy@1` 能力目录\n * require 到的整理策略插件回答(第一方默认策略是 plugins/memory-curation,\n * 与第三方策略走同一公共契约,本模块对两者无差别)。\n *\n * 与来源切割(§6 用户裁决):整理产物是独立原子——不带 sessionRefs、不带指向\n * 会话条目的 sourceRefs、不写 provenance;删除会话不触碰记忆原子。操作凭据\n * 留在本侧 journal(`<agentDir>/archive/sessions/curation-journal.jsonl`,\n * batchId + 内容 digest,不含会话原文)。\n *\n * 批次协议(§5.3.6/§5.3.7):journal 是批次的可恢复事实来源——追加式 JSONL,\n * 行带 status:\"open\" 行先落盘(批次完整结果),全部原子提交完成后追加\n * \"committed\" 事实行,同 batchId 以文件末条为准。curateSession 开始时先查\n * 该会话的 open 批次:存在则不调策略、不读会话,直接按持久化的 statements\n * 以相同确定性 observationId 重放提交(已提交条目去重跳过,剩余补齐),收口\n * 后照常 reportCuration——旧批次未处理时不开始新批次,两批各自不完整的原子\n * 不可能并存;重放发现批次实际早已全部提交(全部幂等跳过)也走完收口。\n * 旧版无 status 字段的行等价 open(旧版在提交前一刻落盘,语义相同)。\n *\n * 暂停/续跑(§5.4 用户裁决):策略抛错、超时(60s 上限)或会话中止信号触发时\n * 返回 paused——不写 curated、不落 journal、不留部分提交;curation 维度保持\n * 缺失,归档事件重投或启动 sweep 会自然续跑。已提交条目经确定性 memoryId\n * (owner + `curation:<batchId>:<index>`)在 store 回查去重,同 batchId 重试\n * 不会产生重复原子。\n */\nimport { createHash } from \"node:crypto\";\nimport { appendFile, mkdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type {\n\tCapabilityAPI,\n\tCapabilityHandle,\n\tDisposableRegistration,\n\tOperationHandle,\n\tSessionArchiveHostV1,\n\tSessionEntryView,\n} from \"@agent-forge/plugin-sdk\";\nimport { buildMemoryAtomV1, type MemoryAtomV1 } from \"./foundation.ts\";\nimport type { DurableMemoryLedgerV1 } from \"./ledger.ts\";\nimport type { MemoryStoreV1 } from \"./store.ts\";\nimport type { SuiteMemoryDomainV1 } from \"./suite-memory.ts\";\nimport { MEMORY_CONTRACT_VERSION_V2 } from \"./transfer.ts\";\nimport type { MemoryVectorProjectionV1 } from \"./vector-projection.ts\";\n\n/** 整理策略能力 id(记忆归档与整理设计 §7.2 冻结契约)。 */\nexport const MEMORY_CURATION_POLICY_CAPABILITY_ID = \"memory.curation-policy\";\n/** 整理策略能力版本(exact version matching)。 */\nexport const MEMORY_CURATION_POLICY_VERSION = 1;\n\n/** 每片最大条目数(有界切片,按条数)。 */\nexport const CURATION_SLICE_MAX_ENTRIES = 200;\n/** 最多片数;超出截断并在 existingStatements 摘要里说明。 */\nexport const CURATION_MAX_SLICES = 20;\n/** 传给策略的既有 statement 摘要条数上限(去重参考)。 */\nexport const CURATION_EXISTING_STATEMENTS_LIMIT = 100;\n/** 既有 statement 摘要的每条截断长度(字符)。 */\nexport const CURATION_EXISTING_STATEMENT_PREFIX_CHARS = 200;\n/** 单批 proposal 条数上限;超出部分丢弃并 warn。 */\nexport const CURATION_MAX_PROPOSALS = 20;\n/** 单条 statement 上限(与 memory_write 内容契约同口径,UTF-16 单元)。 */\nexport const CURATION_STATEMENT_MAX_CHARS = 700;\n/** 策略调用硬截止;超时按暂停处理(模型恢复后续跑)。 */\nexport const CURATION_POLICY_TIMEOUT_MS = 60_000;\n/** 整理产物 facets 的 capability 命名空间(与 tag facet 同域 \"builtin.memory\")。 */\nconst CURATION_FACET_NAMESPACE = \"builtin.memory\";\n/** 整理产物保留档(first-party retention registry \"long\",随记忆自身周期朝生暮死)。 */\nconst CURATION_RETENTION_MODE_ID = \"long\";\n/** 整理批次 journal 路径(相对 agentDir;只含 batchId/digest/结果,无会话原文)。 */\nconst CURATION_JOURNAL_RELATIVE_PATH = join(\"archive\", \"sessions\", \"curation-journal.jsonl\");\n\n/**\n * `session.archived@1`(宿主 lifecycle catalog)数据的结构化收窄——只取整理器\n * 读的字段。订阅走 `{id, version}` 引用形式:定义归宿主 bootstrap lifecycle\n * 插件所有,宿主未定义该事件时注册被结构性拒绝(D-028 插件装载失败,绝不会\n * 变成会话失败)。\n */\nexport const SESSION_ARCHIVED_EVENT_REFERENCE = { id: \"session.archived\", version: 1 } as const;\n\n/** Structural narrowing of the host catalog's `SessionArchivedEventDataV1`. */\nexport interface MemorySessionArchivedEventDataV1 {\n\treadonly version: 1;\n\treadonly sessionId: string;\n}\n\n/** 策略 `propose` 输入(记忆归档与整理设计 §7.2 冻结形状)。 */\nexport interface CurationPolicyProposeInputV1 {\n\treadonly op: \"propose\";\n\treadonly sessionId: string;\n\t/**\n\t * 有界输入(§5.4):整理器逐片调用策略——每片一次 propose、每次恰好一片\n\t * (≤ {@link CURATION_SLICE_MAX_ENTRIES} 条),保留数组形状以维持 §7.2\n\t * 冻结契约;最多 {@link CURATION_MAX_SLICES} 片(超出截断并在\n\t * existingStatements 附说明项)。\n\t */\n\treadonly slices: readonly (readonly SessionEntryView[])[];\n\t/** 既有记忆 statement 前 200 字符列表(≤100 条,去重参考;截断时附说明项)。 */\n\treadonly existingStatements: readonly string[];\n}\n\n/** 策略 `propose` 单条候选(原始形状,提交前由 memory 校验)。 */\nexport interface CurationProposalV1 {\n\treadonly statement: string;\n\treadonly facets?: readonly unknown[];\n}\n\n/** 策略 `propose` 结果(候选——提交与否由 memory 决定)。 */\nexport interface CurationPolicyProposeResultV1 {\n\treadonly proposals: readonly CurationProposalV1[];\n}\n\n/** 校验后进入批次的候选:statement 合法,facets 已规范化。 */\nexport interface AcceptedCurationProposalV1 {\n\treadonly statement: string;\n\treadonly facets: readonly { readonly key: string; readonly value: string }[];\n}\n\n/** 单次 curateSession 的运行结论。 */\nexport type MemoryCurationRunResultV1 =\n\t| {\n\t\t\treadonly status: \"curated\";\n\t\t\treadonly batchId: string;\n\t\t\t/** 本次新提交的原子数。 */\n\t\t\treadonly committed: number;\n\t\t\t/** 同 batchId 重试时已存在而跳过的原子数。 */\n\t\t\treadonly duplicates: number;\n\t }\n\t| {\n\t\t\treadonly status: \"skipped\";\n\t\t\treadonly reason: \"no-archive\" | \"policy-missing\" | \"already-curated\" | \"already-skipped\";\n\t }\n\t| {\n\t\t\treadonly status: \"paused\";\n\t\t\treadonly reason: \"policy-error\" | \"policy-timeout\" | \"aborted\" | \"invalid-result\";\n\t };\n\n/** journal open 行:批次的完整结果(§5.3 重试只读它,不再重新生成)。 */\nexport interface CurationJournalOpenEntryV1 {\n\treadonly batchId: string;\n\treadonly sessionId: string;\n\treadonly at: string;\n\treadonly status: \"open\";\n\treadonly statements: readonly {\n\t\treadonly statement: string;\n\t\treadonly facets: readonly { readonly key: string; readonly value: string }[];\n\t}[];\n\treadonly digests: readonly string[];\n}\n\n/** journal committed 事实行:批次全部原子落库后的追加式收口(同 batchId 以文件末条为准)。 */\nexport interface CurationJournalCommittedEntryV1 {\n\treadonly batchId: string;\n\treadonly sessionId: string;\n\treadonly at: string;\n\treadonly status: \"committed\";\n}\n\n/** 整理批次 journal 行(冻结契约:不含会话原文;追加式,按 batchId 取末条)。 */\nexport type CurationJournalEntryV1 = CurationJournalOpenEntryV1 | CurationJournalCommittedEntryV1;\n\n/** 批次凭据:batchId = sha256(sessionId + 各 statement digest 拼接)。 */\nexport function curationBatchIdOf(sessionId: string, statementDigests: readonly string[]): string {\n\tconst hash = createHash(\"sha256\");\n\thash.update(sessionId);\n\tfor (const digest of statementDigests) hash.update(digest);\n\treturn hash.digest(\"hex\");\n}\n\n/** 单条 statement 的 sha256 digest(journal 与 batchId 共用)。 */\nexport function curationStatementDigest(statement: string): string {\n\treturn createHash(\"sha256\").update(statement, \"utf8\").digest(\"hex\");\n}\n\n/**\n * open 行形状校验(journal 由本模块写出,重放前仍校验——防崩溃残行与外手改写\n * 产生非法原子)。旧版行无 status 字段:形状同 open,等价 open 处理。\n */\nfunction isOpenEntryShape(value: Record<string, unknown>): boolean {\n\tif (value.status !== \"open\" && value.status !== undefined) return false;\n\tif (!Array.isArray(value.statements) || !Array.isArray(value.digests)) return false;\n\treturn value.statements.every(\n\t\t(item) =>\n\t\t\tisPlainRecord(item) &&\n\t\t\ttypeof item.statement === \"string\" &&\n\t\t\titem.statement !== \"\" &&\n\t\t\tArray.isArray(item.facets) &&\n\t\t\titem.facets.every(\n\t\t\t\t(facet) => isPlainRecord(facet) && typeof facet.key === \"string\" && typeof facet.value === \"string\",\n\t\t\t),\n\t);\n}\n\n/**\n * 读取该会话的未完成批次(§5.3.6 崩溃重试入口,§5.3.7 新批次守卫的依据):\n * journal 是追加式事实流,同 batchId 以文件末条为准;末条仍为 open 即未完成。\n * 多个 open 批次并存时(仅可能来自协议启用前的旧文件)取文件序最后一条。\n * 文件不存在返回 undefined;JSON 解析失败的残行告警跳过(只可能是崩溃中追加\n * 的末行,不影响更早的完整行);不可重放的 open 行属于事实来源损坏,向上抛错\n * ——按 §5.3.7 拒绝开始新批次,而不是在坏批次之上再开一批。\n */\nasync function readOpenCurationBatch(\n\tjournalPath: string,\n\tsessionId: string,\n\tlogger: CapabilityAPI[\"logger\"],\n): Promise<CurationJournalOpenEntryV1 | undefined> {\n\tlet text: string;\n\ttry {\n\t\ttext = await readFile(journalPath, \"utf8\");\n\t} catch (error) {\n\t\tif ((error as NodeJS.ErrnoException).code === \"ENOENT\") return undefined;\n\t\tthrow error;\n\t}\n\tinterface JournalLineRecord {\n\t\treadonly line: number;\n\t\treadonly closed: boolean;\n\t\treadonly open: CurationJournalOpenEntryV1 | undefined;\n\t}\n\tconst lastLineByBatch = new Map<string, JournalLineRecord>();\n\tfor (const [line, raw] of text.split(\"\\n\").entries()) {\n\t\tif (raw.trim() === \"\") continue;\n\t\tlet parsed: unknown;\n\t\ttry {\n\t\t\tparsed = JSON.parse(raw);\n\t\t} catch {\n\t\t\tlogger?.warn(`memory curation journal line ${line + 1} is not valid JSON; skipped`);\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isPlainRecord(parsed) || parsed.sessionId !== sessionId) continue;\n\t\tconst batchId = parsed.batchId;\n\t\tif (typeof batchId !== \"string\" || batchId === \"\") continue;\n\t\tif (parsed.status === \"committed\") {\n\t\t\tlastLineByBatch.set(batchId, { line, closed: true, open: undefined });\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isOpenEntryShape(parsed)) {\n\t\t\tlogger?.warn(`memory curation journal line ${line + 1} has an unrecognized shape; skipped`);\n\t\t\tcontinue;\n\t\t}\n\t\tlastLineByBatch.set(batchId, { line, closed: false, open: parsed as unknown as CurationJournalOpenEntryV1 });\n\t}\n\tlet latest: JournalLineRecord | undefined;\n\tfor (const record of lastLineByBatch.values()) {\n\t\tif (record.closed || record.open === undefined) continue;\n\t\tif (latest === undefined || record.line > latest.line) latest = record;\n\t}\n\treturn latest?.open;\n}\n\n/** 追加 committed 事实行(open 行落盘时目录已创建,此处无需 mkdir)。 */\nasync function appendCommittedJournalLine(\n\tjournalPath: string,\n\tbatchId: string,\n\tsessionId: string,\n\tnow: () => number,\n): Promise<void> {\n\tconst entry: CurationJournalCommittedEntryV1 = {\n\t\tbatchId,\n\t\tsessionId,\n\t\tat: new Date(now()).toISOString(),\n\t\tstatus: \"committed\",\n\t};\n\tawait appendFile(journalPath, `${JSON.stringify(entry)}\\n`, \"utf8\");\n}\n\n/**\n * 确定性构造整理原子(记忆归档与整理设计 §5.2 冻结字段表)。不复用 buildWriteAtom——\n * 那里 observationId 前缀写死 memory_write 会话序列。identityHash 由装配方\n * 注入(capability.ts 的 FNV-1a,同一写入身份口径)。\n */\nexport function buildCuratedAtom(input: {\n\treadonly proposal: AcceptedCurationProposalV1;\n\treadonly batchId: string;\n\treadonly index: number;\n\treadonly owner: string;\n\t/** 提交域(当前会话的 suite 绑定解析结果):suite 域原子带 suiteId 读边界。 */\n\treadonly domain: SuiteMemoryDomainV1;\n\treadonly manifestId: string;\n\treadonly now: () => number;\n\treadonly identityHash: (value: string) => string;\n}): MemoryAtomV1 {\n\tconst observationId = `curation:${input.batchId}:${input.index}`;\n\tconst memoryId = `mem-${input.identityHash(`${input.owner}\\u0000${observationId}`)}`;\n\tconst occurredAt = new Date(input.now()).toISOString();\n\treturn buildMemoryAtomV1({\n\t\tmemoryId,\n\t\tcontractVersion: MEMORY_CONTRACT_VERSION_V2,\n\t\tschemaVersion: 1,\n\t\tscope: \"long-term\",\n\t\tretentionMode: CURATION_RETENTION_MODE_ID,\n\t\towner: input.owner,\n\t\tprofileId: input.manifestId,\n\t\t...(input.domain.kind === \"suite\" ? { suiteId: input.domain.suiteId } : {}),\n\t\tretentionPolicyVersion: \"retention@1\",\n\t\tmemoryKind: \"synthesis\",\n\t\tpayload: { statement: input.proposal.statement },\n\t\toccurredAt,\n\t\trecordedAt: occurredAt,\n\t\t// 记忆与来源会话彻底切割(§6):无来源引用、无会话引用、无 provenance。\n\t\tsourceRefs: [],\n\t\tobservationId,\n\t\tsessionRefs: [],\n\t\tagentInstanceRefs: [],\n\t\tprojectRefs: [],\n\t\tsubjectRefs: [],\n\t\tfacets: input.proposal.facets.map((facet) => ({\n\t\t\tnamespace: CURATION_FACET_NAMESPACE,\n\t\t\tschemaVersion: 1,\n\t\t\tkey: facet.key,\n\t\t\tvalue: facet.value,\n\t\t})),\n\t\trelations: [],\n\t\t// 模型归纳内容(§5.2 evidenceClass derived):保守置信与推断写入同档 0.6。\n\t\tconfidence: 0.6,\n\t\timportance: 0.5,\n\t\tevidenceClass: \"derived\",\n\t\tcontentRevision: `c-${input.identityHash(input.proposal.statement)}`,\n\t\twriteReason: `${input.manifestId}/curation`,\n\t});\n}\n\n/**\n * 逐条提交批次原子(顺序照 write-face 工具路径:先账本后可见,投影埋点收尾)。\n * 幂等判定同时看 store 与账本快照(§5.3 崩溃重试语义的提交侧,新批次与 journal\n * 重放共用):提交循环可能在\"账本已 append、store 未 commit\"的窗口被打断——\n * 账本是持久事实,重放对该窗口内的原子只补齐 store 可见性与投影,不再 append\n * 重复账本行;两侧都在的条目跳过,都缺的整条提交。调用方负责 journal 状态收口\n * 与 reportCuration。\n */\nfunction commitBatchAtoms(\n\tdeps: MemoryCuratorDepsV1,\n\taccepted: readonly AcceptedCurationProposalV1[],\n\tbatchId: string,\n): { committed: number; duplicates: number } {\n\tconst { domain, ledger } = deps.resolveDomain();\n\tconst ledgeredMemoryIds = new Set(ledger.atomsSnapshot().map((atom) => atom.memoryId));\n\tlet committed = 0;\n\tlet duplicates = 0;\n\tfor (const [index, proposal] of accepted.entries()) {\n\t\tconst atom = buildCuratedAtom({\n\t\t\tproposal,\n\t\t\tbatchId,\n\t\t\tindex,\n\t\t\towner: deps.owner,\n\t\t\tdomain,\n\t\t\tmanifestId: deps.manifest.id,\n\t\t\tnow: deps.now,\n\t\t\tidentityHash: deps.identityHash,\n\t\t});\n\t\tconst ledgered = ledgeredMemoryIds.has(atom.memoryId);\n\t\tif (ledgered && deps.store.get(atom.memoryId, { owner: deps.owner }) !== undefined) {\n\t\t\tduplicates += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!ledgered) ledger.append(atom);\n\t\tdeps.store.commit(atom);\n\t\tdeps.vectorProjection.upsertAtom(atom);\n\t\tcommitted += 1;\n\t}\n\treturn { committed, duplicates };\n}\n\n/** 整理器对 capability 闭包的显式依赖视图。 */\nexport interface MemoryCuratorDepsV1 {\n\t/** capability API:logger / capabilities(策略 require)/ lifecycle / sessionAbortSignal。 */\n\treadonly api: CapabilityAPI;\n\t/** agent 根目录:journal 落在 `<agentDir>/archive/sessions/`。 */\n\treadonly agentDir: string;\n\t/** 检索行 owner(capability.BUILTIN_MEMORY_OWNER)。 */\n\treadonly owner: string;\n\t/** 时钟(harness now)。 */\n\treadonly now: () => number;\n\t/** capability 清单:profileId 与 writeReason `<manifest.id>/curation` 来源。 */\n\treadonly manifest: { readonly id: string };\n\t/** canonical store(per-capability 单例):幂等回查 + 既有 statement 摘要来源。 */\n\treadonly store: MemoryStoreV1;\n\t/** 域解析(capability.resolveDomain):批次提交前解析一次,取 per-domain ledger。 */\n\treadonly resolveDomain: () => {\n\t\treadonly domain: SuiteMemoryDomainV1;\n\t\treadonly domainName: string;\n\t\treadonly ledger: DurableMemoryLedgerV1;\n\t};\n\t/** 写侧投影(slice 3a 的 vectorProjection):提交后埋点。 */\n\treadonly vectorProjection: MemoryVectorProjectionV1;\n\t/** 写入身份哈希(capability.ts FNV-1a,经 deps 注入避免双头定义)。 */\n\treadonly identityHash: (value: string) => string;\n\t/**\n\t * 会话归档协调面(宿主服务,context/`api.host.sessionArchive` 已解析)。\n\t * undefined = 宿主不开放归档:两个触发都不注册,记忆家族其余能力不受影响。\n\t */\n\treadonly sessionArchive: SessionArchiveHostV1 | undefined;\n}\n\n/** 整理器工厂产物:随 capability 注册/卸载的观察项(归档面缺席时为空)。 */\nexport interface MemoryCuratorV1 {\n\treadonly registrations: readonly DisposableRegistration[];\n}\n\n/** payload `{ statement }` 约定的读取投影(与 capability.statementOf 同构)。 */\nfunction statementTextOf(payload: unknown): string {\n\tif (payload !== null && typeof payload === \"object\" && !Array.isArray(payload)) {\n\t\tconst statement = (payload as { statement?: unknown }).statement;\n\t\tif (typeof statement === \"string\") return statement;\n\t}\n\treturn JSON.stringify(payload);\n}\n\nconst boundedErrorText = (error: unknown): string => {\n\tconst message = error instanceof Error ? error.message : String(error);\n\tconst codePoints = Array.from(message);\n\treturn codePoints.length <= 200 ? message : `${codePoints.slice(0, 200).join(\"\")}…`;\n};\n\nconst isPlainRecord = (value: unknown): value is Record<string, unknown> =>\n\ttypeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/**\n * proposals 校验(提交闸门在 memory 侧,记忆归档与整理设计 §7.2):statement 非空且\n * ≤700 字符、条数 ≤20(超出丢弃并 warn)、facets 形状非法整条丢弃。facets 内\n * 单项 key/value 非空字符串校验,非法项丢弃该 facet(不连坐整条)。结果整体\n * 非 { proposals: [...] } 形状 = 策略契约失败,返回 undefined 交由调用方暂停。\n */\nfunction validateProposals(\n\traw: unknown,\n\tlogger: CapabilityAPI[\"logger\"],\n): { readonly accepted: readonly AcceptedCurationProposalV1[]; readonly dropped: number } | undefined {\n\tif (!isPlainRecord(raw) || !Array.isArray(raw.proposals)) return undefined;\n\tconst accepted: AcceptedCurationProposalV1[] = [];\n\tlet dropped = 0;\n\tfor (const [index, item] of raw.proposals.entries()) {\n\t\tif (accepted.length >= CURATION_MAX_PROPOSALS) {\n\t\t\tdropped += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (!isPlainRecord(item) || typeof item.statement !== \"string\") {\n\t\t\tlogger?.warn(`memory curation dropped proposal[${index}]: statement must be a string`);\n\t\t\tdropped += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst statement = item.statement;\n\t\tif (statement.trim() === \"\") {\n\t\t\tlogger?.warn(`memory curation dropped proposal[${index}]: statement is empty`);\n\t\t\tdropped += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (statement.length > CURATION_STATEMENT_MAX_CHARS) {\n\t\t\tlogger?.warn(\n\t\t\t\t`memory curation dropped proposal[${index}]: statement is ${statement.length} characters (limit ${CURATION_STATEMENT_MAX_CHARS})`,\n\t\t\t);\n\t\t\tdropped += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tif (item.facets !== undefined && !Array.isArray(item.facets)) {\n\t\t\tlogger?.warn(`memory curation dropped proposal[${index}]: facets must be an array when present`);\n\t\t\tdropped += 1;\n\t\t\tcontinue;\n\t\t}\n\t\tconst facets: { key: string; value: string }[] = [];\n\t\tfor (const [facetIndex, rawFacet] of (item.facets ?? []).entries()) {\n\t\t\tif (\n\t\t\t\t!isPlainRecord(rawFacet) ||\n\t\t\t\ttypeof rawFacet.key !== \"string\" ||\n\t\t\t\trawFacet.key.trim() === \"\" ||\n\t\t\t\ttypeof rawFacet.value !== \"string\" ||\n\t\t\t\trawFacet.value.trim() === \"\"\n\t\t\t) {\n\t\t\t\tlogger?.warn(\n\t\t\t\t\t`memory curation dropped proposal[${index}] facet[${facetIndex}]: key/value must be non-empty strings`,\n\t\t\t\t);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tfacets.push({ key: rawFacet.key, value: rawFacet.value });\n\t\t}\n\t\taccepted.push({ statement, facets });\n\t}\n\tif (dropped > 0) {\n\t\tlogger?.warn(`memory curation dropped ${dropped} invalid proposal(s) before committing the batch`);\n\t}\n\treturn { accepted, dropped };\n}\n\n/**\n * 策略调用竞速:`handle.result` vs 60s 硬截止 vs 会话中止信号。三个败因都收敛\n * 为 paused 的 reason(模型不可用/挂起 → 暂停续跑语义,§5.4 用户裁决)。\n */\nasync function awaitPolicyResult(\n\thandle: OperationHandle<unknown>,\n\tsignal: AbortSignal | undefined,\n): Promise<\n\t{ ok: true; value: unknown } | { ok: false; reason: \"policy-timeout\" | \"aborted\" | \"policy-error\"; error: unknown }\n> {\n\tlet timer: NodeJS.Timeout | undefined;\n\t// 中止信号 → 立即拒绝的竞速臂;dispose 摘除监听,竞速已定时不再持有信号。\n\tlet abortArm: { readonly promise: Promise<never>; readonly dispose: () => void } | undefined;\n\tif (signal !== undefined) {\n\t\tabortArm = (() => {\n\t\t\tlet rejectFn: ((reason: Error) => void) | undefined;\n\t\t\tconst onAbort = () => rejectFn?.(new Error(\"memory curation aborted: session abort signal fired\"));\n\t\t\tconst promise = new Promise<never>((_, reject) => {\n\t\t\t\trejectFn = reject;\n\t\t\t\tif (signal.aborted) reject(new Error(\"memory curation aborted: session abort signal fired\"));\n\t\t\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t});\n\t\t\treturn { promise, dispose: () => signal.removeEventListener(\"abort\", onAbort) };\n\t\t})();\n\t}\n\ttry {\n\t\tconst value = await Promise.race([\n\t\t\thandle.result,\n\t\t\tnew Promise<never>((_, reject) => {\n\t\t\t\ttimer = setTimeout(\n\t\t\t\t\t() => reject(new Error(`memory curation policy did not settle within ${CURATION_POLICY_TIMEOUT_MS}ms`)),\n\t\t\t\t\tCURATION_POLICY_TIMEOUT_MS,\n\t\t\t\t);\n\t\t\t\ttimer.unref?.();\n\t\t\t}),\n\t\t\t...(abortArm === undefined ? [] : [abortArm.promise]),\n\t\t]);\n\t\treturn { ok: true, value };\n\t} catch (error) {\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\tif (message.includes(\"did not settle within\")) return { ok: false, reason: \"policy-timeout\", error };\n\t\tif (message.includes(\"abort signal fired\")) return { ok: false, reason: \"aborted\", error };\n\t\treturn { ok: false, reason: \"policy-error\", error };\n\t} finally {\n\t\tif (timer !== undefined) clearTimeout(timer);\n\t\tabortArm?.dispose();\n\t}\n}\n\n/**\n * 整理一个归档会话(记忆归档与整理设计 §5 批次协议):幂等状态回查 → journal\n * open 批次重放(有则不调策略、不读会话,按持久化结果补齐提交并收口,§5.3.6/\n * §5.3.7)→ 策略 require → 有界分页读 → 逐片策略 propose(每片一次调用;任一\n * 片失败/超时/中止/非法结果即整批暂停,§5.4)→ 合并候选 → journal open 行落盘\n * → 逐条幂等提交 → journal committed 收口 → 回写 curated。任何暂停/失败路径都\n * 不写 curated、不留部分提交。\n */\nexport async function curateSession(deps: MemoryCuratorDepsV1, sessionId: string): Promise<MemoryCurationRunResultV1> {\n\tconst { api, sessionArchive, store, owner } = deps;\n\tconst logger = api.logger;\n\tif (sessionArchive === undefined) {\n\t\t// 无归档面则 reportCuration 不可能:本地记录后直接返回。\n\t\tlogger?.warn(`memory curation skipped for session ${sessionId}: host exposes no session-archive face`);\n\t\treturn { status: \"skipped\", reason: \"no-archive\" };\n\t}\n\t// 幂等:该会话已有整理结论时不再跑批(重试链路与事件重投的自然短路)。\n\tconst existingStatus = await sessionArchive.curationStatus(sessionId);\n\tif (existingStatus === \"curated\") return { status: \"skipped\", reason: \"already-curated\" };\n\tif (existingStatus === \"skipped\") return { status: \"skipped\", reason: \"already-skipped\" };\n\n\tconst journalPath = join(deps.agentDir, CURATION_JOURNAL_RELATIVE_PATH);\n\t// 批次协议(§5.3.6/§5.3.7):open 批次是唯一事实来源——不调策略、不读会话,\n\t// 直接按持久化的 statements 以相同确定性 observationId 重放提交(已提交条目\n\t// 去重跳过,剩余补齐),全部落库后收口 committed 并 reportCuration。\"旧批次\n\t// 未处理时拒绝开始新批次\"由此自然成立:open 批次永远优先重放,两批各自不\n\t// 完整的原子不可能并存;全部幂等跳过(实际早已提交完)也走完收口。重放不\n\t// 依赖策略能力——journal 不依赖策略,策略缺席不阻塞恢复。\n\tconst openBatch = await readOpenCurationBatch(journalPath, sessionId, logger);\n\tif (openBatch !== undefined) {\n\t\tconst accepted: AcceptedCurationProposalV1[] = openBatch.statements.map((item) => ({\n\t\t\tstatement: item.statement,\n\t\t\tfacets: item.facets.map((facet) => ({ key: facet.key, value: facet.value })),\n\t\t}));\n\t\tconst { committed, duplicates } = commitBatchAtoms(deps, accepted, openBatch.batchId);\n\t\tawait appendCommittedJournalLine(journalPath, openBatch.batchId, sessionId, deps.now);\n\t\tlogger?.info(\n\t\t\t`memory curation replayed open batch ${openBatch.batchId} for session ${sessionId}: ${committed} committed, ${duplicates} already present`,\n\t\t);\n\t\tawait sessionArchive.reportCuration(sessionId, \"curated\", { batchId: openBatch.batchId });\n\t\treturn { status: \"curated\", batchId: openBatch.batchId, committed, duplicates };\n\t}\n\n\t// 策略 require(optional 消费模式,coding-tools requireCoordination 先例):\n\t// 未装策略 = 整理不可用,会话按 skipped 回写(宿主确认框须明示未经整理)。\n\tlet policyHandle: CapabilityHandle<unknown>;\n\ttry {\n\t\tpolicyHandle = api.capabilities.require(MEMORY_CURATION_POLICY_CAPABILITY_ID, {\n\t\t\tversion: MEMORY_CURATION_POLICY_VERSION,\n\t\t});\n\t} catch {\n\t\tawait sessionArchive.reportCuration(sessionId, \"skipped\");\n\t\treturn { status: \"skipped\", reason: \"policy-missing\" };\n\t}\n\n\t// 有界分页读(整理器读归档会话的唯一公共路径):每片 ≤200 条,最多 20 片,\n\t// 超出截断并在 existingStatements 摘要里说明。\n\tconst slices: (readonly SessionEntryView[])[] = [];\n\tlet offset: number | undefined;\n\tfor (let slice = 0; slice < CURATION_MAX_SLICES; slice += 1) {\n\t\tconst chunk = await sessionArchive.readEntries(sessionId, {\n\t\t\toffset,\n\t\t\tlimit: CURATION_SLICE_MAX_ENTRIES,\n\t\t});\n\t\tif (chunk.entries.length > 0) slices.push(chunk.entries);\n\t\toffset = chunk.nextOffset;\n\t\tif (offset === undefined) break;\n\t}\n\tconst truncated = offset !== undefined;\n\n\t// 既有 statement 摘要(当前 store 实例内,owner 边界;≤100 条,前 200 字符)。\n\tconst existingSet = new Set<string>();\n\tfor (const record of store.list({ owner })) {\n\t\tif (existingSet.size >= CURATION_EXISTING_STATEMENTS_LIMIT) break;\n\t\texistingSet.add(statementTextOf(record.atom.payload).slice(0, CURATION_EXISTING_STATEMENT_PREFIX_CHARS));\n\t}\n\tconst existingStatements = [...existingSet];\n\tif (truncated) {\n\t\texistingStatements.push(\n\t\t\t`[session input truncated after ${CURATION_MAX_SLICES} slices (${CURATION_MAX_SLICES * CURATION_SLICE_MAX_ENTRIES} entries); entries beyond this bound were not read]`,\n\t\t);\n\t}\n\n\t// 策略调用(逐片,§5.4 单次模型调用输入有界):每片一次 propose、顺序执行;\n\t// 任一片失败/超时/中止 → 整批暂停(不写 curated、不留部分提交;curation 维度\n\t// 保持缺失,重投或 sweep 自然续跑)。call 本身同步抛错(宿主分派失败/handler\n\t// 同步 throw)与 result 的 rejection 同语义。\n\tconst accepted: AcceptedCurationProposalV1[] = [];\n\tfor (const [sliceIndex, slice] of slices.entries()) {\n\t\tlet callOutcome:\n\t\t\t| { ok: true; value: unknown }\n\t\t\t| { ok: false; reason: \"policy-timeout\" | \"aborted\" | \"policy-error\"; error: unknown };\n\t\ttry {\n\t\t\tcallOutcome = await awaitPolicyResult(\n\t\t\t\tpolicyHandle.call({\n\t\t\t\t\top: \"propose\",\n\t\t\t\t\tsessionId,\n\t\t\t\t\tslices: [slice],\n\t\t\t\t\texistingStatements,\n\t\t\t\t} satisfies CurationPolicyProposeInputV1),\n\t\t\t\tapi.sessionAbortSignal?.(),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tcallOutcome = { ok: false, reason: \"policy-error\", error };\n\t\t}\n\t\tif (!callOutcome.ok) {\n\t\t\tlogger?.warn(\n\t\t\t\t`memory curation paused for session ${sessionId} (${callOutcome.reason}) at slice ${sliceIndex + 1}/${slices.length}: ${boundedErrorText(callOutcome.error)}`,\n\t\t\t);\n\t\t\treturn { status: \"paused\", reason: callOutcome.reason };\n\t\t}\n\t\tconst validated = validateProposals(callOutcome.value, logger);\n\t\tif (validated === undefined) {\n\t\t\tlogger?.warn(\n\t\t\t\t`memory curation paused for session ${sessionId}: policy returned a malformed propose result at slice ${sliceIndex + 1}/${slices.length}`,\n\t\t\t);\n\t\t\treturn { status: \"paused\", reason: \"invalid-result\" };\n\t\t}\n\t\taccepted.push(...validated.accepted);\n\t}\n\t// 批次条数上限(§7.2 提交闸门)跨片生效:单批上限不变,超出部分丢弃并 warn。\n\tif (accepted.length > CURATION_MAX_PROPOSALS) {\n\t\tconst dropped = accepted.length - CURATION_MAX_PROPOSALS;\n\t\taccepted.splice(CURATION_MAX_PROPOSALS);\n\t\tlogger?.warn(\n\t\t\t`memory curation dropped ${dropped} proposal(s) beyond the batch limit of ${CURATION_MAX_PROPOSALS}`,\n\t\t);\n\t}\n\n\t// 批次凭据:batchId = sha256(sessionId + 各 statement digest 拼接);完整结果\n\t// 先落 journal(可恢复的事实来源,不含会话原文),再逐条提交。\n\tconst digests = accepted.map((proposal) => curationStatementDigest(proposal.statement));\n\tconst batchId = curationBatchIdOf(sessionId, digests);\n\tconst journalEntry: CurationJournalOpenEntryV1 = {\n\t\tbatchId,\n\t\tsessionId,\n\t\tat: new Date(deps.now()).toISOString(),\n\t\tstatus: \"open\",\n\t\tstatements: accepted.map((proposal) => ({ statement: proposal.statement, facets: proposal.facets })),\n\t\tdigests,\n\t};\n\tawait mkdir(join(deps.agentDir, \"archive\", \"sessions\"), { recursive: true });\n\tawait appendFile(journalPath, `${JSON.stringify(journalEntry)}\\n`, \"utf8\");\n\n\t// 逐条提交(§5.3 崩溃重试语义的提交侧),完成后追加 committed 事实行收口,\n\t// 再回写 curated——重试读到 committed 即不再重放该批次。\n\tconst { committed, duplicates } = commitBatchAtoms(deps, accepted, batchId);\n\tawait appendCommittedJournalLine(journalPath, batchId, sessionId, deps.now);\n\tawait sessionArchive.reportCuration(sessionId, \"curated\", { batchId });\n\treturn { status: \"curated\", batchId, committed, duplicates };\n}\n\n/**\n * 装配归档整理器(记忆归档与整理设计 §5-§7):\n * - 启动 sweep:`sessionArchive.listArchived()` 找 curation 缺失的会话逐个整理;\n * - `session.archived@1` 事件观察:归档即后台整理(handler 同步返回,整理在\n * 后台跑,不阻塞事件投递)。\n * 同一会话的整理经每会话一条 promise 链串行(sweep 与事件重投并发时天然去重)。\n * 归档面缺席(testkit/老宿主)时两个触发都不注册,返回空注册列表。\n */\nexport function createMemoryCurator(deps: MemoryCuratorDepsV1): MemoryCuratorV1 {\n\tconst { api, sessionArchive } = deps;\n\tconst logger = api.logger;\n\tif (sessionArchive === undefined) return { registrations: [] };\n\n\tconst chains = new Map<string, Promise<MemoryCurationRunResultV1>>();\n\tconst enqueue = (sessionId: string): void => {\n\t\t// 每会话一条链: 前一链的失败不阻断后续 (catch 抹平), 同会话并发触发\n\t\t// (事件重投 + sweep) 在链上串行, 不会并发跑批。\n\t\tconst last = chains.get(sessionId) ?? Promise.resolve();\n\t\tconst next = last.catch(() => undefined).then(() => curateSession(deps, sessionId));\n\t\tchains.set(sessionId, next);\n\t\tvoid next.catch((error) => {\n\t\t\tlogger?.warn(`memory curation failed for session ${sessionId}: ${boundedErrorText(error)}`);\n\t\t});\n\t\t// 链落定后摘除表项 (守卫: 已被更新的链接手时不删)。catch 抹平后的\n\t\t// finally 臂自身不会 reject, 无 unhandled rejection。\n\t\tvoid next\n\t\t\t.catch(() => undefined)\n\t\t\t.finally(() => {\n\t\t\t\tif (chains.get(sessionId) === next) chains.delete(sessionId);\n\t\t\t});\n\t};\n\n\t// 启动 sweep:后台串行补齐历史归档会话的整理(curation 维度已有结论的跳过)。\n\tconst sweep = async (): Promise<void> => {\n\t\ttry {\n\t\t\tconst archived = await sessionArchive.listArchived();\n\t\t\tfor (const item of archived) {\n\t\t\t\tif (item.curation !== undefined) continue;\n\t\t\t\tenqueue(item.sessionId);\n\t\t\t}\n\t\t} catch (error) {\n\t\t\tlogger?.warn(`memory curation startup sweep failed: ${boundedErrorText(error)}`);\n\t\t}\n\t};\n\tvoid sweep();\n\n\tconst registrations: DisposableRegistration[] = [];\n\t// lifecycle 在 CapabilityAPI 类型上是必选成员(experimental),最小宿主可以\n\t// 不带该面;事件触发缺席时启动 sweep 仍可用,与 hooks 同款降级。\n\tif (api.lifecycle !== undefined) {\n\t\tregistrations.push(\n\t\t\tapi.lifecycle.registerObserve<MemorySessionArchivedEventDataV1>(SESSION_ARCHIVED_EVENT_REFERENCE, (event) => {\n\t\t\t\tenqueue(event.data.sessionId);\n\t\t\t}),\n\t\t);\n\t} else {\n\t\tlogger?.warn(\"memory curator: host exposes no lifecycle face; session.archived trigger is unavailable\");\n\t}\n\treturn { registrations };\n}\n"]}