@xopcai/xopc 0.0.117 → 0.0.118
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/README.md +24 -23
- package/README.zh-CN.md +45 -42
- 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-BBLhJ2C6.js → agent-avatar-dicebear-dzUrQoeZ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BCxZbkOw.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CBpLONvG.js → app-management-settings-panel-bxYJVJpx.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-CGcc54yj.js → appearance-settings-BCIykXlI.js} +1 -1
- package/dist/gateway/static/root/assets/{apps-page-DdDx0V4z.js → apps-page--wMEL00f.js} +1 -1
- package/dist/gateway/static/root/assets/{archive-plugin-DZsVqMhU.js → archive-plugin-Cki4SfU2.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-CIol6JWX.js → attachment-load-D-KnS2Do.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-B3UauMfp.js → binary-plugins-D2sgvJja.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-2HJoFchH.js → block-editor-DIq-4Gvb.js} +27 -27
- package/dist/gateway/static/root/assets/browser-settings-page-DRhKdn81.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-XQoMTI0A.js → capability-presets-api-CorhiHlg.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-qFx9Jtce.js +1 -0
- package/dist/gateway/static/root/assets/channels-settings-BAwAkqIA.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BQLcfitM.js +2 -0
- package/dist/gateway/static/root/assets/{cron-api-R41aQCX9.js → cron-api-qGwmL-24.js} +1 -1
- package/dist/gateway/static/root/assets/cron-page-BBWMAj8-.js +3 -0
- package/dist/gateway/static/root/assets/{dreaming-settings-Bceaw1PG.js → dreaming-settings-Dw89Obml.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DX5WRE_t.js → extension-debug-page-DYu1KaFQ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-Buah7Bw-.js → extension-page-B3W6QwlZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-DuroLVnf.js → extension-settings-page-D7VQ-cxE.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-B5zdl27C.js → fetch-B7xDPu-R.js} +1 -1
- package/dist/gateway/static/root/assets/{format-interval-label-Dn_QKIqb.js → format-interval-label-BzxafKxR.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-gT4ZhE7h.js → gateway-config-api-BTBLSeUu.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-iISWAZRm.js → gateway-settings-Cmwy58rS.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-startup-retry-B3kL8KGY.js → gateway-startup-retry-CYj9FWCp.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-l7mu5GWX.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-AR-fVh0P.js → goals-config-api-CQQgzPr3.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-Cpb21ezg.js → goals-page-BHitvJAv.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-CPAuFwoD.js → goals-settings-CYVY4NGp.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-D7bKFEeO.js → heartbeat-config-api-DriO_CN9.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CUQTKxg7.js +1 -0
- package/dist/gateway/static/root/assets/index-C17Tsd_b.css +1 -0
- package/dist/gateway/static/root/assets/{index-CwhK8qCh.js → index-Cc41r16l.js} +120 -51
- package/dist/gateway/static/root/assets/{interval-presets-0DtsnxE0.js → interval-presets-DFPCKW_W.js} +1 -1
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BPREtN8B.js → keyboard-shortcuts-settings-CcVcqstx.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-DefCgF4o.js → logs-page-C2Uqvae9.js} +2 -2
- package/dist/gateway/static/root/assets/{markdown-split-ChbR9LGO.js → markdown-split-BwOFrJ2E.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-B82oP80n.js → media-plugins-Cnz6Q5G6.js} +1 -1
- package/dist/gateway/static/root/assets/messages-B1iSKjiw.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-BfLfcta8.js +2 -0
- package/dist/gateway/static/root/assets/note-detail-page-BjwOQBfT.js +2 -0
- package/dist/gateway/static/root/assets/{note-image-lightbox-CDknITM3.js → note-image-lightbox-B-Svpmza.js} +1 -1
- package/dist/gateway/static/root/assets/notes-page-DktdBiwB.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-DV3xQsWB.js → preview-open-alternatives-Bss4TiwP.js} +1 -1
- package/dist/gateway/static/root/assets/remote-access-hub-rfVx96fq.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-BODCXnvY.js → save-bar-controls-BRNjdgKq.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-CgJSCD3B.js → schedule-field-CUCKODde.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-qtfEI6QM.js → schema-form-Dub9sy8r.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DbtMFuuH.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-5re5gAnP.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-BHZKjVcS.js → settings-collapsible-section-BeFLavGi.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-5i35D-J1.js → settings-form-section-dmyaPOTG.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-D-WMyLlj.js +1 -0
- package/dist/gateway/static/root/assets/setup-status-panel-Cl-DEJAU.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-B0H63tDv.js → share-preview-page-C8glrdqe.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CyPVvbLt.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-CleTH1oz.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-Ck8hdXqR.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-DXs2VmBt.js → system-settings-panel-DI-LN_8G.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-4gPuydz_.js → typed-models-lib-kX9duch4.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BCjP_VHb.js → use-channel-catalog-DqlWTsDb.js} +1 -1
- package/dist/gateway/static/root/assets/user-profile-settings-panel-B-UFPMXy.js +1 -0
- package/dist/gateway/static/root/assets/utils-Dm0hKalR.js +1 -0
- package/dist/gateway/static/root/assets/voice-api-key-field-C73IVZeC.js +1 -0
- package/dist/gateway/static/root/assets/{voice-player-store-BlF9V05n.js → voice-player-store-C_ArLJPM.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BtFGp2y_.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +2 -1
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/agent-scope.js +0 -2
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/background-review/prompts.d.ts +2 -2
- package/dist/src/agent/background-review/prompts.js +2 -2
- package/dist/src/agent/background-review/prompts.js.map +1 -1
- package/dist/src/agent/background-review/settings.d.ts +1 -1
- package/dist/src/agent/background-review/settings.js +7 -8
- package/dist/src/agent/background-review/settings.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-cache.d.ts +1 -0
- package/dist/src/agent/bootstrap/bootstrap-cache.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-cache.js.map +1 -1
- package/dist/src/agent/bootstrap/bootstrap-files.d.ts +4 -0
- package/dist/src/agent/bootstrap/bootstrap-files.js +4 -3
- package/dist/src/agent/bootstrap/bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +4 -2
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.d.ts +2 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +17 -16
- package/dist/src/agent/bootstrap/load-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/types.d.ts +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/context/workspace.d.ts +4 -2
- package/dist/src/agent/context/workspace.js +5 -4
- package/dist/src/agent/context/workspace.js.map +1 -1
- package/dist/src/agent/embedded/run-for-session.js +4 -1
- package/dist/src/agent/embedded/run-for-session.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +10 -11
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.d.ts +4 -2
- package/dist/src/agent/memory/builtin-memory-store.js +11 -6
- package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
- package/dist/src/agent/memory/builtin-provider.js +36 -7
- package/dist/src/agent/memory/builtin-provider.js.map +1 -1
- package/dist/src/agent/memory/candidate-extractor.d.ts +6 -0
- package/dist/src/agent/memory/candidate-extractor.js +60 -0
- package/dist/src/agent/memory/candidate-extractor.js.map +1 -0
- package/dist/src/agent/memory/manager.d.ts +2 -1
- package/dist/src/agent/memory/manager.js +27 -3
- package/dist/src/agent/memory/manager.js.map +1 -1
- package/dist/src/agent/memory/memory-config.js +3 -0
- package/dist/src/agent/memory/memory-config.js.map +1 -1
- package/dist/src/agent/memory/prefetch-coordinator.js.map +1 -1
- package/dist/src/agent/memory/types.d.ts +27 -4
- package/dist/src/agent/prompt/memory/index.d.ts +4 -2
- package/dist/src/agent/prompt/memory/index.js +18 -12
- package/dist/src/agent/prompt/memory/index.js.map +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js +1 -1
- package/dist/src/agent/prompt/sections/memory-skills.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +4 -19
- package/dist/src/agent/prompt/service-prompt-builder.js.map +1 -1
- package/dist/src/agent/reply/post-compaction-context.js +1 -3
- package/dist/src/agent/reply/post-compaction-context.js.map +1 -1
- package/dist/src/agent/reply/startup-context.js +1 -5
- package/dist/src/agent/reply/startup-context.js.map +1 -1
- package/dist/src/agent/service.d.ts +3 -3
- package/dist/src/agent/service.js +7 -8
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/tools/curated-memory-tool.js +57 -2
- package/dist/src/agent/tools/curated-memory-tool.js.map +1 -1
- package/dist/src/agent/tools/web-extract.js +6 -8
- package/dist/src/agent/tools/web-extract.js.map +1 -1
- package/dist/src/agent-manifest/index.js +2 -2
- package/dist/src/agent-manifest/resolver.d.ts +3 -2
- package/dist/src/agent-manifest/resolver.js +5 -3
- package/dist/src/agent-manifest/resolver.js.map +1 -1
- package/dist/src/agent-manifest/schema.d.ts +232 -0
- package/dist/src/agent-manifest/schema.js +4 -2
- package/dist/src/agent-manifest/schema.js.map +1 -1
- package/dist/src/agent-manifest/validator.d.ts +3 -2
- package/dist/src/agent-manifest/validator.js +2 -1
- package/dist/src/agent-manifest/validator.js.map +1 -1
- package/dist/src/channels/pipeline.d.ts +1 -1
- package/dist/src/channels/pipeline.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +0 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/model.js +2 -2
- package/dist/src/chat-commands/builtins/model.js.map +1 -1
- package/dist/src/cli/command-manifest.d.ts +1 -1
- package/dist/src/cli/command-manifest.js +1 -1
- package/dist/src/cli/command-manifest.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -0
- package/dist/src/cli/commands/doctor/checks/provider-auth.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +0 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js.map +1 -1
- package/dist/src/cli/commands/init.js +7 -6
- package/dist/src/cli/commands/init.js.map +1 -1
- package/dist/src/cli/commands/models.js +13 -31
- package/dist/src/cli/commands/models.js.map +1 -1
- package/dist/src/cli/commands/onboard/model.js +17 -10
- package/dist/src/cli/commands/onboard/model.js.map +1 -1
- package/dist/src/cli/commands/onboard.js +2 -2
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/commands/tui.js +2 -2
- package/dist/src/cli/commands/tui.js.map +1 -1
- package/dist/src/cli/index.d.ts +1 -0
- package/dist/src/cli/index.js +10 -5
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/registry.js +1 -1
- package/dist/src/cli/registry.js.map +1 -1
- package/dist/src/cli/templates.d.ts +1 -1
- package/dist/src/cli/templates.js +1 -11
- package/dist/src/cli/templates.js.map +1 -1
- package/dist/src/commands/agents.config.js +2 -10
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +3 -2
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.js +3 -5
- package/dist/src/config/agent-typed-models.js.map +1 -1
- package/dist/src/config/index.js +2 -2
- package/dist/src/config/paths.d.ts +8 -1
- package/dist/src/config/paths.js +16 -3
- package/dist/src/config/paths.js.map +1 -1
- package/dist/src/config/schema.d.ts +32 -32
- package/dist/src/config/schema.js +46 -26
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +7 -0
- package/dist/src/gateway/agents-admin.js +51 -20
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/chat-stream/mapper.js +9 -2
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/global-defaults-admin.d.ts +36 -0
- package/dist/src/gateway/global-defaults-admin.js +146 -0
- package/dist/src/gateway/global-defaults-admin.js.map +1 -0
- package/dist/src/gateway/hono/routes/agents.js +33 -1
- package/dist/src/gateway/hono/routes/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +4 -5
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/global-defaults.d.ts +3 -0
- package/dist/src/gateway/hono/routes/global-defaults.js +61 -0
- package/dist/src/gateway/hono/routes/global-defaults.js.map +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js +11 -3
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/memory.js +75 -4
- package/dist/src/gateway/hono/routes/memory.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +1 -1
- package/dist/src/gateway/service/marketplace-service.d.ts +4 -4
- package/dist/src/gateway/service/marketplace-service.js +11 -7
- package/dist/src/gateway/service/marketplace-service.js.map +1 -1
- package/dist/src/notes/service.js +3 -1
- package/dist/src/notes/service.js.map +1 -1
- package/dist/src/providers/index.d.ts +4 -5
- package/dist/src/providers/index.js +16 -16
- package/dist/src/providers/index.js.map +1 -1
- package/dist/src/session/session-workspace.js +2 -7
- package/dist/src/session/session-workspace.js.map +1 -1
- package/dist/src/session/store.js +0 -5
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/storage/sqlite/index.d.ts +1 -1
- package/dist/src/storage/sqlite/index.js +2 -2
- package/dist/src/storage/sqlite/memory-index-repository.d.ts +1 -0
- package/dist/src/storage/sqlite/memory-index-repository.js +15 -14
- package/dist/src/storage/sqlite/memory-index-repository.js.map +1 -1
- package/dist/src/storage/sqlite/memory-records-repository.d.ts +44 -1
- package/dist/src/storage/sqlite/memory-records-repository.js +164 -20
- package/dist/src/storage/sqlite/memory-records-repository.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/014_memory_record_governance.sql +10 -0
- package/dist/src/storage/sqlite/migrations/015_memory_trace_feedback.sql +4 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +3 -0
- package/dist/src/tui/backends/embedded-backend.js +37 -20
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +1 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +16 -3
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/tui-header.d.ts +0 -1
- package/dist/src/tui/components/tui-header.js +3 -8
- package/dist/src/tui/components/tui-header.js.map +1 -1
- package/dist/src/tui/tui-startup-resources.js +2 -1
- package/dist/src/tui/tui-startup-resources.js.map +1 -1
- package/dist/src/tui/tui-startup-text.js +12 -12
- package/dist/src/tui/tui-startup-text.js.map +1 -1
- package/dist/src/tui/tui.js +4 -1
- package/dist/src/tui/tui.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-C6xgagZd.js +0 -71
- package/dist/gateway/static/root/assets/browser-settings-page-CUOO-PQk.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-CfqF-kGr.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-BYyRzsex.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DIvEz4NX.js +0 -2
- package/dist/gateway/static/root/assets/cron-page-D97nFqQD.js +0 -3
- package/dist/gateway/static/root/assets/goal-detail-page-DCUROLMQ.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-CC69vNx0.js +0 -1
- package/dist/gateway/static/root/assets/index-CyfhARL-.css +0 -1
- package/dist/gateway/static/root/assets/messages-Cf1O9JB0.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-DmKiIihT.js +0 -2
- package/dist/gateway/static/root/assets/note-detail-page-CxxfLRJZ.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-X2slSx7V.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-BvmUWqgu.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B0yESuuL.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-q2M8RKOo.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CGozabLD.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-FoOSe6nU.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Cy5zWyYQ.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-DaZNFro9.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CnwtUzvw.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-DvKiOglO.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CAVZcONQ.js +0 -18
- package/dist/src/agent/context/workspace-templates/USER.md +0 -24
|
@@ -4,7 +4,8 @@ import { join, relative } from "node:path";
|
|
|
4
4
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
5
5
|
import { createHash } from "node:crypto";
|
|
6
6
|
//#region src/storage/sqlite/memory-index-repository.ts
|
|
7
|
-
const
|
|
7
|
+
const AGENT_MEMORY_FILENAME = "MEMORY.md";
|
|
8
|
+
const USER_MEMORY_DISPLAY_PATH = "user/MEMORY.md";
|
|
8
9
|
const MEMORY_SYNC_CACHE_TTL_MS = 3e4;
|
|
9
10
|
const memorySyncCache = /* @__PURE__ */ new Map();
|
|
10
11
|
function resolveAgentIdFromMemoriesDir(memoriesDir) {
|
|
@@ -15,13 +16,12 @@ function getDailyMemoryPath(baseDir, date) {
|
|
|
15
16
|
const d = date || /* @__PURE__ */ new Date();
|
|
16
17
|
return join(baseDir, "memory", `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, "0")}-${String(d.getDate()).padStart(2, "0")}.md`);
|
|
17
18
|
}
|
|
18
|
-
function getCuratedMemoryPaths(memoriesDir) {
|
|
19
|
-
|
|
20
|
-
return [join(memoriesDir, "MEMORY.md"), join(memoriesDir, "USER.md")].filter((p) => existsSync(p));
|
|
19
|
+
function getCuratedMemoryPaths(memoriesDir, userMemoryPath) {
|
|
20
|
+
return [...memoriesDir ? [join(memoriesDir, AGENT_MEMORY_FILENAME)] : [], ...userMemoryPath ? [userMemoryPath] : []].filter((p) => existsSync(p));
|
|
21
21
|
}
|
|
22
|
-
function collectMemoryPaths(baseDir, memoriesDir) {
|
|
22
|
+
function collectMemoryPaths(baseDir, memoriesDir, userMemoryPath) {
|
|
23
23
|
const paths = [];
|
|
24
|
-
paths.push(...getCuratedMemoryPaths(memoriesDir));
|
|
24
|
+
paths.push(...getCuratedMemoryPaths(memoriesDir, userMemoryPath));
|
|
25
25
|
const longTermPath = join(baseDir, "MEMORY.md");
|
|
26
26
|
if (existsSync(longTermPath)) paths.push(longTermPath);
|
|
27
27
|
if (existsSync(join(baseDir, "memory"))) {
|
|
@@ -35,13 +35,14 @@ function collectMemoryPaths(baseDir, memoriesDir) {
|
|
|
35
35
|
}
|
|
36
36
|
return paths;
|
|
37
37
|
}
|
|
38
|
-
function displayPath(baseDir, memoriesDir, absPath) {
|
|
38
|
+
function displayPath(baseDir, memoriesDir, userMemoryPath, absPath) {
|
|
39
39
|
const normalized = absPath.replace(/\\/g, "/");
|
|
40
|
+
if (userMemoryPath && normalized === userMemoryPath.replace(/\\/g, "/")) return USER_MEMORY_DISPLAY_PATH;
|
|
40
41
|
if (memoriesDir) {
|
|
41
42
|
const memoriesRoot = memoriesDir.replace(/\\/g, "/");
|
|
42
43
|
if (normalized.startsWith(memoriesRoot)) {
|
|
43
44
|
const filename = normalized.slice(memoriesRoot.length).replace(/^\//, "");
|
|
44
|
-
if (
|
|
45
|
+
if (filename === AGENT_MEMORY_FILENAME) return filename;
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
return relative(baseDir, absPath).replace(/\\/g, "/");
|
|
@@ -52,11 +53,11 @@ function contentHash(content) {
|
|
|
52
53
|
function bm25ToScore(rank) {
|
|
53
54
|
return 1 / (1 + Math.max(0, -rank));
|
|
54
55
|
}
|
|
55
|
-
function indexFile(db, agentId, baseDir, memoriesDir, absPath) {
|
|
56
|
+
function indexFile(db, agentId, baseDir, memoriesDir, userMemoryPath, absPath) {
|
|
56
57
|
const content = readFileSync(absPath, "utf-8");
|
|
57
58
|
const mtimeMs = statSync(absPath).mtimeMs;
|
|
58
59
|
const hash = contentHash(content);
|
|
59
|
-
const relPath = displayPath(baseDir, memoriesDir, absPath);
|
|
60
|
+
const relPath = displayPath(baseDir, memoriesDir, userMemoryPath, absPath);
|
|
60
61
|
const fileId = `${agentId}:${relPath}`;
|
|
61
62
|
const existing = db.prepare(`SELECT content_hash, mtime_ms FROM memory_files WHERE file_id = ?`).get(fileId);
|
|
62
63
|
if (existing && existing.content_hash === hash && existing.mtime_ms === mtimeMs) return;
|
|
@@ -80,11 +81,11 @@ function indexFile(db, agentId, baseDir, memoriesDir, absPath) {
|
|
|
80
81
|
}
|
|
81
82
|
}
|
|
82
83
|
function syncMemoryIndex(params) {
|
|
83
|
-
const cacheKey = `${params.agentId}:${params.workspaceDir}:${params.memoriesDir ?? ""}`;
|
|
84
|
+
const cacheKey = `${params.agentId}:${params.workspaceDir}:${params.memoriesDir ?? ""}:${params.userMemoryPath ?? ""}`;
|
|
84
85
|
const now = Date.now();
|
|
85
86
|
const cached = memorySyncCache.get(cacheKey);
|
|
86
87
|
if (cached && now - cached.timestamp < MEMORY_SYNC_CACHE_TTL_MS) return;
|
|
87
|
-
const paths = collectMemoryPaths(params.workspaceDir, params.memoriesDir);
|
|
88
|
+
const paths = collectMemoryPaths(params.workspaceDir, params.memoriesDir, params.userMemoryPath);
|
|
88
89
|
memorySyncCache.set(cacheKey, {
|
|
89
90
|
timestamp: now,
|
|
90
91
|
paths
|
|
@@ -92,8 +93,8 @@ function syncMemoryIndex(params) {
|
|
|
92
93
|
runSqliteWriteTransaction((db) => {
|
|
93
94
|
const seen = /* @__PURE__ */ new Set();
|
|
94
95
|
for (const absPath of paths) {
|
|
95
|
-
seen.add(`${params.agentId}:${displayPath(params.workspaceDir, params.memoriesDir, absPath)}`);
|
|
96
|
-
indexFile(db, params.agentId, params.workspaceDir, params.memoriesDir, absPath);
|
|
96
|
+
seen.add(`${params.agentId}:${displayPath(params.workspaceDir, params.memoriesDir, params.userMemoryPath, absPath)}`);
|
|
97
|
+
indexFile(db, params.agentId, params.workspaceDir, params.memoriesDir, params.userMemoryPath, absPath);
|
|
97
98
|
}
|
|
98
99
|
const stale = db.prepare(`SELECT file_id FROM memory_files WHERE agent_id = ?`).all(params.agentId);
|
|
99
100
|
for (const row of stale) if (!seen.has(row.file_id)) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-index-repository.js","names":[],"sources":["../../../../src/storage/sqlite/memory-index-repository.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { join, relative } from 'node:path';\n\nimport { escapeFts5Query } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\nexport type MemorySearchHit = {\n path: string;\n lines: string;\n score: number;\n lineNumbers: number[];\n};\n\nconst CURATED_MEMORY_FILENAMES = new Set(['MEMORY.md', 'USER.md']);\nconst MEMORY_SYNC_CACHE_TTL_MS = 30_000;\n\ntype MemorySyncCache = {\n timestamp: number;\n paths: string[];\n};\n\nconst memorySyncCache = new Map<string, MemorySyncCache>();\n\nexport function resolveAgentIdFromMemoriesDir(memoriesDir: string | undefined): string {\n if (!memoriesDir) return 'main';\n const normalized = memoriesDir.replace(/\\\\/g, '/');\n const match = normalized.match(/\\/agents\\/([^/]+)\\/memories\\/?$/);\n return match?.[1] ?? 'main';\n}\n\nfunction getDailyMemoryPath(baseDir: string, date?: Date): string {\n const d = date || new Date();\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return join(baseDir, 'memory', `${year}-${month}-${day}.md`);\n}\n\nfunction getCuratedMemoryPaths(memoriesDir: string | undefined): string[] {\n if (!memoriesDir) return [];\n return [join(memoriesDir, 'MEMORY.md'), join(memoriesDir, 'USER.md')].filter((p) => existsSync(p));\n}\n\nfunction collectMemoryPaths(baseDir: string, memoriesDir?: string): string[] {\n const paths: string[] = [];\n paths.push(...getCuratedMemoryPaths(memoriesDir));\n\n const longTermPath = join(baseDir, 'MEMORY.md');\n if (existsSync(longTermPath)) {\n paths.push(longTermPath);\n }\n\n const memoryDir = join(baseDir, 'memory');\n if (existsSync(memoryDir)) {\n const today = new Date();\n for (let i = 0; i < 30; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n const path = getDailyMemoryPath(baseDir, date);\n if (existsSync(path)) {\n paths.push(path);\n }\n }\n }\n\n return paths;\n}\n\nfunction displayPath(baseDir: string, memoriesDir: string | undefined, absPath: string): string {\n const normalized = absPath.replace(/\\\\/g, '/');\n if (memoriesDir) {\n const memoriesRoot = memoriesDir.replace(/\\\\/g, '/');\n if (normalized.startsWith(memoriesRoot)) {\n const filename = normalized.slice(memoriesRoot.length).replace(/^\\//, '');\n if (CURATED_MEMORY_FILENAMES.has(filename)) {\n return filename;\n }\n }\n }\n return relative(baseDir, absPath).replace(/\\\\/g, '/');\n}\n\nfunction contentHash(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction bm25ToScore(rank: number): number {\n return 1 / (1 + Math.max(0, -rank));\n}\n\nfunction indexFile(\n db: ReturnType<typeof getSqliteDatabase>,\n agentId: string,\n baseDir: string,\n memoriesDir: string | undefined,\n absPath: string,\n): void {\n const content = readFileSync(absPath, 'utf-8');\n const mtimeMs = statSync(absPath).mtimeMs;\n const hash = contentHash(content);\n const relPath = displayPath(baseDir, memoriesDir, absPath);\n const fileId = `${agentId}:${relPath}`;\n\n const existing = db\n .prepare(`SELECT content_hash, mtime_ms FROM memory_files WHERE file_id = ?`)\n .get(fileId) as { content_hash: string; mtime_ms: number } | undefined;\n if (existing && existing.content_hash === hash && existing.mtime_ms === mtimeMs) {\n return;\n }\n\n db.prepare(`DELETE FROM memory_fts WHERE chunk_id IN (SELECT chunk_id FROM memory_chunks WHERE file_id = ?)`).run(\n fileId,\n );\n db.prepare(`DELETE FROM memory_chunks WHERE file_id = ?`).run(fileId);\n db.prepare(`DELETE FROM memory_files WHERE file_id = ?`).run(fileId);\n\n db.prepare(\n `INSERT INTO memory_files (file_id, agent_id, path, mtime_ms, content_hash)\n VALUES (?, ?, ?, ?, ?)`,\n ).run(fileId, agentId, relPath, mtimeMs, hash);\n\n const lines = content.split('\\n');\n const insertChunk = db.prepare(\n `INSERT INTO memory_chunks (chunk_id, file_id, start_line, end_line, content)\n VALUES (?, ?, ?, ?, ?)`,\n );\n const insertFts = db.prepare(\n `INSERT INTO memory_fts (content, chunk_id, agent_id, path, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?)`,\n );\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line.trim()) continue;\n const lineNo = i + 1;\n const chunkId = `${fileId}:${lineNo}`;\n insertChunk.run(chunkId, fileId, lineNo, lineNo, line);\n insertFts.run(line, chunkId, agentId, relPath, lineNo, lineNo);\n }\n}\n\nexport function syncMemoryIndex(params: {\n agentId: string;\n workspaceDir: string;\n memoriesDir?: string;\n}): void {\n const cacheKey = `${params.agentId}:${params.workspaceDir}:${params.memoriesDir ?? ''}`;\n const now = Date.now();\n const cached = memorySyncCache.get(cacheKey);\n if (cached && now - cached.timestamp < MEMORY_SYNC_CACHE_TTL_MS) {\n return;\n }\n\n const paths = collectMemoryPaths(params.workspaceDir, params.memoriesDir);\n memorySyncCache.set(cacheKey, { timestamp: now, paths });\n runSqliteWriteTransaction((db) => {\n const seen = new Set<string>();\n for (const absPath of paths) {\n seen.add(`${params.agentId}:${displayPath(params.workspaceDir, params.memoriesDir, absPath)}`);\n indexFile(db, params.agentId, params.workspaceDir, params.memoriesDir, absPath);\n }\n\n const stale = db\n .prepare(`SELECT file_id FROM memory_files WHERE agent_id = ?`)\n .all(params.agentId) as Array<{ file_id: string }>;\n for (const row of stale) {\n if (!seen.has(row.file_id)) {\n db.prepare(\n `DELETE FROM memory_fts WHERE chunk_id IN (SELECT chunk_id FROM memory_chunks WHERE file_id = ?)`,\n ).run(row.file_id);\n db.prepare(`DELETE FROM memory_chunks WHERE file_id = ?`).run(row.file_id);\n db.prepare(`DELETE FROM memory_files WHERE file_id = ?`).run(row.file_id);\n }\n }\n });\n}\n\nexport function searchMemoryIndex(params: {\n agentId: string;\n query: string;\n maxResults?: number;\n minScore?: number;\n}): MemorySearchHit[] {\n const { agentId, query, maxResults = 5, minScore = 0.3 } = params;\n const ftsQuery = escapeFts5Query(query);\n if (!ftsQuery) {\n return [];\n }\n\n const db = getSqliteDatabase();\n const rows = db\n .prepare(\n `SELECT chunk_id, path, start_line, end_line, content, bm25(memory_fts) AS rank\n FROM memory_fts\n WHERE memory_fts MATCH ? AND agent_id = ?\n ORDER BY rank\n LIMIT ?`,\n )\n .all(ftsQuery, agentId, maxResults * 3) as Array<{\n chunk_id: string;\n path: string;\n start_line: number;\n end_line: number;\n content: string;\n rank: number;\n }>;\n\n const results: MemorySearchHit[] = [];\n for (const row of rows) {\n const score = bm25ToScore(row.rank);\n if (score < minScore) continue;\n results.push({\n path: row.path,\n lines: row.content,\n score,\n lineNumbers: [row.start_line],\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, maxResults);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-index-repository.js","names":[],"sources":["../../../../src/storage/sqlite/memory-index-repository.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport { existsSync, readFileSync, statSync } from 'node:fs';\nimport { join, relative } from 'node:path';\n\nimport { escapeFts5Query } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\nexport type MemorySearchHit = {\n path: string;\n lines: string;\n score: number;\n lineNumbers: number[];\n};\n\nconst AGENT_MEMORY_FILENAME = 'MEMORY.md';\nconst USER_MEMORY_DISPLAY_PATH = 'user/MEMORY.md';\nconst MEMORY_SYNC_CACHE_TTL_MS = 30_000;\n\ntype MemorySyncCache = {\n timestamp: number;\n paths: string[];\n};\n\nconst memorySyncCache = new Map<string, MemorySyncCache>();\n\nexport function resolveAgentIdFromMemoriesDir(memoriesDir: string | undefined): string {\n if (!memoriesDir) return 'main';\n const normalized = memoriesDir.replace(/\\\\/g, '/');\n const match = normalized.match(/\\/agents\\/([^/]+)\\/memories\\/?$/);\n return match?.[1] ?? 'main';\n}\n\nfunction getDailyMemoryPath(baseDir: string, date?: Date): string {\n const d = date || new Date();\n const year = d.getFullYear();\n const month = String(d.getMonth() + 1).padStart(2, '0');\n const day = String(d.getDate()).padStart(2, '0');\n return join(baseDir, 'memory', `${year}-${month}-${day}.md`);\n}\n\nfunction getCuratedMemoryPaths(memoriesDir: string | undefined, userMemoryPath: string | undefined): string[] {\n return [\n ...(memoriesDir ? [join(memoriesDir, AGENT_MEMORY_FILENAME)] : []),\n ...(userMemoryPath ? [userMemoryPath] : []),\n ].filter((p) => existsSync(p));\n}\n\nfunction collectMemoryPaths(baseDir: string, memoriesDir?: string, userMemoryPath?: string): string[] {\n const paths: string[] = [];\n paths.push(...getCuratedMemoryPaths(memoriesDir, userMemoryPath));\n\n const longTermPath = join(baseDir, 'MEMORY.md');\n if (existsSync(longTermPath)) {\n paths.push(longTermPath);\n }\n\n const memoryDir = join(baseDir, 'memory');\n if (existsSync(memoryDir)) {\n const today = new Date();\n for (let i = 0; i < 30; i++) {\n const date = new Date(today);\n date.setDate(date.getDate() - i);\n const path = getDailyMemoryPath(baseDir, date);\n if (existsSync(path)) {\n paths.push(path);\n }\n }\n }\n\n return paths;\n}\n\nfunction displayPath(\n baseDir: string,\n memoriesDir: string | undefined,\n userMemoryPath: string | undefined,\n absPath: string,\n): string {\n const normalized = absPath.replace(/\\\\/g, '/');\n if (userMemoryPath && normalized === userMemoryPath.replace(/\\\\/g, '/')) {\n return USER_MEMORY_DISPLAY_PATH;\n }\n if (memoriesDir) {\n const memoriesRoot = memoriesDir.replace(/\\\\/g, '/');\n if (normalized.startsWith(memoriesRoot)) {\n const filename = normalized.slice(memoriesRoot.length).replace(/^\\//, '');\n if (filename === AGENT_MEMORY_FILENAME) {\n return filename;\n }\n }\n }\n return relative(baseDir, absPath).replace(/\\\\/g, '/');\n}\n\nfunction contentHash(content: string): string {\n return createHash('sha256').update(content).digest('hex');\n}\n\nfunction bm25ToScore(rank: number): number {\n return 1 / (1 + Math.max(0, -rank));\n}\n\nfunction indexFile(\n db: ReturnType<typeof getSqliteDatabase>,\n agentId: string,\n baseDir: string,\n memoriesDir: string | undefined,\n userMemoryPath: string | undefined,\n absPath: string,\n): void {\n const content = readFileSync(absPath, 'utf-8');\n const mtimeMs = statSync(absPath).mtimeMs;\n const hash = contentHash(content);\n const relPath = displayPath(baseDir, memoriesDir, userMemoryPath, absPath);\n const fileId = `${agentId}:${relPath}`;\n\n const existing = db\n .prepare(`SELECT content_hash, mtime_ms FROM memory_files WHERE file_id = ?`)\n .get(fileId) as { content_hash: string; mtime_ms: number } | undefined;\n if (existing && existing.content_hash === hash && existing.mtime_ms === mtimeMs) {\n return;\n }\n\n db.prepare(`DELETE FROM memory_fts WHERE chunk_id IN (SELECT chunk_id FROM memory_chunks WHERE file_id = ?)`).run(\n fileId,\n );\n db.prepare(`DELETE FROM memory_chunks WHERE file_id = ?`).run(fileId);\n db.prepare(`DELETE FROM memory_files WHERE file_id = ?`).run(fileId);\n\n db.prepare(\n `INSERT INTO memory_files (file_id, agent_id, path, mtime_ms, content_hash)\n VALUES (?, ?, ?, ?, ?)`,\n ).run(fileId, agentId, relPath, mtimeMs, hash);\n\n const lines = content.split('\\n');\n const insertChunk = db.prepare(\n `INSERT INTO memory_chunks (chunk_id, file_id, start_line, end_line, content)\n VALUES (?, ?, ?, ?, ?)`,\n );\n const insertFts = db.prepare(\n `INSERT INTO memory_fts (content, chunk_id, agent_id, path, start_line, end_line)\n VALUES (?, ?, ?, ?, ?, ?)`,\n );\n\n for (let i = 0; i < lines.length; i++) {\n const line = lines[i];\n if (!line.trim()) continue;\n const lineNo = i + 1;\n const chunkId = `${fileId}:${lineNo}`;\n insertChunk.run(chunkId, fileId, lineNo, lineNo, line);\n insertFts.run(line, chunkId, agentId, relPath, lineNo, lineNo);\n }\n}\n\nexport function syncMemoryIndex(params: {\n agentId: string;\n workspaceDir: string;\n memoriesDir?: string;\n userMemoryPath?: string;\n}): void {\n const cacheKey = `${params.agentId}:${params.workspaceDir}:${params.memoriesDir ?? ''}:${params.userMemoryPath ?? ''}`;\n const now = Date.now();\n const cached = memorySyncCache.get(cacheKey);\n if (cached && now - cached.timestamp < MEMORY_SYNC_CACHE_TTL_MS) {\n return;\n }\n\n const paths = collectMemoryPaths(params.workspaceDir, params.memoriesDir, params.userMemoryPath);\n memorySyncCache.set(cacheKey, { timestamp: now, paths });\n runSqliteWriteTransaction((db) => {\n const seen = new Set<string>();\n for (const absPath of paths) {\n seen.add(`${params.agentId}:${displayPath(params.workspaceDir, params.memoriesDir, params.userMemoryPath, absPath)}`);\n indexFile(db, params.agentId, params.workspaceDir, params.memoriesDir, params.userMemoryPath, absPath);\n }\n\n const stale = db\n .prepare(`SELECT file_id FROM memory_files WHERE agent_id = ?`)\n .all(params.agentId) as Array<{ file_id: string }>;\n for (const row of stale) {\n if (!seen.has(row.file_id)) {\n db.prepare(\n `DELETE FROM memory_fts WHERE chunk_id IN (SELECT chunk_id FROM memory_chunks WHERE file_id = ?)`,\n ).run(row.file_id);\n db.prepare(`DELETE FROM memory_chunks WHERE file_id = ?`).run(row.file_id);\n db.prepare(`DELETE FROM memory_files WHERE file_id = ?`).run(row.file_id);\n }\n }\n });\n}\n\nexport function searchMemoryIndex(params: {\n agentId: string;\n query: string;\n maxResults?: number;\n minScore?: number;\n}): MemorySearchHit[] {\n const { agentId, query, maxResults = 5, minScore = 0.3 } = params;\n const ftsQuery = escapeFts5Query(query);\n if (!ftsQuery) {\n return [];\n }\n\n const db = getSqliteDatabase();\n const rows = db\n .prepare(\n `SELECT chunk_id, path, start_line, end_line, content, bm25(memory_fts) AS rank\n FROM memory_fts\n WHERE memory_fts MATCH ? AND agent_id = ?\n ORDER BY rank\n LIMIT ?`,\n )\n .all(ftsQuery, agentId, maxResults * 3) as Array<{\n chunk_id: string;\n path: string;\n start_line: number;\n end_line: number;\n content: string;\n rank: number;\n }>;\n\n const results: MemorySearchHit[] = [];\n for (const row of rows) {\n const score = bm25ToScore(row.rank);\n if (score < minScore) continue;\n results.push({\n path: row.path,\n lines: row.content,\n score,\n lineNumbers: [row.start_line],\n });\n }\n\n results.sort((a, b) => b.score - a.score);\n return results.slice(0, maxResults);\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MemoryKind, MemoryRecord, MemorySearchResult, MemorySignal } from '../../agent/memory/types.js';
|
|
1
|
+
import type { MemoryKind, MemoryRecord, MemorySensitivity, MemorySearchResult, MemorySignal, MemoryStatus } from '../../agent/memory/types.js';
|
|
2
2
|
export interface UpsertMemoryRecordInput {
|
|
3
3
|
id?: string;
|
|
4
4
|
providerId: string;
|
|
@@ -10,6 +10,11 @@ export interface UpsertMemoryRecordInput {
|
|
|
10
10
|
source?: MemoryRecord['source'];
|
|
11
11
|
confidence?: number;
|
|
12
12
|
tags?: string[];
|
|
13
|
+
status?: MemoryStatus;
|
|
14
|
+
sensitivity?: MemorySensitivity;
|
|
15
|
+
evidence?: MemoryRecord['evidence'];
|
|
16
|
+
reviewAfter?: string;
|
|
17
|
+
expiresAt?: string;
|
|
13
18
|
nowMs?: number;
|
|
14
19
|
}
|
|
15
20
|
export interface ListMemoryRecordsOptions {
|
|
@@ -17,6 +22,7 @@ export interface ListMemoryRecordsOptions {
|
|
|
17
22
|
agentId?: string;
|
|
18
23
|
workspaceId?: string;
|
|
19
24
|
kind?: MemoryKind;
|
|
25
|
+
status?: MemoryStatus;
|
|
20
26
|
limit?: number;
|
|
21
27
|
offset?: number;
|
|
22
28
|
}
|
|
@@ -26,6 +32,7 @@ export interface SearchMemoryRecordsOptions {
|
|
|
26
32
|
workspaceId?: string;
|
|
27
33
|
providerId?: string;
|
|
28
34
|
kinds?: MemoryKind[];
|
|
35
|
+
statuses?: MemoryStatus[];
|
|
29
36
|
maxResults?: number;
|
|
30
37
|
minScore?: number;
|
|
31
38
|
}
|
|
@@ -50,6 +57,15 @@ export interface MemorySignalRowPayload {
|
|
|
50
57
|
metadata: Record<string, unknown>;
|
|
51
58
|
createdAt: string;
|
|
52
59
|
}
|
|
60
|
+
export type MemoryTraceFeedbackOutcome = 'helpful' | 'not_helpful' | 'mixed' | 'irrelevant';
|
|
61
|
+
export interface MemoryTraceFeedback {
|
|
62
|
+
outcome: MemoryTraceFeedbackOutcome;
|
|
63
|
+
score?: number;
|
|
64
|
+
reason?: string;
|
|
65
|
+
source?: 'user' | 'evaluator' | 'system';
|
|
66
|
+
createdAt: string;
|
|
67
|
+
updatedAt?: string;
|
|
68
|
+
}
|
|
53
69
|
export interface AppendMemoryTraceEventInput {
|
|
54
70
|
sessionKey?: string;
|
|
55
71
|
turnId?: string;
|
|
@@ -60,9 +76,18 @@ export interface AppendMemoryTraceEventInput {
|
|
|
60
76
|
selectedRecordIds?: string[];
|
|
61
77
|
skippedReason?: string;
|
|
62
78
|
error?: string;
|
|
79
|
+
feedback?: MemoryTraceFeedback;
|
|
63
80
|
durationMs?: number;
|
|
64
81
|
nowMs?: number;
|
|
65
82
|
}
|
|
83
|
+
export interface SetMemoryTraceFeedbackInput {
|
|
84
|
+
traceId: string;
|
|
85
|
+
feedback: Omit<MemoryTraceFeedback, 'createdAt' | 'updatedAt'> & {
|
|
86
|
+
createdAt?: string;
|
|
87
|
+
updatedAt?: string;
|
|
88
|
+
};
|
|
89
|
+
nowMs?: number;
|
|
90
|
+
}
|
|
66
91
|
export interface MemoryTraceEventPayload {
|
|
67
92
|
traceId: string;
|
|
68
93
|
sessionKey?: string;
|
|
@@ -74,9 +99,20 @@ export interface MemoryTraceEventPayload {
|
|
|
74
99
|
selectedRecordIds: string[];
|
|
75
100
|
skippedReason?: string;
|
|
76
101
|
error?: string;
|
|
102
|
+
feedback?: MemoryTraceFeedback;
|
|
77
103
|
durationMs: number;
|
|
78
104
|
createdAt: string;
|
|
79
105
|
}
|
|
106
|
+
export interface MemoryRecallFeedbackSummary {
|
|
107
|
+
recordId: string;
|
|
108
|
+
helpful: number;
|
|
109
|
+
notHelpful: number;
|
|
110
|
+
mixed: number;
|
|
111
|
+
irrelevant: number;
|
|
112
|
+
total: number;
|
|
113
|
+
averageScore: number | null;
|
|
114
|
+
lastFeedbackAt?: string;
|
|
115
|
+
}
|
|
80
116
|
export declare function upsertMemoryRecord(input: UpsertMemoryRecordInput): MemoryRecord;
|
|
81
117
|
export declare function getMemoryRecord(recordId: string): MemoryRecord | null;
|
|
82
118
|
export declare function listMemoryRecords(options?: ListMemoryRecordsOptions): MemoryRecord[];
|
|
@@ -99,3 +135,10 @@ export declare function listMemoryTraceEvents(options?: {
|
|
|
99
135
|
phase?: string;
|
|
100
136
|
limit?: number;
|
|
101
137
|
}): MemoryTraceEventPayload[];
|
|
138
|
+
export declare function setMemoryTraceFeedback(input: SetMemoryTraceFeedbackInput): MemoryTraceEventPayload | null;
|
|
139
|
+
export declare function summarizeMemoryRecallFeedback(options?: {
|
|
140
|
+
recordId?: string;
|
|
141
|
+
providerId?: string;
|
|
142
|
+
sessionKey?: string;
|
|
143
|
+
limit?: number;
|
|
144
|
+
}): MemoryRecallFeedbackSummary[];
|
|
@@ -10,6 +10,73 @@ function parseStringArray(json) {
|
|
|
10
10
|
return [];
|
|
11
11
|
}
|
|
12
12
|
}
|
|
13
|
+
function parseEvidence(json) {
|
|
14
|
+
try {
|
|
15
|
+
const parsed = JSON.parse(json);
|
|
16
|
+
if (!Array.isArray(parsed)) return [];
|
|
17
|
+
return parsed.filter((item) => Boolean(item) && typeof item === "object");
|
|
18
|
+
} catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function parseMemoryTraceFeedback(json) {
|
|
23
|
+
try {
|
|
24
|
+
const parsed = JSON.parse(json);
|
|
25
|
+
if (!parsed || typeof parsed !== "object") return void 0;
|
|
26
|
+
const obj = parsed;
|
|
27
|
+
const outcome = obj.outcome;
|
|
28
|
+
if (outcome !== "helpful" && outcome !== "not_helpful" && outcome !== "mixed" && outcome !== "irrelevant") return;
|
|
29
|
+
return {
|
|
30
|
+
outcome,
|
|
31
|
+
...typeof obj.score === "number" ? { score: obj.score } : {},
|
|
32
|
+
...typeof obj.reason === "string" ? { reason: obj.reason } : {},
|
|
33
|
+
...obj.source === "user" || obj.source === "evaluator" || obj.source === "system" ? { source: obj.source } : {},
|
|
34
|
+
createdAt: typeof obj.createdAt === "string" ? obj.createdAt : (/* @__PURE__ */ new Date(0)).toISOString(),
|
|
35
|
+
...typeof obj.updatedAt === "string" ? { updatedAt: obj.updatedAt } : {}
|
|
36
|
+
};
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function normalizeMemoryTraceFeedback(input, nowMs = Date.now(), existing) {
|
|
42
|
+
const score = typeof input.score === "number" ? Math.max(-1, Math.min(1, input.score)) : void 0;
|
|
43
|
+
const reason = typeof input.reason === "string" && input.reason.trim() ? input.reason.trim().slice(0, 1e3) : void 0;
|
|
44
|
+
const nowIso = new Date(nowMs).toISOString();
|
|
45
|
+
return {
|
|
46
|
+
outcome: input.outcome,
|
|
47
|
+
...score != null ? { score } : {},
|
|
48
|
+
...reason ? { reason } : {},
|
|
49
|
+
...input.source ? { source: input.source } : {},
|
|
50
|
+
createdAt: input.createdAt ?? existing?.createdAt ?? nowIso,
|
|
51
|
+
updatedAt: input.updatedAt ?? nowIso
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function memoryTraceRowToPayload(row) {
|
|
55
|
+
const feedback = parseMemoryTraceFeedback(row.feedback_json);
|
|
56
|
+
return {
|
|
57
|
+
traceId: row.trace_id,
|
|
58
|
+
...row.session_key ? { sessionKey: row.session_key } : {},
|
|
59
|
+
...row.turn_id ? { turnId: row.turn_id } : {},
|
|
60
|
+
phase: row.phase,
|
|
61
|
+
providerId: row.provider_id,
|
|
62
|
+
request: parseJsonValue(row.request_json, {}),
|
|
63
|
+
...row.result_count != null ? { resultCount: row.result_count } : {},
|
|
64
|
+
selectedRecordIds: parseStringArray(row.selected_record_ids_json),
|
|
65
|
+
...row.skipped_reason ? { skippedReason: row.skipped_reason } : {},
|
|
66
|
+
...row.error ? { error: row.error } : {},
|
|
67
|
+
...feedback ? { feedback } : {},
|
|
68
|
+
durationMs: row.duration_ms,
|
|
69
|
+
createdAt: new Date(row.created_at).toISOString()
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
function parseOptionalTimestamp(value) {
|
|
73
|
+
if (!value?.trim()) return null;
|
|
74
|
+
const parsed = Date.parse(value);
|
|
75
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
76
|
+
}
|
|
77
|
+
function timestampToIso(value) {
|
|
78
|
+
return value == null ? void 0 : new Date(value).toISOString();
|
|
79
|
+
}
|
|
13
80
|
function parseSource(json) {
|
|
14
81
|
try {
|
|
15
82
|
const parsed = JSON.parse(json);
|
|
@@ -22,6 +89,7 @@ function rowToRecord(row) {
|
|
|
22
89
|
return {
|
|
23
90
|
id: row.record_id,
|
|
24
91
|
kind: row.kind,
|
|
92
|
+
status: row.status,
|
|
25
93
|
scope: {
|
|
26
94
|
agentId: row.agent_id,
|
|
27
95
|
...row.workspace_id ? { workspaceId: row.workspace_id } : {},
|
|
@@ -30,6 +98,10 @@ function rowToRecord(row) {
|
|
|
30
98
|
content: row.content,
|
|
31
99
|
source: parseSource(row.source_json),
|
|
32
100
|
...row.confidence != null ? { confidence: row.confidence } : {},
|
|
101
|
+
sensitivity: row.sensitivity,
|
|
102
|
+
evidence: parseEvidence(row.evidence_json),
|
|
103
|
+
...timestampToIso(row.review_after) ? { reviewAfter: timestampToIso(row.review_after) } : {},
|
|
104
|
+
...timestampToIso(row.expires_at) ? { expiresAt: timestampToIso(row.expires_at) } : {},
|
|
33
105
|
createdAt: new Date(row.created_at).toISOString(),
|
|
34
106
|
updatedAt: new Date(row.updated_at).toISOString(),
|
|
35
107
|
tags: parseStringArray(row.tags_json)
|
|
@@ -48,6 +120,10 @@ function upsertMemoryRecordFts(db, row) {
|
|
|
48
120
|
function upsertMemoryRecord(input) {
|
|
49
121
|
const id = input.id ?? randomUUID();
|
|
50
122
|
const now = input.nowMs ?? Date.now();
|
|
123
|
+
const status = input.status ?? "active";
|
|
124
|
+
const sensitivity = input.sensitivity ?? "normal";
|
|
125
|
+
const reviewAfter = parseOptionalTimestamp(input.reviewAfter);
|
|
126
|
+
const expiresAt = parseOptionalTimestamp(input.expiresAt);
|
|
51
127
|
const source = {
|
|
52
128
|
...input.source ?? {},
|
|
53
129
|
provider: input.source?.provider ?? input.providerId
|
|
@@ -55,8 +131,9 @@ function upsertMemoryRecord(input) {
|
|
|
55
131
|
runSqliteWriteTransaction((db) => {
|
|
56
132
|
db.prepare(`INSERT INTO memory_records (
|
|
57
133
|
record_id, provider_id, kind, agent_id, workspace_id, session_key,
|
|
58
|
-
content, source_json, confidence, tags_json,
|
|
59
|
-
|
|
134
|
+
content, source_json, confidence, tags_json, status, sensitivity,
|
|
135
|
+
evidence_json, review_after, expires_at, created_at, updated_at
|
|
136
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
60
137
|
ON CONFLICT(record_id) DO UPDATE SET
|
|
61
138
|
provider_id = excluded.provider_id,
|
|
62
139
|
kind = excluded.kind,
|
|
@@ -67,7 +144,12 @@ function upsertMemoryRecord(input) {
|
|
|
67
144
|
source_json = excluded.source_json,
|
|
68
145
|
confidence = excluded.confidence,
|
|
69
146
|
tags_json = excluded.tags_json,
|
|
70
|
-
|
|
147
|
+
status = excluded.status,
|
|
148
|
+
sensitivity = excluded.sensitivity,
|
|
149
|
+
evidence_json = excluded.evidence_json,
|
|
150
|
+
review_after = excluded.review_after,
|
|
151
|
+
expires_at = excluded.expires_at,
|
|
152
|
+
updated_at = excluded.updated_at`).run(id, input.providerId, input.kind, input.agentId, input.workspaceId ?? null, input.sessionKey ?? null, input.content, JSON.stringify(source), input.confidence ?? null, JSON.stringify(input.tags ?? []), status, sensitivity, JSON.stringify(input.evidence ?? []), reviewAfter, expiresAt, now, now);
|
|
71
153
|
upsertMemoryRecordFts(db, {
|
|
72
154
|
...input,
|
|
73
155
|
id
|
|
@@ -76,6 +158,7 @@ function upsertMemoryRecord(input) {
|
|
|
76
158
|
return {
|
|
77
159
|
id,
|
|
78
160
|
kind: input.kind,
|
|
161
|
+
status,
|
|
79
162
|
scope: {
|
|
80
163
|
agentId: input.agentId,
|
|
81
164
|
...input.workspaceId ? { workspaceId: input.workspaceId } : {},
|
|
@@ -84,6 +167,10 @@ function upsertMemoryRecord(input) {
|
|
|
84
167
|
content: input.content,
|
|
85
168
|
source,
|
|
86
169
|
...input.confidence != null ? { confidence: input.confidence } : {},
|
|
170
|
+
sensitivity,
|
|
171
|
+
evidence: input.evidence ?? [],
|
|
172
|
+
...reviewAfter != null ? { reviewAfter: new Date(reviewAfter).toISOString() } : {},
|
|
173
|
+
...expiresAt != null ? { expiresAt: new Date(expiresAt).toISOString() } : {},
|
|
87
174
|
createdAt: new Date(now).toISOString(),
|
|
88
175
|
updatedAt: new Date(now).toISOString(),
|
|
89
176
|
tags: input.tags ?? []
|
|
@@ -112,6 +199,10 @@ function listMemoryRecords(options = {}) {
|
|
|
112
199
|
where.push("kind = ?");
|
|
113
200
|
params.push(options.kind);
|
|
114
201
|
}
|
|
202
|
+
if (options.status) {
|
|
203
|
+
where.push("status = ?");
|
|
204
|
+
params.push(options.status);
|
|
205
|
+
}
|
|
115
206
|
const limit = Math.max(1, Math.min(500, options.limit ?? 100));
|
|
116
207
|
const offset = Math.max(0, options.offset ?? 0);
|
|
117
208
|
return getSqliteDatabase().prepare(`SELECT * FROM memory_records
|
|
@@ -140,6 +231,9 @@ function searchMemoryRecords(options) {
|
|
|
140
231
|
filters.push(`f.kind IN (${options.kinds.map(() => "?").join(", ")})`);
|
|
141
232
|
params.push(...options.kinds);
|
|
142
233
|
}
|
|
234
|
+
const statuses = options.statuses && options.statuses.length > 0 ? options.statuses : ["active"];
|
|
235
|
+
filters.push(`r.status IN (${statuses.map(() => "?").join(", ")})`);
|
|
236
|
+
params.push(...statuses);
|
|
143
237
|
const maxResults = Math.max(1, Math.min(50, options.maxResults ?? 5));
|
|
144
238
|
const minScore = options.minScore ?? 0;
|
|
145
239
|
return getSqliteDatabase().prepare(`SELECT
|
|
@@ -254,11 +348,12 @@ function setMemoryProviderState(providerId, scopeKey, state) {
|
|
|
254
348
|
function appendMemoryTraceEvent(input) {
|
|
255
349
|
const id = randomUUID();
|
|
256
350
|
const now = input.nowMs ?? Date.now();
|
|
351
|
+
const feedback = input.feedback ? normalizeMemoryTraceFeedback(input.feedback, now) : void 0;
|
|
257
352
|
runSqliteWriteTransaction((db) => {
|
|
258
353
|
db.prepare(`INSERT INTO memory_trace_events (
|
|
259
354
|
trace_id, session_key, turn_id, phase, provider_id, request_json,
|
|
260
|
-
result_count, selected_record_ids_json, skipped_reason, error, duration_ms, created_at
|
|
261
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.sessionKey ?? null, input.turnId ?? null, input.phase, input.providerId, JSON.stringify(input.request ?? {}), input.resultCount ?? null, JSON.stringify(input.selectedRecordIds ?? []), input.skippedReason ?? null, input.error ?? null, Math.max(0, Math.floor(input.durationMs ?? 0)), now);
|
|
355
|
+
result_count, selected_record_ids_json, skipped_reason, error, feedback_json, duration_ms, created_at
|
|
356
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.sessionKey ?? null, input.turnId ?? null, input.phase, input.providerId, JSON.stringify(input.request ?? {}), input.resultCount ?? null, JSON.stringify(input.selectedRecordIds ?? []), input.skippedReason ?? null, input.error ?? null, JSON.stringify(feedback ?? {}), Math.max(0, Math.floor(input.durationMs ?? 0)), now);
|
|
262
357
|
});
|
|
263
358
|
return id;
|
|
264
359
|
}
|
|
@@ -281,20 +376,69 @@ function listMemoryTraceEvents(options = {}) {
|
|
|
281
376
|
return getSqliteDatabase().prepare(`SELECT * FROM memory_trace_events
|
|
282
377
|
${where.length > 0 ? `WHERE ${where.join(" AND ")}` : ""}
|
|
283
378
|
ORDER BY created_at DESC
|
|
284
|
-
LIMIT ?`).all(...params, limit).map(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
...
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
379
|
+
LIMIT ?`).all(...params, limit).map(memoryTraceRowToPayload);
|
|
380
|
+
}
|
|
381
|
+
function setMemoryTraceFeedback(input) {
|
|
382
|
+
const existing = getSqliteDatabase().prepare(`SELECT * FROM memory_trace_events WHERE trace_id = ?`).get(input.traceId);
|
|
383
|
+
if (!existing) return null;
|
|
384
|
+
const feedback = normalizeMemoryTraceFeedback(input.feedback, input.nowMs, parseMemoryTraceFeedback(existing.feedback_json));
|
|
385
|
+
runSqliteWriteTransaction((db) => {
|
|
386
|
+
db.prepare(`UPDATE memory_trace_events SET feedback_json = ? WHERE trace_id = ?`).run(JSON.stringify(feedback), input.traceId);
|
|
387
|
+
});
|
|
388
|
+
return memoryTraceRowToPayload({
|
|
389
|
+
...existing,
|
|
390
|
+
feedback_json: JSON.stringify(feedback)
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function summarizeMemoryRecallFeedback(options = {}) {
|
|
394
|
+
const where = ["phase IN (?, ?)"];
|
|
395
|
+
const params = ["search", "inject"];
|
|
396
|
+
if (options.providerId) {
|
|
397
|
+
where.push("provider_id = ?");
|
|
398
|
+
params.push(options.providerId);
|
|
399
|
+
}
|
|
400
|
+
if (options.sessionKey) {
|
|
401
|
+
where.push("session_key = ?");
|
|
402
|
+
params.push(options.sessionKey);
|
|
403
|
+
}
|
|
404
|
+
const limit = Math.max(1, Math.min(5e3, options.limit ?? 1e3));
|
|
405
|
+
const rows = getSqliteDatabase().prepare(`SELECT * FROM memory_trace_events
|
|
406
|
+
WHERE ${where.join(" AND ")}
|
|
407
|
+
ORDER BY created_at DESC
|
|
408
|
+
LIMIT ?`).all(...params, limit);
|
|
409
|
+
const summaries = /* @__PURE__ */ new Map();
|
|
410
|
+
for (const row of rows) {
|
|
411
|
+
const feedback = parseMemoryTraceFeedback(row.feedback_json);
|
|
412
|
+
if (!feedback) continue;
|
|
413
|
+
const recordIds = parseStringArray(row.selected_record_ids_json);
|
|
414
|
+
for (const recordId of recordIds) {
|
|
415
|
+
if (options.recordId && recordId !== options.recordId) continue;
|
|
416
|
+
const current = summaries.get(recordId) ?? {
|
|
417
|
+
recordId,
|
|
418
|
+
helpful: 0,
|
|
419
|
+
notHelpful: 0,
|
|
420
|
+
mixed: 0,
|
|
421
|
+
irrelevant: 0,
|
|
422
|
+
total: 0,
|
|
423
|
+
averageScore: null,
|
|
424
|
+
scoreTotal: 0,
|
|
425
|
+
scoreCount: 0
|
|
426
|
+
};
|
|
427
|
+
if (feedback.outcome === "helpful") current.helpful += 1;
|
|
428
|
+
if (feedback.outcome === "not_helpful") current.notHelpful += 1;
|
|
429
|
+
if (feedback.outcome === "mixed") current.mixed += 1;
|
|
430
|
+
if (feedback.outcome === "irrelevant") current.irrelevant += 1;
|
|
431
|
+
current.total += 1;
|
|
432
|
+
if (typeof feedback.score === "number") {
|
|
433
|
+
current.scoreTotal += feedback.score;
|
|
434
|
+
current.scoreCount += 1;
|
|
435
|
+
current.averageScore = current.scoreTotal / current.scoreCount;
|
|
436
|
+
}
|
|
437
|
+
current.lastFeedbackAt ??= feedback.updatedAt ?? feedback.createdAt;
|
|
438
|
+
summaries.set(recordId, current);
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
return [...summaries.values()].map(({ scoreTotal: _scoreTotal, scoreCount: _scoreCount, ...summary }) => summary).sort((a, b) => b.total - a.total);
|
|
298
442
|
}
|
|
299
443
|
function parseJsonValue(json, fallback) {
|
|
300
444
|
try {
|
|
@@ -304,6 +448,6 @@ function parseJsonValue(json, fallback) {
|
|
|
304
448
|
}
|
|
305
449
|
}
|
|
306
450
|
//#endregion
|
|
307
|
-
export { appendMemorySignal, appendMemoryTraceEvent, deleteMemoryRecord, getMemoryProviderState, getMemoryRecord, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, searchMemoryRecords, setMemoryProviderState, upsertMemoryRecord };
|
|
451
|
+
export { appendMemorySignal, appendMemoryTraceEvent, deleteMemoryRecord, getMemoryProviderState, getMemoryRecord, listMemoryRecords, listMemorySignals, listMemoryTraceEvents, searchMemoryRecords, setMemoryProviderState, setMemoryTraceFeedback, summarizeMemoryRecallFeedback, upsertMemoryRecord };
|
|
308
452
|
|
|
309
453
|
//# sourceMappingURL=memory-records-repository.js.map
|