dsh-cortex-memory 0.2.0-rc.11 → 0.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/README.md +6 -0
- package/client.js +22 -5
- package/docs/permissions.md +49 -0
- package/docs/privacy.md +48 -0
- package/package.json +5 -3
- package/src/api/routes.js +4 -0
- package/src/tools/definitions.js +2 -0
package/README.md
CHANGED
|
@@ -91,3 +91,9 @@ auto-linked into them.
|
|
|
91
91
|
MIT. External ideas are cited in the research notes; no third-party source
|
|
92
92
|
code is copied into this package.
|
|
93
93
|
|
|
94
|
+
|
|
95
|
+
## Security and privacy
|
|
96
|
+
|
|
97
|
+
- [Permissions and scopes](./docs/permissions.md)
|
|
98
|
+
- [Privacy notes](./docs/privacy.md)
|
|
99
|
+
|
package/client.js
CHANGED
|
@@ -105,6 +105,11 @@ window.__ModuleLoader__.load({
|
|
|
105
105
|
extractTitle: '从本地提取到记忆',
|
|
106
106
|
extractHint: 'OCR/ASR 结果会写成一条派生记忆,不改原 trace。',
|
|
107
107
|
extractTarget: '目标记忆',
|
|
108
|
+
extractLayout: '版面',
|
|
109
|
+
layoutAuto: '自动',
|
|
110
|
+
layoutSingle: '单栏',
|
|
111
|
+
layoutTwoColumn: '双栏',
|
|
112
|
+
layoutHandwriting: '手写',
|
|
108
113
|
extractRun: '提取并写入',
|
|
109
114
|
extractSaved: '已写入派生记忆',
|
|
110
115
|
extractSuggested: '建议:当前这条',
|
|
@@ -176,7 +181,7 @@ window.__ModuleLoader__.load({
|
|
|
176
181
|
graphReject: '拒绝',
|
|
177
182
|
graphCandidateConfidence: '置信',
|
|
178
183
|
settingsTitle: '运行设置',
|
|
179
|
-
settingsHint: '
|
|
184
|
+
settingsHint: '功能开关与指标为只读快照;权限修改会写入本机配置,重启后生效。',
|
|
180
185
|
runtime: '运行时',
|
|
181
186
|
features: '功能开关',
|
|
182
187
|
permissions: '权限 / 网络',
|
|
@@ -238,7 +243,7 @@ window.__ModuleLoader__.load({
|
|
|
238
243
|
p95: 'p95',
|
|
239
244
|
max: 'max',
|
|
240
245
|
metricsEmpty: '还没有指标样本。',
|
|
241
|
-
readOnlyNote: '
|
|
246
|
+
readOnlyNote: '快照只读;权限按钮可写,需确认并重启。',
|
|
242
247
|
refreshAll: '全部刷新',
|
|
243
248
|
metricAt: '采样时间',
|
|
244
249
|
notAvailable: '不可用',
|
|
@@ -363,6 +368,11 @@ window.__ModuleLoader__.load({
|
|
|
363
368
|
extractTitle: 'Extract into memory',
|
|
364
369
|
extractHint: 'OCR/ASR output is stored as a derived trace; the original trace is unchanged.',
|
|
365
370
|
extractTarget: 'Target trace',
|
|
371
|
+
extractLayout: 'Layout',
|
|
372
|
+
layoutAuto: 'Auto',
|
|
373
|
+
layoutSingle: 'Single column',
|
|
374
|
+
layoutTwoColumn: 'Two columns',
|
|
375
|
+
layoutHandwriting: 'Handwriting',
|
|
366
376
|
extractRun: 'Extract and write',
|
|
367
377
|
extractSaved: 'Derived trace written',
|
|
368
378
|
extractSuggested: 'Suggested: current trace',
|
|
@@ -434,7 +444,7 @@ window.__ModuleLoader__.load({
|
|
|
434
444
|
graphReject: 'Reject',
|
|
435
445
|
graphCandidateConfidence: 'Confidence',
|
|
436
446
|
settingsTitle: 'Runtime settings',
|
|
437
|
-
settingsHint: '
|
|
447
|
+
settingsHint: 'Feature flags and metrics are read-only snapshots; permission changes write local config and apply after restart.',
|
|
438
448
|
runtime: 'Runtime',
|
|
439
449
|
features: 'Feature flags',
|
|
440
450
|
permissions: 'Permissions / network',
|
|
@@ -496,7 +506,7 @@ window.__ModuleLoader__.load({
|
|
|
496
506
|
p95: 'p95',
|
|
497
507
|
max: 'max',
|
|
498
508
|
metricsEmpty: 'No metric samples yet.',
|
|
499
|
-
readOnlyNote: '
|
|
509
|
+
readOnlyNote: 'Snapshots are read-only; permission buttons write config after confirmation and need a restart.',
|
|
500
510
|
refreshAll: 'Refresh all',
|
|
501
511
|
metricAt: 'Sampled at',
|
|
502
512
|
notAvailable: 'Not available',
|
|
@@ -1080,6 +1090,7 @@ button.cortex-badge:disabled{cursor:not-allowed;opacity:.55}
|
|
|
1080
1090
|
const [uri, setUri] = useState('');
|
|
1081
1091
|
const [mode, setMode] = useState('ocr');
|
|
1082
1092
|
const [language, setLanguage] = useState('');
|
|
1093
|
+
const [layout, setLayout] = useState('auto');
|
|
1083
1094
|
const [targetId, setTargetId] = useState(trace.id);
|
|
1084
1095
|
const [candidates, setCandidates] = useState([{ id: trace.id, title: trace.title || trace.snippet || trace.id }]);
|
|
1085
1096
|
const [busy, setBusy] = useState(false);
|
|
@@ -1110,7 +1121,7 @@ button.cortex-badge:disabled{cursor:not-allowed;opacity:.55}
|
|
|
1110
1121
|
try {
|
|
1111
1122
|
const result = await api('/attachments/extract', {
|
|
1112
1123
|
method: 'POST',
|
|
1113
|
-
body: JSON.stringify({ uri: uri.trim(), mode, language: language.trim() || undefined, traceId: targetId }),
|
|
1124
|
+
body: JSON.stringify({ uri: uri.trim(), mode, language: language.trim() || undefined, layout, traceId: targetId }),
|
|
1114
1125
|
});
|
|
1115
1126
|
setNote(`${t('extractSaved')} ${result.extractedTraceId ?? ''}`.trim());
|
|
1116
1127
|
setUri('');
|
|
@@ -1129,6 +1140,12 @@ button.cortex-badge:disabled{cursor:not-allowed;opacity:.55}
|
|
|
1129
1140
|
h('option', { key: 'asr', value: 'asr' }, 'ASR'),
|
|
1130
1141
|
]),
|
|
1131
1142
|
h('input', { className: 'cortex-input', value: language, placeholder: mode === 'ocr' ? 'zh-Hans' : 'zh', onChange: (event) => setLanguage(event.target.value) }),
|
|
1143
|
+
h('select', { className: 'cortex-input', value: layout, title: t('extractLayout'), onChange: (event) => setLayout(event.target.value) }, [
|
|
1144
|
+
h('option', { key: 'auto', value: 'auto' }, t('layoutAuto')),
|
|
1145
|
+
h('option', { key: 'single', value: 'single' }, t('layoutSingle')),
|
|
1146
|
+
h('option', { key: 'two-column', value: 'two-column' }, t('layoutTwoColumn')),
|
|
1147
|
+
h('option', { key: 'handwriting', value: 'handwriting' }, t('layoutHandwriting')),
|
|
1148
|
+
]),
|
|
1132
1149
|
]),
|
|
1133
1150
|
h('label', { className: 'cortex-line', style: { marginTop: 8 } }, [
|
|
1134
1151
|
t('extractTarget'),
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Permissions and scopes
|
|
2
|
+
|
|
3
|
+
Cortex is local-first. The defaults are intentionally conservative.
|
|
4
|
+
|
|
5
|
+
## Local API
|
|
6
|
+
|
|
7
|
+
- The API is loopback-only by default.
|
|
8
|
+
- Requests carry a local token; cross-origin and unsafe POSTs are rejected.
|
|
9
|
+
- `POST /permissions` requires `confirm: true`; a permission change writes a local override and takes effect after a DSH restart.
|
|
10
|
+
- `POST /permissions/rollback` removes the override and also takes effect after restart.
|
|
11
|
+
|
|
12
|
+
## Scopes
|
|
13
|
+
|
|
14
|
+
- Every trace, fact, relation, goal and working item has a scope.
|
|
15
|
+
- The global scope is writable by default; shared scopes may be read-only.
|
|
16
|
+
- Scope resolution order is header, then query, then body, then the server default.
|
|
17
|
+
- A write to a read-only scope is refused; it is not silently redirected.
|
|
18
|
+
|
|
19
|
+
## Shared write grants
|
|
20
|
+
|
|
21
|
+
- Shared write grants are for API clients that send `x-cortex-agent`.
|
|
22
|
+
- A grant is a `scope:agent` pair, with an optional expiry.
|
|
23
|
+
- Revoke takes effect immediately; the tool path does not send an agent header.
|
|
24
|
+
- The grant list is visible in the Settings tab.
|
|
25
|
+
|
|
26
|
+
## Network permissions
|
|
27
|
+
|
|
28
|
+
- `llm`: allow the configured model service for QA, consolidation or extraction facts.
|
|
29
|
+
- `embed`: allow remote embedding; local embeddings remain available.
|
|
30
|
+
- `rerank`: allow remote reranking.
|
|
31
|
+
- `vector`: enable vector indexing/search.
|
|
32
|
+
- If a provider fails or a permission is off, Cortex falls back to non-vector or evidence-only paths instead of inventing data.
|
|
33
|
+
|
|
34
|
+
## Feature flags
|
|
35
|
+
|
|
36
|
+
Feature flags and metrics on the Settings page are a read-only snapshot. Permission buttons are the writable part; they always show a confirmation and a restart notice.
|
|
37
|
+
|
|
38
|
+
## Audit and rollback
|
|
39
|
+
|
|
40
|
+
- Writes, merges, forgets, permission changes and guardian operations append to the audit ledger.
|
|
41
|
+
- `cortex_guard` can back up, validate, export and restore.
|
|
42
|
+
- Delete is a privacy cascade; the event ledger keeps only a content hash.
|
|
43
|
+
- A bad permission override can be removed with the rollback button.
|
|
44
|
+
|
|
45
|
+
## What Cortex does not do
|
|
46
|
+
|
|
47
|
+
- It does not read arbitrary files just because they are on disk.
|
|
48
|
+
- It does not send memories to a model unless the corresponding permission and provider are configured.
|
|
49
|
+
- It does not store API keys or passwords in memory.
|
package/docs/privacy.md
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# Privacy notes
|
|
2
|
+
|
|
3
|
+
## Where data lives
|
|
4
|
+
|
|
5
|
+
Default data root:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
~/.dsh/cortex/
|
|
9
|
+
cortex.sqlite
|
|
10
|
+
backups/
|
|
11
|
+
vector/
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
The exact paths are shown in the Settings tab. This data stays on the machine unless the user configures a remote provider or moves it.
|
|
15
|
+
|
|
16
|
+
## What is stored
|
|
17
|
+
|
|
18
|
+
- traces (episodic, semantic, reflective, derived)
|
|
19
|
+
- facts and graph edges
|
|
20
|
+
- working memory, goals, playbook rules
|
|
21
|
+
- audit events
|
|
22
|
+
- emotional appraisals and relationship state
|
|
23
|
+
- optional derived text from local OCR/ASR, with source URI and engine metadata
|
|
24
|
+
|
|
25
|
+
## What is not stored
|
|
26
|
+
|
|
27
|
+
- API keys, tokens or passwords
|
|
28
|
+
- raw model files
|
|
29
|
+
- the contents of arbitrary local files that were not explicitly passed to an extraction tool
|
|
30
|
+
- a copy of a deleted trace's body (delete cascades; the ledger keeps a content hash)
|
|
31
|
+
|
|
32
|
+
## Deletion and export
|
|
33
|
+
|
|
34
|
+
- `cortex_forget` archive keeps a trace recoverable; delete removes it and its derived data.
|
|
35
|
+
- `cortex_guard export` writes a Markdown mirror for inspection.
|
|
36
|
+
- `cortex_guard backup` creates a SQLite backup; validate a backup before restoring.
|
|
37
|
+
- Attachments are metadata references; the default attachment reader is disabled.
|
|
38
|
+
|
|
39
|
+
## OCR / ASR
|
|
40
|
+
|
|
41
|
+
- Extraction is explicit: a `file://` URI and a configured local engine.
|
|
42
|
+
- The extractor never downloads a model automatically.
|
|
43
|
+
- Extracted text is written as a **derived trace**; the target trace is unchanged.
|
|
44
|
+
- PaddleOCR/Tesseract/Whisper models are local files owned by the user.
|
|
45
|
+
|
|
46
|
+
## Cloud / network
|
|
47
|
+
|
|
48
|
+
Remote LLM, embedding and rerank calls are off unless explicitly enabled and configured. The local API is loopback-only by default. There is no automatic telemetry from Cortex itself.
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-cortex-memory",
|
|
3
|
-
"version": "0.2.0
|
|
4
|
-
"description": "A
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "A layered, temporal, self-developing memory engine for DeepSeek Harness: working, episodic, semantic, procedural and reflective memory with hybrid retrieval, DSR forgetting, reflection, consolidation, gated self-evolution and guardian.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"icon": "./icon.svg",
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
"docs/scopes.md",
|
|
32
32
|
"docs/multimodal.md",
|
|
33
33
|
"examples",
|
|
34
|
-
"LICENSE"
|
|
34
|
+
"LICENSE",
|
|
35
|
+
"docs/permissions.md",
|
|
36
|
+
"docs/privacy.md"
|
|
35
37
|
],
|
|
36
38
|
"scripts": {
|
|
37
39
|
"test": "node --test test/unit/ test/integration/",
|
package/src/api/routes.js
CHANGED
|
@@ -299,6 +299,9 @@ export function createApiHandler({ cortex, logger = null, getExtractor = null }
|
|
|
299
299
|
}
|
|
300
300
|
if (route === '/forget') {
|
|
301
301
|
const input = validateForget(body);
|
|
302
|
+
if (!input.id || typeof input.id !== 'string' || !input.id.trim()) {
|
|
303
|
+
return sendJson(response, 400, { ok: false, error: 'traceId is required' });
|
|
304
|
+
}
|
|
302
305
|
if (!cortex.scopeWritableById('trace', input.id, agentOf(request))) {
|
|
303
306
|
return sendJson(response, 403, { ok: false, error: 'scope-read-only' });
|
|
304
307
|
}
|
|
@@ -369,6 +372,7 @@ export function createApiHandler({ cortex, logger = null, getExtractor = null }
|
|
|
369
372
|
uri: requireString(body.uri, 'uri', { max: 2000 }),
|
|
370
373
|
mode: requireString(body.mode, 'mode', { max: 16 }),
|
|
371
374
|
language: body.language ? requireString(body.language, 'language', { max: 32 }) : undefined,
|
|
375
|
+
layout: body.layout ? requireString(body.layout, 'layout', { max: 16 }) : undefined,
|
|
372
376
|
});
|
|
373
377
|
const ingested = cortex.ingestExtractedText({
|
|
374
378
|
targetTraceId: requireString(body.traceId, 'traceId', { max: 200 }),
|
package/src/tools/definitions.js
CHANGED
|
@@ -589,6 +589,7 @@ export function createToolDefinitions(service) {
|
|
|
589
589
|
output: TEXT_OUTPUT,
|
|
590
590
|
isConcurrencySafe: () => true,
|
|
591
591
|
async execute(args = {}) {
|
|
592
|
+
if (!args.id || !String(args.id).trim()) return { text: `没有这条记忆:${args.id}` };
|
|
592
593
|
const trace = service.get(args.id);
|
|
593
594
|
if (!trace) return { text: `没有这条记忆:${args.id}` };
|
|
594
595
|
return {
|
|
@@ -730,6 +731,7 @@ export function createToolDefinitions(service) {
|
|
|
730
731
|
output: TEXT_OUTPUT,
|
|
731
732
|
isConcurrencySafe: () => false,
|
|
732
733
|
async execute(args = {}) {
|
|
734
|
+
if (!args.id || !String(args.id).trim()) throw new Error('traceId is required');
|
|
733
735
|
if (!service.scopeWritableById('trace', args.id)) return { text: '未执行:该记忆属于只读共享 scope。' };
|
|
734
736
|
const result = service.forget({ traceId: args.id, mode: args.mode });
|
|
735
737
|
if (!result.removed) {
|