dsh-memu-memory 1.1.2 → 1.2.0
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/AGENTS.md +8 -6
- package/README.md +50 -5
- package/README.zh.md +49 -5
- package/docs/active-memory-ab.md +385 -0
- package/docs/binding-lifecycle.md +99 -0
- package/docs/contributing.md +6 -4
- package/docs/emotion-model-spec.md +281 -0
- package/docs/env-and-commands.md +13 -0
- package/docs/host-api.md +35 -3
- package/docs/memory-semantics.md +40 -11
- package/docs/recall-benchmark.md +238 -0
- package/docs/troubleshooting.md +395 -366
- package/lib/active-memory.js +165 -0
- package/lib/activity-log.js +190 -0
- package/lib/backup.js +1103 -0
- package/lib/binding-diagnostics.js +635 -0
- package/lib/client.js +728 -58
- package/lib/consolidation-ledger.js +347 -0
- package/lib/consolidation-receipt.js +284 -0
- package/lib/consolidation-snapshot.js +274 -0
- package/lib/consolidation-worker.js +115 -0
- package/lib/curator.js +81 -37
- package/lib/cycle.js +43 -6
- package/lib/embedding-catalog.js +763 -0
- package/lib/embedding-download.js +407 -0
- package/lib/embedding-runtime.js +710 -0
- package/lib/engine.js +2 -2
- package/lib/index.js +36 -0
- package/lib/inject.js +232 -103
- package/lib/local-embedding-entry.js +145 -0
- package/lib/local-embedding-manager.js +267 -0
- package/lib/local-embedding-protocol.js +173 -0
- package/lib/local-embedding-worker.js +652 -0
- package/lib/local-vector-service.js +283 -0
- package/lib/memory.js +599 -57
- package/lib/memu-config.js +10 -22
- package/lib/memu.js +53 -19
- package/lib/mood.js +268 -39
- package/lib/paths.js +24 -0
- package/lib/preset-scope.js +1 -1
- package/lib/private.js +450 -29
- package/lib/prompts/private-consolidation.coding.md +1 -0
- package/lib/prompts/private-consolidation.md +1 -0
- package/lib/prompts/private-consolidation.mixed.md +1 -0
- package/lib/prompts/private-consolidation.rp.md +1 -0
- package/lib/prompts.js +4 -4
- package/lib/remote-summary.js +51 -25
- package/lib/rpc.js +54 -5
- package/lib/state.js +137 -172
- package/lib/tools.js +58 -7
- package/lib/vector-migration.js +878 -0
- package/lib/vector-profile.js +968 -0
- package/package.json +4 -2
- package/scripts/acceptance-local.mjs +7 -5
- package/scripts/active-memory-ab-live.mjs +655 -0
- package/scripts/active-memory-ab.mjs +1302 -0
- package/scripts/chain-matrix.mjs +537 -0
- package/scripts/check-all.mjs +29 -1
- package/scripts/check-doc-drift.mjs +353 -0
- package/scripts/diagnose-bindings.mjs +176 -0
- package/scripts/local-runtime-install.mjs +142 -0
- package/scripts/local-runtime-verify.mjs +56 -0
- package/scripts/local-vector-verify.mjs +93 -0
- package/scripts/recall-bench.mjs +813 -0
- package/scripts/repetition-ab-scenarios.mjs +93 -0
- package/scripts/repetition-detector-snapshot.mjs +314 -0
- package/scripts/repetition-eval-live.mjs +360 -0
- package/scripts/repetition-eval.mjs +702 -0
- package/tests/activation.test.mjs +89 -0
- package/tests/active-memory-ab.test.mjs +745 -0
- package/tests/active-memory.test.mjs +129 -0
- package/tests/activity-log.test.mjs +126 -0
- package/tests/activity-wiring.test.mjs +103 -0
- package/tests/appendix-b.test.mjs +212 -0
- package/tests/appendix-b2.test.mjs +166 -0
- package/tests/audit-regression.test.mjs +272 -0
- package/tests/audit-safety.test.mjs +227 -0
- package/tests/backend-compensation.test.mjs +272 -0
- package/tests/backup.test.mjs +793 -0
- package/tests/binding-diagnostics.test.mjs +720 -0
- package/tests/browser.test.mjs +366 -0
- package/tests/client-render.test.mjs +892 -0
- package/tests/coalesce.test.mjs +113 -0
- package/tests/config.test.mjs +159 -0
- package/tests/consolidation-credential.test.mjs +320 -0
- package/tests/consolidation-fork.test.mjs +357 -0
- package/tests/consolidation-ledger.test.mjs +298 -0
- package/tests/consolidation-snapshot.test.mjs +321 -0
- package/tests/consolidation-value.test.mjs +89 -0
- package/tests/context-scope.test.mjs +40 -0
- package/tests/cue.test.mjs +44 -0
- package/tests/curator-probe.test.mjs +433 -0
- package/tests/curator.test.mjs +150 -0
- package/tests/cycle.test.mjs +411 -0
- package/tests/disclosure.test.mjs +231 -0
- package/tests/doc-drift.test.mjs +222 -0
- package/tests/embedding-catalog.test.mjs +266 -0
- package/tests/embedding-download.test.mjs +391 -0
- package/tests/embedding-runtime.test.mjs +389 -0
- package/tests/emotion-chain.test.mjs +84 -0
- package/tests/emotion-contract.test.mjs +445 -0
- package/tests/engine.test.mjs +35 -0
- package/tests/fixtures/active-memory-ab/README.md +56 -0
- package/tests/fixtures/active-memory-ab/cases/01-clean-dense-turn.json +351 -0
- package/tests/fixtures/active-memory-ab/cases/02-clean-thin-turn.json +122 -0
- package/tests/fixtures/active-memory-ab/cases/03-clean-starved-small.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/04-clean-large-thin.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/05-clean-half-step.json +166 -0
- package/tests/fixtures/active-memory-ab/cases/06-clean-duplicate-reread.json +197 -0
- package/tests/fixtures/active-memory-ab/cases/07-clean-recent-recall.json +125 -0
- package/tests/fixtures/active-memory-ab/cases/08-global-relevant.json +111 -0
- package/tests/fixtures/active-memory-ab/cases/09-global-irrelevant-conflict.json +158 -0
- package/tests/fixtures/active-memory-ab/cases/10-no-human-turn.json +97 -0
- package/tests/fixtures/active-memory-ab/cases/11-clean-scale-100.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/12-clean-scale-1000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/13-clean-scale-5000.json +137 -0
- package/tests/fixtures/active-memory-ab/cases/14-clean-scale-20000.json +137 -0
- package/tests/fixtures/active-memory-ab/lead-ai-reviewed-reference.json +191 -0
- package/tests/fixtures/active-memory-ab/manifest.json +199 -0
- package/tests/fixtures/recall-bench/01-paraphrase.json +184 -0
- package/tests/fixtures/recall-bench/02-exact.json +153 -0
- package/tests/fixtures/recall-bench/03-negation.json +173 -0
- package/tests/fixtures/recall-bench/04-no-answer.json +162 -0
- package/tests/fixtures/recall-bench/05-conflict.json +194 -0
- package/tests/fixtures/recall-bench/06-boundary.json +273 -0
- package/tests/fixtures/recall-bench/07-secret.json +191 -0
- package/tests/fixtures/recall-bench/08-coding.json +164 -0
- package/tests/fixtures/recall-bench-gold-candidates/01-paraphrase.json +193 -0
- package/tests/fixtures/recall-bench-gold-candidates/02-exact.json +197 -0
- package/tests/fixtures/recall-bench-gold-candidates/03-negation.json +244 -0
- package/tests/fixtures/recall-bench-gold-candidates/04-no-answer.json +189 -0
- package/tests/fixtures/recall-bench-gold-candidates/05-conflict.json +245 -0
- package/tests/fixtures/recall-bench-gold-candidates/06-boundary.json +279 -0
- package/tests/fixtures/recall-bench-gold-candidates/07-secret.json +224 -0
- package/tests/fixtures/recall-bench-gold-candidates/08-coding.json +218 -0
- package/tests/fixtures/repetition-eval/01-zh-rp.json +93 -0
- package/tests/fixtures/repetition-eval/02-en.json +97 -0
- package/tests/fixtures/repetition-eval/03-code.json +91 -0
- package/tests/fixtures/repetition-eval/04-names.json +116 -0
- package/tests/fixtures/repetition-eval/05-user-quote.json +96 -0
- package/tests/fixtures/repetition-eval/06-agreement.json +86 -0
- package/tests/graph-view.test.mjs +187 -0
- package/tests/graph.test.mjs +77 -0
- package/tests/hook-order.test.mjs +72 -0
- package/tests/humanlike.test.mjs +232 -0
- package/tests/hybrid-recall.test.mjs +92 -0
- package/tests/inbound.test.mjs +393 -0
- package/tests/inject-guide.test.mjs +364 -0
- package/tests/inject.test.mjs +222 -0
- package/tests/injection-budget-settings.test.mjs +35 -0
- package/tests/injection-budget.test.mjs +64 -0
- package/tests/injection-chain.test.mjs +191 -0
- package/tests/loader-register.mjs +3 -0
- package/tests/loader.mjs +12 -0
- package/tests/local-embedding-entry.test.mjs +95 -0
- package/tests/local-embedding-manager.test.mjs +476 -0
- package/tests/local-embedding-protocol.test.mjs +95 -0
- package/tests/local-embedding-worker.test.mjs +346 -0
- package/tests/managed-memory.test.mjs +536 -0
- package/tests/managed-runtime.test.mjs +40 -0
- package/tests/media.test.mjs +132 -0
- package/tests/migration-payload.test.mjs +42 -0
- package/tests/mood.test.mjs +109 -0
- package/tests/multiprocess.test.mjs +29 -0
- package/tests/new-session-gate.test.mjs +361 -0
- package/tests/package-shipping.test.mjs +84 -0
- package/tests/preset-scope.test.mjs +212 -0
- package/tests/prompts.test.mjs +250 -0
- package/tests/react-snapshot.test.mjs +23 -0
- package/tests/recall-bench.test.mjs +306 -0
- package/tests/remote.test.mjs +140 -0
- package/tests/rename.test.mjs +30 -0
- package/tests/repetition-detector-snapshot.test.mjs +231 -0
- package/tests/repetition-eval-live.test.mjs +177 -0
- package/tests/repetition-eval.test.mjs +373 -0
- package/tests/salient-date.test.mjs +142 -0
- package/tests/settings-beat.test.mjs +221 -0
- package/tests/short-term.test.mjs +166 -0
- package/tests/sidebar-beat.test.mjs +208 -0
- package/tests/sidebar-refresh.test.mjs +123 -0
- package/tests/sidebar.test.mjs +70 -0
- package/tests/snippet.test.mjs +47 -0
- package/tests/source-kind.test.mjs +52 -0
- package/tests/state.test.mjs +150 -0
- package/tests/stats.test.mjs +112 -0
- package/tests/storage.test.mjs +125 -0
- package/tests/stubs/dsh-llm.js +5 -0
- package/tests/stubs/dsh-session.js +7 -0
- package/tests/stubs/dsh-tools.js +101 -0
- package/tests/tool-schema.test.mjs +73 -0
- package/tests/tools.test.mjs +184 -0
- package/tests/ui-defaults.test.mjs +57 -0
- package/tests/update-fields.test.mjs +138 -0
- package/tests/vector-migration.test.mjs +733 -0
- package/tests/vector-profile.test.mjs +425 -0
- package/tests/visibility-migration.test.mjs +152 -0
- package/tests/webui-auth.test.mjs +454 -0
- package/tests/webui.test.mjs +164 -0
- package/tests/windows-env.test.mjs +89 -0
package/lib/remote-summary.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { getSummaryConfig } from './memu-config.js'
|
|
2
2
|
import { loadPromptForDomain, CONSOLIDATION_CONTRACTS } from './prompts.js'
|
|
3
3
|
import { getSettings } from './state.js'
|
|
4
|
+
import { normalizeEmotion } from './mood.js'
|
|
5
|
+
import { record } from './activity-log.js'
|
|
4
6
|
|
|
5
7
|
function parseJsonObject(text) {
|
|
6
8
|
const raw = String(text || '').trim()
|
|
@@ -12,31 +14,42 @@ function parseJsonObject(text) {
|
|
|
12
14
|
try { return JSON.parse(raw.slice(start, end + 1)) } catch { return null }
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
// 逐条清洗。非法字段不修,只把这一条连同原因丢进 problems:一条坏数据不该让
|
|
18
|
+
// 整批整理白跑,也不该被悄悄改成"看起来合法"的情绪留在库里。
|
|
19
|
+
function cleanMemories(value, problems = []) {
|
|
16
20
|
const list = Array.isArray(value) ? value : []
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
21
|
+
const out = []
|
|
22
|
+
list.forEach((m, index) => {
|
|
23
|
+
try {
|
|
24
|
+
out.push({
|
|
25
|
+
title: String(m?.title || '').trim().slice(0, 120),
|
|
26
|
+
content: String(m?.content || '').trim(),
|
|
27
|
+
tags: Array.isArray(m?.tags) ? m.tags.slice(0, 20).map((t) => String(t)) : [],
|
|
28
|
+
openLoop: m?.open_loop === true || m?.openLoop === true,
|
|
29
|
+
confidence: Number.isFinite(Number(m?.confidence)) ? Number(m.confidence) : 0.8,
|
|
30
|
+
layer: ['long_term', 'short_term'].includes(m?.layer) ? m.layer : 'long_term',
|
|
31
|
+
disclosure: ['can_tell', 'only_if_asked', 'never_say'].includes(m?.disclosure) ? m.disclosure : 'can_tell',
|
|
32
|
+
// A consolidation pass that forgets the field must not invent a scope: the default
|
|
33
|
+
// here has to match the tool path (`privateRemember`, which defaults to 'shared').
|
|
34
|
+
// 'session' used to be the fallback, which silently turned every sloppy summary into
|
|
35
|
+
// a memory that died with its conversation (and the level itself is gone now).
|
|
36
|
+
visibility: ['shared', 'secret'].includes(m?.visibility) ? m.visibility : 'shared',
|
|
37
|
+
owner: ['me', 'us', 'about_user', 'about_project'].includes(m?.owner) ? m.owner : 'me',
|
|
38
|
+
source: ['user_said', 'inferred', 'imagined', 'told'].includes(m?.source) ? m.source : 'inferred',
|
|
39
|
+
// 缺字段是"没读到情绪",null 才是;这里不能拿 valence 反推四轴。
|
|
40
|
+
emotion: normalizeEmotion(m?.emotion ?? null),
|
|
41
|
+
// 缺失或非法给 null 而不是 0:0 表示"明确中性",不是"不知道"。
|
|
42
|
+
dominance: Number.isFinite(m?.dominance) ? Math.max(-1, Math.min(1, m.dominance)) : null,
|
|
43
|
+
moodValence: Number.isFinite(m?.mood_valence) ? Math.max(-1, Math.min(1, m.mood_valence)) : null,
|
|
44
|
+
arousal: Number.isFinite(m?.arousal) ? Math.max(0, Math.min(1, m.arousal)) : null,
|
|
45
|
+
peak: m?.peak === true,
|
|
46
|
+
salientDate: typeof m?.salient_date === 'string' ? m.salient_date : null,
|
|
47
|
+
})
|
|
48
|
+
} catch (error) {
|
|
49
|
+
problems.push({ index, title: String(m?.title || '').slice(0, 120), error: String(error?.message || error) })
|
|
50
|
+
}
|
|
51
|
+
})
|
|
52
|
+
return out.filter((m) => m.content).slice(0, 20)
|
|
40
53
|
}
|
|
41
54
|
|
|
42
55
|
// Remote mode: the configured chat endpoint does the summarizing. The session
|
|
@@ -87,7 +100,20 @@ export async function summarizeRemote({ transcript, libraryName, domain, signal,
|
|
|
87
100
|
const text = data?.choices?.[0]?.message?.content
|
|
88
101
|
const parsed = parseJsonObject(text)
|
|
89
102
|
if (!parsed) throw new Error(`remote summary returned non-JSON: ${String(text || body).slice(0, 600)}`)
|
|
90
|
-
|
|
103
|
+
const problems = []
|
|
104
|
+
const memories = cleanMemories(parsed.memories, problems)
|
|
105
|
+
if (problems.length) {
|
|
106
|
+
// 远程模型的错误只能靠日志查,静默丢弃等于把问题留给下一个人复现。
|
|
107
|
+
record({
|
|
108
|
+
kind: 'consolidate',
|
|
109
|
+
scope: 'private',
|
|
110
|
+
ok: false,
|
|
111
|
+
level: 'warn',
|
|
112
|
+
message: `远程整理有 ${problems.length} 条被拒绝:${problems[0].error}`,
|
|
113
|
+
detail: { rejected: problems },
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
return memories
|
|
91
117
|
} finally {
|
|
92
118
|
clearTimeout(timer)
|
|
93
119
|
signal?.removeEventListener?.('abort', onAbort)
|
package/lib/rpc.js
CHANGED
|
@@ -16,9 +16,11 @@ import { maybeMigrateLibraries } from './migrate.js'
|
|
|
16
16
|
import { getPromptStates, savePromptOverride, resetPrompt, resetAllPrompts } from './prompts.js'
|
|
17
17
|
import { statsView } from './stats.js'
|
|
18
18
|
import { getMemuConfig, saveMemuConfig, setEmbeddingSource, testMemuConfig, getSummaryConfig, getVisionConfig } from './memu-config.js'
|
|
19
|
+
import { getLocalVectorState, downloadLocalVectorModel, installLocalVectorRuntime, selectLocalVectorModel, switchLocalVectorProfile, rollbackLocalVectorProfile, abortLocalVectorMigration, testLocalVector } from './local-vector-service.js'
|
|
19
20
|
import { webUiHtml, WEBUI_PATH, standaloneHtml, standaloneAsset, SETTINGS_PATH } from './webui.js'
|
|
20
21
|
import { getGraph, listEntities, createEntity, renameEntity, linkEntries, unlinkEntry, getRelationship, updateRelationship, graphExport, restoreGraphData } from './graph.js'
|
|
21
22
|
import { getAttachment, attachmentThumbnail, attachmentPreview, exportMediaBundle, importMediaBundle, streamMediaExport, importMediaStream } from './media.js'
|
|
23
|
+
import { listEvents, logStats, clearEvents } from './activity-log.js'
|
|
22
24
|
|
|
23
25
|
const ENDPOINT = '/dsh-memu-memory'
|
|
24
26
|
|
|
@@ -84,6 +86,11 @@ async function privateListView(scope) {
|
|
|
84
86
|
decay: Math.min(1, Math.max(0, decayStrength(e) / 1.5)),
|
|
85
87
|
moodValence: e?.moodValence ?? null,
|
|
86
88
|
arousal: e?.arousal ?? null,
|
|
89
|
+
// 构成与掌控感分开投影:同一个 valence 说得出"多难过",说不出"是怒还是怕"。
|
|
90
|
+
emotion: e?.emotion ?? null,
|
|
91
|
+
dominance: e?.dominance ?? null,
|
|
92
|
+
// 来源是审计字段,只读:面板显示"这个情绪是谁给的",不给改。
|
|
93
|
+
emotionSource: e?.emotionSource ?? null,
|
|
87
94
|
peak: e?.peak === true,
|
|
88
95
|
salientDate: e?.salientDate || null,
|
|
89
96
|
attachments: attachmentPreview(libraryId, e || {}),
|
|
@@ -95,7 +102,7 @@ async function privateListView(scope) {
|
|
|
95
102
|
content: String(content ?? e?.content ?? '').slice(0, 4000),
|
|
96
103
|
})
|
|
97
104
|
try {
|
|
98
|
-
const result = await privateList(scope)
|
|
105
|
+
const result = await privateList({ ...scope, preferIndex: true })
|
|
99
106
|
return {
|
|
100
107
|
libraryId: result.libraryId,
|
|
101
108
|
source: result.source || 'engine',
|
|
@@ -451,6 +458,7 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
451
458
|
} catch {}
|
|
452
459
|
const rows = Object.entries(state.sessions || {})
|
|
453
460
|
.map(([sessionId, binding]) => {
|
|
461
|
+
if (binding.consolidationFork) return null
|
|
454
462
|
const inFolder = binding.scopeKey === scopeKey
|
|
455
463
|
|| (binding.libraryId && state.libraries?.[binding.libraryId]?.scopeKey === scopeKey)
|
|
456
464
|
if (!inFolder) return null
|
|
@@ -492,6 +500,7 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
492
500
|
memuConfig: getMemuConfig(),
|
|
493
501
|
summaryConfig: getSummaryConfig(),
|
|
494
502
|
visionConfig: getVisionConfig(),
|
|
503
|
+
localVector: getLocalVectorState(),
|
|
495
504
|
settings: getSettings(),
|
|
496
505
|
libraries: libraryView(),
|
|
497
506
|
archivedLibraries: archivedLibraryView(),
|
|
@@ -524,6 +533,9 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
524
533
|
newSessionDefault: getSettings().newSessionDefault || 'both',
|
|
525
534
|
},
|
|
526
535
|
libraries: listLibraries().map(({ id, name, scopeKey: key }) => ({ id, name, scopeKey: key })),
|
|
536
|
+
// Memory domains accepted by setDomain. Prompt page types are a different
|
|
537
|
+
// concept (getPromptDomains), so this stays a fixed list.
|
|
538
|
+
domains: ['rp', 'coding', 'general', 'mixed'],
|
|
527
539
|
// A folder with both layers off never prompts: there is nothing to ask.
|
|
528
540
|
folder,
|
|
529
541
|
shouldPrompt: folder.useLibrary !== false || folder.useGlobal !== false,
|
|
@@ -550,7 +562,7 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
550
562
|
case 'resetSettings': {
|
|
551
563
|
const patch = {}
|
|
552
564
|
for (const key of [
|
|
553
|
-
'autoInject', 'privateTopK', 'globalTopK', 'anchorTokens', 'turnTokens', 'dedupeTurns',
|
|
565
|
+
'autoInject', 'privateTopK', 'globalTopK', 'anchorTokens', 'turnTokens', 'injectionTotalTokens', 'dedupeTurns',
|
|
554
566
|
'globalEveryNTurns', 'minUserChars', 'mustRememberCap', 'randomCueChance',
|
|
555
567
|
'autoInstallEngine', 'newSessionPromptDismissed', 'newSessionDefault', 'habitsInjection',
|
|
556
568
|
'sleepConsolidation', 'sleepAfterIdleMinutes', 'autoCurateEveryHours',
|
|
@@ -564,7 +576,7 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
564
576
|
case 'setSettings': {
|
|
565
577
|
const patch = payload?.patch && typeof payload.patch === 'object' ? payload.patch : {}
|
|
566
578
|
const allowed = new Set([
|
|
567
|
-
'autoInject', 'privateTopK', 'globalTopK', 'anchorTokens', 'turnTokens',
|
|
579
|
+
'autoInject', 'privateTopK', 'globalTopK', 'anchorTokens', 'turnTokens', 'injectionTotalTokens',
|
|
568
580
|
'relevanceThreshold', 'dedupeTurns', 'globalEveryNTurns', 'minUserChars',
|
|
569
581
|
// newSessionDefault has to be writable here: "remember my choice" stores
|
|
570
582
|
// it, and a dropped patch silently turned every remembered answer into
|
|
@@ -765,7 +777,9 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
765
777
|
// `source` is writable: correcting provenance is the point of showing it.
|
|
766
778
|
// `salientDate` is writable for the same reason: an entry whose year was
|
|
767
779
|
// dropped has to be repairable from the browser, not only from JSON.
|
|
768
|
-
|
|
780
|
+
// `emotion`/`dominance` 可写:面板修的是那条记忆所述事件的感受。
|
|
781
|
+
// `emotionSource` 故意不在名单里:来源是审计结论,能改就等于能伪造。
|
|
782
|
+
const allowed = ['content', 'title', 'tags', 'status', 'openLoop', 'disclosure', 'confidence', 'owner', 'visibility', 'layer', 'source', 'salientDate', 'track', 'peak', 'moodValence', 'arousal', 'emotion', 'dominance', 'attachments', 'context']
|
|
769
783
|
// An unknown key used to be dropped in silence, so a typo here or in a script
|
|
770
784
|
// came back as a successful save that changed nothing. Refuse instead: the
|
|
771
785
|
// caller can only fix a field name it is told is wrong.
|
|
@@ -880,8 +894,10 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
880
894
|
const sessionId = payload?.sessionId || null
|
|
881
895
|
const exec = sessionId ? execFor(sessionId) : { agent: null }
|
|
882
896
|
try {
|
|
883
|
-
const result = await globalList({ exec, domain: payload?.domain })
|
|
897
|
+
const result = await globalList({ exec, domain: payload?.domain, preferIndex: true })
|
|
884
898
|
return {
|
|
899
|
+
warning: result.warning || null,
|
|
900
|
+
source: result.source || null,
|
|
885
901
|
files: (result.files || []).map((f) => ({
|
|
886
902
|
id: f.name,
|
|
887
903
|
title: f.entry?.title || f.description || '',
|
|
@@ -1086,6 +1102,24 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
1086
1102
|
})
|
|
1087
1103
|
case 'testMemuConfig':
|
|
1088
1104
|
return testMemuConfig()
|
|
1105
|
+
case 'getLocalVectorState':
|
|
1106
|
+
return getLocalVectorState()
|
|
1107
|
+
case 'downloadLocalVectorModel':
|
|
1108
|
+
return await downloadLocalVectorModel(String(payload?.id || ''), { confirmed: payload?.confirmed === true })
|
|
1109
|
+
case 'selectLocalVectorModel':
|
|
1110
|
+
return selectLocalVectorModel(String(payload?.id || ''))
|
|
1111
|
+
case 'installLocalVectorRuntime':
|
|
1112
|
+
return await installLocalVectorRuntime({ modelId: payload?.id || null, confirmed: payload?.confirmed === true })
|
|
1113
|
+
case 'switchLocalVectorProfile':
|
|
1114
|
+
if (payload?.confirmed !== true) throw new Error('switching the local vector profile requires explicit confirmation')
|
|
1115
|
+
return await switchLocalVectorProfile({ id: payload?.id })
|
|
1116
|
+
case 'rollbackLocalVectorProfile':
|
|
1117
|
+
if (payload?.confirmed !== true) throw new Error('rolling back the local vector profile requires explicit confirmation')
|
|
1118
|
+
return await rollbackLocalVectorProfile()
|
|
1119
|
+
case 'abortLocalVectorMigration':
|
|
1120
|
+
return abortLocalVectorMigration()
|
|
1121
|
+
case 'testLocalVector':
|
|
1122
|
+
return await testLocalVector()
|
|
1089
1123
|
case 'savePrompt': {
|
|
1090
1124
|
const key = String(payload?.key || '')
|
|
1091
1125
|
const text = String(payload?.text ?? '')
|
|
@@ -1104,6 +1138,21 @@ async function dispatch(ctx, endpoint, payload = {}) {
|
|
|
1104
1138
|
return { sizes: engineVersionSizes() }
|
|
1105
1139
|
case 'getEngine':
|
|
1106
1140
|
return engineView()
|
|
1141
|
+
case 'getActivityLog':
|
|
1142
|
+
return {
|
|
1143
|
+
events: listEvents({
|
|
1144
|
+
limit: payload?.limit,
|
|
1145
|
+
kind: payload?.kind,
|
|
1146
|
+
level: payload?.level,
|
|
1147
|
+
scope: payload?.scope,
|
|
1148
|
+
sessionId: payload?.sessionId,
|
|
1149
|
+
since: payload?.since,
|
|
1150
|
+
q: payload?.q,
|
|
1151
|
+
}),
|
|
1152
|
+
stats: logStats(),
|
|
1153
|
+
}
|
|
1154
|
+
case 'clearActivityLog':
|
|
1155
|
+
return clearEvents()
|
|
1107
1156
|
default:
|
|
1108
1157
|
throw new Error(`unknown endpoint: ${endpoint}`)
|
|
1109
1158
|
}
|