@xopcai/xopc 0.0.140 → 0.0.142
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/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DtONoxBN.js → agent-avatar-dicebear-BawPxiu5.js} +1 -1
- package/dist/gateway/static/root/assets/agents-CyvCIHnB.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BRBxLECY.js → app-management-settings-panel-81xd1p9R.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-ChvyuSEt.js → appearance-settings-DYeQsYU8.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DgHWTnjs.js → apps-page-DK_Vx6nl.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-CdIoagem.js → archive-plugin-D_oa7oti.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Ch411Kht.js → attachment-load-Cd-bwI2N.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-SVq27yw2.js → automation-suggestion-card-B1LV3YYv.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-fzrovqhv.js +4 -0
- package/dist/gateway/static/root/assets/{binary-plugins-D8cV-emn.js → binary-plugins-O8svLKWw.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CXDkby6y.js → block-editor-Dhj5f4Bx.js} +47 -47
- package/dist/gateway/static/root/assets/browser-settings-page-BDn-n-UB.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-DLxI--Ge.js → capability-presets-api-dJy1Eqgx.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-presets-settings-panel-DKyRbnlH.js → capability-presets-settings-panel-Co5ipo_Q.js} +1 -1
- package/dist/gateway/static/root/assets/{channel-recipient-api-DllrPmp-.js → channel-recipient-api-Bfuhp2ty.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-BWlpaxg9.js +1 -0
- package/dist/gateway/static/root/assets/channels-status-swr-D_jkIZLV.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BcekbW4q.js +2 -0
- package/dist/gateway/static/root/assets/{desktop-pet-Bz9ommjr.js → desktop-pet-DFMfIb5F.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-BnLgxgoR.js → desktop-pet-settings-BJCUuL8Y.js} +1 -1
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DLsCwFaf.js → directory-picker-path-field-BrYt1gAr.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-BzkF1-XT.js → dreaming-settings-BN1Z2mIo.js} +3 -3
- package/dist/gateway/static/root/assets/{extension-debug-page-CdERvf3L.js → extension-debug-page-Bh630pLD.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-D1fz474Z.js → extension-page-B-1KxvVy.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DoQMkNOK.js → extension-settings-page-BF9NACI3.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-BID89uCH.js → fetch-B1WtuprY.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-Rygo8UAs.js → gateway-config-api-De2N821l.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-kb8KIeQL.js → gateway-settings-DN9sNREz.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BkrLLlpE.js → gateway-startup-retry-nEujFSDj.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BpoQW8cD.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-CBRSPd0b.js +4 -0
- package/dist/gateway/static/root/assets/{goals-config-api-BuY6-l0a.js → goals-config-api-DUy3eEse.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-BCcBi407.js +2 -0
- package/dist/gateway/static/root/assets/{goals-settings-DoH5fZWo.js → goals-settings-pkTXzXkh.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-settings-BqDs48B-.js → heartbeat-settings-ezsufgLQ.js} +1 -1
- package/dist/gateway/static/root/assets/{index-CrPRlGMg.js → index-DcUaXYeb.js} +65 -65
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-CVIwwM15.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-DQtTRXtj.js +7 -0
- package/dist/gateway/static/root/assets/{markdown-split-CSt32FWE.js → markdown-split-B_6us9j7.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-ByItHxBj.js → media-plugins-D_fryIyj.js} +1 -1
- package/dist/gateway/static/root/assets/messages-BXNELNBa.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BP2M9n6Q.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CspveYaO.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-BHwzJ0OC.js +2 -0
- package/dist/gateway/static/root/assets/{page-tabs-DOfMaq_L.js → page-tabs-D_8jGlqx.js} +1 -1
- package/dist/gateway/static/root/assets/{preview-open-alternatives-BArxASu7.js → preview-open-alternatives-BBLMK8Mp.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-Dy3rsobs.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CWKpPE0L.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CqNRyXEo.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BRxlkhG8.js → save-bar-controls-DVS3FR5r.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BzM1iyOc.js → schedule-field-D6vKd6-T.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-ChVcm0DX.js → schema-form-BPy4lbIh.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-MEME7ivF.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-JVd0qaSF.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BcD9xrvY.js → settings-collapsible-section-WzdikxPt.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Cu30CXVl.js → settings-form-section-CvfzhBV-.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-loading-skeleton-Cfd37IYb.js → settings-loading-skeleton-BxR-Ulhi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-EINHyzLo.js → settings-page-DYEbB1EV.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-C15zixct.js → settings-page-layout-CKefvbYi.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Bu7SdpD4.js → setup-status-panel-dWN8BJ3z.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-CjjAFV-v.js → share-preview-page-D8foINzP.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-Tgbv1s7G.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-D_YK0b_Z.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DGytfoZK.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DlQMtzPf.js → system-settings-panel-BokgAgf7.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-BS1BwExE.js → typed-models-lib-BwHlNL3L.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-EA4hfbsP.js → use-channel-catalog-DR11ap3A.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-B7RCdmSp.js → user-profile-settings-panel-8YtygcJp.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-BrhEgVaa.js → utils-BKUWB-TT.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-BVH71EFf.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-JeTE7XNM.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-CL_rnAUB.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-BZCY7N42.js → workflow-start-dialog-_u8Uc1ze.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-ixgk_y1l.js +18 -0
- package/dist/gateway/static/root/index.html +4 -4
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +13 -21
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/background-review/run-background-review.js +1 -0
- package/dist/src/agent/background-review/run-background-review.js.map +1 -1
- package/dist/src/agent/embedded/session-runner.js +5 -5
- package/dist/src/agent/embedded/session-runner.js.map +1 -1
- package/dist/src/agent/embedded/xopc-auth-storage.d.ts +4 -3
- package/dist/src/agent/embedded/xopc-auth-storage.js +6 -6
- package/dist/src/agent/embedded/xopc-auth-storage.js.map +1 -1
- package/dist/src/agent/embedded/xopc-stream-bridge.js +1 -0
- package/dist/src/agent/embedded/xopc-stream-bridge.js.map +1 -1
- package/dist/src/agent/goals/checklist-judge.js +3 -3
- package/dist/src/agent/goals/checklist-judge.js.map +1 -1
- package/dist/src/agent/goals/judge.js +2 -2
- package/dist/src/agent/goals/judge.js.map +1 -1
- package/dist/src/agent/image/understanding/pi-ai-provider.js +2 -2
- package/dist/src/agent/image/understanding/pi-ai-provider.js.map +1 -1
- package/dist/src/agent/memory/access-policy.d.ts +12 -0
- package/dist/src/agent/memory/access-policy.js +44 -0
- package/dist/src/agent/memory/access-policy.js.map +1 -0
- package/dist/src/agent/memory/builtin-provider.d.ts +4 -1
- package/dist/src/agent/memory/builtin-provider.js +51 -16
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/compaction.js +2 -2
- package/dist/src/agent/memory/compaction.js.map +1 -1
- package/dist/src/agent/memory/context/planner.d.ts +1 -0
- package/dist/src/agent/memory/context/planner.js +9 -5
- package/dist/src/agent/memory/context/planner.js.map +1 -1
- package/dist/src/agent/memory/create-memory-manager.d.ts +1 -1
- package/dist/src/agent/memory/create-memory-manager.js +8 -5
- package/dist/src/agent/memory/create-memory-manager.js.map +1 -1
- package/dist/src/agent/memory/dreaming/config.d.ts +2 -0
- package/dist/src/agent/memory/dreaming/config.js +13 -1
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +2 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +24 -3
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/light-sweep.js +184 -16
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.d.ts +30 -0
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js +85 -0
- package/dist/src/agent/memory/dreaming/promotion-lifecycle.js.map +1 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +4 -0
- package/dist/src/agent/memory/dreaming/rem-patterns.js +76 -53
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +10 -0
- package/dist/src/agent/memory/dreaming/short-term-store.js +157 -79
- package/dist/src/agent/memory/dreaming/short-term-store.js.map +1 -1
- package/dist/src/agent/memory/manager.d.ts +7 -0
- package/dist/src/agent/memory/manager.js +31 -6
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.d.ts +1 -1
- package/dist/src/agent/memory/memory-config.js +3 -3
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/sensitivity.d.ts +3 -0
- package/dist/src/agent/memory/sensitivity.js +13 -0
- package/dist/src/agent/memory/sensitivity.js.map +1 -0
- package/dist/src/agent/memory/understanding/service.js +10 -14
- package/dist/src/agent/memory/understanding/service.js.map +1 -1
- package/dist/src/agent/memory/user-context-coordinator.d.ts +1 -0
- package/dist/src/agent/memory/user-context-coordinator.js +2 -0
- package/dist/src/agent/memory/user-context-coordinator.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +8 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js.map +1 -1
- package/dist/src/agent/service/btw-query.d.ts +4 -0
- package/dist/src/agent/service/btw-query.js +94 -13
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +9 -1
- package/dist/src/agent/session/session-inspector.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +3 -12
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.js +14 -2
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +3 -0
- package/dist/src/agent/tools/memory-tool.js +6 -3
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/session-search-tool.js +2 -2
- package/dist/src/agent/tools/session-search-tool.js.map +1 -1
- package/dist/src/agent/tools/web-extract.js +2 -2
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent/workspace-runtime/registry.d.ts +6 -6
- package/dist/src/agent/workspace-runtime/registry.js +19 -12
- package/dist/src/agent/workspace-runtime/registry.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +4 -0
- package/dist/src/agent-manifest/schema.js +2 -1
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-runtime/index.js +1 -1
- package/dist/src/agent-runtime/runtime-profile.js +1 -1
- package/dist/src/ai-assist/text-assist.d.ts +2 -1
- package/dist/src/ai-assist/text-assist.js +10 -23
- package/dist/src/ai-assist/text-assist.js.map +1 -1
- package/dist/src/auth/credentials.js +5 -2
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/oauth/github-copilot.d.ts +3 -4
- package/dist/src/auth/oauth/github-copilot.js +66 -2
- package/dist/src/auth/oauth/github-copilot.js.map +1 -0
- package/dist/src/auth/oauth/index.js +2 -2
- package/dist/src/automations/draft/automation-draft-service.js +3 -3
- package/dist/src/automations/draft/automation-draft-service.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.js +22 -5
- package/dist/src/chat-commands/builtins/review.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +4 -0
- package/dist/src/config/schema.d.ts +4 -0
- package/dist/src/gateway/hono/lib/config-payload.d.ts +2 -0
- package/dist/src/gateway/hono/routes/dreaming.js +28 -21
- package/dist/src/gateway/hono/routes/dreaming.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +16 -4
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -0
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/voice.js +2 -2
- package/dist/src/gateway/hono/routes/voice.js.map +1 -1
- package/dist/src/goals/goal-contract-draft.js +2 -2
- package/dist/src/goals/goal-contract-draft.js.map +1 -1
- package/dist/src/goals/goal-evidence-review.js +2 -2
- package/dist/src/goals/goal-evidence-review.js.map +1 -1
- package/dist/src/notes/service.js +2 -2
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/constants.d.ts +2 -0
- package/dist/src/providers/constants.js +11 -0
- package/dist/src/providers/constants.js.map +1 -0
- package/dist/src/providers/extension-stream-bridge.js +1 -0
- package/dist/src/providers/extension-stream-bridge.js.map +1 -1
- package/dist/src/providers/index.d.ts +3 -3
- package/dist/src/providers/index.js +5 -4
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/providers/model-call.d.ts +17 -0
- package/dist/src/providers/model-call.js +60 -0
- package/dist/src/providers/model-call.js.map +1 -0
- package/dist/src/session/session-title.js +2 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/storage/sqlite/fts.d.ts +6 -0
- package/dist/src/storage/sqlite/fts.js +70 -1
- package/dist/src/storage/sqlite/fts.js.map +1 -1
- package/dist/src/storage/sqlite/memory-index-repository.js +16 -7
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +18 -0
- package/dist/src/storage/sqlite/memory-records-repository.js +55 -8
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/voice/tts/summarize.js +2 -2
- package/dist/src/voice/tts/summarize.js.map +1 -1
- package/dist/src/workflows/draft/workflow-draft-service.js +2 -2
- package/dist/src/workflows/draft/workflow-draft-service.js.map +1 -1
- package/package.json +5 -5
- package/dist/gateway/static/root/assets/agents-Dl9EWnUh.js +0 -2
- package/dist/gateway/static/root/assets/automations-page-CFt5Ik4q.js +0 -4
- package/dist/gateway/static/root/assets/browser-settings-page-ColJPwer.js +0 -8
- package/dist/gateway/static/root/assets/channels-settings-BDLHV3Jx.js +0 -1
- package/dist/gateway/static/root/assets/channels-status-swr-EUwWYx8l.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-CA752gY8.js +0 -2
- package/dist/gateway/static/root/assets/goal-create-dialog-DVAHnifk.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BuOEQZn_.js +0 -4
- package/dist/gateway/static/root/assets/goals-page-WV4cHvD-.js +0 -2
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-D51yogNZ.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-CL22jleU.js +0 -7
- package/dist/gateway/static/root/assets/messages-DbNQuFdA.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BkV9hDc-.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-BK9yydrL.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-Dd0v-hK2.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-DSPhB3do.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-C-fZk1f7.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BGaVc3t7.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-DbnzgQOP.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-CuDBoz5k.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-06IYvwDt.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-0ODH0DXl.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-3W2-wDyO.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-BPn1ZEga.js +0 -1
- package/dist/gateway/static/root/assets/work-item-detail-page-BQGTTsz1.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-na-N4jZ6.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-CjeVDs4h.js +0 -18
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builtin-provider.js","names":[],"sources":["../../../../src/agent/memory/builtin-provider.ts"],"sourcesContent":["import type { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';\nimport { memoryGet, memorySearch } from '../prompt/memory/index.js';\nimport {\n appendMemorySignal,\n deleteMemoryRecord,\n getMemoryRecord,\n listMemoryRecords,\n searchMemoryRecords,\n upsertMemoryRecord,\n} from '../../storage/sqlite/index.js';\nimport type {\n MemoryDeleteRequest,\n MemoryListRequest,\n MemoryReadRequest,\n MemoryReadResult,\n MemoryRecord,\n MemorySearchRequest,\n MemorySearchResult,\n MemoryUpdateRequest,\n MemoryWriteRequest,\n MemoryWriteResult,\n MemorySyncEvent,\n} from './types.js';\n\n/**\n * Builtin local memory provider backed by profile memory, agent-home curated files,\n * and the local SQLite FTS index.\n */\nexport class BuiltinMemoryProvider implements MemoryProvider {\n readonly id = 'local';\n readonly displayName = 'Local Knowledge Store';\n readonly capabilities = {\n search: true,\n read: true,\n write: true,\n update: true,\n delete: true,\n keywordSearch: true,\n semanticSearch: false,\n hybridSearch: false,\n citations: true,\n sync: false,\n local: true,\n };\n\n private workspaceDir = '';\n private agentId = 'main';\n\n constructor(private readonly store: BuiltinMemoryStore) {}\n\n isAvailable(): boolean {\n return true;\n }\n\n async initialize(_sessionId: string, options?: MemoryProviderInitOptions): Promise<void> {\n this.workspaceDir = options?.workspace ?? options?.agentWorkspace ?? this.store.workspaceDir;\n this.agentId = String(options?.agentId ?? this.agentId);\n }\n\n systemPromptBlock(): string {\n return '';\n }\n\n queuePrefetch(): void {}\n\n getToolSchemas() {\n return [];\n }\n\n async search(request: MemorySearchRequest): Promise<MemorySearchResult[]> {\n const agentId = request.scope?.agentId ?? this.agentId;\n const workspaceId = request.scope?.workspaceId ?? this.workspaceDir;\n const recordHits = searchMemoryRecords({\n query: request.query,\n agentId,\n workspaceId,\n providerId: this.id,\n kinds: request.kinds,\n maxResults: request.maxResults,\n minScore: request.minScore,\n });\n if (recordHits.length > 0) {\n return recordHits;\n }\n\n const results = await memorySearch(this.workspaceDir, request.query, {\n maxResults: request.maxResults,\n minScore: request.minScore,\n memoriesDir: this.store.memoriesDir,\n userMemoryPath: this.store.userMemoryPath,\n agentId,\n });\n return results.map((entry) => {\n const start = entry.lineNumbers[0] ?? 1;\n const end = entry.lineNumbers[entry.lineNumbers.length - 1] ?? start;\n const id = `${entry.file}#L${start}-L${end}`;\n const kind = inferKindFromPath(entry.file);\n const record = upsertMemoryRecord({\n id,\n providerId: this.id,\n kind,\n agentId,\n workspaceId,\n content: entry.lines,\n source: {\n provider: this.id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n confidence: entry.score,\n });\n return {\n record,\n score: entry.score,\n snippet: entry.lines,\n citation: {\n providerId: this.id,\n recordId: id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n };\n });\n }\n\n async read(request: MemoryReadRequest): Promise<MemoryReadResult | null> {\n if (request.id && !request.path) {\n const existing = getMemoryRecord(request.id);\n if (existing) {\n return { record: existing };\n }\n }\n const result = memoryGet(\n this.workspaceDir,\n request.path ?? request.id ?? '',\n request.from,\n request.lines,\n this.store.memoriesDir,\n this.store.userMemoryPath,\n );\n if (!result) return null;\n const path = request.path ?? request.id ?? '';\n const record = upsertMemoryRecord({\n id: `${path}#L${result.lineNumbers.start}-L${result.lineNumbers.end}`,\n providerId: this.id,\n kind: inferKindFromPath(path),\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content: result.content,\n source: {\n provider: this.id,\n path,\n lineStart: result.lineNumbers.start,\n lineEnd: result.lineNumbers.end,\n },\n });\n return {\n record,\n lineNumbers: result.lineNumbers,\n };\n }\n\n async get(id: string): Promise<MemoryRecord | null> {\n const parsed = parseLineAddress(id);\n const result = await this.read({\n path: parsed.path,\n from: parsed.lineStart,\n lines: parsed.lineEnd != null ? parsed.lineEnd - parsed.lineStart + 1 : undefined,\n });\n return result?.record ?? null;\n }\n\n async list(request: MemoryListRequest): Promise<MemoryRecord[]> {\n const records = listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: request.kind,\n status: request.status,\n canonicalKey: request.canonicalKey,\n limit: 200,\n });\n if (records.length > 0 || request.kind || request.status || request.canonicalKey) {\n return request.target\n ? records.filter((record) => targetForKind(record.kind) === request.target)\n : records;\n }\n\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n return this.store.getLiveEntries(target).map((content, index) =>\n upsertMemoryRecord({\n id: `curated:${target}:${index + 1}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content,\n source: {\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n }),\n );\n }\n\n async write(request: MemoryWriteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n if (request.status === 'candidate') {\n const record = upsertMemoryRecord({\n providerId: this.id,\n kind: request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n },\n confidence: request.confidence,\n tags: request.tags,\n status: 'candidate',\n sensitivity: request.sensitivity,\n canonicalKey: request.canonicalKey,\n explicitness: request.explicitness,\n durability: request.durability,\n importance: request.importance,\n disclosurePolicy: request.disclosurePolicy,\n evidence: request.evidence,\n validFrom: request.validFrom,\n validTo: request.validTo,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n supersedesRecordId: request.supersedesRecordId,\n conflictGroupId: request.conflictGroupId,\n });\n return {\n success: true,\n message: 'Memory candidate added to inbox',\n record,\n };\n }\n const result = await this.store.add(target, request.content);\n if (!result.success) return { success: false, error: result.error };\n return {\n success: true,\n message: result.message,\n record: upsertMemoryRecord({\n id: `curated:${target}:${Date.now()}`,\n providerId: this.id,\n kind: request.kind,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n tags: request.tags,\n canonicalKey: request.canonicalKey,\n explicitness: request.explicitness,\n durability: request.durability,\n importance: request.importance,\n disclosurePolicy: request.disclosurePolicy,\n evidence: request.evidence,\n validFrom: request.validFrom,\n validTo: request.validTo,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n supersedesRecordId: request.supersedesRecordId,\n conflictGroupId: request.conflictGroupId,\n }),\n };\n }\n\n async update(request: MemoryUpdateRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.replace(target, request.matchText ?? request.id ?? '', request.content);\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n const existing = getMemoryRecord(request.id);\n upsertMemoryRecord({\n id: request.id,\n providerId: this.id,\n kind: existing?.kind ?? (target === 'user' ? 'user_profile' : 'agent_note'),\n agentId: existing?.scope.agentId ?? request.scope?.agentId ?? this.agentId,\n workspaceId: existing?.scope.workspaceId ?? request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: existing?.scope.sessionKey ?? request.scope?.sessionKey,\n content: request.content,\n source: existing?.source ?? { provider: this.id, path: sourcePathForTarget(target) },\n tags: existing?.tags,\n });\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (!existing.content.includes(request.matchText)) continue;\n upsertMemoryRecord({\n id: existing.id,\n providerId: this.id,\n kind: existing.kind,\n agentId: existing.scope.agentId,\n workspaceId: existing.scope.workspaceId,\n sessionKey: existing.scope.sessionKey,\n content: request.content,\n source: existing.source,\n tags: existing.tags,\n });\n }\n }\n return { success: true, message: result.message };\n }\n\n async delete(request: MemoryDeleteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const result = await this.store.remove(target, request.matchText ?? request.id ?? '');\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n deleteMemoryRecord(request.id);\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (existing.content.includes(request.matchText)) {\n deleteMemoryRecord(existing.id);\n }\n }\n }\n return { success: true, message: result.message };\n }\n\n sync(event: MemorySyncEvent): void {\n if (event.type !== 'signal') return;\n appendMemorySignal({\n signal: event.signal,\n providerId: this.id,\n agentId: this.agentId,\n workspaceId: this.workspaceDir,\n sessionKey:\n typeof event.signal.metadata?.sessionKey === 'string'\n ? event.signal.metadata.sessionKey\n : undefined,\n });\n }\n\n async shutdown(): Promise<void> {}\n}\n\nfunction inferKindFromPath(path: string): MemoryRecord['kind'] {\n const normalized = path.replace(/\\\\/g, '/');\n if (normalized === 'user/MEMORY.md' || normalized.endsWith('/user/MEMORY.md')) return 'user_profile';\n if (/^memory\\/\\d{4}-\\d{2}-\\d{2}\\.md$/.test(normalized)) return 'daily_note';\n if (normalized.endsWith('MEMORY.md')) return 'agent_note';\n return 'workspace_fact';\n}\n\nfunction targetForKind(kind: MemoryRecord['kind']): 'memory' | 'user' {\n return kind === 'user_profile' || kind === 'preference' || kind === 'relationship' ||\n kind === 'routine' || kind === 'personal_logistics'\n ? 'user'\n : 'memory';\n}\n\nfunction sourcePathForTarget(target: 'memory' | 'user'): string {\n return target === 'user' ? 'user/MEMORY.md' : 'MEMORY.md';\n}\n\nfunction parseLineAddress(id: string): { path: string; lineStart?: number; lineEnd?: number } {\n const match = /^(.*)#L(\\d+)(?:-L(\\d+))?$/.exec(id);\n if (!match) return { path: id };\n const lineStart = Number.parseInt(match[2] ?? '1', 10);\n const lineEnd = Number.parseInt(match[3] ?? match[2] ?? '1', 10);\n return {\n path: match[1] ?? id,\n lineStart: Number.isFinite(lineStart) ? lineStart : undefined,\n lineEnd: Number.isFinite(lineEnd) ? lineEnd : undefined,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"builtin-provider.js","names":[],"sources":["../../../../src/agent/memory/builtin-provider.ts"],"sourcesContent":["import type { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport type { MemoryAccessPolicy } from './access-policy.js';\nimport { normalizeAgentId } from '../../routing/agent-session-key.js';\nimport type { MemoryProvider, MemoryProviderInitOptions } from './provider.js';\nimport { memoryGet, memorySearch } from '../prompt/memory/index.js';\nimport {\n appendMemorySignal,\n deleteMemoryRecord,\n getMemoryRecord,\n listMemoryRecords,\n searchMemoryRecords,\n upsertMemoryRecord,\n} from '../../storage/sqlite/index.js';\nimport type {\n MemoryDeleteRequest,\n MemoryListRequest,\n MemoryReadRequest,\n MemoryReadResult,\n MemoryRecord,\n MemorySearchRequest,\n MemorySearchResult,\n MemoryUpdateRequest,\n MemoryWriteRequest,\n MemoryWriteResult,\n MemorySyncEvent,\n} from './types.js';\n\n/**\n * Builtin local memory provider backed by profile memory, agent-home curated files,\n * and the local SQLite FTS index.\n */\nexport class BuiltinMemoryProvider implements MemoryProvider {\n readonly id = 'local';\n readonly displayName = 'Local Knowledge Store';\n readonly capabilities = {\n search: true,\n read: true,\n write: true,\n update: true,\n delete: true,\n keywordSearch: true,\n semanticSearch: false,\n hybridSearch: false,\n citations: true,\n sync: false,\n local: true,\n };\n\n private workspaceDir = '';\n private agentId = 'main';\n\n constructor(\n private readonly store: BuiltinMemoryStore,\n private readonly accessPolicy?: MemoryAccessPolicy,\n ) {}\n\n isAvailable(): boolean {\n return true;\n }\n\n async initialize(_sessionId: string, options?: MemoryProviderInitOptions): Promise<void> {\n this.workspaceDir = options?.workspace ?? options?.agentWorkspace ?? this.store.workspaceDir;\n this.agentId = normalizeAgentId(String(options?.agentId ?? this.agentId));\n }\n\n systemPromptBlock(): string {\n return '';\n }\n\n queuePrefetch(): void {}\n\n getToolSchemas() {\n return [];\n }\n\n async search(request: MemorySearchRequest): Promise<MemorySearchResult[]> {\n const workspaceId = request.scope?.workspaceId ?? this.workspaceDir;\n const readableAgentIds = this.accessPolicy?.readableAgentIds ?? [this.agentId];\n const recordHits = readableAgentIds\n .flatMap((ownerAgentId) => searchMemoryRecords({\n query: request.query,\n agentId: ownerAgentId,\n workspaceId: ownerAgentId === this.agentId ? workspaceId : undefined,\n visibleToSessionKey: request.scope?.sessionKey,\n unscopedSessionOnly: request.scope?.sessionKey == null,\n visibleToProjectId: request.scope?.projectId,\n unscopedProjectOnly: request.scope?.projectId == null,\n providerId: this.id,\n kinds: request.kinds,\n maxResults: request.maxResults,\n minScore: request.minScore,\n }))\n .filter((result) => this.canReadRecord(result.record, request.scope))\n .sort((left, right) => right.score - left.score)\n .slice(0, request.maxResults ?? 5);\n if (recordHits.length > 0) {\n return recordHits;\n }\n\n const results = await memorySearch(this.workspaceDir, request.query, {\n maxResults: request.maxResults,\n minScore: request.minScore,\n memoriesDir: this.store.memoriesDir,\n userMemoryPath: this.store.userMemoryPath,\n agentId: this.agentId,\n });\n return results.map((entry) => {\n const start = entry.lineNumbers[0] ?? 1;\n const end = entry.lineNumbers[entry.lineNumbers.length - 1] ?? start;\n const id = `${entry.file}#L${start}-L${end}`;\n const kind = inferKindFromPath(entry.file);\n const record = upsertMemoryRecord({\n id,\n providerId: this.id,\n kind,\n agentId: this.agentId,\n workspaceId,\n content: entry.lines,\n source: {\n provider: this.id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n confidence: entry.score,\n });\n return {\n record,\n score: entry.score,\n snippet: entry.lines,\n citation: {\n providerId: this.id,\n recordId: id,\n path: entry.file,\n lineStart: start,\n lineEnd: end,\n },\n };\n });\n }\n\n async read(request: MemoryReadRequest): Promise<MemoryReadResult | null> {\n if (request.id && !request.path) {\n const existing = getMemoryRecord(request.id);\n if (existing && this.canReadRecord(existing, request.scope)) {\n return { record: existing };\n }\n if (existing) return null;\n }\n const result = memoryGet(\n this.workspaceDir,\n request.path ?? request.id ?? '',\n request.from,\n request.lines,\n this.store.memoriesDir,\n this.store.userMemoryPath,\n );\n if (!result) return null;\n const path = request.path ?? request.id ?? '';\n const record = upsertMemoryRecord({\n id: `${path}#L${result.lineNumbers.start}-L${result.lineNumbers.end}`,\n providerId: this.id,\n kind: inferKindFromPath(path),\n agentId: this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content: result.content,\n source: {\n provider: this.id,\n path,\n lineStart: result.lineNumbers.start,\n lineEnd: result.lineNumbers.end,\n },\n });\n return {\n record,\n lineNumbers: result.lineNumbers,\n };\n }\n\n async get(id: string): Promise<MemoryRecord | null> {\n const parsed = parseLineAddress(id);\n const result = await this.read({\n path: parsed.path,\n from: parsed.lineStart,\n lines: parsed.lineEnd != null ? parsed.lineEnd - parsed.lineStart + 1 : undefined,\n });\n return result?.record ?? null;\n }\n\n async list(request: MemoryListRequest): Promise<MemoryRecord[]> {\n const records = listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n visibleToSessionKey: request.scope?.sessionKey,\n visibleToProjectId: request.scope?.projectId,\n kind: request.kind,\n status: request.status,\n canonicalKey: request.canonicalKey,\n limit: 200,\n });\n if (records.length > 0 || request.kind || request.status || request.canonicalKey) {\n return request.target\n ? records.filter((record) => targetForKind(record.kind) === request.target)\n : records;\n }\n\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n return this.store.getLiveEntries(target).map((content, index) =>\n upsertMemoryRecord({\n id: `curated:${target}:${index + 1}`,\n providerId: this.id,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n content,\n source: {\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n }),\n );\n }\n\n async write(request: MemoryWriteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? (request.kind === 'user_profile' ? 'user' : 'memory');\n const ownerAgentId = normalizeAgentId(request.scope?.agentId ?? this.agentId);\n const isCrossAgentWrite = ownerAgentId !== this.agentId;\n if (isCrossAgentWrite && request.status !== 'candidate') {\n return { success: false, error: 'Cross-agent writes must be submitted as candidates' };\n }\n if (isCrossAgentWrite && !this.accessPolicy?.canSubmitCandidate(ownerAgentId)) {\n return { success: false, error: 'Cross-agent candidate submission is not allowed' };\n }\n if (request.status === 'candidate') {\n const record = upsertMemoryRecord({\n providerId: this.id,\n kind: request.kind,\n agentId: ownerAgentId,\n workspaceId: isCrossAgentWrite ? request.scope?.workspaceId : request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: isCrossAgentWrite ? undefined : request.scope?.sessionKey,\n projectId: isCrossAgentWrite ? undefined : request.scope?.projectId,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n },\n confidence: request.confidence,\n tags: isCrossAgentWrite\n ? [...(request.tags ?? []), `shared-from:${this.agentId}`]\n : request.tags,\n status: 'candidate',\n sensitivity: request.sensitivity,\n canonicalKey: request.canonicalKey,\n explicitness: request.explicitness,\n durability: request.durability,\n importance: request.importance,\n disclosurePolicy: request.disclosurePolicy,\n evidence: request.evidence,\n validFrom: request.validFrom,\n validTo: request.validTo,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n supersedesRecordId: request.supersedesRecordId,\n conflictGroupId: request.conflictGroupId,\n });\n return {\n success: true,\n message: 'Memory candidate added to inbox',\n record,\n };\n }\n const result = await this.store.add(target, request.content);\n if (!result.success) return { success: false, error: result.error };\n return {\n success: true,\n message: result.message,\n record: upsertMemoryRecord({\n id: `curated:${target}:${Date.now()}`,\n providerId: this.id,\n kind: request.kind,\n agentId: this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: request.scope?.sessionKey,\n content: request.content,\n source: {\n ...(request.source ?? {}),\n provider: this.id,\n path: sourcePathForTarget(target),\n },\n tags: request.tags,\n canonicalKey: request.canonicalKey,\n explicitness: request.explicitness,\n durability: request.durability,\n importance: request.importance,\n disclosurePolicy: request.disclosurePolicy,\n evidence: request.evidence,\n validFrom: request.validFrom,\n validTo: request.validTo,\n reviewAfter: request.reviewAfter,\n expiresAt: request.expiresAt,\n supersedesRecordId: request.supersedesRecordId,\n conflictGroupId: request.conflictGroupId,\n }),\n };\n }\n\n async update(request: MemoryUpdateRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const existingRecord = request.id ? getMemoryRecord(request.id) : null;\n const requestedOwnerAgentId = existingRecord?.scope.agentId ?? request.scope?.agentId ?? this.agentId;\n if (requestedOwnerAgentId !== this.agentId) {\n return { success: false, error: 'Cross-agent memory updates are not allowed' };\n }\n const result = await this.store.replace(target, request.matchText ?? request.id ?? '', request.content);\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n const existing = getMemoryRecord(request.id);\n upsertMemoryRecord({\n id: request.id,\n providerId: this.id,\n kind: existing?.kind ?? (target === 'user' ? 'user_profile' : 'agent_note'),\n agentId: existing?.scope.agentId ?? request.scope?.agentId ?? this.agentId,\n workspaceId: existing?.scope.workspaceId ?? request.scope?.workspaceId ?? this.workspaceDir,\n sessionKey: existing?.scope.sessionKey ?? request.scope?.sessionKey,\n content: request.content,\n source: existing?.source ?? { provider: this.id, path: sourcePathForTarget(target) },\n tags: existing?.tags,\n });\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (!existing.content.includes(request.matchText)) continue;\n upsertMemoryRecord({\n id: existing.id,\n providerId: this.id,\n kind: existing.kind,\n agentId: existing.scope.agentId,\n workspaceId: existing.scope.workspaceId,\n sessionKey: existing.scope.sessionKey,\n content: request.content,\n source: existing.source,\n tags: existing.tags,\n });\n }\n }\n return { success: true, message: result.message };\n }\n\n async delete(request: MemoryDeleteRequest): Promise<MemoryWriteResult> {\n const target = request.target ?? 'memory';\n const existingRecord = request.id ? getMemoryRecord(request.id) : null;\n const requestedOwnerAgentId = existingRecord?.scope.agentId ?? request.scope?.agentId ?? this.agentId;\n if (requestedOwnerAgentId !== this.agentId) {\n return { success: false, error: 'Cross-agent memory deletion is not allowed' };\n }\n const result = await this.store.remove(target, request.matchText ?? request.id ?? '');\n if (!result.success) return { success: false, error: result.error };\n if (request.id) {\n deleteMemoryRecord(request.id);\n } else if (request.matchText) {\n for (const existing of listMemoryRecords({\n providerId: this.id,\n agentId: request.scope?.agentId ?? this.agentId,\n workspaceId: request.scope?.workspaceId ?? this.workspaceDir,\n kind: target === 'user' ? 'user_profile' : 'agent_note',\n limit: 200,\n })) {\n if (existing.content.includes(request.matchText)) {\n deleteMemoryRecord(existing.id);\n }\n }\n }\n return { success: true, message: result.message };\n }\n\n sync(event: MemorySyncEvent): void {\n if (event.type !== 'signal') return;\n appendMemorySignal({\n signal: event.signal,\n providerId: this.id,\n agentId: this.agentId,\n workspaceId: this.workspaceDir,\n sessionKey:\n typeof event.signal.metadata?.sessionKey === 'string'\n ? event.signal.metadata.sessionKey\n : undefined,\n });\n }\n\n async shutdown(): Promise<void> {}\n\n private canReadRecord(record: MemoryRecord, scope: MemoryReadRequest['scope']): boolean {\n if (this.accessPolicy) return this.accessPolicy.canReadRecord(record, scope);\n if (record.scope.agentId !== this.agentId) return false;\n if (record.scope.sessionKey && record.scope.sessionKey !== scope?.sessionKey) return false;\n if (record.scope.projectId && record.scope.projectId !== scope?.projectId) return false;\n return true;\n }\n}\n\nfunction inferKindFromPath(path: string): MemoryRecord['kind'] {\n const normalized = path.replace(/\\\\/g, '/');\n if (normalized === 'user/MEMORY.md' || normalized.endsWith('/user/MEMORY.md')) return 'user_profile';\n if (/^memory\\/\\d{4}-\\d{2}-\\d{2}\\.md$/.test(normalized)) return 'daily_note';\n if (normalized.endsWith('MEMORY.md')) return 'agent_note';\n return 'workspace_fact';\n}\n\nfunction targetForKind(kind: MemoryRecord['kind']): 'memory' | 'user' {\n return kind === 'user_profile' || kind === 'preference' || kind === 'relationship' ||\n kind === 'routine' || kind === 'personal_logistics'\n ? 'user'\n : 'memory';\n}\n\nfunction sourcePathForTarget(target: 'memory' | 'user'): string {\n return target === 'user' ? 'user/MEMORY.md' : 'MEMORY.md';\n}\n\nfunction parseLineAddress(id: string): { path: string; lineStart?: number; lineEnd?: number } {\n const match = /^(.*)#L(\\d+)(?:-L(\\d+))?$/.exec(id);\n if (!match) return { path: id };\n const lineStart = Number.parseInt(match[2] ?? '1', 10);\n const lineEnd = Number.parseInt(match[3] ?? match[2] ?? '1', 10);\n return {\n path: match[1] ?? id,\n lineStart: Number.isFinite(lineStart) ? lineStart : undefined,\n lineEnd: Number.isFinite(lineEnd) ? lineEnd : undefined,\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
+
import { completeWithResolvedCredentials } from "../../providers/model-call.js";
|
|
1
2
|
import { readAgentMessageContent } from "./agent-message-access.js";
|
|
2
3
|
import { formatSummaryAsText, generateStructuredSummary } from "./summary-generator.js";
|
|
3
|
-
import { complete } from "@earendil-works/pi-ai/compat";
|
|
4
4
|
//#region src/agent/memory/compaction.ts
|
|
5
5
|
const DEFAULT_CONFIG = {
|
|
6
6
|
enabled: true,
|
|
@@ -212,7 +212,7 @@ Summary:`;
|
|
|
212
212
|
content: prompt,
|
|
213
213
|
timestamp: Date.now()
|
|
214
214
|
};
|
|
215
|
-
const result = await
|
|
215
|
+
const result = await completeWithResolvedCredentials(this.model, { messages: [summaryMessage] }, {
|
|
216
216
|
maxTokens: this.config.summaryMaxTokens,
|
|
217
217
|
temperature: .3,
|
|
218
218
|
signal: controller.signal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compaction.js","names":[],"sources":["../../../../src/agent/memory/compaction.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport { complete, type Model, type Api, type UserMessage } from '@earendil-works/pi-ai/compat';\nimport { readAgentMessageContent } from './agent-message-access.js';\nimport { generateStructuredSummary, formatSummaryAsText, type ConversationSummary } from './summary-generator.js';\n\nexport interface CompactionResult {\n summary: string;\n firstKeptIndex: number;\n tokensBefore: number;\n tokensAfter: number;\n compacted: boolean;\n structuredSummary?: ConversationSummary;\n compactedUsage?: {\n input: number;\n output: number;\n total: number;\n cost?: number;\n };\n}\n\nexport interface CompactionConfig {\n enabled: boolean;\n mode: 'extractive' | 'abstractive' | 'structured';\n reserveTokens: number;\n triggerThreshold: number;\n minMessagesBeforeCompact: number;\n keepRecentMessages: number;\n summaryMaxTokens: number;\n evictionWindow: number;\n retentionWindow: number;\n preserveReasoning: boolean;\n accumulateUsage: boolean;\n}\n\nconst DEFAULT_CONFIG: CompactionConfig = {\n enabled: true,\n mode: 'abstractive',\n reserveTokens: 8000,\n triggerThreshold: 0.8,\n minMessagesBeforeCompact: 10,\n keepRecentMessages: 10,\n summaryMaxTokens: 500,\n evictionWindow: 0.2,\n retentionWindow: 6,\n preserveReasoning: true,\n accumulateUsage: true,\n};\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction estimateMessageTokens(msg: AgentMessage): number {\n let text = '';\n const raw = readAgentMessageContent(msg);\n\n if (typeof raw === 'string') {\n text = raw;\n } else if (Array.isArray(raw)) {\n text = raw\n .filter(c => c.type === 'text')\n .map(c => (c as { text?: string }).text || '')\n .join('\\n');\n }\n \n return estimateTokens(text) + 10;\n}\n\n// Internal: Reasoning extraction utilities\ninterface ReasoningDetails {\n thinking?: string;\n signature?: string;\n}\n\nfunction extractLastReasoning(messages: AgentMessage[]): ReasoningDetails | null {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.role === 'assistant') {\n const rd = (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details;\n if (rd && (rd.thinking || rd.signature)) {\n return rd;\n }\n }\n }\n return null;\n}\n\n// Internal: Inject reasoning into first assistant message\nfunction injectReasoningIntoFirstAssistant(\n messages: AgentMessage[],\n reasoning: ReasoningDetails\n): void {\n for (const msg of messages) {\n if (msg.role === 'assistant') {\n const existing = (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details;\n if (!existing || (!existing.thinking && !existing.signature)) {\n (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details = reasoning;\n }\n break;\n }\n }\n}\n\n// Internal: Message usage tracking\ninterface MessageUsage {\n input: number;\n output: number;\n total: number;\n cost?: number;\n}\n\nexport function accumulateUsage(messages: AgentMessage[]): MessageUsage | undefined {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCost = 0;\n let hasUsage = false;\n\n for (const msg of messages) {\n const usage = (msg as unknown as { usage?: MessageUsage }).usage;\n if (usage) {\n hasUsage = true;\n totalInput += usage.input || 0;\n totalOutput += usage.output || 0;\n totalCost += usage.cost || 0;\n }\n }\n\n if (!hasUsage) return undefined;\n\n return {\n input: totalInput,\n output: totalOutput,\n total: totalInput + totalOutput,\n cost: totalCost > 0 ? totalCost : undefined,\n };\n}\n\n// Internal: Droppable message filtering\ntype DroppableMessage = AgentMessage & {\n droppable?: boolean;\n};\n\nfunction filterDroppableMessages(messages: AgentMessage[]): AgentMessage[] {\n return messages.filter(msg => !(msg as DroppableMessage).droppable);\n}\n\nfunction findNthTurnFromEnd(messages: AgentMessage[], n: number): number {\n if (n <= 0) return messages.length;\n \n let turnsFound = 0;\n let lastRole: string | null = null;\n \n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n \n if (msg.role === 'user' && lastRole !== 'user') {\n turnsFound++;\n if (turnsFound === n) {\n return i;\n }\n }\n lastRole = msg.role;\n }\n \n return 0;\n}\n\n// Internal: Calculate compaction range\nfunction calculateCompactionRange(\n messages: AgentMessage[],\n config: CompactionConfig\n): { start: number; end: number } | null {\n const totalMessages = messages.length;\n \n if (totalMessages < config.minMessagesBeforeCompact) {\n return null;\n }\n \n const evictionEnd = Math.floor(totalMessages * config.evictionWindow);\n const retentionStart = findNthTurnFromEnd(messages, config.retentionWindow);\n const retentionEnd = retentionStart > 0 ? retentionStart - 1 : 0;\n const compactionEnd = Math.min(evictionEnd, retentionEnd);\n \n if (compactionEnd <= 1) {\n return null;\n }\n \n return { start: 0, end: compactionEnd };\n}\n\nexport class SessionCompactor {\n private config: CompactionConfig;\n \n constructor(\n config?: Partial<CompactionConfig>,\n private model?: Model<Api>\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n needsCompaction(\n messages: AgentMessage[],\n contextWindow: number\n ): { needed: boolean; reason: string; usagePercent?: number } {\n if (!this.config.enabled) {\n return { needed: false, reason: 'disabled' };\n }\n\n if (messages.length < this.config.minMessagesBeforeCompact) {\n return { needed: false, reason: 'not_enough_messages' };\n }\n\n const totalTokens = this.estimateTotalTokens(messages);\n const usagePercent = totalTokens / contextWindow;\n\n if (usagePercent > this.config.triggerThreshold) {\n return { \n needed: true, \n reason: 'threshold_exceeded',\n usagePercent \n };\n }\n\n return { needed: false, reason: 'within_threshold' };\n }\n\n async compact(\n messages: AgentMessage[],\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n const effectiveMessages = filterDroppableMessages(messages);\n\n const minRequired = this.config.minMessagesBeforeCompact;\n if (!force && effectiveMessages.length < minRequired) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n if (force && effectiveMessages.length < 2) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n const range = calculateCompactionRange(effectiveMessages, this.config);\n let messagesToSummarize: AgentMessage[];\n let keptMessages: AgentMessage[];\n\n if (range) {\n messagesToSummarize = effectiveMessages.slice(0, range.end);\n keptMessages = effectiveMessages.slice(range.end);\n } else if (force) {\n const keep = Math.min(\n this.config.keepRecentMessages,\n Math.max(1, effectiveMessages.length - 1),\n );\n messagesToSummarize = effectiveMessages.slice(0, effectiveMessages.length - keep);\n keptMessages = effectiveMessages.slice(-keep);\n } else {\n const keepRecent = this.config.keepRecentMessages;\n messagesToSummarize = effectiveMessages.slice(0, -keepRecent);\n keptMessages = effectiveMessages.slice(-keepRecent);\n }\n\n if (messagesToSummarize.length === 0) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n let preservedReasoning: ReasoningDetails | null = null;\n if (this.config.preserveReasoning) {\n preservedReasoning = extractLastReasoning(messagesToSummarize);\n if (preservedReasoning) {\n injectReasoningIntoFirstAssistant(keptMessages, preservedReasoning);\n }\n }\n\n const summary = await this.generateSummary(messagesToSummarize, instructions);\n const structuredSummary = this.config.mode === 'structured' \n ? generateStructuredSummary(messagesToSummarize)\n : undefined;\n\n const tokensBefore = this.estimateTotalTokens(effectiveMessages);\n const summaryTokens = estimateTokens(summary) + 20;\n const keptTokens = this.estimateTotalTokens(keptMessages);\n const tokensAfter = summaryTokens + keptTokens;\n\n let compactedUsage: MessageUsage | undefined;\n if (this.config.accumulateUsage) {\n compactedUsage = accumulateUsage(messagesToSummarize);\n }\n\n return {\n summary,\n firstKeptIndex: keptMessages.length > 0 ? effectiveMessages.length - keptMessages.length : 0,\n tokensBefore,\n tokensAfter,\n compacted: true,\n structuredSummary,\n compactedUsage,\n };\n }\n\n private async generateSummary(messages: AgentMessage[], instructions?: string): Promise<string> {\n if (this.model && (this.config.mode === 'abstractive' || this.config.mode === 'structured')) {\n try {\n if (this.config.mode === 'structured') {\n const structured = generateStructuredSummary(messages);\n return formatSummaryAsText(structured, true);\n } else {\n return await this.llmAbstractiveSummary(messages, instructions);\n }\n } catch (err) {\n console.warn('[Compactor] LLM summarization failed, falling back to extractive', err);\n }\n }\n\n return this.extractiveSummary(messages);\n }\n\n private async llmAbstractiveSummary(messages: AgentMessage[], instructions?: string): Promise<string> {\n if (!this.model) {\n throw new Error('Model not available');\n }\n\n const conversation = this.formatMessages(messages);\n const extra = instructions?.trim()\n ? `\\nAdditional focus from the user:\\n${instructions.trim()}\\n`\n : '';\n const prompt = `Summarize the following conversation in 2-3 concise sentences. Focus on:\n1. What the user was trying to accomplish\n2. Key decisions, outcomes, or solutions\n3. Any important context that should be preserved\n${extra}\nConversation:\n${conversation}\n\nSummary:`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 30000);\n\n try {\n const summaryMessage: UserMessage = { role: 'user', content: prompt, timestamp: Date.now() };\n const result = await complete(this.model, { \n messages: [summaryMessage]\n }, {\n maxTokens: this.config.summaryMaxTokens,\n temperature: 0.3,\n signal: controller.signal as any,\n });\n\n const text = Array.isArray(result.content)\n ? result.content.filter((c: any) => c.type === 'text').map((c: any) => c.text).join('')\n : '';\n\n return text.trim();\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('LLM summarization timed out after 30 seconds');\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private formatMessages(messages: AgentMessage[]): string {\n return messages\n .map(m => {\n const role = m.role;\n const raw = readAgentMessageContent(m);\n const content = typeof raw === 'string'\n ? raw\n : (raw as Array<{ type: string; text?: string }>).filter(c => c.type === 'text').map(c => c.text || '').join('\\n');\n return `[${role}]: ${content}`;\n })\n .join('\\n\\n');\n }\n\n private extractiveSummary(messages: AgentMessage[]): string {\n const userMessages = messages\n .filter(m => m.role === 'user')\n .slice(-5)\n .map(m => {\n const raw = readAgentMessageContent(m);\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) {\n return raw\n .filter(c => c.type === 'text')\n .map(c => (c as { text?: string }).text || '')\n .join('\\n');\n }\n return '';\n })\n .filter(t => t.length > 0)\n .join('; ');\n\n return `Previous conversation covered: ${userMessages.slice(0, 300)}...`;\n }\n\n estimateTotalTokens(messages: AgentMessage[]): number {\n return messages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);\n }\n\n applyCompaction(\n messages: AgentMessage[],\n result: CompactionResult\n ): AgentMessage[] {\n if (!result.compacted || !result.summary) {\n return messages;\n }\n\n const summaryMessage: AgentMessage & { usage?: MessageUsage } = {\n role: 'user',\n content: [{ type: 'text', text: `[Previous conversation summary]: ${result.summary}` }],\n timestamp: Date.now(),\n };\n\n if (result.compactedUsage) {\n summaryMessage.usage = result.compactedUsage;\n }\n\n const keptMessages = messages.slice(result.firstKeptIndex);\n return [summaryMessage, ...keptMessages];\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"compaction.js","names":[],"sources":["../../../../src/agent/memory/compaction.ts"],"sourcesContent":["import type { AgentMessage } from '@earendil-works/pi-agent-core';\nimport { type Model, type Api, type UserMessage } from '@earendil-works/pi-ai/compat';\n\nimport { completeWithResolvedCredentials } from '../../providers/model-call.js';\nimport { readAgentMessageContent } from './agent-message-access.js';\nimport { generateStructuredSummary, formatSummaryAsText, type ConversationSummary } from './summary-generator.js';\n\nexport interface CompactionResult {\n summary: string;\n firstKeptIndex: number;\n tokensBefore: number;\n tokensAfter: number;\n compacted: boolean;\n structuredSummary?: ConversationSummary;\n compactedUsage?: {\n input: number;\n output: number;\n total: number;\n cost?: number;\n };\n}\n\nexport interface CompactionConfig {\n enabled: boolean;\n mode: 'extractive' | 'abstractive' | 'structured';\n reserveTokens: number;\n triggerThreshold: number;\n minMessagesBeforeCompact: number;\n keepRecentMessages: number;\n summaryMaxTokens: number;\n evictionWindow: number;\n retentionWindow: number;\n preserveReasoning: boolean;\n accumulateUsage: boolean;\n}\n\nconst DEFAULT_CONFIG: CompactionConfig = {\n enabled: true,\n mode: 'abstractive',\n reserveTokens: 8000,\n triggerThreshold: 0.8,\n minMessagesBeforeCompact: 10,\n keepRecentMessages: 10,\n summaryMaxTokens: 500,\n evictionWindow: 0.2,\n retentionWindow: 6,\n preserveReasoning: true,\n accumulateUsage: true,\n};\n\nfunction estimateTokens(text: string): number {\n return Math.ceil(text.length / 4);\n}\n\nfunction estimateMessageTokens(msg: AgentMessage): number {\n let text = '';\n const raw = readAgentMessageContent(msg);\n\n if (typeof raw === 'string') {\n text = raw;\n } else if (Array.isArray(raw)) {\n text = raw\n .filter(c => c.type === 'text')\n .map(c => (c as { text?: string }).text || '')\n .join('\\n');\n }\n \n return estimateTokens(text) + 10;\n}\n\n// Internal: Reasoning extraction utilities\ninterface ReasoningDetails {\n thinking?: string;\n signature?: string;\n}\n\nfunction extractLastReasoning(messages: AgentMessage[]): ReasoningDetails | null {\n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n if (msg.role === 'assistant') {\n const rd = (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details;\n if (rd && (rd.thinking || rd.signature)) {\n return rd;\n }\n }\n }\n return null;\n}\n\n// Internal: Inject reasoning into first assistant message\nfunction injectReasoningIntoFirstAssistant(\n messages: AgentMessage[],\n reasoning: ReasoningDetails\n): void {\n for (const msg of messages) {\n if (msg.role === 'assistant') {\n const existing = (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details;\n if (!existing || (!existing.thinking && !existing.signature)) {\n (msg as unknown as { reasoning_details?: ReasoningDetails }).reasoning_details = reasoning;\n }\n break;\n }\n }\n}\n\n// Internal: Message usage tracking\ninterface MessageUsage {\n input: number;\n output: number;\n total: number;\n cost?: number;\n}\n\nexport function accumulateUsage(messages: AgentMessage[]): MessageUsage | undefined {\n let totalInput = 0;\n let totalOutput = 0;\n let totalCost = 0;\n let hasUsage = false;\n\n for (const msg of messages) {\n const usage = (msg as unknown as { usage?: MessageUsage }).usage;\n if (usage) {\n hasUsage = true;\n totalInput += usage.input || 0;\n totalOutput += usage.output || 0;\n totalCost += usage.cost || 0;\n }\n }\n\n if (!hasUsage) return undefined;\n\n return {\n input: totalInput,\n output: totalOutput,\n total: totalInput + totalOutput,\n cost: totalCost > 0 ? totalCost : undefined,\n };\n}\n\n// Internal: Droppable message filtering\ntype DroppableMessage = AgentMessage & {\n droppable?: boolean;\n};\n\nfunction filterDroppableMessages(messages: AgentMessage[]): AgentMessage[] {\n return messages.filter(msg => !(msg as DroppableMessage).droppable);\n}\n\nfunction findNthTurnFromEnd(messages: AgentMessage[], n: number): number {\n if (n <= 0) return messages.length;\n \n let turnsFound = 0;\n let lastRole: string | null = null;\n \n for (let i = messages.length - 1; i >= 0; i--) {\n const msg = messages[i];\n \n if (msg.role === 'user' && lastRole !== 'user') {\n turnsFound++;\n if (turnsFound === n) {\n return i;\n }\n }\n lastRole = msg.role;\n }\n \n return 0;\n}\n\n// Internal: Calculate compaction range\nfunction calculateCompactionRange(\n messages: AgentMessage[],\n config: CompactionConfig\n): { start: number; end: number } | null {\n const totalMessages = messages.length;\n \n if (totalMessages < config.minMessagesBeforeCompact) {\n return null;\n }\n \n const evictionEnd = Math.floor(totalMessages * config.evictionWindow);\n const retentionStart = findNthTurnFromEnd(messages, config.retentionWindow);\n const retentionEnd = retentionStart > 0 ? retentionStart - 1 : 0;\n const compactionEnd = Math.min(evictionEnd, retentionEnd);\n \n if (compactionEnd <= 1) {\n return null;\n }\n \n return { start: 0, end: compactionEnd };\n}\n\nexport class SessionCompactor {\n private config: CompactionConfig;\n \n constructor(\n config?: Partial<CompactionConfig>,\n private model?: Model<Api>\n ) {\n this.config = { ...DEFAULT_CONFIG, ...config };\n }\n\n needsCompaction(\n messages: AgentMessage[],\n contextWindow: number\n ): { needed: boolean; reason: string; usagePercent?: number } {\n if (!this.config.enabled) {\n return { needed: false, reason: 'disabled' };\n }\n\n if (messages.length < this.config.minMessagesBeforeCompact) {\n return { needed: false, reason: 'not_enough_messages' };\n }\n\n const totalTokens = this.estimateTotalTokens(messages);\n const usagePercent = totalTokens / contextWindow;\n\n if (usagePercent > this.config.triggerThreshold) {\n return { \n needed: true, \n reason: 'threshold_exceeded',\n usagePercent \n };\n }\n\n return { needed: false, reason: 'within_threshold' };\n }\n\n async compact(\n messages: AgentMessage[],\n instructions?: string,\n force?: boolean,\n ): Promise<CompactionResult> {\n const effectiveMessages = filterDroppableMessages(messages);\n\n const minRequired = this.config.minMessagesBeforeCompact;\n if (!force && effectiveMessages.length < minRequired) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n if (force && effectiveMessages.length < 2) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n const range = calculateCompactionRange(effectiveMessages, this.config);\n let messagesToSummarize: AgentMessage[];\n let keptMessages: AgentMessage[];\n\n if (range) {\n messagesToSummarize = effectiveMessages.slice(0, range.end);\n keptMessages = effectiveMessages.slice(range.end);\n } else if (force) {\n const keep = Math.min(\n this.config.keepRecentMessages,\n Math.max(1, effectiveMessages.length - 1),\n );\n messagesToSummarize = effectiveMessages.slice(0, effectiveMessages.length - keep);\n keptMessages = effectiveMessages.slice(-keep);\n } else {\n const keepRecent = this.config.keepRecentMessages;\n messagesToSummarize = effectiveMessages.slice(0, -keepRecent);\n keptMessages = effectiveMessages.slice(-keepRecent);\n }\n\n if (messagesToSummarize.length === 0) {\n return {\n summary: '',\n firstKeptIndex: 0,\n tokensBefore: this.estimateTotalTokens(effectiveMessages),\n tokensAfter: this.estimateTotalTokens(effectiveMessages),\n compacted: false,\n };\n }\n\n let preservedReasoning: ReasoningDetails | null = null;\n if (this.config.preserveReasoning) {\n preservedReasoning = extractLastReasoning(messagesToSummarize);\n if (preservedReasoning) {\n injectReasoningIntoFirstAssistant(keptMessages, preservedReasoning);\n }\n }\n\n const summary = await this.generateSummary(messagesToSummarize, instructions);\n const structuredSummary = this.config.mode === 'structured' \n ? generateStructuredSummary(messagesToSummarize)\n : undefined;\n\n const tokensBefore = this.estimateTotalTokens(effectiveMessages);\n const summaryTokens = estimateTokens(summary) + 20;\n const keptTokens = this.estimateTotalTokens(keptMessages);\n const tokensAfter = summaryTokens + keptTokens;\n\n let compactedUsage: MessageUsage | undefined;\n if (this.config.accumulateUsage) {\n compactedUsage = accumulateUsage(messagesToSummarize);\n }\n\n return {\n summary,\n firstKeptIndex: keptMessages.length > 0 ? effectiveMessages.length - keptMessages.length : 0,\n tokensBefore,\n tokensAfter,\n compacted: true,\n structuredSummary,\n compactedUsage,\n };\n }\n\n private async generateSummary(messages: AgentMessage[], instructions?: string): Promise<string> {\n if (this.model && (this.config.mode === 'abstractive' || this.config.mode === 'structured')) {\n try {\n if (this.config.mode === 'structured') {\n const structured = generateStructuredSummary(messages);\n return formatSummaryAsText(structured, true);\n } else {\n return await this.llmAbstractiveSummary(messages, instructions);\n }\n } catch (err) {\n console.warn('[Compactor] LLM summarization failed, falling back to extractive', err);\n }\n }\n\n return this.extractiveSummary(messages);\n }\n\n private async llmAbstractiveSummary(messages: AgentMessage[], instructions?: string): Promise<string> {\n if (!this.model) {\n throw new Error('Model not available');\n }\n\n const conversation = this.formatMessages(messages);\n const extra = instructions?.trim()\n ? `\\nAdditional focus from the user:\\n${instructions.trim()}\\n`\n : '';\n const prompt = `Summarize the following conversation in 2-3 concise sentences. Focus on:\n1. What the user was trying to accomplish\n2. Key decisions, outcomes, or solutions\n3. Any important context that should be preserved\n${extra}\nConversation:\n${conversation}\n\nSummary:`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), 30000);\n\n try {\n const summaryMessage: UserMessage = { role: 'user', content: prompt, timestamp: Date.now() };\n const result = await completeWithResolvedCredentials(this.model, {\n messages: [summaryMessage]\n }, {\n maxTokens: this.config.summaryMaxTokens,\n temperature: 0.3,\n signal: controller.signal as any,\n });\n\n const text = Array.isArray(result.content)\n ? result.content.filter((c: any) => c.type === 'text').map((c: any) => c.text).join('')\n : '';\n\n return text.trim();\n } catch (err) {\n if (err instanceof Error && err.name === 'AbortError') {\n throw new Error('LLM summarization timed out after 30 seconds');\n }\n throw err;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n private formatMessages(messages: AgentMessage[]): string {\n return messages\n .map(m => {\n const role = m.role;\n const raw = readAgentMessageContent(m);\n const content = typeof raw === 'string'\n ? raw\n : (raw as Array<{ type: string; text?: string }>).filter(c => c.type === 'text').map(c => c.text || '').join('\\n');\n return `[${role}]: ${content}`;\n })\n .join('\\n\\n');\n }\n\n private extractiveSummary(messages: AgentMessage[]): string {\n const userMessages = messages\n .filter(m => m.role === 'user')\n .slice(-5)\n .map(m => {\n const raw = readAgentMessageContent(m);\n if (typeof raw === 'string') return raw;\n if (Array.isArray(raw)) {\n return raw\n .filter(c => c.type === 'text')\n .map(c => (c as { text?: string }).text || '')\n .join('\\n');\n }\n return '';\n })\n .filter(t => t.length > 0)\n .join('; ');\n\n return `Previous conversation covered: ${userMessages.slice(0, 300)}...`;\n }\n\n estimateTotalTokens(messages: AgentMessage[]): number {\n return messages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);\n }\n\n applyCompaction(\n messages: AgentMessage[],\n result: CompactionResult\n ): AgentMessage[] {\n if (!result.compacted || !result.summary) {\n return messages;\n }\n\n const summaryMessage: AgentMessage & { usage?: MessageUsage } = {\n role: 'user',\n content: [{ type: 'text', text: `[Previous conversation summary]: ${result.summary}` }],\n timestamp: Date.now(),\n };\n\n if (result.compactedUsage) {\n summaryMessage.usage = result.compactedUsage;\n }\n\n const keptMessages = messages.slice(result.firstKeptIndex);\n return [summaryMessage, ...keptMessages];\n }\n}\n"],"mappings":"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"}
|
|
@@ -28,11 +28,12 @@ function scoreResult(result, now) {
|
|
|
28
28
|
const freshness = Math.exp(-ageDays / 180);
|
|
29
29
|
return Math.max(0, Math.min(1, result.score * .5 + confidence * .15 + result.record.importance * .2 + explicitness * .1 + freshness * .05));
|
|
30
30
|
}
|
|
31
|
-
function citationFor(result) {
|
|
31
|
+
function citationFor(result, requesterAgentId) {
|
|
32
32
|
const base = result.citation.path ?? `${result.citation.providerId}:${result.citation.recordId}`;
|
|
33
|
-
|
|
33
|
+
const ownerPrefix = result.record.scope.agentId !== requesterAgentId ? `shared-from-agent:${result.record.scope.agentId} ` : "";
|
|
34
|
+
if (result.citation.lineStart == null) return `${ownerPrefix}${base}`;
|
|
34
35
|
const end = result.citation.lineEnd && result.citation.lineEnd !== result.citation.lineStart ? `-L${result.citation.lineEnd}` : "";
|
|
35
|
-
return `${base}#L${result.citation.lineStart}${end}`;
|
|
36
|
+
return `${ownerPrefix}${base}#L${result.citation.lineStart}${end}`;
|
|
36
37
|
}
|
|
37
38
|
function prependContext(message, block) {
|
|
38
39
|
if (!block) return message;
|
|
@@ -79,7 +80,10 @@ var UserContextPlanner = class {
|
|
|
79
80
|
const started = Date.now();
|
|
80
81
|
const results = await params.memoryManager.search({
|
|
81
82
|
query,
|
|
82
|
-
scope: {
|
|
83
|
+
scope: {
|
|
84
|
+
agentId: params.agentId,
|
|
85
|
+
sessionKey: params.sessionKey
|
|
86
|
+
},
|
|
83
87
|
maxResults: MAX_RESULTS,
|
|
84
88
|
minScore: .15
|
|
85
89
|
}).catch(() => []);
|
|
@@ -114,7 +118,7 @@ var UserContextPlanner = class {
|
|
|
114
118
|
content,
|
|
115
119
|
score,
|
|
116
120
|
section: sectionFor(result.record),
|
|
117
|
-
citation: citationFor(result)
|
|
121
|
+
citation: citationFor(result, params.agentId)
|
|
118
122
|
});
|
|
119
123
|
}
|
|
120
124
|
const sections = [];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"planner.js","names":[],"sources":["../../../../../src/agent/memory/context/planner.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport { appendMemoryTraceEvent } from '../../../storage/sqlite/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { readAgentMessageContent } from '../agent-message-access.js';\nimport { buildUserContextBlock } from '../context-fence.js';\nimport type { MemoryManager } from '../manager.js';\nimport type { MemoryRecord, MemorySearchResult } from '../types.js';\nimport type {\n PlannedUserContextItem,\n UserContextPlan,\n UserContextRejectionReason,\n} from './types.js';\n\nconst MAX_CONTEXT_CHARS = 6_000;\nconst MAX_RESULTS = 8;\nconst log = createLogger('UserContextPlanner');\n\nfunction sectionFor(record: MemoryRecord): PlannedUserContextItem['section'] {\n if (record.kind === 'boundary') return 'safety';\n if (\n record.kind === 'preference' ||\n record.kind === 'user_profile' ||\n record.kind === 'relationship' ||\n record.kind === 'routine' ||\n record.kind === 'personal_logistics' ||\n record.kind === 'tool_preference'\n ) return 'interaction';\n return 'task';\n}\n\nfunction rejectReason(record: MemoryRecord, now: number): UserContextRejectionReason | undefined {\n if (record.validFrom && Date.parse(record.validFrom) > now) return 'not_yet_valid';\n if (\n (record.validTo && Date.parse(record.validTo) < now) ||\n (record.expiresAt && Date.parse(record.expiresAt) < now)\n ) return 'expired';\n if (record.sensitivity === 'secret' || record.sensitivity === 'regulated') return 'sensitive';\n if (record.disclosurePolicy === 'ask_before_reference') return 'requires_consent';\n return undefined;\n}\n\nfunction scoreResult(result: MemorySearchResult, now: number): number {\n const confidence = result.record.confidence ?? 0.5;\n const explicitness = result.record.explicitness === 'explicit'\n ? 1\n : result.record.explicitness === 'observed' ? 0.65 : 0.4;\n const ageDays = Math.max(0, (now - Date.parse(result.record.updatedAt)) / 86_400_000);\n const freshness = Math.exp(-ageDays / 180);\n return Math.max(0, Math.min(1,\n result.score * 0.5 + confidence * 0.15 + result.record.importance * 0.2 + explicitness * 0.1 + freshness * 0.05,\n ));\n}\n\nfunction citationFor(result: MemorySearchResult): string {\n const base = result.citation.path ?? `${result.citation.providerId}:${result.citation.recordId}`;\n if (result.citation.lineStart == null) return base;\n const end = result.citation.lineEnd && result.citation.lineEnd !== result.citation.lineStart\n ? `-L${result.citation.lineEnd}`\n : '';\n return `${base}#L${result.citation.lineStart}${end}`;\n}\n\nfunction prependContext(message: AgentMessage, block: string): AgentMessage {\n if (!block) return message;\n const prefix = `${block}\\n\\n`;\n const content = readAgentMessageContent(message);\n if (typeof content === 'string') return { ...message, content: prefix + content } as AgentMessage;\n if (Array.isArray(content) && content.length > 0) {\n const first = content[0] as { type?: string; text?: string };\n if (first.type === 'text' && typeof first.text === 'string') {\n const copy = [...content];\n copy[0] = { type: 'text', text: prefix + first.text };\n return { ...message, content: copy } as AgentMessage;\n }\n return { ...message, content: [{ type: 'text' as const, text: prefix }, ...content] } as AgentMessage;\n }\n return message;\n}\n\nexport class UserContextPlanner {\n async plan(params: {\n memoryManager: MemoryManager;\n sessionKey: string;\n query: string;\n userMessage: AgentMessage;\n }): Promise<UserContextPlan> {\n const traceId = randomUUID();\n const query = params.query.trim();\n if (!query) {\n return { traceId, modelMessage: params.userMessage, items: [], rejected: [], estimatedTokens: 0 };\n }\n const started = Date.now();\n const results = await params.memoryManager.search({\n query,\n scope: { sessionKey: params.sessionKey },\n maxResults: MAX_RESULTS,\n minScore: 0.15,\n }).catch(() => []);\n const now = Date.now();\n const rejected: UserContextPlan['rejected'] = [];\n const ranked = results\n .map((result) => ({ result, score: scoreResult(result, now) }))\n .sort((a, b) => b.score - a.score);\n const items: PlannedUserContextItem[] = [];\n let usedChars = 0;\n for (const { result, score } of ranked) {\n const reason = rejectReason(result.record, now) ?? (score < 0.25 ? 'low_score' : undefined);\n if (reason) {\n rejected.push({ recordId: result.record.id, reason });\n continue;\n }\n const content = result.snippet.trim();\n if (usedChars + content.length > MAX_CONTEXT_CHARS) {\n rejected.push({ recordId: result.record.id, reason: 'budget' });\n continue;\n }\n usedChars += content.length;\n items.push({\n recordId: result.record.id,\n content,\n score,\n section: sectionFor(result.record),\n citation: citationFor(result),\n });\n }\n const sections: string[] = [];\n for (const [section, title] of [['safety', 'Boundaries'], ['task', 'Relevant facts'], ['interaction', 'Interaction preferences']] as const) {\n const sectionItems = items.filter((item) => item.section === section);\n if (sectionItems.length > 0) {\n sections.push(`${title}:\\n${sectionItems.map((item) => `- ${item.content}\\n Source: ${item.citation}`).join('\\n')}`);\n }\n }\n const block = buildUserContextBlock(sections.join('\\n\\n'));\n try {\n appendMemoryTraceEvent({\n traceId,\n phase: 'inject',\n providerId: 'user-understanding',\n sessionKey: params.sessionKey,\n request: { query, rejected },\n resultCount: items.length,\n selectedRecordIds: items.map((item) => item.recordId),\n durationMs: Date.now() - started,\n });\n } catch (err) {\n log.debug({ err, traceId, sessionKey: params.sessionKey }, 'Context plan trace was not persisted');\n }\n return {\n traceId,\n modelMessage: prependContext(params.userMessage, block),\n items,\n rejected,\n estimatedTokens: Math.ceil(block.length / 4),\n };\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"planner.js","names":[],"sources":["../../../../../src/agent/memory/context/planner.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type { AgentMessage } from '@earendil-works/pi-agent-core';\n\nimport { appendMemoryTraceEvent } from '../../../storage/sqlite/index.js';\nimport { createLogger } from '../../../utils/logger.js';\nimport { readAgentMessageContent } from '../agent-message-access.js';\nimport { buildUserContextBlock } from '../context-fence.js';\nimport type { MemoryManager } from '../manager.js';\nimport type { MemoryRecord, MemorySearchResult } from '../types.js';\nimport type {\n PlannedUserContextItem,\n UserContextPlan,\n UserContextRejectionReason,\n} from './types.js';\n\nconst MAX_CONTEXT_CHARS = 6_000;\nconst MAX_RESULTS = 8;\nconst log = createLogger('UserContextPlanner');\n\nfunction sectionFor(record: MemoryRecord): PlannedUserContextItem['section'] {\n if (record.kind === 'boundary') return 'safety';\n if (\n record.kind === 'preference' ||\n record.kind === 'user_profile' ||\n record.kind === 'relationship' ||\n record.kind === 'routine' ||\n record.kind === 'personal_logistics' ||\n record.kind === 'tool_preference'\n ) return 'interaction';\n return 'task';\n}\n\nfunction rejectReason(record: MemoryRecord, now: number): UserContextRejectionReason | undefined {\n if (record.validFrom && Date.parse(record.validFrom) > now) return 'not_yet_valid';\n if (\n (record.validTo && Date.parse(record.validTo) < now) ||\n (record.expiresAt && Date.parse(record.expiresAt) < now)\n ) return 'expired';\n if (record.sensitivity === 'secret' || record.sensitivity === 'regulated') return 'sensitive';\n if (record.disclosurePolicy === 'ask_before_reference') return 'requires_consent';\n return undefined;\n}\n\nfunction scoreResult(result: MemorySearchResult, now: number): number {\n const confidence = result.record.confidence ?? 0.5;\n const explicitness = result.record.explicitness === 'explicit'\n ? 1\n : result.record.explicitness === 'observed' ? 0.65 : 0.4;\n const ageDays = Math.max(0, (now - Date.parse(result.record.updatedAt)) / 86_400_000);\n const freshness = Math.exp(-ageDays / 180);\n return Math.max(0, Math.min(1,\n result.score * 0.5 + confidence * 0.15 + result.record.importance * 0.2 + explicitness * 0.1 + freshness * 0.05,\n ));\n}\n\nfunction citationFor(result: MemorySearchResult, requesterAgentId: string): string {\n const base = result.citation.path ?? `${result.citation.providerId}:${result.citation.recordId}`;\n const ownerPrefix = result.record.scope.agentId !== requesterAgentId\n ? `shared-from-agent:${result.record.scope.agentId} `\n : '';\n if (result.citation.lineStart == null) return `${ownerPrefix}${base}`;\n const end = result.citation.lineEnd && result.citation.lineEnd !== result.citation.lineStart\n ? `-L${result.citation.lineEnd}`\n : '';\n return `${ownerPrefix}${base}#L${result.citation.lineStart}${end}`;\n}\n\nfunction prependContext(message: AgentMessage, block: string): AgentMessage {\n if (!block) return message;\n const prefix = `${block}\\n\\n`;\n const content = readAgentMessageContent(message);\n if (typeof content === 'string') return { ...message, content: prefix + content } as AgentMessage;\n if (Array.isArray(content) && content.length > 0) {\n const first = content[0] as { type?: string; text?: string };\n if (first.type === 'text' && typeof first.text === 'string') {\n const copy = [...content];\n copy[0] = { type: 'text', text: prefix + first.text };\n return { ...message, content: copy } as AgentMessage;\n }\n return { ...message, content: [{ type: 'text' as const, text: prefix }, ...content] } as AgentMessage;\n }\n return message;\n}\n\nexport class UserContextPlanner {\n async plan(params: {\n memoryManager: MemoryManager;\n agentId: string;\n sessionKey: string;\n query: string;\n userMessage: AgentMessage;\n }): Promise<UserContextPlan> {\n const traceId = randomUUID();\n const query = params.query.trim();\n if (!query) {\n return { traceId, modelMessage: params.userMessage, items: [], rejected: [], estimatedTokens: 0 };\n }\n const started = Date.now();\n const results = await params.memoryManager.search({\n query,\n scope: { agentId: params.agentId, sessionKey: params.sessionKey },\n maxResults: MAX_RESULTS,\n minScore: 0.15,\n }).catch(() => []);\n const now = Date.now();\n const rejected: UserContextPlan['rejected'] = [];\n const ranked = results\n .map((result) => ({ result, score: scoreResult(result, now) }))\n .sort((a, b) => b.score - a.score);\n const items: PlannedUserContextItem[] = [];\n let usedChars = 0;\n for (const { result, score } of ranked) {\n const reason = rejectReason(result.record, now) ?? (score < 0.25 ? 'low_score' : undefined);\n if (reason) {\n rejected.push({ recordId: result.record.id, reason });\n continue;\n }\n const content = result.snippet.trim();\n if (usedChars + content.length > MAX_CONTEXT_CHARS) {\n rejected.push({ recordId: result.record.id, reason: 'budget' });\n continue;\n }\n usedChars += content.length;\n items.push({\n recordId: result.record.id,\n content,\n score,\n section: sectionFor(result.record),\n citation: citationFor(result, params.agentId),\n });\n }\n const sections: string[] = [];\n for (const [section, title] of [['safety', 'Boundaries'], ['task', 'Relevant facts'], ['interaction', 'Interaction preferences']] as const) {\n const sectionItems = items.filter((item) => item.section === section);\n if (sectionItems.length > 0) {\n sections.push(`${title}:\\n${sectionItems.map((item) => `- ${item.content}\\n Source: ${item.citation}`).join('\\n')}`);\n }\n }\n const block = buildUserContextBlock(sections.join('\\n\\n'));\n try {\n appendMemoryTraceEvent({\n traceId,\n phase: 'inject',\n providerId: 'user-understanding',\n sessionKey: params.sessionKey,\n request: { query, rejected },\n resultCount: items.length,\n selectedRecordIds: items.map((item) => item.recordId),\n durationMs: Date.now() - started,\n });\n } catch (err) {\n log.debug({ err, traceId, sessionKey: params.sessionKey }, 'Context plan trace was not persisted');\n }\n return {\n traceId,\n modelMessage: prependContext(params.userMessage, block),\n items,\n rejected,\n estimatedTokens: Math.ceil(block.length / 4),\n };\n }\n}\n"],"mappings":"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"}
|
|
@@ -2,4 +2,4 @@ import type { Config } from '../../config/schema.js';
|
|
|
2
2
|
import { BuiltinMemoryStore } from './builtin-memory-store.js';
|
|
3
3
|
import { MemoryManager } from './manager.js';
|
|
4
4
|
export type MemoryProviderId = 'none' | 'stub';
|
|
5
|
-
export declare function createMemoryManagerFromConfig(
|
|
5
|
+
export declare function createMemoryManagerFromConfig(workspaceDir: string, store: BuiltinMemoryStore, config: Config | undefined, agentId?: string): MemoryManager;
|
|
@@ -1,25 +1,28 @@
|
|
|
1
1
|
import { init_agent_scope, resolveAgentIdForWorkspacePath } from "../agent-scope.js";
|
|
2
2
|
import { resolveEffectiveAgentManifestForAgent } from "../../config/agent-profile.js";
|
|
3
3
|
import { isMemorySubsystemEnabled } from "./memory-config.js";
|
|
4
|
+
import { resolveMemoryAccessPolicy } from "./access-policy.js";
|
|
4
5
|
import { BuiltinMemoryProvider } from "./builtin-provider.js";
|
|
5
6
|
import { MemoryManager } from "./manager.js";
|
|
6
7
|
import { loadMemoryPluginProviders } from "./plugin-discovery.js";
|
|
7
8
|
//#region src/agent/memory/create-memory-manager.ts
|
|
8
9
|
init_agent_scope();
|
|
9
|
-
function createMemoryManagerFromConfig(
|
|
10
|
-
const routing = resolveMemoryManagerOptions(
|
|
10
|
+
function createMemoryManagerFromConfig(workspaceDir, store, config, agentId) {
|
|
11
|
+
const routing = resolveMemoryManagerOptions(workspaceDir, config, agentId);
|
|
12
|
+
const accessPolicy = config && agentId ? resolveMemoryAccessPolicy(config, agentId) : void 0;
|
|
11
13
|
const enabled = isMemorySubsystemEnabled(config);
|
|
12
14
|
const mgr = new MemoryManager({
|
|
13
15
|
...routing,
|
|
16
|
+
accessPolicy,
|
|
14
17
|
...enabled ? { loadProviders: () => loadMemoryPluginProviders({ config }) } : {}
|
|
15
18
|
});
|
|
16
|
-
mgr.addProvider(new BuiltinMemoryProvider(store));
|
|
19
|
+
mgr.addProvider(new BuiltinMemoryProvider(store, accessPolicy));
|
|
17
20
|
if (!enabled) return mgr;
|
|
18
21
|
return mgr;
|
|
19
22
|
}
|
|
20
|
-
function resolveMemoryManagerOptions(workspaceDir, config) {
|
|
23
|
+
function resolveMemoryManagerOptions(workspaceDir, config, requestedAgentId) {
|
|
21
24
|
if (!config) return {};
|
|
22
|
-
const providerRouting = resolveEffectiveAgentManifestForAgent(config, resolveAgentIdForWorkspacePath(config, workspaceDir)).memory.providerRouting;
|
|
25
|
+
const providerRouting = resolveEffectiveAgentManifestForAgent(config, requestedAgentId?.trim() || resolveAgentIdForWorkspacePath(config, workspaceDir)).memory.providerRouting;
|
|
23
26
|
if (!providerRouting) return {};
|
|
24
27
|
return {
|
|
25
28
|
searchStrategy: providerRouting.searchStrategy,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"create-memory-manager.js","names":[],"sources":["../../../../src/agent/memory/create-memory-manager.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { resolveEffectiveAgentManifestForAgent } from '../../config/agent-profile.js';\nimport { resolveAgentIdForWorkspacePath } from '../agent-scope.js';\nimport { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport { BuiltinMemoryProvider } from './builtin-provider.js';\nimport { isMemorySubsystemEnabled } from './memory-config.js';\nimport { MemoryManager, type MemoryManagerOptions } from './manager.js';\nimport { loadMemoryPluginProviders } from './plugin-discovery.js';\n\nexport type MemoryProviderId = 'none' | 'stub';\n\nexport function createMemoryManagerFromConfig(\n
|
|
1
|
+
{"version":3,"file":"create-memory-manager.js","names":[],"sources":["../../../../src/agent/memory/create-memory-manager.ts"],"sourcesContent":["import type { Config } from '../../config/schema.js';\nimport { resolveEffectiveAgentManifestForAgent } from '../../config/agent-profile.js';\nimport { resolveAgentIdForWorkspacePath } from '../agent-scope.js';\nimport { resolveMemoryAccessPolicy } from './access-policy.js';\nimport { BuiltinMemoryStore } from './builtin-memory-store.js';\nimport { BuiltinMemoryProvider } from './builtin-provider.js';\nimport { isMemorySubsystemEnabled } from './memory-config.js';\nimport { MemoryManager, type MemoryManagerOptions } from './manager.js';\nimport { loadMemoryPluginProviders } from './plugin-discovery.js';\n\nexport type MemoryProviderId = 'none' | 'stub';\n\nexport function createMemoryManagerFromConfig(\n workspaceDir: string,\n store: BuiltinMemoryStore,\n config: Config | undefined,\n agentId?: string,\n): MemoryManager {\n const routing = resolveMemoryManagerOptions(workspaceDir, config, agentId);\n const accessPolicy = config && agentId ? resolveMemoryAccessPolicy(config, agentId) : undefined;\n const enabled = isMemorySubsystemEnabled(config);\n const mgr = new MemoryManager({\n ...routing,\n accessPolicy,\n ...(enabled ? { loadProviders: () => loadMemoryPluginProviders({ config }) } : {}),\n });\n mgr.addProvider(new BuiltinMemoryProvider(\n store,\n accessPolicy,\n ));\n\n if (!enabled) {\n return mgr;\n }\n\n return mgr;\n}\n\nfunction resolveMemoryManagerOptions(\n workspaceDir: string,\n config: Config | undefined,\n requestedAgentId?: string,\n): Omit<MemoryManagerOptions, 'loadProviders'> {\n if (!config) return {};\n const agentId = requestedAgentId?.trim() || resolveAgentIdForWorkspacePath(config, workspaceDir);\n const manifest = resolveEffectiveAgentManifestForAgent(config, agentId);\n const providerRouting = manifest.memory.providerRouting;\n if (!providerRouting) return {};\n return {\n searchStrategy: providerRouting.searchStrategy,\n writeStrategy: providerRouting.writeStrategy,\n writePolicy: {\n allowExternalWrites: providerRouting.allowExternalWrites,\n allowedProviderIds: providerRouting.allowedProviderIds,\n autoWriteKinds: providerRouting.autoWriteKinds,\n },\n };\n}\n"],"mappings":";;;;;;;;kBAEmE;AAUnE,SAAgB,8BACd,cACA,OACA,QACA,SACe;CACf,MAAM,UAAU,4BAA4B,cAAc,QAAQ,QAAQ;CAC1E,MAAM,eAAe,UAAU,UAAU,0BAA0B,QAAQ,QAAQ,GAAG,KAAA;CACtF,MAAM,UAAU,yBAAyB,OAAO;CAChD,MAAM,MAAM,IAAI,cAAc;EAC5B,GAAG;EACH;EACA,GAAI,UAAU,EAAE,qBAAqB,0BAA0B,EAAE,QAAQ,CAAC,EAAE,GAAG,EAAE;EAClF,CAAC;AACF,KAAI,YAAY,IAAI,sBAClB,OACA,aACD,CAAC;AAEF,KAAI,CAAC,QACH,QAAO;AAGT,QAAO;;AAGT,SAAS,4BACP,cACA,QACA,kBAC6C;AAC7C,KAAI,CAAC,OAAQ,QAAO,EAAE;CAGtB,MAAM,kBADW,sCAAsC,QADvC,kBAAkB,MAAM,IAAI,+BAA+B,QAAQ,aAAa,CAEhE,CAAC,OAAO;AACxC,KAAI,CAAC,gBAAiB,QAAO,EAAE;AAC/B,QAAO;EACL,gBAAgB,gBAAgB;EAChC,eAAe,gBAAgB;EAC/B,aAAa;GACX,qBAAqB,gBAAgB;GACrC,oBAAoB,gBAAgB;GACpC,gBAAgB,gBAAgB;GACjC;EACF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Config } from '../../../config/schema.js';
|
|
2
|
+
import { type MemoryWriteCheckResult } from '../../../agent-runtime/memory-runtime.js';
|
|
2
3
|
import { type DreamingPhaseId } from './constants.js';
|
|
3
4
|
export type DreamingLightConfig = {
|
|
4
5
|
enabled: boolean;
|
|
@@ -26,6 +27,7 @@ export type DreamingRemConfig = {
|
|
|
26
27
|
};
|
|
27
28
|
export type DreamingResolvedConfig = {
|
|
28
29
|
enabled: boolean;
|
|
30
|
+
promotionWritePolicy: MemoryWriteCheckResult;
|
|
29
31
|
frequency: string;
|
|
30
32
|
timezone?: string;
|
|
31
33
|
phases: {
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { init_agent_scope, resolveDefaultAgentId } from "../../agent-scope.js";
|
|
2
2
|
import { resolveEffectiveAgentManifestForAgent } from "../../../config/agent-profile.js";
|
|
3
3
|
import { DEFAULT_DEEP_CRON, DEFAULT_LIGHT_CRON, DEFAULT_REM_CRON } from "./constants.js";
|
|
4
|
+
import { buildMemoryRuntime } from "../../../agent-runtime/memory-runtime.js";
|
|
4
5
|
//#region src/agent/memory/dreaming/config.ts
|
|
5
6
|
init_agent_scope();
|
|
6
7
|
function clampScore(value, fallback) {
|
|
@@ -31,6 +32,16 @@ function resolveDreamingConfig(cfg, requestedAgentId) {
|
|
|
31
32
|
const manifest = cfg && agentId ? resolveEffectiveAgentManifestForAgent(cfg, agentId) : void 0;
|
|
32
33
|
const dreaming = manifest?.memory.dreaming;
|
|
33
34
|
const enabled = dreaming?.enabled === true && manifest?.memory.mode !== "off";
|
|
35
|
+
const promotionWritePolicy = manifest ? buildMemoryRuntime(manifest).checkWrite({
|
|
36
|
+
target: "curated",
|
|
37
|
+
content: "Dreaming automatic memory promotion",
|
|
38
|
+
source: "dreaming",
|
|
39
|
+
confidence: 1,
|
|
40
|
+
sensitive: false
|
|
41
|
+
}) : {
|
|
42
|
+
decision: "deny",
|
|
43
|
+
reason: "agent memory manifest is unavailable"
|
|
44
|
+
};
|
|
34
45
|
const frequency = trimmedStringOr(dreaming?.frequency, DEFAULT_DEEP_CRON);
|
|
35
46
|
const timezone = optionalTrimmedString(dreaming?.timezone);
|
|
36
47
|
const lightRaw = dreaming?.phases?.light ?? {};
|
|
@@ -43,7 +54,7 @@ function resolveDreamingConfig(cfg, requestedAgentId) {
|
|
|
43
54
|
};
|
|
44
55
|
const deepRaw = dreaming?.phases?.deep ?? {};
|
|
45
56
|
const deep = {
|
|
46
|
-
enabled: enabled && deepRaw?.enabled !== false,
|
|
57
|
+
enabled: enabled && deepRaw?.enabled !== false && promotionWritePolicy.decision === "allow",
|
|
47
58
|
cron: trimmedStringOr(deepRaw?.cron, frequency),
|
|
48
59
|
minScore: clampScore(Number(deepRaw?.minScore), .8),
|
|
49
60
|
minRecallCount: toPositiveInt(deepRaw?.minRecallCount, 3),
|
|
@@ -62,6 +73,7 @@ function resolveDreamingConfig(cfg, requestedAgentId) {
|
|
|
62
73
|
};
|
|
63
74
|
return {
|
|
64
75
|
enabled,
|
|
76
|
+
promotionWritePolicy,
|
|
65
77
|
frequency,
|
|
66
78
|
...timezone ? { timezone } : {},
|
|
67
79
|
phases: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/config.ts"],"sourcesContent":["import type { Config } from '../../../config/schema.js';\nimport { resolveDefaultAgentId } from '../../agent-scope.js';\nimport { resolveEffectiveAgentManifestForAgent } from '../../../config/agent-profile.js';\nimport {\n DEFAULT_DEEP_CRON,\n DEFAULT_LIGHT_CRON,\n DEFAULT_MAX_AGE_DAYS,\n DEFAULT_RECENCY_HALF_LIFE_DAYS,\n DEFAULT_REM_CRON,\n type DreamingPhaseId,\n} from './constants.js';\n\n// ── Phase config types ─────────────────────────────────────────────────\n\nexport type DreamingLightConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n dedupeSimilarity: number;\n};\n\nexport type DreamingDeepConfig = {\n enabled: boolean;\n cron: string;\n minScore: number;\n minRecallCount: number;\n minUniqueQueries: number;\n limit: number;\n recencyHalfLifeDays: number;\n maxAgeDays: number;\n};\n\nexport type DreamingRemConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n minPatternStrength: number;\n};\n\nexport type DreamingResolvedConfig = {\n enabled: boolean;\n frequency: string;\n timezone?: string;\n phases: {\n light: DreamingLightConfig;\n deep: DreamingDeepConfig;\n rem: DreamingRemConfig;\n };\n deep: DreamingDeepConfig;\n};\n\n// ── Helpers ────────────────────────────────────────────────────────────\n\nfunction clampScore(value: number, fallback: number): number {\n if (!Number.isFinite(value)) return fallback;\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toPositiveInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored > 0 ? floored : fallback;\n}\n\nfunction toNonNegInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored >= 0 ? floored : fallback;\n}\n\nfunction trimmedStringOr(value: unknown, fallback: string): string {\n return typeof value === 'string' && value.trim() ? value.trim() : fallback;\n}\n\nfunction optionalTrimmedString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\n// ── Resolver ───────────────────────────────────────────────────────────\n\n/** Resolve the full three-phase dreaming config from an agent manifest. */\nexport function resolveDreamingConfig(cfg: Config | undefined, requestedAgentId?: string | null): DreamingResolvedConfig {\n const agentId = cfg ? (requestedAgentId?.trim() || resolveDefaultAgentId(cfg)) : undefined;\n const manifest = cfg && agentId ? resolveEffectiveAgentManifestForAgent(cfg, agentId) : undefined;\n const dreaming = manifest?.memory.dreaming;\n const enabled = dreaming?.enabled === true && manifest?.memory.mode !== 'off';\n\n const frequency = trimmedStringOr(dreaming?.frequency, DEFAULT_DEEP_CRON);\n const timezone = optionalTrimmedString(dreaming?.timezone);\n\n // ── Light phase ────────────────────────────────────────────────────\n const lightRaw = dreaming?.phases?.light ?? {};\n const light: DreamingLightConfig = {\n enabled: enabled && lightRaw?.enabled !== false,\n cron: trimmedStringOr(lightRaw?.cron, DEFAULT_LIGHT_CRON),\n lookbackDays: toPositiveInt(lightRaw?.lookbackDays, 2),\n limit: toNonNegInt(lightRaw?.limit, 100),\n dedupeSimilarity: clampScore(Number(lightRaw?.dedupeSimilarity), 0.9),\n };\n\n // ── Deep phase ─────────────────────────────────────────────────────\n const deepRaw = dreaming?.phases?.deep ?? {};\n const deep: DreamingDeepConfig = {\n enabled: enabled && deepRaw?.enabled !== false,\n cron: trimmedStringOr(deepRaw?.cron, frequency),\n minScore: clampScore(Number(deepRaw?.minScore), 0.8),\n minRecallCount: toPositiveInt(deepRaw?.minRecallCount, 3),\n minUniqueQueries: toPositiveInt(deepRaw?.minUniqueQueries, 3),\n limit: toNonNegInt(deepRaw?.limit, 10),\n recencyHalfLifeDays: toPositiveInt(deepRaw?.recencyHalfLifeDays, DEFAULT_RECENCY_HALF_LIFE_DAYS),\n maxAgeDays: toPositiveInt(deepRaw?.maxAgeDays, DEFAULT_MAX_AGE_DAYS),\n };\n\n // ── REM phase ──────────────────────────────────────────────────────\n const remRaw = dreaming?.phases?.rem ?? {};\n const rem: DreamingRemConfig = {\n enabled: enabled && remRaw?.enabled !== false,\n cron: trimmedStringOr(remRaw?.cron, DEFAULT_REM_CRON),\n lookbackDays: toPositiveInt(remRaw?.lookbackDays, 7),\n limit: toNonNegInt(remRaw?.limit, 10),\n minPatternStrength: clampScore(Number(remRaw?.minPatternStrength), 0.75),\n };\n\n return {\n enabled,\n frequency,\n ...(timezone ? { timezone } : {}),\n phases: { light, deep, rem },\n deep,\n };\n}\n\n/** Get the cron expression for a specific phase from resolved config. */\nexport function getPhaseCron(config: DreamingResolvedConfig, phase: DreamingPhaseId): string {\n return config.phases[phase].cron;\n}\n\n/** Check if a specific phase is enabled (global + phase-level). */\nexport function isPhaseEnabled(config: DreamingResolvedConfig, phase: DreamingPhaseId): boolean {\n return config.enabled && config.phases[phase].enabled;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","names":[],"sources":["../../../../../src/agent/memory/dreaming/config.ts"],"sourcesContent":["import type { Config } from '../../../config/schema.js';\nimport { buildMemoryRuntime, type MemoryWriteCheckResult } from '../../../agent-runtime/memory-runtime.js';\nimport { resolveDefaultAgentId } from '../../agent-scope.js';\nimport { resolveEffectiveAgentManifestForAgent } from '../../../config/agent-profile.js';\nimport {\n DEFAULT_DEEP_CRON,\n DEFAULT_LIGHT_CRON,\n DEFAULT_MAX_AGE_DAYS,\n DEFAULT_RECENCY_HALF_LIFE_DAYS,\n DEFAULT_REM_CRON,\n type DreamingPhaseId,\n} from './constants.js';\n\n// ── Phase config types ─────────────────────────────────────────────────\n\nexport type DreamingLightConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n dedupeSimilarity: number;\n};\n\nexport type DreamingDeepConfig = {\n enabled: boolean;\n cron: string;\n minScore: number;\n minRecallCount: number;\n minUniqueQueries: number;\n limit: number;\n recencyHalfLifeDays: number;\n maxAgeDays: number;\n};\n\nexport type DreamingRemConfig = {\n enabled: boolean;\n cron: string;\n lookbackDays: number;\n limit: number;\n minPatternStrength: number;\n};\n\nexport type DreamingResolvedConfig = {\n enabled: boolean;\n promotionWritePolicy: MemoryWriteCheckResult;\n frequency: string;\n timezone?: string;\n phases: {\n light: DreamingLightConfig;\n deep: DreamingDeepConfig;\n rem: DreamingRemConfig;\n };\n deep: DreamingDeepConfig;\n};\n\n// ── Helpers ────────────────────────────────────────────────────────────\n\nfunction clampScore(value: number, fallback: number): number {\n if (!Number.isFinite(value)) return fallback;\n return Math.max(0, Math.min(1, value));\n}\n\nfunction toPositiveInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored > 0 ? floored : fallback;\n}\n\nfunction toNonNegInt(value: unknown, fallback: number): number {\n const num = typeof value === 'string' ? Number(value) : Number(value);\n if (!Number.isFinite(num)) return fallback;\n const floored = Math.floor(num);\n return floored >= 0 ? floored : fallback;\n}\n\nfunction trimmedStringOr(value: unknown, fallback: string): string {\n return typeof value === 'string' && value.trim() ? value.trim() : fallback;\n}\n\nfunction optionalTrimmedString(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim() ? value.trim() : undefined;\n}\n\n// ── Resolver ───────────────────────────────────────────────────────────\n\n/** Resolve the full three-phase dreaming config from an agent manifest. */\nexport function resolveDreamingConfig(cfg: Config | undefined, requestedAgentId?: string | null): DreamingResolvedConfig {\n const agentId = cfg ? (requestedAgentId?.trim() || resolveDefaultAgentId(cfg)) : undefined;\n const manifest = cfg && agentId ? resolveEffectiveAgentManifestForAgent(cfg, agentId) : undefined;\n const dreaming = manifest?.memory.dreaming;\n const enabled = dreaming?.enabled === true && manifest?.memory.mode !== 'off';\n const promotionWritePolicy = manifest\n ? buildMemoryRuntime(manifest).checkWrite({\n target: 'curated',\n content: 'Dreaming automatic memory promotion',\n source: 'dreaming',\n confidence: 1,\n sensitive: false,\n })\n : { decision: 'deny' as const, reason: 'agent memory manifest is unavailable' };\n\n const frequency = trimmedStringOr(dreaming?.frequency, DEFAULT_DEEP_CRON);\n const timezone = optionalTrimmedString(dreaming?.timezone);\n\n // ── Light phase ────────────────────────────────────────────────────\n const lightRaw = dreaming?.phases?.light ?? {};\n const light: DreamingLightConfig = {\n enabled: enabled && lightRaw?.enabled !== false,\n cron: trimmedStringOr(lightRaw?.cron, DEFAULT_LIGHT_CRON),\n lookbackDays: toPositiveInt(lightRaw?.lookbackDays, 2),\n limit: toNonNegInt(lightRaw?.limit, 100),\n dedupeSimilarity: clampScore(Number(lightRaw?.dedupeSimilarity), 0.9),\n };\n\n // ── Deep phase ─────────────────────────────────────────────────────\n const deepRaw = dreaming?.phases?.deep ?? {};\n const deep: DreamingDeepConfig = {\n enabled: enabled && deepRaw?.enabled !== false && promotionWritePolicy.decision === 'allow',\n cron: trimmedStringOr(deepRaw?.cron, frequency),\n minScore: clampScore(Number(deepRaw?.minScore), 0.8),\n minRecallCount: toPositiveInt(deepRaw?.minRecallCount, 3),\n minUniqueQueries: toPositiveInt(deepRaw?.minUniqueQueries, 3),\n limit: toNonNegInt(deepRaw?.limit, 10),\n recencyHalfLifeDays: toPositiveInt(deepRaw?.recencyHalfLifeDays, DEFAULT_RECENCY_HALF_LIFE_DAYS),\n maxAgeDays: toPositiveInt(deepRaw?.maxAgeDays, DEFAULT_MAX_AGE_DAYS),\n };\n\n // ── REM phase ──────────────────────────────────────────────────────\n const remRaw = dreaming?.phases?.rem ?? {};\n const rem: DreamingRemConfig = {\n enabled: enabled && remRaw?.enabled !== false,\n cron: trimmedStringOr(remRaw?.cron, DEFAULT_REM_CRON),\n lookbackDays: toPositiveInt(remRaw?.lookbackDays, 7),\n limit: toNonNegInt(remRaw?.limit, 10),\n minPatternStrength: clampScore(Number(remRaw?.minPatternStrength), 0.75),\n };\n\n return {\n enabled,\n promotionWritePolicy,\n frequency,\n ...(timezone ? { timezone } : {}),\n phases: { light, deep, rem },\n deep,\n };\n}\n\n/** Get the cron expression for a specific phase from resolved config. */\nexport function getPhaseCron(config: DreamingResolvedConfig, phase: DreamingPhaseId): string {\n return config.phases[phase].cron;\n}\n\n/** Check if a specific phase is enabled (global + phase-level). */\nexport function isPhaseEnabled(config: DreamingResolvedConfig, phase: DreamingPhaseId): boolean {\n return config.enabled && config.phases[phase].enabled;\n}\n"],"mappings":";;;;;kBAE6D;AAuD7D,SAAS,WAAW,OAAe,UAA0B;AAC3D,KAAI,CAAC,OAAO,SAAS,MAAM,CAAE,QAAO;AACpC,QAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,MAAM,CAAC;;AAGxC,SAAS,cAAc,OAAgB,UAA0B;CAC/D,MAAM,MAAM,OAAO,UAAU,WAAW,OAAO,MAAM,GAAG,OAAO,MAAM;AACrE,KAAI,CAAC,OAAO,SAAS,IAAI,CAAE,QAAO;CAClC,MAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,QAAO,UAAU,IAAI,UAAU;;AAGjC,SAAS,YAAY,OAAgB,UAA0B;CAC7D,MAAM,MAAM,OAAO,UAAU,WAAW,OAAO,MAAM,GAAG,OAAO,MAAM;AACrE,KAAI,CAAC,OAAO,SAAS,IAAI,CAAE,QAAO;CAClC,MAAM,UAAU,KAAK,MAAM,IAAI;AAC/B,QAAO,WAAW,IAAI,UAAU;;AAGlC,SAAS,gBAAgB,OAAgB,UAA0B;AACjE,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG;;AAGpE,SAAS,sBAAsB,OAAoC;AACjE,QAAO,OAAO,UAAU,YAAY,MAAM,MAAM,GAAG,MAAM,MAAM,GAAG,KAAA;;;AAMpE,SAAgB,sBAAsB,KAAyB,kBAA0D;CACvH,MAAM,UAAU,MAAO,kBAAkB,MAAM,IAAI,sBAAsB,IAAI,GAAI,KAAA;CACjF,MAAM,WAAW,OAAO,UAAU,sCAAsC,KAAK,QAAQ,GAAG,KAAA;CACxF,MAAM,WAAW,UAAU,OAAO;CAClC,MAAM,UAAU,UAAU,YAAY,QAAQ,UAAU,OAAO,SAAS;CACxE,MAAM,uBAAuB,WACzB,mBAAmB,SAAS,CAAC,WAAW;EACtC,QAAQ;EACR,SAAS;EACT,QAAQ;EACR,YAAY;EACZ,WAAW;EACZ,CAAC,GACF;EAAE,UAAU;EAAiB,QAAQ;EAAwC;CAEjF,MAAM,YAAY,gBAAgB,UAAU,WAAW,kBAAkB;CACzE,MAAM,WAAW,sBAAsB,UAAU,SAAS;CAG1D,MAAM,WAAW,UAAU,QAAQ,SAAS,EAAE;CAC9C,MAAM,QAA6B;EACjC,SAAS,WAAW,UAAU,YAAY;EAC1C,MAAM,gBAAgB,UAAU,MAAM,mBAAmB;EACzD,cAAc,cAAc,UAAU,cAAc,EAAE;EACtD,OAAO,YAAY,UAAU,OAAO,IAAI;EACxC,kBAAkB,WAAW,OAAO,UAAU,iBAAiB,EAAE,GAAI;EACtE;CAGD,MAAM,UAAU,UAAU,QAAQ,QAAQ,EAAE;CAC5C,MAAM,OAA2B;EAC/B,SAAS,WAAW,SAAS,YAAY,SAAS,qBAAqB,aAAa;EACpF,MAAM,gBAAgB,SAAS,MAAM,UAAU;EAC/C,UAAU,WAAW,OAAO,SAAS,SAAS,EAAE,GAAI;EACpD,gBAAgB,cAAc,SAAS,gBAAgB,EAAE;EACzD,kBAAkB,cAAc,SAAS,kBAAkB,EAAE;EAC7D,OAAO,YAAY,SAAS,OAAO,GAAG;EACtC,qBAAqB,cAAc,SAAS,qBAAA,GAAoD;EAChG,YAAY,cAAc,SAAS,YAAA,GAAiC;EACrE;CAGD,MAAM,SAAS,UAAU,QAAQ,OAAO,EAAE;CAC1C,MAAM,MAAyB;EAC7B,SAAS,WAAW,QAAQ,YAAY;EACxC,MAAM,gBAAgB,QAAQ,MAAM,iBAAiB;EACrD,cAAc,cAAc,QAAQ,cAAc,EAAE;EACpD,OAAO,YAAY,QAAQ,OAAO,GAAG;EACrC,oBAAoB,WAAW,OAAO,QAAQ,mBAAmB,EAAE,IAAK;EACzE;AAED,QAAO;EACL;EACA;EACA;EACA,GAAI,WAAW,EAAE,UAAU,GAAG,EAAE;EAChC,QAAQ;GAAE;GAAO;GAAM;GAAK;EAC5B;EACD;;;AAIH,SAAgB,aAAa,QAAgC,OAAgC;AAC3F,QAAO,OAAO,OAAO,OAAO;;;AAI9B,SAAgB,eAAe,QAAgC,OAAiC;AAC9F,QAAO,OAAO,WAAW,OAAO,OAAO,OAAO"}
|
|
@@ -10,9 +10,11 @@ export type DreamingPromotionCandidate = DreamingStoreEntry & {
|
|
|
10
10
|
recencyDecay: number;
|
|
11
11
|
};
|
|
12
12
|
export declare function runDreamingDeepPromotion(params: {
|
|
13
|
+
agentId: string;
|
|
13
14
|
workspaceDir: string;
|
|
14
15
|
dreamingRoot: string;
|
|
15
16
|
config?: Partial<DreamingDeepConfig>;
|
|
17
|
+
sensitiveWritePolicy?: 'deny' | 'confirm' | 'allow';
|
|
16
18
|
memoryManager?: MemoryManager;
|
|
17
19
|
now?: Date;
|
|
18
20
|
}): Promise<{
|
|
@@ -2,8 +2,10 @@ import { createLogger } from "../../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../../utils/logger.js";
|
|
3
3
|
import { MEMORY_MD_FILENAME } from "./constants.js";
|
|
4
4
|
import { clamp01, compareCandidatesByScore, computeCandidateScore, extractPromotionMarkers, isContaminatedSnippet, isExpiredEntry, isoDay, readFileLines, resolveDeepDefaults, sliceRange, snippetHash } from "./utils.js";
|
|
5
|
-
import { loadDreamingStore, saveDreamingStore,
|
|
5
|
+
import { loadDreamingStore, saveDreamingStore, withDreamingStoreLock } from "./short-term-store.js";
|
|
6
|
+
import { inferMemorySensitivity } from "../sensitivity.js";
|
|
6
7
|
import { emptyDeepPhaseSkipped, writeDreamingDeepLastRun } from "./last-run.js";
|
|
8
|
+
import { activateDreamingPromotion } from "./promotion-lifecycle.js";
|
|
7
9
|
import path from "node:path";
|
|
8
10
|
import fs from "node:fs/promises";
|
|
9
11
|
//#region src/agent/memory/dreaming/deep-promotion.ts
|
|
@@ -80,7 +82,7 @@ async function runDreamingDeepPromotion(params) {
|
|
|
80
82
|
};
|
|
81
83
|
}
|
|
82
84
|
try {
|
|
83
|
-
const result = await
|
|
85
|
+
const result = await withDreamingStoreLock(params.dreamingRoot, async () => {
|
|
84
86
|
const { store } = await loadDreamingStore({ dreamingRoot: params.dreamingRoot });
|
|
85
87
|
const nowMs = now.getTime();
|
|
86
88
|
const ranked = Object.values(store.entries ?? {}).filter((e) => {
|
|
@@ -134,6 +136,11 @@ async function runDreamingDeepPromotion(params) {
|
|
|
134
136
|
skipped.contaminated += 1;
|
|
135
137
|
continue;
|
|
136
138
|
}
|
|
139
|
+
const sensitivity = inferMemorySensitivity(rehydrated.snippet);
|
|
140
|
+
if (sensitivity !== "normal" && params.sensitiveWritePolicy !== "allow") {
|
|
141
|
+
skipped.contaminated += 1;
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
137
144
|
const hash = snippetHash(rehydrated.snippet);
|
|
138
145
|
if (existingMarkers.hashes.has(hash)) {
|
|
139
146
|
skipped.hashDuplicate += 1;
|
|
@@ -150,7 +157,8 @@ async function runDreamingDeepPromotion(params) {
|
|
|
150
157
|
endLine: rehydrated.endLine,
|
|
151
158
|
score: candidate.score,
|
|
152
159
|
recallCount: candidate.recallCount,
|
|
153
|
-
avgScore: candidate.avgScore
|
|
160
|
+
avgScore: candidate.avgScore,
|
|
161
|
+
sensitivity
|
|
154
162
|
});
|
|
155
163
|
}
|
|
156
164
|
if (appliedCandidates.length === 0) {
|
|
@@ -181,6 +189,19 @@ async function runDreamingDeepPromotion(params) {
|
|
|
181
189
|
}
|
|
182
190
|
sectionLines.push("");
|
|
183
191
|
const next = `${header}${existing.endsWith("\n") || existing.length === 0 ? existing : `${existing}\n`}${sectionLines.join("\n")}`;
|
|
192
|
+
for (const c of appliedCandidates) activateDreamingPromotion({
|
|
193
|
+
agentId: params.agentId,
|
|
194
|
+
workspaceId: params.workspaceDir,
|
|
195
|
+
candidateKey: c.key,
|
|
196
|
+
content: c.snippet,
|
|
197
|
+
sourcePath: c.path,
|
|
198
|
+
lineStart: c.startLine,
|
|
199
|
+
lineEnd: c.endLine,
|
|
200
|
+
score: c.score,
|
|
201
|
+
recallCount: c.recallCount,
|
|
202
|
+
observedAt: now.toISOString(),
|
|
203
|
+
sensitivity: c.sensitivity
|
|
204
|
+
});
|
|
184
205
|
await fs.mkdir(path.dirname(memoryPath), { recursive: true });
|
|
185
206
|
await fs.writeFile(memoryPath, next, "utf-8");
|
|
186
207
|
const nowIso = now.toISOString();
|