@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,5 +1,5 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "./transaction.js";
|
|
2
|
-
import {
|
|
2
|
+
import { buildFts5SearchQuery, fts5RankToScore, memoryLexicalSimilarity } from "./fts.js";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
//#region src/storage/sqlite/memory-records-repository.ts
|
|
5
5
|
const USER_UNDERSTANDING_REMEDIATION_POLICY = {
|
|
@@ -121,9 +121,6 @@ function rowToRecord(row) {
|
|
|
121
121
|
tags: parseStringArray(row.tags_json)
|
|
122
122
|
};
|
|
123
123
|
}
|
|
124
|
-
function bm25ToScore(rank) {
|
|
125
|
-
return Math.max(0, Math.min(1, 1 / (1 + Math.max(0, rank))));
|
|
126
|
-
}
|
|
127
124
|
function upsertMemoryRecordFts(db, row) {
|
|
128
125
|
db.prepare(`DELETE FROM memory_records_fts WHERE record_id = ?`).run(row.id);
|
|
129
126
|
if (!row.content.trim()) return;
|
|
@@ -257,6 +254,14 @@ function listMemoryRecords(options = {}) {
|
|
|
257
254
|
where.push("project_id = ?");
|
|
258
255
|
params.push(options.projectId);
|
|
259
256
|
}
|
|
257
|
+
if (options.visibleToSessionKey) {
|
|
258
|
+
where.push("(session_key IS NULL OR session_key = ?)");
|
|
259
|
+
params.push(options.visibleToSessionKey);
|
|
260
|
+
} else if (options.unscopedSessionOnly) where.push("session_key IS NULL");
|
|
261
|
+
if (options.visibleToProjectId) {
|
|
262
|
+
where.push("(project_id IS NULL OR project_id = ?)");
|
|
263
|
+
params.push(options.visibleToProjectId);
|
|
264
|
+
} else if (options.unscopedProjectOnly) where.push("project_id IS NULL");
|
|
260
265
|
if (options.kind) {
|
|
261
266
|
where.push("kind = ?");
|
|
262
267
|
params.push(options.kind);
|
|
@@ -277,7 +282,7 @@ function listMemoryRecords(options = {}) {
|
|
|
277
282
|
LIMIT ? OFFSET ?`).all(...params, limit, offset).map(rowToRecord);
|
|
278
283
|
}
|
|
279
284
|
function searchMemoryRecords(options) {
|
|
280
|
-
const query =
|
|
285
|
+
const query = buildFts5SearchQuery(options.query);
|
|
281
286
|
if (!query) return [];
|
|
282
287
|
const filters = ["memory_records_fts MATCH ?"];
|
|
283
288
|
const params = [query];
|
|
@@ -293,6 +298,14 @@ function searchMemoryRecords(options) {
|
|
|
293
298
|
filters.push("r.project_id = ?");
|
|
294
299
|
params.push(options.projectId);
|
|
295
300
|
}
|
|
301
|
+
if (options.visibleToSessionKey) {
|
|
302
|
+
filters.push("(r.session_key IS NULL OR r.session_key = ?)");
|
|
303
|
+
params.push(options.visibleToSessionKey);
|
|
304
|
+
} else if (options.unscopedSessionOnly) filters.push("r.session_key IS NULL");
|
|
305
|
+
if (options.visibleToProjectId) {
|
|
306
|
+
filters.push("(r.project_id IS NULL OR r.project_id = ?)");
|
|
307
|
+
params.push(options.visibleToProjectId);
|
|
308
|
+
} else if (options.unscopedProjectOnly) filters.push("r.project_id IS NULL");
|
|
296
309
|
if (options.providerId) {
|
|
297
310
|
filters.push("f.provider_id = ?");
|
|
298
311
|
params.push(options.providerId);
|
|
@@ -306,18 +319,44 @@ function searchMemoryRecords(options) {
|
|
|
306
319
|
params.push(...statuses);
|
|
307
320
|
const maxResults = Math.max(1, Math.min(50, options.maxResults ?? 5));
|
|
308
321
|
const minScore = options.minScore ?? 0;
|
|
309
|
-
|
|
322
|
+
const rows = getSqliteDatabase().prepare(`SELECT
|
|
310
323
|
r.*,
|
|
311
324
|
bm25(memory_records_fts) AS rank
|
|
312
325
|
FROM memory_records_fts f
|
|
313
326
|
JOIN memory_records r ON r.record_id = f.record_id
|
|
314
327
|
WHERE ${filters.join(" AND ")}
|
|
315
328
|
ORDER BY rank
|
|
316
|
-
LIMIT ?`).all(...params, maxResults * 3)
|
|
329
|
+
LIMIT ?`).all(...params, maxResults * 3);
|
|
330
|
+
if (rows.length === 0) return listMemoryRecords({
|
|
331
|
+
providerId: options.providerId,
|
|
332
|
+
agentId: options.agentId,
|
|
333
|
+
workspaceId: options.workspaceId,
|
|
334
|
+
projectId: options.projectId,
|
|
335
|
+
visibleToSessionKey: options.visibleToSessionKey,
|
|
336
|
+
unscopedSessionOnly: options.unscopedSessionOnly,
|
|
337
|
+
visibleToProjectId: options.visibleToProjectId,
|
|
338
|
+
unscopedProjectOnly: options.unscopedProjectOnly,
|
|
339
|
+
limit: 500
|
|
340
|
+
}).filter((record) => statuses.includes(record.status ?? "active") && (!options.kinds?.length || options.kinds.includes(record.kind))).map((record) => ({
|
|
341
|
+
record,
|
|
342
|
+
score: memoryLexicalSimilarity(options.query, record.content),
|
|
343
|
+
snippet: record.content,
|
|
344
|
+
citation: {
|
|
345
|
+
providerId: record.source.provider ?? options.providerId ?? "local",
|
|
346
|
+
recordId: record.id,
|
|
347
|
+
path: record.source.path,
|
|
348
|
+
lineStart: record.source.lineStart,
|
|
349
|
+
lineEnd: record.source.lineEnd,
|
|
350
|
+
createdAt: record.createdAt
|
|
351
|
+
}
|
|
352
|
+
})).filter((result) => result.score >= minScore).sort((a, b) => b.score - a.score).slice(0, maxResults);
|
|
353
|
+
const bestRank = Math.min(...rows.map((row) => row.rank));
|
|
354
|
+
const worstRank = Math.max(...rows.map((row) => row.rank));
|
|
355
|
+
return rows.map((row) => {
|
|
317
356
|
const record = rowToRecord(row);
|
|
318
357
|
return {
|
|
319
358
|
record,
|
|
320
|
-
score:
|
|
359
|
+
score: fts5RankToScore(row.rank, bestRank, worstRank),
|
|
321
360
|
snippet: record.content,
|
|
322
361
|
citation: {
|
|
323
362
|
providerId: row.provider_id,
|
|
@@ -434,6 +473,10 @@ function listMemoryTraceEvents(options = {}) {
|
|
|
434
473
|
where.push("provider_id = ?");
|
|
435
474
|
params.push(options.providerId);
|
|
436
475
|
}
|
|
476
|
+
if (options.agentId) {
|
|
477
|
+
where.push("session_key LIKE ?");
|
|
478
|
+
params.push(`agent:${options.agentId}:%`);
|
|
479
|
+
}
|
|
437
480
|
if (options.sessionKey) {
|
|
438
481
|
where.push("session_key = ?");
|
|
439
482
|
params.push(options.sessionKey);
|
|
@@ -554,6 +597,10 @@ function summarizeMemoryRecallFeedback(options = {}) {
|
|
|
554
597
|
where.push("provider_id = ?");
|
|
555
598
|
params.push(options.providerId);
|
|
556
599
|
}
|
|
600
|
+
if (options.agentId) {
|
|
601
|
+
where.push("session_key LIKE ?");
|
|
602
|
+
params.push(`agent:${options.agentId}:%`);
|
|
603
|
+
}
|
|
557
604
|
if (options.sessionKey) {
|
|
558
605
|
where.push("session_key = ?");
|
|
559
606
|
params.push(options.sessionKey);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory-records-repository.js","names":[],"sources":["../../../../src/storage/sqlite/memory-records-repository.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type {\n MemoryDisclosurePolicy,\n MemoryDurability,\n MemoryExplicitness,\n MemoryKind,\n MemoryRecord,\n MemorySensitivity,\n MemorySearchResult,\n MemorySignal,\n MemoryStatus,\n} from '../../agent/memory/types.js';\nimport { escapeFts5Query } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\ntype MemoryRecordRow = {\n record_id: string;\n provider_id: string;\n kind: string;\n agent_id: string;\n workspace_id: string | null;\n session_key: string | null;\n project_id: string | null;\n content: string;\n source_json: string;\n confidence: number | null;\n tags_json: string;\n status: string;\n sensitivity: string;\n evidence_json: string;\n canonical_key: string | null;\n explicitness: string;\n durability: string;\n importance: number;\n disclosure_policy: string;\n valid_from: number | null;\n valid_to: number | null;\n review_after: number | null;\n expires_at: number | null;\n supersedes_record_id: string | null;\n conflict_group_id: string | null;\n created_at: number;\n updated_at: number;\n};\n\ntype MemoryRecordSearchRow = MemoryRecordRow & {\n rank: number;\n};\n\nexport interface UpsertMemoryRecordInput {\n id?: string;\n providerId: string;\n kind: MemoryKind;\n agentId: string;\n workspaceId?: string;\n sessionKey?: string;\n projectId?: string;\n content: string;\n canonicalKey?: string;\n source?: MemoryRecord['source'];\n confidence?: number;\n tags?: string[];\n status?: MemoryStatus;\n sensitivity?: MemorySensitivity;\n explicitness?: MemoryExplicitness;\n durability?: MemoryDurability;\n importance?: number;\n disclosurePolicy?: MemoryDisclosurePolicy;\n evidence?: MemoryRecord['evidence'];\n validFrom?: string;\n validTo?: string;\n reviewAfter?: string;\n expiresAt?: string;\n supersedesRecordId?: string;\n conflictGroupId?: string;\n nowMs?: number;\n}\n\nexport interface ListMemoryRecordsOptions {\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n projectId?: string;\n kind?: MemoryKind;\n status?: MemoryStatus;\n canonicalKey?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface SearchMemoryRecordsOptions {\n query: string;\n agentId?: string;\n workspaceId?: string;\n projectId?: string;\n providerId?: string;\n kinds?: MemoryKind[];\n statuses?: MemoryStatus[];\n maxResults?: number;\n minScore?: number;\n}\n\nexport interface AppendMemorySignalInput {\n signal: MemorySignal;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n sessionKey?: string;\n nowMs?: number;\n}\n\nexport interface MemorySignalRowPayload {\n signalId: string;\n source: string;\n recordId?: string;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n sessionKey?: string;\n score?: number;\n content?: string;\n metadata: Record<string, unknown>;\n createdAt: string;\n}\n\ntype MemorySignalRow = {\n signal_id: string;\n source: string;\n record_id: string | null;\n provider_id: string | null;\n agent_id: string | null;\n workspace_id: string | null;\n session_key: string | null;\n score: number | null;\n content: string | null;\n metadata_json: string;\n created_at: number;\n};\n\ntype MemoryTraceRow = {\n trace_id: string;\n session_key: string | null;\n turn_id: string | null;\n phase: string;\n provider_id: string;\n request_json: string;\n result_count: number | null;\n selected_record_ids_json: string;\n skipped_reason: string | null;\n error: string | null;\n feedback_json: string;\n duration_ms: number;\n created_at: number;\n};\n\nexport type MemoryTraceFeedbackOutcome = 'helpful' | 'not_helpful' | 'mixed' | 'irrelevant';\n\nexport interface MemoryTraceFeedback {\n outcome: MemoryTraceFeedbackOutcome;\n score?: number;\n reason?: string;\n source?: 'user' | 'evaluator' | 'system';\n createdAt: string;\n updatedAt?: string;\n}\n\nexport interface AppendMemoryTraceEventInput {\n traceId?: string;\n sessionKey?: string;\n turnId?: string;\n phase: 'search' | 'read' | 'write' | 'update' | 'delete' | 'sync' | 'inject' | 'test' | 'understanding' | 'remediation';\n providerId: string;\n request?: unknown;\n resultCount?: number;\n selectedRecordIds?: string[];\n skippedReason?: string;\n error?: string;\n feedback?: MemoryTraceFeedback;\n durationMs?: number;\n nowMs?: number;\n}\n\nexport interface SetMemoryTraceFeedbackInput {\n traceId: string;\n feedback: Omit<MemoryTraceFeedback, 'createdAt' | 'updatedAt'> & {\n createdAt?: string;\n updatedAt?: string;\n };\n nowMs?: number;\n}\n\nexport interface SetLatestMemoryInjectFeedbackInput {\n sessionKey: string;\n beforeMs?: number;\n requireSelectedRecords?: boolean;\n feedback: SetMemoryTraceFeedbackInput['feedback'];\n nowMs?: number;\n}\n\nexport type FindLatestMemoryInjectTraceInput = Pick<\n SetLatestMemoryInjectFeedbackInput,\n 'sessionKey' | 'beforeMs' | 'requireSelectedRecords'\n>;\n\nexport interface MemoryTraceEventPayload {\n traceId: string;\n sessionKey?: string;\n turnId?: string;\n phase: string;\n providerId: string;\n request: unknown;\n resultCount?: number;\n selectedRecordIds: string[];\n skippedReason?: string;\n error?: string;\n feedback?: MemoryTraceFeedback;\n remediation?: MemoryFeedbackRemediationResult;\n durationMs: number;\n createdAt: string;\n}\n\nexport interface MemoryFeedbackRemediationResult {\n triggerTraceId: string;\n evaluatedRecordIds: string[];\n needsReviewRecordIds: string[];\n}\n\nexport const USER_UNDERSTANDING_REMEDIATION_POLICY = {\n minNotHelpful: 2,\n confidencePenalty: 0.2,\n} as const;\n\nexport interface MemoryRecallFeedbackSummary {\n recordId: string;\n helpful: number;\n notHelpful: number;\n mixed: number;\n irrelevant: number;\n total: number;\n averageScore: number | null;\n lastFeedbackAt?: string;\n}\n\nexport interface UserUnderstandingQualityMetrics {\n agentId?: string;\n windowDays: number;\n since: string;\n attempts: {\n total: number;\n turn: number;\n background: number;\n };\n candidates: {\n proposed: number;\n created: number;\n deduplicated: number;\n rejectedByPolicy: number;\n };\n records: {\n total: number;\n candidate: number;\n active: number;\n rejected: number;\n needsReview: number;\n stale: number;\n archived: number;\n agingCandidates: number;\n explicit: number;\n inferred: number;\n averageConfidence: number | null;\n };\n decisions: {\n total: number;\n acceptanceRate: number | null;\n };\n recall: {\n total: number;\n helpful: number;\n notHelpful: number;\n mixed: number;\n irrelevant: number;\n helpfulRate: number | null;\n };\n}\n\nfunction parseStringArray(json: string): string[] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((v): v is string => typeof v === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction parseEvidence(json: string): MemoryRecord['evidence'] {\n try {\n const parsed = JSON.parse(json) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((item): item is NonNullable<MemoryRecord['evidence']>[number] =>\n Boolean(item) && typeof item === 'object',\n );\n } catch {\n return [];\n }\n}\n\nfunction parseMemoryTraceFeedback(json: string): MemoryTraceFeedback | undefined {\n try {\n const parsed = JSON.parse(json) as unknown;\n if (!parsed || typeof parsed !== 'object') return undefined;\n const obj = parsed as Record<string, unknown>;\n const outcome = obj.outcome;\n if (\n outcome !== 'helpful' &&\n outcome !== 'not_helpful' &&\n outcome !== 'mixed' &&\n outcome !== 'irrelevant'\n ) {\n return undefined;\n }\n return {\n outcome,\n ...(typeof obj.score === 'number' ? { score: obj.score } : {}),\n ...(typeof obj.reason === 'string' ? { reason: obj.reason } : {}),\n ...(obj.source === 'user' || obj.source === 'evaluator' || obj.source === 'system'\n ? { source: obj.source }\n : {}),\n createdAt: typeof obj.createdAt === 'string' ? obj.createdAt : new Date(0).toISOString(),\n ...(typeof obj.updatedAt === 'string' ? { updatedAt: obj.updatedAt } : {}),\n };\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeMemoryTraceFeedback(\n input: SetMemoryTraceFeedbackInput['feedback'],\n nowMs = Date.now(),\n existing?: MemoryTraceFeedback,\n): MemoryTraceFeedback {\n const score = typeof input.score === 'number'\n ? Math.max(-1, Math.min(1, input.score))\n : undefined;\n const reason = typeof input.reason === 'string' && input.reason.trim()\n ? input.reason.trim().slice(0, 1000)\n : undefined;\n const nowIso = new Date(nowMs).toISOString();\n return {\n outcome: input.outcome,\n ...(score != null ? { score } : {}),\n ...(reason ? { reason } : {}),\n ...(input.source ? { source: input.source } : {}),\n createdAt: input.createdAt ?? existing?.createdAt ?? nowIso,\n updatedAt: input.updatedAt ?? nowIso,\n };\n}\n\nfunction memoryTraceRowToPayload(row: MemoryTraceRow): MemoryTraceEventPayload {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n return {\n traceId: row.trace_id,\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.turn_id ? { turnId: row.turn_id } : {}),\n phase: row.phase,\n providerId: row.provider_id,\n request: parseJsonValue(row.request_json, {}),\n ...(row.result_count != null ? { resultCount: row.result_count } : {}),\n selectedRecordIds: parseStringArray(row.selected_record_ids_json),\n ...(row.skipped_reason ? { skippedReason: row.skipped_reason } : {}),\n ...(row.error ? { error: row.error } : {}),\n ...(feedback ? { feedback } : {}),\n durationMs: row.duration_ms,\n createdAt: new Date(row.created_at).toISOString(),\n };\n}\n\nfunction parseOptionalTimestamp(value: string | undefined): number | null {\n if (!value?.trim()) return null;\n const parsed = Date.parse(value);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction timestampToIso(value: number | null): string | undefined {\n return value == null ? undefined : new Date(value).toISOString();\n}\n\nfunction parseSource(json: string): MemoryRecord['source'] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return parsed && typeof parsed === 'object' ? (parsed as MemoryRecord['source']) : {};\n } catch {\n return {};\n }\n}\n\nfunction rowToRecord(row: MemoryRecordRow): MemoryRecord {\n return {\n id: row.record_id,\n kind: row.kind as MemoryKind,\n status: row.status as MemoryStatus,\n ...(row.canonical_key ? { canonicalKey: row.canonical_key } : {}),\n scope: {\n agentId: row.agent_id,\n ...(row.workspace_id ? { workspaceId: row.workspace_id } : {}),\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.project_id ? { projectId: row.project_id } : {}),\n },\n content: row.content,\n source: parseSource(row.source_json),\n ...(row.confidence != null ? { confidence: row.confidence } : {}),\n sensitivity: row.sensitivity as MemorySensitivity,\n explicitness: row.explicitness as MemoryExplicitness,\n durability: row.durability as MemoryDurability,\n importance: row.importance,\n disclosurePolicy: row.disclosure_policy as MemoryDisclosurePolicy,\n evidence: parseEvidence(row.evidence_json),\n ...(timestampToIso(row.valid_from) ? { validFrom: timestampToIso(row.valid_from) } : {}),\n ...(timestampToIso(row.valid_to) ? { validTo: timestampToIso(row.valid_to) } : {}),\n ...(timestampToIso(row.review_after) ? { reviewAfter: timestampToIso(row.review_after) } : {}),\n ...(timestampToIso(row.expires_at) ? { expiresAt: timestampToIso(row.expires_at) } : {}),\n ...(row.supersedes_record_id ? { supersedesRecordId: row.supersedes_record_id } : {}),\n ...(row.conflict_group_id ? { conflictGroupId: row.conflict_group_id } : {}),\n createdAt: new Date(row.created_at).toISOString(),\n updatedAt: new Date(row.updated_at).toISOString(),\n tags: parseStringArray(row.tags_json),\n };\n}\n\nfunction bm25ToScore(rank: number): number {\n return Math.max(0, Math.min(1, 1 / (1 + Math.max(0, rank))));\n}\n\nfunction upsertMemoryRecordFts(\n db: ReturnType<typeof getSqliteDatabase>,\n row: Pick<UpsertMemoryRecordInput, 'providerId' | 'kind' | 'agentId' | 'workspaceId' | 'content'> & { id: string },\n): void {\n db.prepare(`DELETE FROM memory_records_fts WHERE record_id = ?`).run(row.id);\n if (!row.content.trim()) return;\n db.prepare(\n `INSERT INTO memory_records_fts (\n content, record_id, provider_id, kind, agent_id, workspace_id\n ) VALUES (?, ?, ?, ?, ?, ?)`,\n ).run(row.content, row.id, row.providerId, row.kind, row.agentId, row.workspaceId ?? null);\n}\n\nexport function upsertMemoryRecord(input: UpsertMemoryRecordInput): MemoryRecord {\n const id = input.id ?? randomUUID();\n const now = input.nowMs ?? Date.now();\n const status = input.status ?? 'active';\n const sensitivity = input.sensitivity ?? 'normal';\n const explicitness = input.explicitness ?? 'inferred';\n const durability = input.durability ?? 'durable';\n const importance = Math.max(0, Math.min(1, input.importance ?? 0.5));\n const disclosurePolicy = input.disclosurePolicy ?? 'referenceable';\n const validFrom = parseOptionalTimestamp(input.validFrom);\n const validTo = parseOptionalTimestamp(input.validTo);\n const reviewAfter = parseOptionalTimestamp(input.reviewAfter);\n const expiresAt = parseOptionalTimestamp(input.expiresAt);\n const source = {\n ...(input.source ?? {}),\n provider: input.source?.provider ?? input.providerId,\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_records (\n record_id, provider_id, kind, agent_id, workspace_id, session_key, project_id,\n content, source_json, confidence, tags_json, status, sensitivity,\n evidence_json, canonical_key, explicitness, durability, importance,\n disclosure_policy, valid_from, valid_to, review_after, expires_at,\n supersedes_record_id, conflict_group_id, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(record_id) DO UPDATE SET\n provider_id = excluded.provider_id,\n kind = excluded.kind,\n agent_id = excluded.agent_id,\n workspace_id = excluded.workspace_id,\n session_key = excluded.session_key,\n project_id = excluded.project_id,\n content = excluded.content,\n source_json = excluded.source_json,\n confidence = excluded.confidence,\n tags_json = excluded.tags_json,\n status = excluded.status,\n sensitivity = excluded.sensitivity,\n evidence_json = excluded.evidence_json,\n canonical_key = excluded.canonical_key,\n explicitness = excluded.explicitness,\n durability = excluded.durability,\n importance = excluded.importance,\n disclosure_policy = excluded.disclosure_policy,\n valid_from = excluded.valid_from,\n valid_to = excluded.valid_to,\n review_after = excluded.review_after,\n expires_at = excluded.expires_at,\n supersedes_record_id = excluded.supersedes_record_id,\n conflict_group_id = excluded.conflict_group_id,\n updated_at = excluded.updated_at`,\n ).run(\n id,\n input.providerId,\n input.kind,\n input.agentId,\n input.workspaceId ?? null,\n input.sessionKey ?? null,\n input.projectId ?? null,\n input.content,\n JSON.stringify(source),\n input.confidence ?? null,\n JSON.stringify(input.tags ?? []),\n status,\n sensitivity,\n JSON.stringify(input.evidence ?? []),\n input.canonicalKey ?? null,\n explicitness,\n durability,\n importance,\n disclosurePolicy,\n validFrom,\n validTo,\n reviewAfter,\n expiresAt,\n input.supersedesRecordId ?? null,\n input.conflictGroupId ?? null,\n now,\n now,\n );\n upsertMemoryRecordFts(db, { ...input, id });\n if (input.supersedesRecordId && input.supersedesRecordId !== id) {\n const target = db.prepare(`SELECT 1 FROM memory_records WHERE record_id = ?`)\n .get(input.supersedesRecordId);\n if (target) {\n db.prepare(\n `INSERT INTO memory_relations (\n relation_id, from_record_id, relation_type, to_record_id,\n confidence, valid_from, valid_to, created_at, updated_at\n ) VALUES (?, ?, 'supersedes', ?, ?, ?, NULL, ?, ?)\n ON CONFLICT(from_record_id, relation_type, to_record_id) DO UPDATE SET\n confidence = excluded.confidence,\n valid_from = excluded.valid_from,\n valid_to = NULL,\n updated_at = excluded.updated_at`,\n ).run(\n randomUUID(),\n id,\n input.supersedesRecordId,\n input.confidence ?? 1,\n validFrom ?? now,\n now,\n now,\n );\n if (status === 'active') {\n db.prepare(\n `UPDATE memory_records\n SET status = 'archived', valid_to = COALESCE(valid_to, ?), updated_at = ?\n WHERE record_id = ? AND status IN ('active', 'needs_review', 'stale')`,\n ).run(now, now, input.supersedesRecordId);\n }\n }\n }\n });\n\n return {\n id,\n kind: input.kind,\n status,\n ...(input.canonicalKey ? { canonicalKey: input.canonicalKey } : {}),\n scope: {\n agentId: input.agentId,\n ...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),\n ...(input.sessionKey ? { sessionKey: input.sessionKey } : {}),\n ...(input.projectId ? { projectId: input.projectId } : {}),\n },\n content: input.content,\n source,\n ...(input.confidence != null ? { confidence: input.confidence } : {}),\n sensitivity,\n explicitness,\n durability,\n importance,\n disclosurePolicy,\n evidence: input.evidence ?? [],\n ...(validFrom != null ? { validFrom: new Date(validFrom).toISOString() } : {}),\n ...(validTo != null ? { validTo: new Date(validTo).toISOString() } : {}),\n ...(reviewAfter != null ? { reviewAfter: new Date(reviewAfter).toISOString() } : {}),\n ...(expiresAt != null ? { expiresAt: new Date(expiresAt).toISOString() } : {}),\n ...(input.supersedesRecordId ? { supersedesRecordId: input.supersedesRecordId } : {}),\n ...(input.conflictGroupId ? { conflictGroupId: input.conflictGroupId } : {}),\n createdAt: new Date(now).toISOString(),\n updatedAt: new Date(now).toISOString(),\n tags: input.tags ?? [],\n };\n}\n\nexport function getMemoryRecord(recordId: string): MemoryRecord | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM memory_records WHERE record_id = ?`)\n .get(recordId) as MemoryRecordRow | undefined;\n return row ? rowToRecord(row) : null;\n}\n\nexport function listMemoryRecords(options: ListMemoryRecordsOptions = {}): MemoryRecord[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n where.push('workspace_id = ?');\n params.push(options.workspaceId);\n }\n if (options.projectId) {\n where.push('project_id = ?');\n params.push(options.projectId);\n }\n if (options.kind) {\n where.push('kind = ?');\n params.push(options.kind);\n }\n if (options.status) {\n where.push('status = ?');\n params.push(options.status);\n }\n if (options.canonicalKey) {\n where.push('canonical_key = ?');\n params.push(options.canonicalKey);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const offset = Math.max(0, options.offset ?? 0);\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_records\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY updated_at DESC\n LIMIT ? OFFSET ?`,\n )\n .all(...params, limit, offset) as MemoryRecordRow[];\n return rows.map(rowToRecord);\n}\n\nexport function searchMemoryRecords(options: SearchMemoryRecordsOptions): MemorySearchResult[] {\n const query = escapeFts5Query(options.query);\n if (!query) return [];\n\n const filters: string[] = ['memory_records_fts MATCH ?'];\n const params: Array<string | number | null> = [query];\n if (options.agentId) {\n filters.push('f.agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n filters.push('f.workspace_id = ?');\n params.push(options.workspaceId);\n }\n if (options.projectId) {\n filters.push('r.project_id = ?');\n params.push(options.projectId);\n }\n if (options.providerId) {\n filters.push('f.provider_id = ?');\n params.push(options.providerId);\n }\n if (options.kinds && options.kinds.length > 0) {\n filters.push(`f.kind IN (${options.kinds.map(() => '?').join(', ')})`);\n params.push(...options.kinds);\n }\n const statuses = options.statuses && options.statuses.length > 0 ? options.statuses : ['active'];\n filters.push(`r.status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n\n const maxResults = Math.max(1, Math.min(50, options.maxResults ?? 5));\n const minScore = options.minScore ?? 0;\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT\n r.*,\n bm25(memory_records_fts) AS rank\n FROM memory_records_fts f\n JOIN memory_records r ON r.record_id = f.record_id\n WHERE ${filters.join(' AND ')}\n ORDER BY rank\n LIMIT ?`,\n )\n .all(...params, maxResults * 3) as MemoryRecordSearchRow[];\n\n return rows\n .map((row) => {\n const record = rowToRecord(row);\n const score = bm25ToScore(row.rank);\n return {\n record,\n score,\n snippet: record.content,\n citation: {\n providerId: row.provider_id,\n recordId: row.record_id,\n path: record.source.path,\n lineStart: record.source.lineStart,\n lineEnd: record.source.lineEnd,\n createdAt: record.createdAt,\n },\n };\n })\n .filter((result) => result.score >= minScore)\n .slice(0, maxResults);\n}\n\nexport function deleteMemoryRecord(recordId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM memory_records_fts WHERE record_id = ?`).run(recordId);\n const result = db.prepare(`DELETE FROM memory_records WHERE record_id = ?`).run(recordId);\n return result.changes > 0;\n });\n}\n\nexport function appendMemorySignal(input: AppendMemorySignalInput): string {\n const id = randomUUID();\n const now = input.nowMs ?? Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_signals (\n signal_id, source, record_id, provider_id, agent_id, workspace_id,\n session_key, score, content, metadata_json, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n input.signal.source,\n input.signal.recordId ?? null,\n input.providerId ?? null,\n input.agentId ?? null,\n input.workspaceId ?? null,\n input.sessionKey ?? null,\n input.signal.score ?? null,\n input.signal.content ?? null,\n JSON.stringify(input.signal.metadata ?? {}),\n now,\n );\n if (input.signal.recordId) {\n db.prepare(\n `UPDATE memory_records\n SET recall_count = recall_count + 1, last_recalled_at = ?, updated_at = MAX(updated_at, ?)\n WHERE record_id = ?`,\n ).run(now, now, input.signal.recordId);\n }\n });\n return id;\n}\n\nexport function listMemorySignals(options: {\n recordId?: string;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n limit?: number;\n} = {}): MemorySignalRowPayload[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.recordId) {\n where.push('record_id = ?');\n params.push(options.recordId);\n }\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n where.push('workspace_id = ?');\n params.push(options.workspaceId);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_signals\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemorySignalRow[];\n return rows.map((row) => {\n let metadata: Record<string, unknown> = {};\n try {\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (parsed && typeof parsed === 'object') metadata = parsed as Record<string, unknown>;\n } catch {\n metadata = {};\n }\n return {\n signalId: row.signal_id,\n source: row.source,\n ...(row.record_id ? { recordId: row.record_id } : {}),\n ...(row.provider_id ? { providerId: row.provider_id } : {}),\n ...(row.agent_id ? { agentId: row.agent_id } : {}),\n ...(row.workspace_id ? { workspaceId: row.workspace_id } : {}),\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.score != null ? { score: row.score } : {}),\n ...(row.content ? { content: row.content } : {}),\n metadata,\n createdAt: new Date(row.created_at).toISOString(),\n };\n });\n}\n\nexport function getMemoryProviderState(providerId: string, scopeKey: string): unknown | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT state_json FROM memory_provider_state WHERE provider_id = ? AND scope_key = ?`)\n .get(providerId, scopeKey) as { state_json: string } | undefined;\n if (!row) return null;\n try {\n return JSON.parse(row.state_json) as unknown;\n } catch {\n return null;\n }\n}\n\nexport function setMemoryProviderState(providerId: string, scopeKey: string, state: unknown): void {\n const now = Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_provider_state (provider_id, scope_key, state_json, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(provider_id, scope_key) DO UPDATE SET\n state_json = excluded.state_json,\n updated_at = excluded.updated_at`,\n ).run(providerId, scopeKey, JSON.stringify(state ?? null), now);\n });\n}\n\nexport function appendMemoryTraceEvent(input: AppendMemoryTraceEventInput): string {\n const id = input.traceId ?? randomUUID();\n const now = input.nowMs ?? Date.now();\n const feedback = input.feedback\n ? normalizeMemoryTraceFeedback(input.feedback, now)\n : undefined;\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_trace_events (\n trace_id, session_key, turn_id, phase, provider_id, request_json,\n result_count, selected_record_ids_json, skipped_reason, error, feedback_json, duration_ms, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n input.sessionKey ?? null,\n input.turnId ?? null,\n input.phase,\n input.providerId,\n JSON.stringify(input.request ?? {}),\n input.resultCount ?? null,\n JSON.stringify(input.selectedRecordIds ?? []),\n input.skippedReason ?? null,\n input.error ?? null,\n JSON.stringify(feedback ?? {}),\n Math.max(0, Math.floor(input.durationMs ?? 0)),\n now,\n );\n });\n return id;\n}\n\nexport function listMemoryTraceEvents(options: {\n providerId?: string;\n sessionKey?: string;\n phase?: string;\n limit?: number;\n} = {}): MemoryTraceEventPayload[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.sessionKey) {\n where.push('session_key = ?');\n params.push(options.sessionKey);\n }\n if (options.phase) {\n where.push('phase = ?');\n params.push(options.phase);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemoryTraceRow[];\n return rows.map(memoryTraceRowToPayload);\n}\n\nexport function setMemoryTraceFeedback(input: SetMemoryTraceFeedbackInput): MemoryTraceEventPayload | null {\n const existing = getSqliteDatabase()\n .prepare(`SELECT * FROM memory_trace_events WHERE trace_id = ?`)\n .get(input.traceId) as MemoryTraceRow | undefined;\n if (!existing) {\n return null;\n }\n const nowMs = input.nowMs ?? Date.now();\n const feedback = normalizeMemoryTraceFeedback(\n input.feedback,\n nowMs,\n parseMemoryTraceFeedback(existing.feedback_json),\n );\n let remediation: MemoryFeedbackRemediationResult | undefined;\n runSqliteWriteTransaction((db) => {\n db.prepare(`UPDATE memory_trace_events SET feedback_json = ? WHERE trace_id = ?`)\n .run(JSON.stringify(feedback), input.traceId);\n remediation = reconcileUserUnderstandingFeedback(db, existing, feedback, nowMs);\n });\n return {\n ...memoryTraceRowToPayload({ ...existing, feedback_json: JSON.stringify(feedback) }),\n ...(remediation ? { remediation } : {}),\n };\n}\n\nfunction reconcileUserUnderstandingFeedback(\n db: ReturnType<typeof getSqliteDatabase>,\n trace: MemoryTraceRow,\n feedback: MemoryTraceFeedback,\n nowMs: number,\n): MemoryFeedbackRemediationResult | undefined {\n if (trace.phase !== 'inject' || feedback.outcome !== 'not_helpful') return undefined;\n const explicitCorrection = feedback.source === 'system'\n && feedback.reason === 'detected_explicit_user_correction';\n const evaluatedRecordIds: string[] = [];\n const needsReviewRecordIds: string[] = [];\n const actions: Array<Record<string, unknown>> = [];\n\n for (const recordId of new Set(parseStringArray(trace.selected_record_ids_json))) {\n const record = db.prepare(\n `SELECT * FROM memory_records\n WHERE record_id = ?\n AND status = 'active'\n AND tags_json LIKE '%\\\"user-understanding\\\"%'`,\n ).get(recordId) as MemoryRecordRow | undefined;\n if (!record) continue;\n evaluatedRecordIds.push(recordId);\n const feedbackRows = db.prepare(\n `SELECT trace.feedback_json\n FROM memory_trace_events AS trace\n JOIN json_each(trace.selected_record_ids_json) AS selected\n ON selected.value = ?\n WHERE trace.phase = 'inject'`,\n ).all(recordId) as Array<{ feedback_json: string }>;\n let helpful = 0;\n let notHelpful = 0;\n for (const row of feedbackRows) {\n const recordFeedback = parseMemoryTraceFeedback(row.feedback_json);\n if (recordFeedback?.outcome === 'helpful') helpful += 1;\n if (recordFeedback?.outcome === 'not_helpful') notHelpful += 1;\n }\n if (!explicitCorrection && (\n notHelpful < USER_UNDERSTANDING_REMEDIATION_POLICY.minNotHelpful\n || notHelpful <= helpful\n )) {\n continue;\n }\n const nextConfidence = record.confidence == null\n ? null\n : Math.round(Math.max(0.1, record.confidence - USER_UNDERSTANDING_REMEDIATION_POLICY.confidencePenalty) * 1000) / 1000;\n const update = db.prepare(\n `UPDATE memory_records\n SET status = 'needs_review', confidence = ?, review_after = ?, updated_at = ?\n WHERE record_id = ? AND status = 'active'`,\n ).run(nextConfidence, nowMs, nowMs, recordId);\n if (update.changes === 0) continue;\n needsReviewRecordIds.push(recordId);\n actions.push({\n recordId,\n previousStatus: record.status,\n nextStatus: 'needs_review',\n previousConfidence: record.confidence,\n nextConfidence,\n helpful,\n notHelpful,\n });\n }\n\n const result: MemoryFeedbackRemediationResult = {\n triggerTraceId: trace.trace_id,\n evaluatedRecordIds,\n needsReviewRecordIds,\n };\n if (needsReviewRecordIds.length > 0) {\n db.prepare(\n `INSERT INTO memory_trace_events (\n trace_id, session_key, turn_id, phase, provider_id, request_json,\n result_count, selected_record_ids_json, skipped_reason, error,\n feedback_json, duration_ms, created_at\n ) VALUES (?, ?, ?, 'remediation', 'user-understanding', ?, ?, ?, NULL, NULL, '{}', 0, ?)`,\n ).run(\n randomUUID(),\n trace.session_key,\n trace.turn_id,\n JSON.stringify({\n triggerTraceId: trace.trace_id,\n reason: explicitCorrection\n ? 'explicit_user_correction'\n : 'repeated_not_helpful_feedback',\n policy: USER_UNDERSTANDING_REMEDIATION_POLICY,\n actions,\n }),\n needsReviewRecordIds.length,\n JSON.stringify(needsReviewRecordIds),\n nowMs,\n );\n }\n return result;\n}\n\nexport function findLatestMemoryInjectTrace(\n input: FindLatestMemoryInjectTraceInput,\n): MemoryTraceEventPayload | null {\n const where = [\n `session_key = ?`,\n `phase = 'inject'`,\n `created_at <= ?`,\n ];\n const row = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n WHERE ${where.join(' AND ')}\n ORDER BY created_at DESC\n LIMIT 1`,\n )\n .get(input.sessionKey, input.beforeMs ?? Date.now()) as MemoryTraceRow | undefined;\n if (!row) return null;\n const trace = memoryTraceRowToPayload(row);\n if (input.requireSelectedRecords && trace.selectedRecordIds.length === 0) return null;\n return trace;\n}\n\nexport function setLatestMemoryInjectFeedback(\n input: SetLatestMemoryInjectFeedbackInput,\n): MemoryTraceEventPayload | null {\n const row = findLatestMemoryInjectTrace(input);\n if (!row) return null;\n return setMemoryTraceFeedback({\n traceId: row.traceId,\n feedback: input.feedback,\n nowMs: input.nowMs,\n });\n}\n\nexport function summarizeMemoryRecallFeedback(options: {\n recordId?: string;\n providerId?: string;\n sessionKey?: string;\n limit?: number;\n} = {}): MemoryRecallFeedbackSummary[] {\n const where = ['phase IN (?, ?)'];\n const params: Array<string | number> = ['search', 'inject'];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.sessionKey) {\n where.push('session_key = ?');\n params.push(options.sessionKey);\n }\n const limit = Math.max(1, Math.min(5000, options.limit ?? 1000));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n WHERE ${where.join(' AND ')}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemoryTraceRow[];\n\n const summaries = new Map<string, MemoryRecallFeedbackSummary & { scoreTotal: number; scoreCount: number }>();\n for (const row of rows) {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n if (!feedback) continue;\n const recordIds = parseStringArray(row.selected_record_ids_json);\n for (const recordId of recordIds) {\n if (options.recordId && recordId !== options.recordId) continue;\n const current = summaries.get(recordId) ?? {\n recordId,\n helpful: 0,\n notHelpful: 0,\n mixed: 0,\n irrelevant: 0,\n total: 0,\n averageScore: null,\n scoreTotal: 0,\n scoreCount: 0,\n };\n if (feedback.outcome === 'helpful') current.helpful += 1;\n if (feedback.outcome === 'not_helpful') current.notHelpful += 1;\n if (feedback.outcome === 'mixed') current.mixed += 1;\n if (feedback.outcome === 'irrelevant') current.irrelevant += 1;\n current.total += 1;\n if (typeof feedback.score === 'number') {\n current.scoreTotal += feedback.score;\n current.scoreCount += 1;\n current.averageScore = current.scoreTotal / current.scoreCount;\n }\n current.lastFeedbackAt ??= feedback.updatedAt ?? feedback.createdAt;\n summaries.set(recordId, current);\n }\n }\n\n return [...summaries.values()]\n .map(({ scoreTotal: _scoreTotal, scoreCount: _scoreCount, ...summary }) => summary)\n .sort((a, b) => b.total - a.total);\n}\n\nfunction boundedMetricCount(value: unknown): number {\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction metricRate(numerator: number, denominator: number): number | null {\n return denominator > 0 ? Math.round((numerator / denominator) * 10_000) / 10_000 : null;\n}\n\nexport function summarizeUserUnderstandingQuality(options: {\n agentId?: string;\n windowDays?: number;\n agingCandidateDays?: number;\n nowMs?: number;\n} = {}): UserUnderstandingQualityMetrics {\n const nowMs = options.nowMs ?? Date.now();\n const windowDays = Math.max(1, Math.min(365, Math.floor(options.windowDays ?? 30)));\n const sinceMs = nowMs - windowDays * 24 * 60 * 60 * 1000;\n const agingCandidateDays = Math.max(1, Math.min(windowDays, Math.floor(options.agingCandidateDays ?? 7)));\n const agingCutoffMs = nowMs - agingCandidateDays * 24 * 60 * 60 * 1000;\n const db = getSqliteDatabase();\n const agentWhere = options.agentId ? 'AND agent_id = ?' : '';\n const recordRows = db.prepare(\n `SELECT record_id, status, explicitness, confidence, created_at, updated_at\n FROM memory_records\n WHERE tags_json LIKE '%\"user-understanding\"%'\n ${agentWhere}`,\n ).all(...(options.agentId ? [options.agentId] : [])) as Array<{\n record_id: string;\n status: string;\n explicitness: string;\n confidence: number | null;\n created_at: number;\n updated_at: number;\n }>;\n\n const records: UserUnderstandingQualityMetrics['records'] = {\n total: recordRows.length,\n candidate: 0,\n active: 0,\n rejected: 0,\n needsReview: 0,\n stale: 0,\n archived: 0,\n agingCandidates: 0,\n explicit: 0,\n inferred: 0,\n averageConfidence: null,\n };\n let confidenceTotal = 0;\n let confidenceCount = 0;\n const understandingRecordIds = new Set<string>();\n for (const row of recordRows) {\n understandingRecordIds.add(row.record_id);\n if (row.status === 'candidate') records.candidate += 1;\n if (row.status === 'active') records.active += 1;\n if (row.status === 'rejected') records.rejected += 1;\n if (row.status === 'needs_review') records.needsReview += 1;\n if (row.status === 'stale') records.stale += 1;\n if (row.status === 'archived') records.archived += 1;\n if (row.status === 'candidate' && row.created_at <= agingCutoffMs) records.agingCandidates += 1;\n if (row.explicitness === 'explicit') records.explicit += 1;\n if (row.explicitness === 'inferred') records.inferred += 1;\n if (typeof row.confidence === 'number') {\n confidenceTotal += row.confidence;\n confidenceCount += 1;\n }\n }\n records.averageConfidence = confidenceCount > 0\n ? Math.round((confidenceTotal / confidenceCount) * 10_000) / 10_000\n : null;\n\n const attempts: UserUnderstandingQualityMetrics['attempts'] = { total: 0, turn: 0, background: 0 };\n const candidates: UserUnderstandingQualityMetrics['candidates'] = {\n proposed: 0,\n created: 0,\n deduplicated: 0,\n rejectedByPolicy: 0,\n };\n const understandingTraces = db.prepare(\n `SELECT request_json FROM memory_trace_events\n WHERE phase = 'understanding' AND created_at >= ?`,\n ).all(sinceMs) as Array<{ request_json: string }>;\n for (const row of understandingTraces) {\n const parsed = parseJsonValue(row.request_json, {});\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;\n const request = parsed as Record<string, unknown>;\n if (options.agentId && request.agentId !== options.agentId) continue;\n attempts.total += 1;\n if (request.source === 'turn') attempts.turn += 1;\n if (request.source === 'background') attempts.background += 1;\n candidates.proposed += boundedMetricCount(request.proposed);\n candidates.created += boundedMetricCount(request.created);\n candidates.deduplicated += boundedMetricCount(request.deduplicated);\n candidates.rejectedByPolicy += boundedMetricCount(request.rejected);\n }\n\n const recall: UserUnderstandingQualityMetrics['recall'] = {\n total: 0,\n helpful: 0,\n notHelpful: 0,\n mixed: 0,\n irrelevant: 0,\n helpfulRate: null,\n };\n if (understandingRecordIds.size > 0) {\n const recallRows = db.prepare(\n `SELECT selected_record_ids_json, feedback_json FROM memory_trace_events\n WHERE phase IN ('search', 'inject') AND created_at >= ?`,\n ).all(sinceMs) as Array<{ selected_record_ids_json: string; feedback_json: string }>;\n for (const row of recallRows) {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n if (!feedback) continue;\n const selected = parseStringArray(row.selected_record_ids_json);\n if (!selected.some((recordId) => understandingRecordIds.has(recordId))) continue;\n recall.total += 1;\n if (feedback.outcome === 'helpful') recall.helpful += 1;\n if (feedback.outcome === 'not_helpful') recall.notHelpful += 1;\n if (feedback.outcome === 'mixed') recall.mixed += 1;\n if (feedback.outcome === 'irrelevant') recall.irrelevant += 1;\n }\n }\n recall.helpfulRate = metricRate(recall.helpful, recall.total);\n const recentDecisions = recordRows.filter(\n (row) => (row.status === 'active' || row.status === 'rejected') && row.updated_at >= sinceMs,\n );\n const acceptedDecisions = recentDecisions.filter((row) => row.status === 'active').length;\n const decisionTotal = recentDecisions.length;\n\n return {\n ...(options.agentId ? { agentId: options.agentId } : {}),\n windowDays,\n since: new Date(sinceMs).toISOString(),\n attempts,\n candidates,\n records,\n decisions: {\n total: decisionTotal,\n acceptanceRate: metricRate(acceptedDecisions, decisionTotal),\n },\n recall,\n };\n}\n\nfunction parseJsonValue(json: string, fallback: unknown): unknown {\n try {\n return JSON.parse(json) as unknown;\n } catch {\n return fallback;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"memory-records-repository.js","names":[],"sources":["../../../../src/storage/sqlite/memory-records-repository.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport type {\n MemoryDisclosurePolicy,\n MemoryDurability,\n MemoryExplicitness,\n MemoryKind,\n MemoryRecord,\n MemorySensitivity,\n MemorySearchResult,\n MemorySignal,\n MemoryStatus,\n} from '../../agent/memory/types.js';\nimport { buildFts5SearchQuery, fts5RankToScore, memoryLexicalSimilarity } from './fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from './transaction.js';\n\ntype MemoryRecordRow = {\n record_id: string;\n provider_id: string;\n kind: string;\n agent_id: string;\n workspace_id: string | null;\n session_key: string | null;\n project_id: string | null;\n content: string;\n source_json: string;\n confidence: number | null;\n tags_json: string;\n status: string;\n sensitivity: string;\n evidence_json: string;\n canonical_key: string | null;\n explicitness: string;\n durability: string;\n importance: number;\n disclosure_policy: string;\n valid_from: number | null;\n valid_to: number | null;\n review_after: number | null;\n expires_at: number | null;\n supersedes_record_id: string | null;\n conflict_group_id: string | null;\n created_at: number;\n updated_at: number;\n};\n\ntype MemoryRecordSearchRow = MemoryRecordRow & {\n rank: number;\n};\n\nexport interface UpsertMemoryRecordInput {\n id?: string;\n providerId: string;\n kind: MemoryKind;\n agentId: string;\n workspaceId?: string;\n sessionKey?: string;\n projectId?: string;\n content: string;\n canonicalKey?: string;\n source?: MemoryRecord['source'];\n confidence?: number;\n tags?: string[];\n status?: MemoryStatus;\n sensitivity?: MemorySensitivity;\n explicitness?: MemoryExplicitness;\n durability?: MemoryDurability;\n importance?: number;\n disclosurePolicy?: MemoryDisclosurePolicy;\n evidence?: MemoryRecord['evidence'];\n validFrom?: string;\n validTo?: string;\n reviewAfter?: string;\n expiresAt?: string;\n supersedesRecordId?: string;\n conflictGroupId?: string;\n nowMs?: number;\n}\n\nexport interface ListMemoryRecordsOptions {\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n projectId?: string;\n /** Include unscoped records plus records visible to this session. */\n visibleToSessionKey?: string;\n /** Return only records that are not scoped to a session. */\n unscopedSessionOnly?: boolean;\n /** Include unscoped records plus records visible to this project. */\n visibleToProjectId?: string;\n /** Return only records that are not scoped to a project. */\n unscopedProjectOnly?: boolean;\n kind?: MemoryKind;\n status?: MemoryStatus;\n canonicalKey?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface SearchMemoryRecordsOptions {\n query: string;\n agentId?: string;\n workspaceId?: string;\n projectId?: string;\n /** Include unscoped records plus records visible to this session. */\n visibleToSessionKey?: string;\n /** Return only records that are not scoped to a session. */\n unscopedSessionOnly?: boolean;\n /** Include unscoped records plus records visible to this project. */\n visibleToProjectId?: string;\n /** Return only records that are not scoped to a project. */\n unscopedProjectOnly?: boolean;\n providerId?: string;\n kinds?: MemoryKind[];\n statuses?: MemoryStatus[];\n maxResults?: number;\n minScore?: number;\n}\n\nexport interface AppendMemorySignalInput {\n signal: MemorySignal;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n sessionKey?: string;\n nowMs?: number;\n}\n\nexport interface MemorySignalRowPayload {\n signalId: string;\n source: string;\n recordId?: string;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n sessionKey?: string;\n score?: number;\n content?: string;\n metadata: Record<string, unknown>;\n createdAt: string;\n}\n\ntype MemorySignalRow = {\n signal_id: string;\n source: string;\n record_id: string | null;\n provider_id: string | null;\n agent_id: string | null;\n workspace_id: string | null;\n session_key: string | null;\n score: number | null;\n content: string | null;\n metadata_json: string;\n created_at: number;\n};\n\ntype MemoryTraceRow = {\n trace_id: string;\n session_key: string | null;\n turn_id: string | null;\n phase: string;\n provider_id: string;\n request_json: string;\n result_count: number | null;\n selected_record_ids_json: string;\n skipped_reason: string | null;\n error: string | null;\n feedback_json: string;\n duration_ms: number;\n created_at: number;\n};\n\nexport type MemoryTraceFeedbackOutcome = 'helpful' | 'not_helpful' | 'mixed' | 'irrelevant';\n\nexport interface MemoryTraceFeedback {\n outcome: MemoryTraceFeedbackOutcome;\n score?: number;\n reason?: string;\n source?: 'user' | 'evaluator' | 'system';\n createdAt: string;\n updatedAt?: string;\n}\n\nexport interface AppendMemoryTraceEventInput {\n traceId?: string;\n sessionKey?: string;\n turnId?: string;\n phase: 'search' | 'read' | 'write' | 'update' | 'delete' | 'sync' | 'inject' | 'test' | 'understanding' | 'remediation';\n providerId: string;\n request?: unknown;\n resultCount?: number;\n selectedRecordIds?: string[];\n skippedReason?: string;\n error?: string;\n feedback?: MemoryTraceFeedback;\n durationMs?: number;\n nowMs?: number;\n}\n\nexport interface SetMemoryTraceFeedbackInput {\n traceId: string;\n feedback: Omit<MemoryTraceFeedback, 'createdAt' | 'updatedAt'> & {\n createdAt?: string;\n updatedAt?: string;\n };\n nowMs?: number;\n}\n\nexport interface SetLatestMemoryInjectFeedbackInput {\n sessionKey: string;\n beforeMs?: number;\n requireSelectedRecords?: boolean;\n feedback: SetMemoryTraceFeedbackInput['feedback'];\n nowMs?: number;\n}\n\nexport type FindLatestMemoryInjectTraceInput = Pick<\n SetLatestMemoryInjectFeedbackInput,\n 'sessionKey' | 'beforeMs' | 'requireSelectedRecords'\n>;\n\nexport interface MemoryTraceEventPayload {\n traceId: string;\n sessionKey?: string;\n turnId?: string;\n phase: string;\n providerId: string;\n request: unknown;\n resultCount?: number;\n selectedRecordIds: string[];\n skippedReason?: string;\n error?: string;\n feedback?: MemoryTraceFeedback;\n remediation?: MemoryFeedbackRemediationResult;\n durationMs: number;\n createdAt: string;\n}\n\nexport interface MemoryFeedbackRemediationResult {\n triggerTraceId: string;\n evaluatedRecordIds: string[];\n needsReviewRecordIds: string[];\n}\n\nexport const USER_UNDERSTANDING_REMEDIATION_POLICY = {\n minNotHelpful: 2,\n confidencePenalty: 0.2,\n} as const;\n\nexport interface MemoryRecallFeedbackSummary {\n recordId: string;\n helpful: number;\n notHelpful: number;\n mixed: number;\n irrelevant: number;\n total: number;\n averageScore: number | null;\n lastFeedbackAt?: string;\n}\n\nexport interface UserUnderstandingQualityMetrics {\n agentId?: string;\n windowDays: number;\n since: string;\n attempts: {\n total: number;\n turn: number;\n background: number;\n };\n candidates: {\n proposed: number;\n created: number;\n deduplicated: number;\n rejectedByPolicy: number;\n };\n records: {\n total: number;\n candidate: number;\n active: number;\n rejected: number;\n needsReview: number;\n stale: number;\n archived: number;\n agingCandidates: number;\n explicit: number;\n inferred: number;\n averageConfidence: number | null;\n };\n decisions: {\n total: number;\n acceptanceRate: number | null;\n };\n recall: {\n total: number;\n helpful: number;\n notHelpful: number;\n mixed: number;\n irrelevant: number;\n helpfulRate: number | null;\n };\n}\n\nfunction parseStringArray(json: string): string[] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return Array.isArray(parsed) ? parsed.filter((v): v is string => typeof v === 'string') : [];\n } catch {\n return [];\n }\n}\n\nfunction parseEvidence(json: string): MemoryRecord['evidence'] {\n try {\n const parsed = JSON.parse(json) as unknown;\n if (!Array.isArray(parsed)) return [];\n return parsed.filter((item): item is NonNullable<MemoryRecord['evidence']>[number] =>\n Boolean(item) && typeof item === 'object',\n );\n } catch {\n return [];\n }\n}\n\nfunction parseMemoryTraceFeedback(json: string): MemoryTraceFeedback | undefined {\n try {\n const parsed = JSON.parse(json) as unknown;\n if (!parsed || typeof parsed !== 'object') return undefined;\n const obj = parsed as Record<string, unknown>;\n const outcome = obj.outcome;\n if (\n outcome !== 'helpful' &&\n outcome !== 'not_helpful' &&\n outcome !== 'mixed' &&\n outcome !== 'irrelevant'\n ) {\n return undefined;\n }\n return {\n outcome,\n ...(typeof obj.score === 'number' ? { score: obj.score } : {}),\n ...(typeof obj.reason === 'string' ? { reason: obj.reason } : {}),\n ...(obj.source === 'user' || obj.source === 'evaluator' || obj.source === 'system'\n ? { source: obj.source }\n : {}),\n createdAt: typeof obj.createdAt === 'string' ? obj.createdAt : new Date(0).toISOString(),\n ...(typeof obj.updatedAt === 'string' ? { updatedAt: obj.updatedAt } : {}),\n };\n } catch {\n return undefined;\n }\n}\n\nfunction normalizeMemoryTraceFeedback(\n input: SetMemoryTraceFeedbackInput['feedback'],\n nowMs = Date.now(),\n existing?: MemoryTraceFeedback,\n): MemoryTraceFeedback {\n const score = typeof input.score === 'number'\n ? Math.max(-1, Math.min(1, input.score))\n : undefined;\n const reason = typeof input.reason === 'string' && input.reason.trim()\n ? input.reason.trim().slice(0, 1000)\n : undefined;\n const nowIso = new Date(nowMs).toISOString();\n return {\n outcome: input.outcome,\n ...(score != null ? { score } : {}),\n ...(reason ? { reason } : {}),\n ...(input.source ? { source: input.source } : {}),\n createdAt: input.createdAt ?? existing?.createdAt ?? nowIso,\n updatedAt: input.updatedAt ?? nowIso,\n };\n}\n\nfunction memoryTraceRowToPayload(row: MemoryTraceRow): MemoryTraceEventPayload {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n return {\n traceId: row.trace_id,\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.turn_id ? { turnId: row.turn_id } : {}),\n phase: row.phase,\n providerId: row.provider_id,\n request: parseJsonValue(row.request_json, {}),\n ...(row.result_count != null ? { resultCount: row.result_count } : {}),\n selectedRecordIds: parseStringArray(row.selected_record_ids_json),\n ...(row.skipped_reason ? { skippedReason: row.skipped_reason } : {}),\n ...(row.error ? { error: row.error } : {}),\n ...(feedback ? { feedback } : {}),\n durationMs: row.duration_ms,\n createdAt: new Date(row.created_at).toISOString(),\n };\n}\n\nfunction parseOptionalTimestamp(value: string | undefined): number | null {\n if (!value?.trim()) return null;\n const parsed = Date.parse(value);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nfunction timestampToIso(value: number | null): string | undefined {\n return value == null ? undefined : new Date(value).toISOString();\n}\n\nfunction parseSource(json: string): MemoryRecord['source'] {\n try {\n const parsed = JSON.parse(json) as unknown;\n return parsed && typeof parsed === 'object' ? (parsed as MemoryRecord['source']) : {};\n } catch {\n return {};\n }\n}\n\nfunction rowToRecord(row: MemoryRecordRow): MemoryRecord {\n return {\n id: row.record_id,\n kind: row.kind as MemoryKind,\n status: row.status as MemoryStatus,\n ...(row.canonical_key ? { canonicalKey: row.canonical_key } : {}),\n scope: {\n agentId: row.agent_id,\n ...(row.workspace_id ? { workspaceId: row.workspace_id } : {}),\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.project_id ? { projectId: row.project_id } : {}),\n },\n content: row.content,\n source: parseSource(row.source_json),\n ...(row.confidence != null ? { confidence: row.confidence } : {}),\n sensitivity: row.sensitivity as MemorySensitivity,\n explicitness: row.explicitness as MemoryExplicitness,\n durability: row.durability as MemoryDurability,\n importance: row.importance,\n disclosurePolicy: row.disclosure_policy as MemoryDisclosurePolicy,\n evidence: parseEvidence(row.evidence_json),\n ...(timestampToIso(row.valid_from) ? { validFrom: timestampToIso(row.valid_from) } : {}),\n ...(timestampToIso(row.valid_to) ? { validTo: timestampToIso(row.valid_to) } : {}),\n ...(timestampToIso(row.review_after) ? { reviewAfter: timestampToIso(row.review_after) } : {}),\n ...(timestampToIso(row.expires_at) ? { expiresAt: timestampToIso(row.expires_at) } : {}),\n ...(row.supersedes_record_id ? { supersedesRecordId: row.supersedes_record_id } : {}),\n ...(row.conflict_group_id ? { conflictGroupId: row.conflict_group_id } : {}),\n createdAt: new Date(row.created_at).toISOString(),\n updatedAt: new Date(row.updated_at).toISOString(),\n tags: parseStringArray(row.tags_json),\n };\n}\n\nfunction upsertMemoryRecordFts(\n db: ReturnType<typeof getSqliteDatabase>,\n row: Pick<UpsertMemoryRecordInput, 'providerId' | 'kind' | 'agentId' | 'workspaceId' | 'content'> & { id: string },\n): void {\n db.prepare(`DELETE FROM memory_records_fts WHERE record_id = ?`).run(row.id);\n if (!row.content.trim()) return;\n db.prepare(\n `INSERT INTO memory_records_fts (\n content, record_id, provider_id, kind, agent_id, workspace_id\n ) VALUES (?, ?, ?, ?, ?, ?)`,\n ).run(row.content, row.id, row.providerId, row.kind, row.agentId, row.workspaceId ?? null);\n}\n\nexport function upsertMemoryRecord(input: UpsertMemoryRecordInput): MemoryRecord {\n const id = input.id ?? randomUUID();\n const now = input.nowMs ?? Date.now();\n const status = input.status ?? 'active';\n const sensitivity = input.sensitivity ?? 'normal';\n const explicitness = input.explicitness ?? 'inferred';\n const durability = input.durability ?? 'durable';\n const importance = Math.max(0, Math.min(1, input.importance ?? 0.5));\n const disclosurePolicy = input.disclosurePolicy ?? 'referenceable';\n const validFrom = parseOptionalTimestamp(input.validFrom);\n const validTo = parseOptionalTimestamp(input.validTo);\n const reviewAfter = parseOptionalTimestamp(input.reviewAfter);\n const expiresAt = parseOptionalTimestamp(input.expiresAt);\n const source = {\n ...(input.source ?? {}),\n provider: input.source?.provider ?? input.providerId,\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_records (\n record_id, provider_id, kind, agent_id, workspace_id, session_key, project_id,\n content, source_json, confidence, tags_json, status, sensitivity,\n evidence_json, canonical_key, explicitness, durability, importance,\n disclosure_policy, valid_from, valid_to, review_after, expires_at,\n supersedes_record_id, conflict_group_id, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n ON CONFLICT(record_id) DO UPDATE SET\n provider_id = excluded.provider_id,\n kind = excluded.kind,\n agent_id = excluded.agent_id,\n workspace_id = excluded.workspace_id,\n session_key = excluded.session_key,\n project_id = excluded.project_id,\n content = excluded.content,\n source_json = excluded.source_json,\n confidence = excluded.confidence,\n tags_json = excluded.tags_json,\n status = excluded.status,\n sensitivity = excluded.sensitivity,\n evidence_json = excluded.evidence_json,\n canonical_key = excluded.canonical_key,\n explicitness = excluded.explicitness,\n durability = excluded.durability,\n importance = excluded.importance,\n disclosure_policy = excluded.disclosure_policy,\n valid_from = excluded.valid_from,\n valid_to = excluded.valid_to,\n review_after = excluded.review_after,\n expires_at = excluded.expires_at,\n supersedes_record_id = excluded.supersedes_record_id,\n conflict_group_id = excluded.conflict_group_id,\n updated_at = excluded.updated_at`,\n ).run(\n id,\n input.providerId,\n input.kind,\n input.agentId,\n input.workspaceId ?? null,\n input.sessionKey ?? null,\n input.projectId ?? null,\n input.content,\n JSON.stringify(source),\n input.confidence ?? null,\n JSON.stringify(input.tags ?? []),\n status,\n sensitivity,\n JSON.stringify(input.evidence ?? []),\n input.canonicalKey ?? null,\n explicitness,\n durability,\n importance,\n disclosurePolicy,\n validFrom,\n validTo,\n reviewAfter,\n expiresAt,\n input.supersedesRecordId ?? null,\n input.conflictGroupId ?? null,\n now,\n now,\n );\n upsertMemoryRecordFts(db, { ...input, id });\n if (input.supersedesRecordId && input.supersedesRecordId !== id) {\n const target = db.prepare(`SELECT 1 FROM memory_records WHERE record_id = ?`)\n .get(input.supersedesRecordId);\n if (target) {\n db.prepare(\n `INSERT INTO memory_relations (\n relation_id, from_record_id, relation_type, to_record_id,\n confidence, valid_from, valid_to, created_at, updated_at\n ) VALUES (?, ?, 'supersedes', ?, ?, ?, NULL, ?, ?)\n ON CONFLICT(from_record_id, relation_type, to_record_id) DO UPDATE SET\n confidence = excluded.confidence,\n valid_from = excluded.valid_from,\n valid_to = NULL,\n updated_at = excluded.updated_at`,\n ).run(\n randomUUID(),\n id,\n input.supersedesRecordId,\n input.confidence ?? 1,\n validFrom ?? now,\n now,\n now,\n );\n if (status === 'active') {\n db.prepare(\n `UPDATE memory_records\n SET status = 'archived', valid_to = COALESCE(valid_to, ?), updated_at = ?\n WHERE record_id = ? AND status IN ('active', 'needs_review', 'stale')`,\n ).run(now, now, input.supersedesRecordId);\n }\n }\n }\n });\n\n return {\n id,\n kind: input.kind,\n status,\n ...(input.canonicalKey ? { canonicalKey: input.canonicalKey } : {}),\n scope: {\n agentId: input.agentId,\n ...(input.workspaceId ? { workspaceId: input.workspaceId } : {}),\n ...(input.sessionKey ? { sessionKey: input.sessionKey } : {}),\n ...(input.projectId ? { projectId: input.projectId } : {}),\n },\n content: input.content,\n source,\n ...(input.confidence != null ? { confidence: input.confidence } : {}),\n sensitivity,\n explicitness,\n durability,\n importance,\n disclosurePolicy,\n evidence: input.evidence ?? [],\n ...(validFrom != null ? { validFrom: new Date(validFrom).toISOString() } : {}),\n ...(validTo != null ? { validTo: new Date(validTo).toISOString() } : {}),\n ...(reviewAfter != null ? { reviewAfter: new Date(reviewAfter).toISOString() } : {}),\n ...(expiresAt != null ? { expiresAt: new Date(expiresAt).toISOString() } : {}),\n ...(input.supersedesRecordId ? { supersedesRecordId: input.supersedesRecordId } : {}),\n ...(input.conflictGroupId ? { conflictGroupId: input.conflictGroupId } : {}),\n createdAt: new Date(now).toISOString(),\n updatedAt: new Date(now).toISOString(),\n tags: input.tags ?? [],\n };\n}\n\nexport function getMemoryRecord(recordId: string): MemoryRecord | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM memory_records WHERE record_id = ?`)\n .get(recordId) as MemoryRecordRow | undefined;\n return row ? rowToRecord(row) : null;\n}\n\nexport function listMemoryRecords(options: ListMemoryRecordsOptions = {}): MemoryRecord[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n where.push('workspace_id = ?');\n params.push(options.workspaceId);\n }\n if (options.projectId) {\n where.push('project_id = ?');\n params.push(options.projectId);\n }\n if (options.visibleToSessionKey) {\n where.push('(session_key IS NULL OR session_key = ?)');\n params.push(options.visibleToSessionKey);\n } else if (options.unscopedSessionOnly) {\n where.push('session_key IS NULL');\n }\n if (options.visibleToProjectId) {\n where.push('(project_id IS NULL OR project_id = ?)');\n params.push(options.visibleToProjectId);\n } else if (options.unscopedProjectOnly) {\n where.push('project_id IS NULL');\n }\n if (options.kind) {\n where.push('kind = ?');\n params.push(options.kind);\n }\n if (options.status) {\n where.push('status = ?');\n params.push(options.status);\n }\n if (options.canonicalKey) {\n where.push('canonical_key = ?');\n params.push(options.canonicalKey);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const offset = Math.max(0, options.offset ?? 0);\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_records\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY updated_at DESC\n LIMIT ? OFFSET ?`,\n )\n .all(...params, limit, offset) as MemoryRecordRow[];\n return rows.map(rowToRecord);\n}\n\nexport function searchMemoryRecords(options: SearchMemoryRecordsOptions): MemorySearchResult[] {\n const query = buildFts5SearchQuery(options.query);\n if (!query) return [];\n\n const filters: string[] = ['memory_records_fts MATCH ?'];\n const params: Array<string | number | null> = [query];\n if (options.agentId) {\n filters.push('f.agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n filters.push('f.workspace_id = ?');\n params.push(options.workspaceId);\n }\n if (options.projectId) {\n filters.push('r.project_id = ?');\n params.push(options.projectId);\n }\n if (options.visibleToSessionKey) {\n filters.push('(r.session_key IS NULL OR r.session_key = ?)');\n params.push(options.visibleToSessionKey);\n } else if (options.unscopedSessionOnly) {\n filters.push('r.session_key IS NULL');\n }\n if (options.visibleToProjectId) {\n filters.push('(r.project_id IS NULL OR r.project_id = ?)');\n params.push(options.visibleToProjectId);\n } else if (options.unscopedProjectOnly) {\n filters.push('r.project_id IS NULL');\n }\n if (options.providerId) {\n filters.push('f.provider_id = ?');\n params.push(options.providerId);\n }\n if (options.kinds && options.kinds.length > 0) {\n filters.push(`f.kind IN (${options.kinds.map(() => '?').join(', ')})`);\n params.push(...options.kinds);\n }\n const statuses = options.statuses && options.statuses.length > 0 ? options.statuses : ['active'];\n filters.push(`r.status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n\n const maxResults = Math.max(1, Math.min(50, options.maxResults ?? 5));\n const minScore = options.minScore ?? 0;\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT\n r.*,\n bm25(memory_records_fts) AS rank\n FROM memory_records_fts f\n JOIN memory_records r ON r.record_id = f.record_id\n WHERE ${filters.join(' AND ')}\n ORDER BY rank\n LIMIT ?`,\n )\n .all(...params, maxResults * 3) as MemoryRecordSearchRow[];\n\n if (rows.length === 0) {\n const fallbackRecords = listMemoryRecords({\n providerId: options.providerId,\n agentId: options.agentId,\n workspaceId: options.workspaceId,\n projectId: options.projectId,\n visibleToSessionKey: options.visibleToSessionKey,\n unscopedSessionOnly: options.unscopedSessionOnly,\n visibleToProjectId: options.visibleToProjectId,\n unscopedProjectOnly: options.unscopedProjectOnly,\n limit: 500,\n }).filter((record) =>\n statuses.includes(record.status ?? 'active')\n && (!options.kinds?.length || options.kinds.includes(record.kind)),\n );\n return fallbackRecords\n .map((record) => ({\n record,\n score: memoryLexicalSimilarity(options.query, record.content),\n snippet: record.content,\n citation: {\n providerId: record.source.provider ?? options.providerId ?? 'local',\n recordId: record.id,\n path: record.source.path,\n lineStart: record.source.lineStart,\n lineEnd: record.source.lineEnd,\n createdAt: record.createdAt,\n },\n }))\n .filter((result) => result.score >= minScore)\n .sort((a, b) => b.score - a.score)\n .slice(0, maxResults);\n }\n\n const bestRank = Math.min(...rows.map((row) => row.rank));\n const worstRank = Math.max(...rows.map((row) => row.rank));\n return rows\n .map((row) => {\n const record = rowToRecord(row);\n const score = fts5RankToScore(row.rank, bestRank, worstRank);\n return {\n record,\n score,\n snippet: record.content,\n citation: {\n providerId: row.provider_id,\n recordId: row.record_id,\n path: record.source.path,\n lineStart: record.source.lineStart,\n lineEnd: record.source.lineEnd,\n createdAt: record.createdAt,\n },\n };\n })\n .filter((result) => result.score >= minScore)\n .slice(0, maxResults);\n}\n\nexport function deleteMemoryRecord(recordId: string): boolean {\n return runSqliteWriteTransaction((db) => {\n db.prepare(`DELETE FROM memory_records_fts WHERE record_id = ?`).run(recordId);\n const result = db.prepare(`DELETE FROM memory_records WHERE record_id = ?`).run(recordId);\n return result.changes > 0;\n });\n}\n\nexport function appendMemorySignal(input: AppendMemorySignalInput): string {\n const id = randomUUID();\n const now = input.nowMs ?? Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_signals (\n signal_id, source, record_id, provider_id, agent_id, workspace_id,\n session_key, score, content, metadata_json, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n input.signal.source,\n input.signal.recordId ?? null,\n input.providerId ?? null,\n input.agentId ?? null,\n input.workspaceId ?? null,\n input.sessionKey ?? null,\n input.signal.score ?? null,\n input.signal.content ?? null,\n JSON.stringify(input.signal.metadata ?? {}),\n now,\n );\n if (input.signal.recordId) {\n db.prepare(\n `UPDATE memory_records\n SET recall_count = recall_count + 1, last_recalled_at = ?, updated_at = MAX(updated_at, ?)\n WHERE record_id = ?`,\n ).run(now, now, input.signal.recordId);\n }\n });\n return id;\n}\n\nexport function listMemorySignals(options: {\n recordId?: string;\n providerId?: string;\n agentId?: string;\n workspaceId?: string;\n limit?: number;\n} = {}): MemorySignalRowPayload[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.recordId) {\n where.push('record_id = ?');\n params.push(options.recordId);\n }\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('agent_id = ?');\n params.push(options.agentId);\n }\n if (options.workspaceId) {\n where.push('workspace_id = ?');\n params.push(options.workspaceId);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_signals\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemorySignalRow[];\n return rows.map((row) => {\n let metadata: Record<string, unknown> = {};\n try {\n const parsed = JSON.parse(row.metadata_json) as unknown;\n if (parsed && typeof parsed === 'object') metadata = parsed as Record<string, unknown>;\n } catch {\n metadata = {};\n }\n return {\n signalId: row.signal_id,\n source: row.source,\n ...(row.record_id ? { recordId: row.record_id } : {}),\n ...(row.provider_id ? { providerId: row.provider_id } : {}),\n ...(row.agent_id ? { agentId: row.agent_id } : {}),\n ...(row.workspace_id ? { workspaceId: row.workspace_id } : {}),\n ...(row.session_key ? { sessionKey: row.session_key } : {}),\n ...(row.score != null ? { score: row.score } : {}),\n ...(row.content ? { content: row.content } : {}),\n metadata,\n createdAt: new Date(row.created_at).toISOString(),\n };\n });\n}\n\nexport function getMemoryProviderState(providerId: string, scopeKey: string): unknown | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT state_json FROM memory_provider_state WHERE provider_id = ? AND scope_key = ?`)\n .get(providerId, scopeKey) as { state_json: string } | undefined;\n if (!row) return null;\n try {\n return JSON.parse(row.state_json) as unknown;\n } catch {\n return null;\n }\n}\n\nexport function setMemoryProviderState(providerId: string, scopeKey: string, state: unknown): void {\n const now = Date.now();\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_provider_state (provider_id, scope_key, state_json, updated_at)\n VALUES (?, ?, ?, ?)\n ON CONFLICT(provider_id, scope_key) DO UPDATE SET\n state_json = excluded.state_json,\n updated_at = excluded.updated_at`,\n ).run(providerId, scopeKey, JSON.stringify(state ?? null), now);\n });\n}\n\nexport function appendMemoryTraceEvent(input: AppendMemoryTraceEventInput): string {\n const id = input.traceId ?? randomUUID();\n const now = input.nowMs ?? Date.now();\n const feedback = input.feedback\n ? normalizeMemoryTraceFeedback(input.feedback, now)\n : undefined;\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO memory_trace_events (\n trace_id, session_key, turn_id, phase, provider_id, request_json,\n result_count, selected_record_ids_json, skipped_reason, error, feedback_json, duration_ms, created_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n id,\n input.sessionKey ?? null,\n input.turnId ?? null,\n input.phase,\n input.providerId,\n JSON.stringify(input.request ?? {}),\n input.resultCount ?? null,\n JSON.stringify(input.selectedRecordIds ?? []),\n input.skippedReason ?? null,\n input.error ?? null,\n JSON.stringify(feedback ?? {}),\n Math.max(0, Math.floor(input.durationMs ?? 0)),\n now,\n );\n });\n return id;\n}\n\nexport function listMemoryTraceEvents(options: {\n providerId?: string;\n agentId?: string;\n sessionKey?: string;\n phase?: string;\n limit?: number;\n} = {}): MemoryTraceEventPayload[] {\n const where: string[] = [];\n const params: Array<string | number | null> = [];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('session_key LIKE ?');\n params.push(`agent:${options.agentId}:%`);\n }\n if (options.sessionKey) {\n where.push('session_key = ?');\n params.push(options.sessionKey);\n }\n if (options.phase) {\n where.push('phase = ?');\n params.push(options.phase);\n }\n const limit = Math.max(1, Math.min(500, options.limit ?? 100));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n ${where.length > 0 ? `WHERE ${where.join(' AND ')}` : ''}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemoryTraceRow[];\n return rows.map(memoryTraceRowToPayload);\n}\n\nexport function setMemoryTraceFeedback(input: SetMemoryTraceFeedbackInput): MemoryTraceEventPayload | null {\n const existing = getSqliteDatabase()\n .prepare(`SELECT * FROM memory_trace_events WHERE trace_id = ?`)\n .get(input.traceId) as MemoryTraceRow | undefined;\n if (!existing) {\n return null;\n }\n const nowMs = input.nowMs ?? Date.now();\n const feedback = normalizeMemoryTraceFeedback(\n input.feedback,\n nowMs,\n parseMemoryTraceFeedback(existing.feedback_json),\n );\n let remediation: MemoryFeedbackRemediationResult | undefined;\n runSqliteWriteTransaction((db) => {\n db.prepare(`UPDATE memory_trace_events SET feedback_json = ? WHERE trace_id = ?`)\n .run(JSON.stringify(feedback), input.traceId);\n remediation = reconcileUserUnderstandingFeedback(db, existing, feedback, nowMs);\n });\n return {\n ...memoryTraceRowToPayload({ ...existing, feedback_json: JSON.stringify(feedback) }),\n ...(remediation ? { remediation } : {}),\n };\n}\n\nfunction reconcileUserUnderstandingFeedback(\n db: ReturnType<typeof getSqliteDatabase>,\n trace: MemoryTraceRow,\n feedback: MemoryTraceFeedback,\n nowMs: number,\n): MemoryFeedbackRemediationResult | undefined {\n if (trace.phase !== 'inject' || feedback.outcome !== 'not_helpful') return undefined;\n const explicitCorrection = feedback.source === 'system'\n && feedback.reason === 'detected_explicit_user_correction';\n const evaluatedRecordIds: string[] = [];\n const needsReviewRecordIds: string[] = [];\n const actions: Array<Record<string, unknown>> = [];\n\n for (const recordId of new Set(parseStringArray(trace.selected_record_ids_json))) {\n const record = db.prepare(\n `SELECT * FROM memory_records\n WHERE record_id = ?\n AND status = 'active'\n AND tags_json LIKE '%\\\"user-understanding\\\"%'`,\n ).get(recordId) as MemoryRecordRow | undefined;\n if (!record) continue;\n evaluatedRecordIds.push(recordId);\n const feedbackRows = db.prepare(\n `SELECT trace.feedback_json\n FROM memory_trace_events AS trace\n JOIN json_each(trace.selected_record_ids_json) AS selected\n ON selected.value = ?\n WHERE trace.phase = 'inject'`,\n ).all(recordId) as Array<{ feedback_json: string }>;\n let helpful = 0;\n let notHelpful = 0;\n for (const row of feedbackRows) {\n const recordFeedback = parseMemoryTraceFeedback(row.feedback_json);\n if (recordFeedback?.outcome === 'helpful') helpful += 1;\n if (recordFeedback?.outcome === 'not_helpful') notHelpful += 1;\n }\n if (!explicitCorrection && (\n notHelpful < USER_UNDERSTANDING_REMEDIATION_POLICY.minNotHelpful\n || notHelpful <= helpful\n )) {\n continue;\n }\n const nextConfidence = record.confidence == null\n ? null\n : Math.round(Math.max(0.1, record.confidence - USER_UNDERSTANDING_REMEDIATION_POLICY.confidencePenalty) * 1000) / 1000;\n const update = db.prepare(\n `UPDATE memory_records\n SET status = 'needs_review', confidence = ?, review_after = ?, updated_at = ?\n WHERE record_id = ? AND status = 'active'`,\n ).run(nextConfidence, nowMs, nowMs, recordId);\n if (update.changes === 0) continue;\n needsReviewRecordIds.push(recordId);\n actions.push({\n recordId,\n previousStatus: record.status,\n nextStatus: 'needs_review',\n previousConfidence: record.confidence,\n nextConfidence,\n helpful,\n notHelpful,\n });\n }\n\n const result: MemoryFeedbackRemediationResult = {\n triggerTraceId: trace.trace_id,\n evaluatedRecordIds,\n needsReviewRecordIds,\n };\n if (needsReviewRecordIds.length > 0) {\n db.prepare(\n `INSERT INTO memory_trace_events (\n trace_id, session_key, turn_id, phase, provider_id, request_json,\n result_count, selected_record_ids_json, skipped_reason, error,\n feedback_json, duration_ms, created_at\n ) VALUES (?, ?, ?, 'remediation', 'user-understanding', ?, ?, ?, NULL, NULL, '{}', 0, ?)`,\n ).run(\n randomUUID(),\n trace.session_key,\n trace.turn_id,\n JSON.stringify({\n triggerTraceId: trace.trace_id,\n reason: explicitCorrection\n ? 'explicit_user_correction'\n : 'repeated_not_helpful_feedback',\n policy: USER_UNDERSTANDING_REMEDIATION_POLICY,\n actions,\n }),\n needsReviewRecordIds.length,\n JSON.stringify(needsReviewRecordIds),\n nowMs,\n );\n }\n return result;\n}\n\nexport function findLatestMemoryInjectTrace(\n input: FindLatestMemoryInjectTraceInput,\n): MemoryTraceEventPayload | null {\n const where = [\n `session_key = ?`,\n `phase = 'inject'`,\n `created_at <= ?`,\n ];\n const row = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n WHERE ${where.join(' AND ')}\n ORDER BY created_at DESC\n LIMIT 1`,\n )\n .get(input.sessionKey, input.beforeMs ?? Date.now()) as MemoryTraceRow | undefined;\n if (!row) return null;\n const trace = memoryTraceRowToPayload(row);\n if (input.requireSelectedRecords && trace.selectedRecordIds.length === 0) return null;\n return trace;\n}\n\nexport function setLatestMemoryInjectFeedback(\n input: SetLatestMemoryInjectFeedbackInput,\n): MemoryTraceEventPayload | null {\n const row = findLatestMemoryInjectTrace(input);\n if (!row) return null;\n return setMemoryTraceFeedback({\n traceId: row.traceId,\n feedback: input.feedback,\n nowMs: input.nowMs,\n });\n}\n\nexport function summarizeMemoryRecallFeedback(options: {\n recordId?: string;\n providerId?: string;\n agentId?: string;\n sessionKey?: string;\n limit?: number;\n} = {}): MemoryRecallFeedbackSummary[] {\n const where = ['phase IN (?, ?)'];\n const params: Array<string | number> = ['search', 'inject'];\n if (options.providerId) {\n where.push('provider_id = ?');\n params.push(options.providerId);\n }\n if (options.agentId) {\n where.push('session_key LIKE ?');\n params.push(`agent:${options.agentId}:%`);\n }\n if (options.sessionKey) {\n where.push('session_key = ?');\n params.push(options.sessionKey);\n }\n const limit = Math.max(1, Math.min(5000, options.limit ?? 1000));\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT * FROM memory_trace_events\n WHERE ${where.join(' AND ')}\n ORDER BY created_at DESC\n LIMIT ?`,\n )\n .all(...params, limit) as MemoryTraceRow[];\n\n const summaries = new Map<string, MemoryRecallFeedbackSummary & { scoreTotal: number; scoreCount: number }>();\n for (const row of rows) {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n if (!feedback) continue;\n const recordIds = parseStringArray(row.selected_record_ids_json);\n for (const recordId of recordIds) {\n if (options.recordId && recordId !== options.recordId) continue;\n const current = summaries.get(recordId) ?? {\n recordId,\n helpful: 0,\n notHelpful: 0,\n mixed: 0,\n irrelevant: 0,\n total: 0,\n averageScore: null,\n scoreTotal: 0,\n scoreCount: 0,\n };\n if (feedback.outcome === 'helpful') current.helpful += 1;\n if (feedback.outcome === 'not_helpful') current.notHelpful += 1;\n if (feedback.outcome === 'mixed') current.mixed += 1;\n if (feedback.outcome === 'irrelevant') current.irrelevant += 1;\n current.total += 1;\n if (typeof feedback.score === 'number') {\n current.scoreTotal += feedback.score;\n current.scoreCount += 1;\n current.averageScore = current.scoreTotal / current.scoreCount;\n }\n current.lastFeedbackAt ??= feedback.updatedAt ?? feedback.createdAt;\n summaries.set(recordId, current);\n }\n }\n\n return [...summaries.values()]\n .map(({ scoreTotal: _scoreTotal, scoreCount: _scoreCount, ...summary }) => summary)\n .sort((a, b) => b.total - a.total);\n}\n\nfunction boundedMetricCount(value: unknown): number {\n return typeof value === 'number' && Number.isFinite(value)\n ? Math.max(0, Math.floor(value))\n : 0;\n}\n\nfunction metricRate(numerator: number, denominator: number): number | null {\n return denominator > 0 ? Math.round((numerator / denominator) * 10_000) / 10_000 : null;\n}\n\nexport function summarizeUserUnderstandingQuality(options: {\n agentId?: string;\n windowDays?: number;\n agingCandidateDays?: number;\n nowMs?: number;\n} = {}): UserUnderstandingQualityMetrics {\n const nowMs = options.nowMs ?? Date.now();\n const windowDays = Math.max(1, Math.min(365, Math.floor(options.windowDays ?? 30)));\n const sinceMs = nowMs - windowDays * 24 * 60 * 60 * 1000;\n const agingCandidateDays = Math.max(1, Math.min(windowDays, Math.floor(options.agingCandidateDays ?? 7)));\n const agingCutoffMs = nowMs - agingCandidateDays * 24 * 60 * 60 * 1000;\n const db = getSqliteDatabase();\n const agentWhere = options.agentId ? 'AND agent_id = ?' : '';\n const recordRows = db.prepare(\n `SELECT record_id, status, explicitness, confidence, created_at, updated_at\n FROM memory_records\n WHERE tags_json LIKE '%\"user-understanding\"%'\n ${agentWhere}`,\n ).all(...(options.agentId ? [options.agentId] : [])) as Array<{\n record_id: string;\n status: string;\n explicitness: string;\n confidence: number | null;\n created_at: number;\n updated_at: number;\n }>;\n\n const records: UserUnderstandingQualityMetrics['records'] = {\n total: recordRows.length,\n candidate: 0,\n active: 0,\n rejected: 0,\n needsReview: 0,\n stale: 0,\n archived: 0,\n agingCandidates: 0,\n explicit: 0,\n inferred: 0,\n averageConfidence: null,\n };\n let confidenceTotal = 0;\n let confidenceCount = 0;\n const understandingRecordIds = new Set<string>();\n for (const row of recordRows) {\n understandingRecordIds.add(row.record_id);\n if (row.status === 'candidate') records.candidate += 1;\n if (row.status === 'active') records.active += 1;\n if (row.status === 'rejected') records.rejected += 1;\n if (row.status === 'needs_review') records.needsReview += 1;\n if (row.status === 'stale') records.stale += 1;\n if (row.status === 'archived') records.archived += 1;\n if (row.status === 'candidate' && row.created_at <= agingCutoffMs) records.agingCandidates += 1;\n if (row.explicitness === 'explicit') records.explicit += 1;\n if (row.explicitness === 'inferred') records.inferred += 1;\n if (typeof row.confidence === 'number') {\n confidenceTotal += row.confidence;\n confidenceCount += 1;\n }\n }\n records.averageConfidence = confidenceCount > 0\n ? Math.round((confidenceTotal / confidenceCount) * 10_000) / 10_000\n : null;\n\n const attempts: UserUnderstandingQualityMetrics['attempts'] = { total: 0, turn: 0, background: 0 };\n const candidates: UserUnderstandingQualityMetrics['candidates'] = {\n proposed: 0,\n created: 0,\n deduplicated: 0,\n rejectedByPolicy: 0,\n };\n const understandingTraces = db.prepare(\n `SELECT request_json FROM memory_trace_events\n WHERE phase = 'understanding' AND created_at >= ?`,\n ).all(sinceMs) as Array<{ request_json: string }>;\n for (const row of understandingTraces) {\n const parsed = parseJsonValue(row.request_json, {});\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) continue;\n const request = parsed as Record<string, unknown>;\n if (options.agentId && request.agentId !== options.agentId) continue;\n attempts.total += 1;\n if (request.source === 'turn') attempts.turn += 1;\n if (request.source === 'background') attempts.background += 1;\n candidates.proposed += boundedMetricCount(request.proposed);\n candidates.created += boundedMetricCount(request.created);\n candidates.deduplicated += boundedMetricCount(request.deduplicated);\n candidates.rejectedByPolicy += boundedMetricCount(request.rejected);\n }\n\n const recall: UserUnderstandingQualityMetrics['recall'] = {\n total: 0,\n helpful: 0,\n notHelpful: 0,\n mixed: 0,\n irrelevant: 0,\n helpfulRate: null,\n };\n if (understandingRecordIds.size > 0) {\n const recallRows = db.prepare(\n `SELECT selected_record_ids_json, feedback_json FROM memory_trace_events\n WHERE phase IN ('search', 'inject') AND created_at >= ?`,\n ).all(sinceMs) as Array<{ selected_record_ids_json: string; feedback_json: string }>;\n for (const row of recallRows) {\n const feedback = parseMemoryTraceFeedback(row.feedback_json);\n if (!feedback) continue;\n const selected = parseStringArray(row.selected_record_ids_json);\n if (!selected.some((recordId) => understandingRecordIds.has(recordId))) continue;\n recall.total += 1;\n if (feedback.outcome === 'helpful') recall.helpful += 1;\n if (feedback.outcome === 'not_helpful') recall.notHelpful += 1;\n if (feedback.outcome === 'mixed') recall.mixed += 1;\n if (feedback.outcome === 'irrelevant') recall.irrelevant += 1;\n }\n }\n recall.helpfulRate = metricRate(recall.helpful, recall.total);\n const recentDecisions = recordRows.filter(\n (row) => (row.status === 'active' || row.status === 'rejected') && row.updated_at >= sinceMs,\n );\n const acceptedDecisions = recentDecisions.filter((row) => row.status === 'active').length;\n const decisionTotal = recentDecisions.length;\n\n return {\n ...(options.agentId ? { agentId: options.agentId } : {}),\n windowDays,\n since: new Date(sinceMs).toISOString(),\n attempts,\n candidates,\n records,\n decisions: {\n total: decisionTotal,\n acceptanceRate: metricRate(acceptedDecisions, decisionTotal),\n },\n recall,\n };\n}\n\nfunction parseJsonValue(json: string, fallback: unknown): unknown {\n try {\n return JSON.parse(json) as unknown;\n } catch {\n return fallback;\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { createLogger } from "../../utils/logger/index.js";
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { getDefaultModelSync, init_providers, resolveModel } from "../../providers/index.js";
|
|
4
|
+
import { completeWithResolvedCredentials } from "../../providers/model-call.js";
|
|
4
5
|
import { truncateAtSentenceBoundary } from "./sentence-boundary.js";
|
|
5
|
-
import { complete } from "@earendil-works/pi-ai/compat";
|
|
6
6
|
//#region src/voice/tts/summarize.ts
|
|
7
7
|
init_providers();
|
|
8
8
|
init_logger();
|
|
@@ -67,7 +67,7 @@ async function summarizeForTts(options) {
|
|
|
67
67
|
};
|
|
68
68
|
const timeoutSignal = typeof AbortSignal !== "undefined" && typeof AbortSignal.timeout === "function" ? AbortSignal.timeout(SUMMARIZE_TIMEOUT_MS) : void 0;
|
|
69
69
|
const mergedSignal = signal && timeoutSignal && typeof AbortSignal.any === "function" ? AbortSignal.any([signal, timeoutSignal]) : signal ?? timeoutSignal;
|
|
70
|
-
const result = await
|
|
70
|
+
const result = await completeWithResolvedCredentials(model, { messages: [userMsg] }, {
|
|
71
71
|
maxTokens: Math.min(Math.ceil(targetLength / 2), 4096),
|
|
72
72
|
temperature: .3,
|
|
73
73
|
signal: mergedSignal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summarize.js","names":[],"sources":["../../../../src/voice/tts/summarize.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"summarize.js","names":[],"sources":["../../../../src/voice/tts/summarize.ts"],"sourcesContent":["import { type UserMessage } from '@earendil-works/pi-ai/compat';\nimport type { Api, Model } from '@earendil-works/pi-ai';\n\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport { completeWithResolvedCredentials } from '../../providers/model-call.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { truncateAtSentenceBoundary } from './sentence-boundary.js';\n\nconst log = createLogger('TTS:Summarize');\n\nconst SUMMARIZE_TIMEOUT_MS = 45_000;\n\nconst SUMMARIZE_SYSTEM_PROMPT = `You are a text summarizer for a text-to-speech system.\nYour task is to condense the given text while preserving the key information and meaning.\n\nRules:\n1. Output ONLY the summarized text, no explanations or meta-commentary\n2. Keep the summary in the same language as the input\n3. Preserve key facts, numbers, names, and conclusions\n4. Use natural, spoken language suitable for audio playback\n5. Remove code blocks, URLs, markdown formatting, and technical syntax where possible\n6. Keep the summary under the specified character limit\n7. End with a complete sentence, never mid-sentence`;\n\nexport interface SummarizeForTtsOptions {\n text: string;\n targetLength: number;\n config?: Config;\n modelRef?: string;\n signal?: AbortSignal;\n}\n\nexport interface SummarizeResult {\n summary: string;\n originalLength: number;\n summaryLength: number;\n wasSummarized: boolean;\n}\n\nfunction resolveSummarizeModel(config: Config | undefined, modelRef?: string): Model<Api> {\n const envRef = process.env.XOPC_TTS_SUMMARIZE_MODEL?.trim();\n const ref = modelRef?.trim() || envRef;\n if (ref) {\n try {\n return resolveModel(ref);\n } catch {\n /* fall through */\n }\n }\n for (const candidate of ['openai/gpt-5.6-luna', 'google/gemini-3.5-flash']) {\n try {\n return resolveModel(candidate);\n } catch {\n /* next */\n }\n }\n return resolveModel(getDefaultModelSync(config));\n}\n\nfunction fallbackTruncate(text: string, maxLength: number): SummarizeResult {\n const truncated = truncateAtSentenceBoundary(text, maxLength);\n return {\n summary: truncated,\n originalLength: text.length,\n summaryLength: truncated.length,\n wasSummarized: false,\n };\n}\n\n/**\n * Condense text for TTS using a small LLM pass; falls back to sentence-boundary truncation.\n */\nexport async function summarizeForTts(options: SummarizeForTtsOptions): Promise<SummarizeResult> {\n const { text, targetLength, config, modelRef, signal } = options;\n\n if (text.length <= targetLength) {\n return {\n summary: text,\n originalLength: text.length,\n summaryLength: text.length,\n wasSummarized: false,\n };\n }\n\n const startTime = Date.now();\n\n try {\n const model = resolveSummarizeModel(config, modelRef);\n const userPrompt = [\n `Summarize the following text to fit within ${targetLength} characters.`,\n `The summary will be read aloud by a text-to-speech system, so use natural spoken language.`,\n '',\n '---',\n '',\n text,\n ].join('\\n');\n\n const userMsg: UserMessage = {\n role: 'user',\n content: `${SUMMARIZE_SYSTEM_PROMPT}\\n\\n---\\n\\n${userPrompt}`,\n timestamp: Date.now(),\n };\n\n const timeoutSignal =\n typeof AbortSignal !== 'undefined' && typeof AbortSignal.timeout === 'function'\n ? AbortSignal.timeout(SUMMARIZE_TIMEOUT_MS)\n : undefined;\n const mergedSignal =\n signal && timeoutSignal && typeof AbortSignal.any === 'function'\n ? AbortSignal.any([signal, timeoutSignal])\n : signal ?? timeoutSignal;\n\n const result = await completeWithResolvedCredentials(\n model,\n { messages: [userMsg] },\n {\n maxTokens: Math.min(Math.ceil(targetLength / 2), 4096),\n temperature: 0.3,\n signal: mergedSignal as AbortSignal,\n },\n );\n\n let out = '';\n if (Array.isArray(result.content)) {\n for (const c of result.content) {\n if (c && typeof c === 'object' && (c as { type?: string }).type === 'text') {\n out += String((c as { text?: string }).text || '');\n }\n }\n }\n\n const summary = out.trim();\n if (!summary) {\n log.warn('Empty summary returned, falling back to truncation');\n return fallbackTruncate(text, targetLength);\n }\n\n const finalSummary =\n summary.length > targetLength ? truncateAtSentenceBoundary(summary, targetLength) : summary;\n\n log.info(\n {\n originalLength: text.length,\n summaryLength: finalSummary.length,\n durationMs: Date.now() - startTime,\n },\n 'Text summarized for TTS',\n );\n\n return {\n summary: finalSummary,\n originalLength: text.length,\n summaryLength: finalSummary.length,\n wasSummarized: true,\n };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.warn({ errorMessage: em }, 'Summarization failed, falling back to truncation');\n return fallbackTruncate(text, targetLength);\n }\n}\n"],"mappings":";;;;;;gBAI6E;aAExB;AAGrD,MAAM,MAAM,aAAa,gBAAgB;AAEzC,MAAM,uBAAuB;AAE7B,MAAM,0BAA0B;;;;;;;;;;;AA2BhC,SAAS,sBAAsB,QAA4B,UAA+B;CACxF,MAAM,SAAS,QAAQ,IAAI,0BAA0B,MAAM;CAC3D,MAAM,MAAM,UAAU,MAAM,IAAI;AAChC,KAAI,IACF,KAAI;AACF,SAAO,aAAa,IAAI;SAClB;AAIV,MAAK,MAAM,aAAa,CAAC,uBAAuB,0BAA0B,CACxE,KAAI;AACF,SAAO,aAAa,UAAU;SACxB;AAIV,QAAO,aAAa,oBAAoB,OAAO,CAAC;;AAGlD,SAAS,iBAAiB,MAAc,WAAoC;CAC1E,MAAM,YAAY,2BAA2B,MAAM,UAAU;AAC7D,QAAO;EACL,SAAS;EACT,gBAAgB,KAAK;EACrB,eAAe,UAAU;EACzB,eAAe;EAChB;;;;;AAMH,eAAsB,gBAAgB,SAA2D;CAC/F,MAAM,EAAE,MAAM,cAAc,QAAQ,UAAU,WAAW;AAEzD,KAAI,KAAK,UAAU,aACjB,QAAO;EACL,SAAS;EACT,gBAAgB,KAAK;EACrB,eAAe,KAAK;EACpB,eAAe;EAChB;CAGH,MAAM,YAAY,KAAK,KAAK;AAE5B,KAAI;EACF,MAAM,QAAQ,sBAAsB,QAAQ,SAAS;EAUrD,MAAM,UAAuB;GAC3B,MAAM;GACN,SAAS,GAAG,wBAAwB,aAXnB;IACjB,8CAA8C,aAAa;IAC3D;IACA;IACA;IACA;IACA;IACD,CAAC,KAAK,KAIsD;GAC3D,WAAW,KAAK,KAAK;GACtB;EAED,MAAM,gBACJ,OAAO,gBAAgB,eAAe,OAAO,YAAY,YAAY,aACjE,YAAY,QAAQ,qBAAqB,GACzC,KAAA;EACN,MAAM,eACJ,UAAU,iBAAiB,OAAO,YAAY,QAAQ,aAClD,YAAY,IAAI,CAAC,QAAQ,cAAc,CAAC,GACxC,UAAU;EAEhB,MAAM,SAAS,MAAM,gCACnB,OACA,EAAE,UAAU,CAAC,QAAQ,EAAE,EACvB;GACE,WAAW,KAAK,IAAI,KAAK,KAAK,eAAe,EAAE,EAAE,KAAK;GACtD,aAAa;GACb,QAAQ;GACT,CACF;EAED,IAAI,MAAM;AACV,MAAI,MAAM,QAAQ,OAAO,QAAQ;QAC1B,MAAM,KAAK,OAAO,QACrB,KAAI,KAAK,OAAO,MAAM,YAAa,EAAwB,SAAS,OAClE,QAAO,OAAQ,EAAwB,QAAQ,GAAG;;EAKxD,MAAM,UAAU,IAAI,MAAM;AAC1B,MAAI,CAAC,SAAS;AACZ,OAAI,KAAK,qDAAqD;AAC9D,UAAO,iBAAiB,MAAM,aAAa;;EAG7C,MAAM,eACJ,QAAQ,SAAS,eAAe,2BAA2B,SAAS,aAAa,GAAG;AAEtF,MAAI,KACF;GACE,gBAAgB,KAAK;GACrB,eAAe,aAAa;GAC5B,YAAY,KAAK,KAAK,GAAG;GAC1B,EACD,0BACD;AAED,SAAO;GACL,SAAS;GACT,gBAAgB,KAAK;GACrB,eAAe,aAAa;GAC5B,eAAe;GAChB;UACM,OAAO;EACd,MAAM,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACjE,MAAI,KAAK,EAAE,cAAc,IAAI,EAAE,mDAAmD;AAClF,SAAO,iBAAiB,MAAM,aAAa"}
|
|
@@ -2,10 +2,10 @@ import { createLogger } from "../../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../../utils/logger.js";
|
|
3
3
|
import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
|
|
4
4
|
import { getDefaultModelSync, init_providers, resolveModel } from "../../providers/index.js";
|
|
5
|
+
import { completeWithResolvedCredentials } from "../../providers/model-call.js";
|
|
5
6
|
import { resolveModelRef } from "../../config/agent-typed-models.js";
|
|
6
7
|
import { buildWorkflowDraftPrompt, buildWorkflowDraftRepairPrompt } from "./workflow-draft-prompt.js";
|
|
7
8
|
import { buildWorkflowDraftResponse, parseGeneratedWorkflowDraft } from "./workflow-draft-validator.js";
|
|
8
|
-
import { complete } from "@earendil-works/pi-ai/compat";
|
|
9
9
|
//#region src/workflows/draft/workflow-draft-service.ts
|
|
10
10
|
init_schema();
|
|
11
11
|
init_providers();
|
|
@@ -32,7 +32,7 @@ var WorkflowDraftService = class {
|
|
|
32
32
|
let lastIssues = [];
|
|
33
33
|
let lastText = "";
|
|
34
34
|
for (let attempt = 0; attempt <= maxRepairAttempts; attempt += 1) {
|
|
35
|
-
lastText = extractText(await
|
|
35
|
+
lastText = extractText(await completeWithResolvedCredentials(model, { messages: [{
|
|
36
36
|
role: "user",
|
|
37
37
|
content: messageContent,
|
|
38
38
|
timestamp: Date.now()
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-draft-service.js","names":[],"sources":["../../../../src/workflows/draft/workflow-draft-service.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"workflow-draft-service.js","names":[],"sources":["../../../../src/workflows/draft/workflow-draft-service.ts"],"sourcesContent":["import { type UserMessage } from '@earendil-works/pi-ai/compat';\n\nimport { resolveModelRef } from '../../config/agent-typed-models.js';\nimport { getAgentDefaultModelRef } from '../../config/schema.js';\nimport type { Config } from '../../config/schema.js';\nimport { getDefaultModelSync, resolveModel } from '../../providers/index.js';\nimport { completeWithResolvedCredentials } from '../../providers/model-call.js';\nimport { createLogger } from '../../utils/logger.js';\n\nimport {\n buildWorkflowDraftPrompt,\n buildWorkflowDraftRepairPrompt,\n type WorkflowDraftRepairIssue,\n} from './workflow-draft-prompt.js';\nimport type { CreateWorkflowDraftRequest, WorkflowDraftResponse } from './workflow-draft.types.js';\nimport { buildWorkflowDraftResponse, parseGeneratedWorkflowDraft } from './workflow-draft-validator.js';\n\nconst log = createLogger('WorkflowDraft');\nconst DEFAULT_MAX_REPAIR_ATTEMPTS = 2;\n\nexport interface WorkflowDraftServiceOptions {\n config: Config;\n maxRepairAttempts?: number;\n}\n\nexport class WorkflowDraftService {\n constructor(private readonly options: WorkflowDraftServiceOptions) {}\n\n async createDraft(request: CreateWorkflowDraftRequest, signal?: AbortSignal): Promise<WorkflowDraftResponse> {\n const prompt = request.prompt.trim();\n if (!prompt) throw new Error('prompt is required');\n const modelRef = resolveDraftModelRef(this.options.config, request.agentId);\n const model = resolveModel(modelRef);\n const maxRepairAttempts = this.options.maxRepairAttempts ?? DEFAULT_MAX_REPAIR_ATTEMPTS;\n let messageContent = buildWorkflowDraftPrompt({\n prompt,\n language: request.language,\n mode: request.mode ?? (request.existingScript ? 'improve' : 'create'),\n existingScript: request.existingScript,\n constraints: request.constraints,\n });\n let lastIssues: WorkflowDraftRepairIssue[] = [];\n let lastText = '';\n\n for (let attempt = 0; attempt <= maxRepairAttempts; attempt += 1) {\n const userMsg: UserMessage = {\n role: 'user',\n content: messageContent,\n timestamp: Date.now(),\n };\n const result = await completeWithResolvedCredentials(\n model,\n { messages: [userMsg] },\n { maxTokens: 4096, temperature: attempt === 0 ? 0.25 : 0.1, signal: signal as AbortSignal },\n );\n lastText = extractText(result);\n try {\n const draft = parseGeneratedWorkflowDraft(lastText);\n const response = buildWorkflowDraftResponse(draft, request.constraints);\n const blockingIssues = getBlockingDraftIssues(response);\n if (blockingIssues.length === 0) {\n return { ...response, repairAttempts: attempt };\n }\n lastIssues = blockingIssues;\n } catch (err) {\n lastIssues = [{\n source: 'parse',\n severity: 'error',\n code: 'invalid_model_output',\n message: err instanceof Error ? err.message : String(err),\n }];\n }\n\n if (attempt >= maxRepairAttempts) break;\n log.warn(\n { modelRef, attempt: attempt + 1, issueCount: lastIssues.length, preview: lastText.slice(0, 500) },\n 'Workflow draft validation failed; asking model to repair',\n );\n messageContent = buildWorkflowDraftRepairPrompt({\n prompt,\n language: request.language,\n constraints: request.constraints,\n previousOutput: lastText,\n issues: lastIssues,\n });\n }\n\n const message = `Unable to generate a valid workflow draft after ${maxRepairAttempts + 1} attempts: ${formatRepairIssues(lastIssues)}`;\n log.warn({ modelRef, issues: lastIssues, preview: lastText.slice(0, 500) }, message);\n throw new Error(message);\n }\n}\n\nexport function resolveDraftModelRef(config: Config, agentId: string): string {\n try {\n return resolveModelRef(config, agentId, 'large');\n } catch {\n return getAgentDefaultModelRef(config) ?? getDefaultModelSync(config);\n }\n}\n\nfunction extractText(result: unknown): string {\n const content = (result as { content?: unknown }).content;\n if (typeof content === 'string') return content;\n if (Array.isArray(content)) {\n return content.map((item) => {\n if (item && typeof item === 'object' && (item as { type?: string }).type === 'text') {\n return String((item as { text?: string }).text ?? '');\n }\n return '';\n }).join('');\n }\n return '';\n}\n\nfunction getBlockingDraftIssues(response: WorkflowDraftResponse): WorkflowDraftRepairIssue[] {\n const validationIssues: WorkflowDraftRepairIssue[] = [\n ...response.validation.errors.map((issue) => ({\n source: 'validation' as const,\n severity: 'error' as const,\n code: issue.code,\n message: issue.message,\n line: issue.line,\n column: issue.column,\n })),\n ...response.validation.warnings.map((issue) => ({\n source: 'validation' as const,\n severity: 'warning' as const,\n code: issue.code,\n message: issue.message,\n line: issue.line,\n column: issue.column,\n })),\n ];\n const lintIssues = response.lint\n .filter((issue) => issue.severity === 'error')\n .map((issue) => ({\n source: 'lint' as const,\n severity: issue.severity,\n code: issue.code,\n message: issue.message,\n }));\n return [...validationIssues, ...lintIssues];\n}\n\nfunction formatRepairIssues(issues: WorkflowDraftRepairIssue[]): string {\n if (issues.length === 0) return 'unknown validation failure';\n return issues.slice(0, 5).map((issue) => `${issue.source}:${issue.code}: ${issue.message}`).join('; ');\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xopcai/xopc",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.142",
|
|
4
4
|
"description": "Local-first AI system that remembers context, coordinates AI, and sustains long-term progress.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/src/index.js",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"node": ">=22.19.0"
|
|
66
66
|
},
|
|
67
67
|
"dependencies": {
|
|
68
|
-
"@earendil-works/pi-agent-core": "
|
|
69
|
-
"@earendil-works/pi-ai": "
|
|
70
|
-
"@earendil-works/pi-coding-agent": "
|
|
71
|
-
"@earendil-works/pi-tui": "
|
|
68
|
+
"@earendil-works/pi-agent-core": "0.80.10",
|
|
69
|
+
"@earendil-works/pi-ai": "0.80.10",
|
|
70
|
+
"@earendil-works/pi-coding-agent": "0.80.10",
|
|
71
|
+
"@earendil-works/pi-tui": "0.80.10",
|
|
72
72
|
"@grammyjs/runner": "^2.0.3",
|
|
73
73
|
"@hono/node-server": "^2.0.4",
|
|
74
74
|
"@inquirer/prompts": "^8.5.0",
|