dsh-engram 0.5.0 → 0.6.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 +119 -32
- package/README.zh.md +103 -35
- package/docs/CONTEXT-GC-GUIDE.zh.md +15 -9
- package/docs/PROPOSAL-evolution.zh.md +684 -0
- package/docs/RELEASE-NOTES-v0.5.1.md +54 -0
- package/docs/RELEASE-NOTES-v0.6.0.md +64 -0
- package/lib/api.js +5 -0
- package/lib/boundary-prune.js +29 -2
- package/lib/client.js +329 -5
- package/lib/index.js +165 -18
- package/lib/jit.js +224 -0
- package/lib/ledger.js +458 -0
- package/lib/session-cjk.js +2 -2
- package/lib/settings.js +12 -4
- package/lib/usage.js +47 -4
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -153,6 +153,28 @@ var EngramApi = class {
|
|
|
153
153
|
})
|
|
154
154
|
);
|
|
155
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Data contract (issue #3) — dump the selected workspace, or every
|
|
158
|
+
* workspace when omitted, as a `dsh-engram/export` v1 payload. The same
|
|
159
|
+
* format `POST /import` restores, so the dump is a portable backup.
|
|
160
|
+
*/
|
|
161
|
+
async exportData(workspace) {
|
|
162
|
+
return readJson(await fetch(`${API_PREFIX}/export${query({ workspace })}`));
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Data contract (issue #3) — restore a dump. `merge` adds missing rows
|
|
166
|
+
* (idempotent), `replace` wipes the target workspace first (the host then
|
|
167
|
+
* requires `confirm: "restore"`). `dryRun` plans without writing.
|
|
168
|
+
*/
|
|
169
|
+
async importData(body) {
|
|
170
|
+
return readJson(
|
|
171
|
+
await fetch(`${API_PREFIX}/import`, {
|
|
172
|
+
method: "POST",
|
|
173
|
+
headers: { "content-type": "application/json" },
|
|
174
|
+
body: JSON.stringify(body)
|
|
175
|
+
})
|
|
176
|
+
);
|
|
177
|
+
}
|
|
156
178
|
/** Settings card transport — read the `dsh-engram` namespace through our
|
|
157
179
|
* own HTTP API instead of the host connection/remote RPC. */
|
|
158
180
|
async getSettings() {
|
|
@@ -2001,6 +2023,11 @@ function pct(v) {
|
|
|
2001
2023
|
if (v === null || v === void 0) return "\u2013";
|
|
2002
2024
|
return `${Math.round(v * 100)}%`;
|
|
2003
2025
|
}
|
|
2026
|
+
function tokenCount(n) {
|
|
2027
|
+
const sign = n > 0 ? "+" : n < 0 ? "\u2212" : "";
|
|
2028
|
+
const abs = Math.abs(n);
|
|
2029
|
+
return abs >= 1e3 ? `${sign}${(abs / 1e3).toFixed(1)}k` : `${sign}${abs}`;
|
|
2030
|
+
}
|
|
2004
2031
|
function EngramTelemetry({ api, workspace }) {
|
|
2005
2032
|
const { dark, vars } = useEngramTheme();
|
|
2006
2033
|
const [stats, setStats] = (0, import_react5.useState)(null);
|
|
@@ -2043,6 +2070,10 @@ function EngramTelemetry({ api, workspace }) {
|
|
|
2043
2070
|
}, [stats]);
|
|
2044
2071
|
const dose = stats && stats.ratios ? stats.ratios : null;
|
|
2045
2072
|
const sampleText = stats && stats.ratios && stats.ratios.calls < 10 ? `\u6837\u672C\u4E0D\u8DB3\uFF08${stats.ratios.calls} \u6B21\uFF09\uFF0C\u6BD4\u4F8B\u4EC5\u4F9B\u53C2\u8003` : null;
|
|
2073
|
+
const ledger = stats?.ledger ?? null;
|
|
2074
|
+
const ledgerBucket = ledger === null ? null : workspace === "" ? ledger.totals : ledger.byWorkspace?.[workspace] ?? null;
|
|
2075
|
+
const ledgerDays = ledger === null || workspace !== "" ? [] : [...ledger.byDay ?? []].slice(0, 14).reverse();
|
|
2076
|
+
const ledgerMax = Math.max(1, ...ledgerDays.map((d) => Math.abs(d.netTokens)));
|
|
2046
2077
|
const hb2 = {
|
|
2047
2078
|
root: { display: "flex", flexDirection: "column", gap: 12, ...vars },
|
|
2048
2079
|
head: { display: "flex", alignItems: "center", gap: 8, flexWrap: "wrap" },
|
|
@@ -2156,6 +2187,68 @@ function EngramTelemetry({ api, workspace }) {
|
|
|
2156
2187
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.statLabel, children: "\u5931\u8D25\u6B21\u6570" })
|
|
2157
2188
|
] })
|
|
2158
2189
|
] }),
|
|
2190
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.panel, children: [
|
|
2191
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { ...hb2.panelTitle, display: "flex", alignItems: "baseline", gap: 8, flexWrap: "wrap" }, children: [
|
|
2192
|
+
"Context Ledger \xB7 \u4E0A\u4E0B\u6587\u51C0\u6536\u76CA",
|
|
2193
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: hb2.sub, children: workspace === "" ? "\u5168\u90E8\u5DE5\u4F5C\u533A" : workspace })
|
|
2194
|
+
] }),
|
|
2195
|
+
!ledger ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.sub, children: "\u8D26\u672C\u672A\u542F\u7528\uFF08`ledgerEnabled:false`\uFF09\u6216\u5BBF\u4E3B API \u672A\u5C31\u7EEA\u3002" }) : !ledgerBucket ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.sub, children: "\u8BE5\u5DE5\u4F5C\u533A\u8FD8\u6CA1\u6709\u8D26\u672C\u8BB0\u5F55\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
|
|
2196
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { display: "flex", alignItems: "baseline", gap: 10, flexWrap: "wrap" }, children: [
|
|
2197
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: { ...hb2.statNum, fontSize: 24, color: ledgerBucket.netTokens >= 0 ? "#059669" : "#dc2626" }, children: tokenCount(ledgerBucket.netTokens) }),
|
|
2198
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { style: hb2.statLabel, children: "\u51C0 token\uFF08\u8282\u7701 \u2212 \u6CE8\u5165 \u2212 \u91CD\u5199\u7F5A\u91D1\uFF09" }),
|
|
2199
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { style: hb2.gaugeSub, children: [
|
|
2200
|
+
"\u8BF7\u6C42 ",
|
|
2201
|
+
ledgerBucket.requests,
|
|
2202
|
+
" \xB7 \u4F1A\u8BDD ",
|
|
2203
|
+
ledgerBucket.sessions,
|
|
2204
|
+
" \xB7 open ",
|
|
2205
|
+
ledger.openSessions,
|
|
2206
|
+
stats.jit ? ` \xB7 JIT \u63A8\u9001 ${stats.jit.pushes}` : ""
|
|
2207
|
+
] })
|
|
2208
|
+
] }),
|
|
2209
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { ...hb2.grid, marginTop: 8 }, children: [
|
|
2210
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.statCard, children: [
|
|
2211
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...hb2.statNum, color: "#059669" }, children: tokenCount(ledgerBucket.avoidedTokens) }),
|
|
2212
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.statLabel, children: "\u8282\u7701 \xB7 \u526A\u679D/\u538B\u7F29" })
|
|
2213
|
+
] }),
|
|
2214
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.statCard, children: [
|
|
2215
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...hb2.statNum, color: "#d97706" }, children: tokenCount(-ledgerBucket.injectedTokens) }),
|
|
2216
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.statLabel, children: "\u6CE8\u5165\u6210\u672C \xB7 \u7D22\u5F15/\u53EC\u56DE/ESR" })
|
|
2217
|
+
] }),
|
|
2218
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.statCard, children: [
|
|
2219
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...hb2.statNum, color: "#dc2626" }, children: tokenCount(-Math.round(ledgerBucket.rewritesCostChars / ledger.charsPerToken)) }),
|
|
2220
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.statLabel, children: [
|
|
2221
|
+
"\u91CD\u5199\u7F5A\u91D1 \xB7 ",
|
|
2222
|
+
ledgerBucket.rewriteCount,
|
|
2223
|
+
" \u6B21"
|
|
2224
|
+
] })
|
|
2225
|
+
] })
|
|
2226
|
+
] }),
|
|
2227
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { ...hb2.sub, marginTop: 6 }, children: [
|
|
2228
|
+
"\u53E3\u5F84\uFF1Achars/",
|
|
2229
|
+
ledger.charsPerToken,
|
|
2230
|
+
" \u4F30\u7B97 \xB7 \u7F13\u5B58\u6298\u4EF7 ",
|
|
2231
|
+
Math.round(ledger.cacheDiscount * 100),
|
|
2232
|
+
"% \uFF08\u91CD\u5199\u6309 ",
|
|
2233
|
+
Math.round((1 - ledger.cacheDiscount) * 100),
|
|
2234
|
+
"% \u8BA1\uFF09\xB7 \u672A\u8BA1\u6A21\u578B\u8D28\u91CF\u5DEE"
|
|
2235
|
+
] }),
|
|
2236
|
+
ledgerDays.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("svg", { width: 460, height: 96, viewBox: "0 0 460 96", style: { display: "block", maxWidth: "100%", marginTop: 8 }, children: [
|
|
2237
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("line", { x1: 0, y1: 48, x2: 460, y2: 48, stroke: dark ? "rgba(148,163,184,.35)" : "rgba(107,114,128,.35)", strokeDasharray: "3 3" }),
|
|
2238
|
+
ledgerDays.map((d, i) => {
|
|
2239
|
+
const w = Math.max(6, Math.min(22, 420 / ledgerDays.length - 4));
|
|
2240
|
+
const x = 8 + i * (w + 4);
|
|
2241
|
+
const h = Math.abs(d.netTokens) / ledgerMax * 38;
|
|
2242
|
+
const positive = d.netTokens >= 0;
|
|
2243
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("g", { children: [
|
|
2244
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("rect", { x, y: positive ? 48 - h : 48, width: w, height: Math.max(1, h), rx: 2, fill: positive ? "#059669" : "#dc2626", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("title", { children: `${d.day} \xB7 net ${d.netTokens} tok \xB7 \u8BF7\u6C42 ${d.requests}` }) }),
|
|
2245
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("text", { x: x + w / 2, y: 92, fontSize: 8, fill: dark ? "#8b93a7" : "#6b7280", textAnchor: "middle", children: (d.day ?? "").slice(5).replace("-", "/") })
|
|
2246
|
+
] }, d.day);
|
|
2247
|
+
})
|
|
2248
|
+
] }),
|
|
2249
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { ...hb2.sub, marginTop: 4 }, children: "\u7EFF = \u5F53\u65E5\u51C0\u7701 \xB7 \u7EA2 = \u5F53\u65E5\u51C0\u4E8F\uFF08\u6309\u5929\u6EDA\u52A8\uFF0C\u6700\u8FD1 14 \u5929\uFF09" })
|
|
2250
|
+
] })
|
|
2251
|
+
] }),
|
|
2159
2252
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: hb2.panel, children: [
|
|
2160
2253
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.panelTitle, children: "\u8FD1 14 \u5929\u6BCF\u65E5\u6D3B\u52A8 \xB7 mem vs esr" }),
|
|
2161
2254
|
daily.rows.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: hb2.sub, children: "\u8FD8\u6CA1\u6709\u6309\u5929\u6570\u636E\uFF08\u5DE5\u5177\u8C03\u7528\u4F1A\u5B9E\u65F6\u7D2F\u8BA1\uFF09\u3002" }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: BW, height: BH, viewBox: `0 0 ${BW} ${BH}`, style: { display: "block", maxWidth: "100%" }, children: daily.rows.map((d, i) => {
|
|
@@ -2254,7 +2347,7 @@ function gapsOf(t) {
|
|
|
2254
2347
|
if (!t.memoryRefs || t.memoryRefs.length === 0) gaps.push("memory_ref");
|
|
2255
2348
|
return gaps;
|
|
2256
2349
|
}
|
|
2257
|
-
function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMemory, onChanged }) {
|
|
2350
|
+
function EngramDetail({ target, api, tasks, nodes, links, memories = [], onClose, onNavigateMemory, onChanged }) {
|
|
2258
2351
|
const { dark, vars } = useEngramTheme();
|
|
2259
2352
|
const [gArt, setGArt] = (0, import_react6.useState)("");
|
|
2260
2353
|
const [gEval, setGEval] = (0, import_react6.useState)("");
|
|
@@ -2274,6 +2367,15 @@ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMem
|
|
|
2274
2367
|
if (target.kind !== "node" || !node) return [];
|
|
2275
2368
|
return links.filter((l) => l.source === node.id || l.target === node.id).map((l) => ({ l, outgoing: l.source === node.id }));
|
|
2276
2369
|
}, [links, node, target.kind]);
|
|
2370
|
+
const memoryLinks = (0, import_react6.useMemo)(() => {
|
|
2371
|
+
if (target.kind !== "memory") return null;
|
|
2372
|
+
const m = target.memory;
|
|
2373
|
+
return {
|
|
2374
|
+
m,
|
|
2375
|
+
replacedBy: memories.filter((x) => x.status === "active" && x.supersedes === m.id),
|
|
2376
|
+
contradictedBy: memories.filter((x) => x.status === "active" && x.contradicts === m.id)
|
|
2377
|
+
};
|
|
2378
|
+
}, [target, memories]);
|
|
2277
2379
|
const hb2 = {
|
|
2278
2380
|
root: {
|
|
2279
2381
|
...vars,
|
|
@@ -2304,6 +2406,8 @@ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMem
|
|
|
2304
2406
|
badge: { fontSize: 10.5, fontWeight: 700, padding: "2px 8px", borderRadius: 999, color: "#fff" },
|
|
2305
2407
|
tag: { fontSize: 11, padding: "1px 8px", borderRadius: 999, background: "var(--dsh-color-hover-bg, #f3f4f6)", color: "var(--dsh-color-muted, #6b7280)", border: "1px solid var(--dsh-color-border, #e5e7eb)" },
|
|
2306
2408
|
chip: { fontSize: 11, padding: "2px 9px", borderRadius: 999, background: "rgba(37,99,235,.1)", color: "#2563eb", border: "1px solid rgba(37,99,235,.25)", cursor: "pointer" },
|
|
2409
|
+
chipSup: { fontSize: 11, padding: "2px 9px", borderRadius: 999, background: "rgba(124,58,237,.1)", color: "#7c3aed", border: "1px solid rgba(124,58,237,.25)", cursor: "pointer" },
|
|
2410
|
+
chipDanger: { fontSize: 11, padding: "2px 9px", borderRadius: 999, background: "rgba(220,38,38,.1)", color: "#dc2626", border: "1px solid rgba(220,38,38,.25)", cursor: "pointer" },
|
|
2307
2411
|
input: { fontSize: 12, padding: "5px 8px", border: "1px solid var(--dsh-color-border, #d1d5db)", borderRadius: 8, background: "var(--dsh-color-surface, #ffffff)", color: "var(--dsh-color-muted-strong, #374151)", width: "100%", boxSizing: "border-box" },
|
|
2308
2412
|
btn: { fontSize: 11.5, fontWeight: 600, padding: "5px 10px", borderRadius: 8, cursor: "pointer", border: "1px solid var(--dsh-color-border, #d1d5db)", background: "transparent", color: "var(--dsh-color-muted-strong, #374151)" },
|
|
2309
2413
|
btnPrimary: { fontSize: 11.5, fontWeight: 700, padding: "5px 12px", borderRadius: 8, cursor: "pointer", border: "none", background: "#2563eb", color: "#fff" },
|
|
@@ -2442,6 +2546,29 @@ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMem
|
|
|
2442
2546
|
t
|
|
2443
2547
|
] }, t)) })
|
|
2444
2548
|
] }),
|
|
2549
|
+
memoryLinks && (memoryLinks.m.supersedes || memoryLinks.m.contradicts || memoryLinks.replacedBy.length > 0 || memoryLinks.contradictedBy.length > 0) && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: hb2.section, children: [
|
|
2550
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: hb2.k, children: "\u66FF\u6362 / \u51B2\u7A81" }),
|
|
2551
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", gap: 5, flexWrap: "wrap", marginTop: 3 }, children: [
|
|
2552
|
+
memoryLinks.m.supersedes && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: hb2.chipSup, title: `\u672C\u6761\u66FF\u4EE3 ${memoryLinks.m.supersedes}\uFF08\u65E7\u884C\u4FDD\u7559\u3001\u53EC\u56DE\u964D\u7EA7\uFF09`, onClick: () => onNavigateMemory(memoryLinks.m.supersedes), children: [
|
|
2553
|
+
"\u66FF\u4EE3 #",
|
|
2554
|
+
memoryLinks.m.supersedes.slice(0, 8)
|
|
2555
|
+
] }),
|
|
2556
|
+
memoryLinks.m.contradicts && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: hb2.chipDanger, title: `\u672C\u6761\u4E0E ${memoryLinks.m.contradicts} \u51B2\u7A81\uFF08\u4E24\u6761\u90FD\u4FDD\u7559\uFF09`, onClick: () => onNavigateMemory(memoryLinks.m.contradicts), children: [
|
|
2557
|
+
"\u51B2\u7A81 #",
|
|
2558
|
+
memoryLinks.m.contradicts.slice(0, 8)
|
|
2559
|
+
] }),
|
|
2560
|
+
memoryLinks.replacedBy.map((x) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: hb2.chipSup, title: `\u5DF2\u88AB ${x.text.slice(0, 40)}\u2026 \u66FF\u4EE3`, onClick: () => onNavigateMemory(x.id), children: [
|
|
2561
|
+
"\u2190 \u88AB #",
|
|
2562
|
+
x.id.slice(0, 8),
|
|
2563
|
+
" \u66FF\u4EE3"
|
|
2564
|
+
] }, x.id)),
|
|
2565
|
+
memoryLinks.contradictedBy.map((x) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: hb2.chipDanger, title: `${x.text.slice(0, 40)}\u2026 \u4E0E\u672C\u6761\u51B2\u7A81`, onClick: () => onNavigateMemory(x.id), children: [
|
|
2566
|
+
"\u21C4 #",
|
|
2567
|
+
x.id.slice(0, 8),
|
|
2568
|
+
" \u51B2\u7A81"
|
|
2569
|
+
] }, x.id))
|
|
2570
|
+
] })
|
|
2571
|
+
] }),
|
|
2445
2572
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: hb2.section, children: [
|
|
2446
2573
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: hb2.k, children: "\u5143\u6570\u636E" }),
|
|
2447
2574
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 2, marginTop: 3, fontSize: 11.5, fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace", color: "var(--dsh-color-muted, #6b7280)" }, children: [
|
|
@@ -2469,6 +2596,18 @@ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMem
|
|
|
2469
2596
|
" \xB7 updated ",
|
|
2470
2597
|
fmtDate(target.memory.updatedAt)
|
|
2471
2598
|
] }),
|
|
2599
|
+
target.memory.source && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
2600
|
+
"source ",
|
|
2601
|
+
target.memory.source
|
|
2602
|
+
] }),
|
|
2603
|
+
target.memory.conditions && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
2604
|
+
"conditions ",
|
|
2605
|
+
target.memory.conditions
|
|
2606
|
+
] }),
|
|
2607
|
+
target.memory.filePath && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
2608
|
+
"file ",
|
|
2609
|
+
target.memory.filePath
|
|
2610
|
+
] }),
|
|
2472
2611
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
|
|
2473
2612
|
"TTL ",
|
|
2474
2613
|
daysLeft(target.memory.expiresAt)
|
|
@@ -2568,6 +2707,11 @@ function EngramDetail({ target, api, tasks, nodes, links, onClose, onNavigateMem
|
|
|
2568
2707
|
|
|
2569
2708
|
// client/src/EngramSection.tsx
|
|
2570
2709
|
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
2710
|
+
function signedTokens(n) {
|
|
2711
|
+
const sign = n > 0 ? "+" : n < 0 ? "\u2212" : "";
|
|
2712
|
+
const abs = Math.abs(n);
|
|
2713
|
+
return abs >= 1e3 ? `${sign}${(abs / 1e3).toFixed(1)}k` : `${sign}${abs}`;
|
|
2714
|
+
}
|
|
2571
2715
|
var KIND_COLORS2 = {
|
|
2572
2716
|
preference: "#b45309",
|
|
2573
2717
|
decision: "#2563eb",
|
|
@@ -2791,6 +2935,14 @@ function EngramSection({ api, t }) {
|
|
|
2791
2935
|
const [closeEval, setCloseEval] = (0, import_react7.useState)("");
|
|
2792
2936
|
const [closeRefs, setCloseRefs] = (0, import_react7.useState)("");
|
|
2793
2937
|
const [closeBusy, setCloseBusy] = (0, import_react7.useState)(false);
|
|
2938
|
+
const [importDump, setImportDump] = (0, import_react7.useState)(null);
|
|
2939
|
+
const [importName, setImportName] = (0, import_react7.useState)("");
|
|
2940
|
+
const [importMode, setImportMode] = (0, import_react7.useState)("merge");
|
|
2941
|
+
const [importDryRun, setImportDryRun] = (0, import_react7.useState)(true);
|
|
2942
|
+
const [importReplaceOk, setImportReplaceOk] = (0, import_react7.useState)(false);
|
|
2943
|
+
const [importBusy, setImportBusy] = (0, import_react7.useState)(false);
|
|
2944
|
+
const [importReport, setImportReport] = (0, import_react7.useState)(null);
|
|
2945
|
+
const [dataError, setDataError] = (0, import_react7.useState)(null);
|
|
2794
2946
|
const refresh = (0, import_react7.useCallback)(async () => {
|
|
2795
2947
|
setBusy(true);
|
|
2796
2948
|
setError(null);
|
|
@@ -2847,6 +2999,24 @@ function EngramSection({ api, t }) {
|
|
|
2847
2999
|
for (const t2 of tasks) map.set(t2.id, t2.name);
|
|
2848
3000
|
return (id) => map.get(id) ?? id;
|
|
2849
3001
|
}, [nodes, tasks]);
|
|
3002
|
+
const supersedeIndex = (0, import_react7.useMemo)(() => {
|
|
3003
|
+
const replacedBy = /* @__PURE__ */ new Map();
|
|
3004
|
+
const contradictedBy = /* @__PURE__ */ new Map();
|
|
3005
|
+
for (const m of memories) {
|
|
3006
|
+
if (m.status !== "active") continue;
|
|
3007
|
+
if (m.supersedes) {
|
|
3008
|
+
const list = replacedBy.get(m.supersedes) ?? [];
|
|
3009
|
+
list.push(m);
|
|
3010
|
+
replacedBy.set(m.supersedes, list);
|
|
3011
|
+
}
|
|
3012
|
+
if (m.contradicts) {
|
|
3013
|
+
const list = contradictedBy.get(m.contradicts) ?? [];
|
|
3014
|
+
list.push(m);
|
|
3015
|
+
contradictedBy.set(m.contradicts, list);
|
|
3016
|
+
}
|
|
3017
|
+
}
|
|
3018
|
+
return { replacedBy, contradictedBy };
|
|
3019
|
+
}, [memories]);
|
|
2850
3020
|
(0, import_react7.useEffect)(() => {
|
|
2851
3021
|
if (!newTaskWs && workspaces.length > 0 && !workspace) setNewTaskWs(workspaces[0]);
|
|
2852
3022
|
}, [newTaskWs, workspaces, workspace]);
|
|
@@ -2880,6 +3050,60 @@ function EngramSection({ api, t }) {
|
|
|
2880
3050
|
setGcRunning(false);
|
|
2881
3051
|
}
|
|
2882
3052
|
};
|
|
3053
|
+
const downloadExport = async () => {
|
|
3054
|
+
setDataError(null);
|
|
3055
|
+
try {
|
|
3056
|
+
const dump = await api.exportData(workspace || void 0);
|
|
3057
|
+
const blob = new Blob([JSON.stringify(dump, null, 2)], { type: "application/json" });
|
|
3058
|
+
const url = URL.createObjectURL(blob);
|
|
3059
|
+
const a = document.createElement("a");
|
|
3060
|
+
const safe = (workspace || "all").replace(/[^a-zA-Z0-9._-]+/g, "_");
|
|
3061
|
+
a.href = url;
|
|
3062
|
+
a.download = `dsh-engram-export-${safe}-${(/* @__PURE__ */ new Date()).toISOString().slice(0, 10)}.json`;
|
|
3063
|
+
a.click();
|
|
3064
|
+
URL.revokeObjectURL(url);
|
|
3065
|
+
} catch (e) {
|
|
3066
|
+
setDataError(e instanceof Error ? e.message : String(e));
|
|
3067
|
+
}
|
|
3068
|
+
};
|
|
3069
|
+
const pickImportFile = async (file) => {
|
|
3070
|
+
setDataError(null);
|
|
3071
|
+
setImportReport(null);
|
|
3072
|
+
setImportDump(null);
|
|
3073
|
+
setImportName("");
|
|
3074
|
+
if (!file) return;
|
|
3075
|
+
try {
|
|
3076
|
+
const text = await file.text();
|
|
3077
|
+
setImportDump(JSON.parse(text));
|
|
3078
|
+
setImportName(file.name);
|
|
3079
|
+
} catch (e) {
|
|
3080
|
+
setDataError(`\u65E0\u6CD5\u89E3\u6790 ${file.name}\uFF1A${e instanceof Error ? e.message : String(e)}`);
|
|
3081
|
+
}
|
|
3082
|
+
};
|
|
3083
|
+
const runImport = async () => {
|
|
3084
|
+
if (importDump === null) return;
|
|
3085
|
+
if (importMode === "replace" && !importReplaceOk) {
|
|
3086
|
+
setDataError("\u66FF\u6362\u6A21\u5F0F\u4F1A\u5148\u6E05\u7A7A\u76EE\u6807\u5DE5\u4F5C\u533A \u2014 \u8BF7\u5148\u52FE\u9009\u786E\u8BA4");
|
|
3087
|
+
return;
|
|
3088
|
+
}
|
|
3089
|
+
setImportBusy(true);
|
|
3090
|
+
setDataError(null);
|
|
3091
|
+
try {
|
|
3092
|
+
const report = await api.importData({
|
|
3093
|
+
payload: importDump,
|
|
3094
|
+
mode: importMode,
|
|
3095
|
+
dryRun: importDryRun,
|
|
3096
|
+
workspace: workspace || void 0,
|
|
3097
|
+
confirm: importMode === "replace" ? "restore" : void 0
|
|
3098
|
+
});
|
|
3099
|
+
setImportReport(report);
|
|
3100
|
+
if (!report.dryRun) await refresh();
|
|
3101
|
+
} catch (e) {
|
|
3102
|
+
setDataError(e instanceof Error ? e.message : String(e));
|
|
3103
|
+
} finally {
|
|
3104
|
+
setImportBusy(false);
|
|
3105
|
+
}
|
|
3106
|
+
};
|
|
2883
3107
|
const groupedRows = workspace === "" ? groupByWorkspace(memories) : [[workspace, memories]];
|
|
2884
3108
|
const taskGroups = workspace === "" ? groupByWorkspace(tasks) : [[workspace, tasks]];
|
|
2885
3109
|
const linkGroups = workspace === "" ? groupByWorkspace(links) : [[workspace, links]];
|
|
@@ -2992,6 +3216,7 @@ function EngramSection({ api, t }) {
|
|
|
2992
3216
|
const memNum = wsCounts ? wsCounts.memories : overview.totals.memories;
|
|
2993
3217
|
const taskNum = wsCounts ? wsCounts.tasks : overview.totals.tasks;
|
|
2994
3218
|
const linkNum = wsCounts ? wsCounts.links : overview.totals.links;
|
|
3219
|
+
const ledgerBucket = overview.ledger ? workspace && overview.ledger.byWorkspace[workspace] || overview.ledger.totals : null;
|
|
2995
3220
|
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.stats, children: [
|
|
2996
3221
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StatCard, { num: String(memNum), label: wsCounts ? "\u8BB0\u5FC6 (active)" : "\u8BB0\u5FC6 (active, \u5168\u5C40)" }),
|
|
2997
3222
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(StatCard, { num: String(taskNum), label: wsCounts ? "\u4EFB\u52A1 (active)" : "\u4EFB\u52A1 (active, \u5168\u5C40)" }),
|
|
@@ -3013,6 +3238,13 @@ function EngramSection({ api, t }) {
|
|
|
3013
3238
|
num: String(gc.archivedMemories + gc.archivedTasks),
|
|
3014
3239
|
label: `GC \u5DF2\u5F52\u6863 \xB7 \u94FE\u63A5-${gc.removedLinks}`
|
|
3015
3240
|
}
|
|
3241
|
+
),
|
|
3242
|
+
ledgerBucket && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3243
|
+
StatCard,
|
|
3244
|
+
{
|
|
3245
|
+
num: signedTokens(ledgerBucket.netTokens),
|
|
3246
|
+
label: `\u4E0A\u4E0B\u6587\u51C0 token \xB7 \u8BF7\u6C42 ${ledgerBucket.requests}`
|
|
3247
|
+
}
|
|
3016
3248
|
)
|
|
3017
3249
|
] });
|
|
3018
3250
|
})(),
|
|
@@ -3069,6 +3301,90 @@ function EngramSection({ api, t }) {
|
|
|
3069
3301
|
] }, l.id))
|
|
3070
3302
|
] })
|
|
3071
3303
|
] }),
|
|
3304
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.subPanel, children: [
|
|
3305
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }, children: [
|
|
3306
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { fontWeight: 700, fontSize: 13 }, children: "\u6570\u636E\u5907\u4EFD\uFF08export / import\uFF09" }),
|
|
3307
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: s2.btn, title: "\u4E0B\u8F7D\u5F53\u524D\u5DE5\u4F5C\u533A\uFF08\u6216\u5168\u90E8\uFF09\u7684 dsh-engram/export v1 \u8F6C\u50A8", onClick: () => void downloadExport(), children: "\u5BFC\u51FA JSON" }),
|
|
3308
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { ...s2.btn, display: "inline-flex", alignItems: "center", gap: 6, cursor: "pointer" }, children: [
|
|
3309
|
+
"\u9009\u62E9\u5BFC\u5165\u6587\u4EF6\u2026",
|
|
3310
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3311
|
+
"input",
|
|
3312
|
+
{
|
|
3313
|
+
type: "file",
|
|
3314
|
+
accept: "application/json,.json",
|
|
3315
|
+
style: { display: "none" },
|
|
3316
|
+
onChange: (e) => {
|
|
3317
|
+
void pickImportFile(e.target.files?.[0] ?? null);
|
|
3318
|
+
e.currentTarget.value = "";
|
|
3319
|
+
}
|
|
3320
|
+
}
|
|
3321
|
+
)
|
|
3322
|
+
] }),
|
|
3323
|
+
importName && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: s2.mono, children: importName })
|
|
3324
|
+
] }),
|
|
3325
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { fontSize: 11.5, color: "var(--dsh-color-muted, #6b7280)", marginTop: 4 }, children: [
|
|
3326
|
+
"\u5BFC\u51FA\u5373\u53EF\u79FB\u690D\u5907\u4EFD\uFF08\u8BB0\u5FC6/\u4EFB\u52A1/\u5173\u7CFB/\u8282\u70B9\uFF0C\u542B\u5F52\u6863\uFF09\uFF1B",
|
|
3327
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: "merge" }),
|
|
3328
|
+
" \u53EA\u8865\u7F3A\u5931\uFF08\u5E42\u7B49\uFF09\uFF0C",
|
|
3329
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("b", { children: "replace" }),
|
|
3330
|
+
" \u5148\u6E05\u7A7A\u76EE\u6807\u5DE5\u4F5C\u533A\u518D\u6062\u590D\u3002\u8BB0\u5FC6\u6B63\u6587\u4E0E\u6240\u6709\u5199\u5165\u8DEF\u5F84\u4E00\u6837\u8FC7\u8131\u654F\u3002"
|
|
3331
|
+
] }),
|
|
3332
|
+
importDump !== null && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { marginTop: 8, display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
3333
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { display: "flex", gap: 10, alignItems: "center", flexWrap: "wrap", fontSize: 12.5 }, children: [
|
|
3334
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { display: "inline-flex", gap: 4, alignItems: "center" }, children: [
|
|
3335
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: importDryRun, onChange: (e) => setImportDryRun(e.target.checked) }),
|
|
3336
|
+
"\u4EC5\u9884\u89C8\uFF08dry run\uFF09"
|
|
3337
|
+
] }),
|
|
3338
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3339
|
+
"select",
|
|
3340
|
+
{
|
|
3341
|
+
style: s2.input,
|
|
3342
|
+
value: importMode,
|
|
3343
|
+
onChange: (e) => {
|
|
3344
|
+
const mode = e.target.value;
|
|
3345
|
+
setImportMode(mode);
|
|
3346
|
+
if (mode !== "replace") setImportReplaceOk(false);
|
|
3347
|
+
},
|
|
3348
|
+
children: [
|
|
3349
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "merge", children: "\u5408\u5E76\uFF08merge\uFF0C\u5E42\u7B49\uFF09" }),
|
|
3350
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "replace", children: "\u66FF\u6362\uFF08replace\uFF0C\u5148\u6E05\u7A7A\u5DE5\u4F5C\u533A\uFF09" })
|
|
3351
|
+
]
|
|
3352
|
+
}
|
|
3353
|
+
),
|
|
3354
|
+
importMode === "replace" && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("label", { style: { display: "inline-flex", gap: 4, alignItems: "center", color: "#b45309" }, children: [
|
|
3355
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("input", { type: "checkbox", checked: importReplaceOk, onChange: (e) => setImportReplaceOk(e.target.checked) }),
|
|
3356
|
+
"\u6211\u786E\u8BA4\u66FF\u6362",
|
|
3357
|
+
workspace ? `\uFF08${workspace}\uFF09` : "\uFF08\u9700\u5148\u9009\u5DE5\u4F5C\u533A\uFF09"
|
|
3358
|
+
] }),
|
|
3359
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3360
|
+
"button",
|
|
3361
|
+
{
|
|
3362
|
+
style: s2.btnPrimary,
|
|
3363
|
+
disabled: importBusy || importMode === "replace" && (!importReplaceOk || !workspace),
|
|
3364
|
+
onClick: () => void runImport(),
|
|
3365
|
+
children: importBusy ? "\u2026" : importDryRun ? "\u9884\u89C8\u5BFC\u5165" : "\u6267\u884C\u5BFC\u5165"
|
|
3366
|
+
}
|
|
3367
|
+
)
|
|
3368
|
+
] }),
|
|
3369
|
+
importReport && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: { fontSize: 12.5 }, children: [
|
|
3370
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { children: [
|
|
3371
|
+
importReport.dryRun ? "dry-run \u9884\u89C8\uFF1A" : "\u5DF2\u5BFC\u5165\uFF1A",
|
|
3372
|
+
" ",
|
|
3373
|
+
Object.entries(importReport.written).map(([k, v]) => `${k} ${v}`).join(" \xB7 ") || "\u2014",
|
|
3374
|
+
importReport.skipped.length > 0 ? ` \xB7 \u8DF3\u8FC7 ${importReport.skipped.length}` : ""
|
|
3375
|
+
] }),
|
|
3376
|
+
importReport.skipped.slice(0, 5).map((x, i) => /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.mono, children: [
|
|
3377
|
+
"- ",
|
|
3378
|
+
x.table,
|
|
3379
|
+
" ",
|
|
3380
|
+
x.id ? x.id.slice(0, 8) : "?",
|
|
3381
|
+
": ",
|
|
3382
|
+
x.reason
|
|
3383
|
+
] }, `${x.table}-${x.id ?? i}`))
|
|
3384
|
+
] }),
|
|
3385
|
+
dataError && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { fontSize: 12, color: "#dc2626", fontWeight: 600 }, children: dataError })
|
|
3386
|
+
] })
|
|
3387
|
+
] }),
|
|
3072
3388
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { style: s2.row, children: [
|
|
3073
3389
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("select", { style: s2.input, value: kind, onChange: (e) => setKind(e.target.value), children: [
|
|
3074
3390
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("option", { value: "", children: "\u5168\u90E8\u7C7B\u578B" }),
|
|
@@ -3142,7 +3458,8 @@ function EngramSection({ api, t }) {
|
|
|
3142
3458
|
] }) }, `h-${r.ws}`) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("tr", { children: [
|
|
3143
3459
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: { ...s2.td, whiteSpace: "nowrap" }, children: [
|
|
3144
3460
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...s2.badge, background: KIND_COLORS2[r.m.kind] ?? "#6b7280" }, children: KIND_LABEL2[r.m.kind] ?? r.m.kind }),
|
|
3145
|
-
r.m.status === "archived" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...s2.tag, color: "#b45309", background: "#fef3c7" }, children: "archived" })
|
|
3461
|
+
r.m.status === "archived" && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...s2.tag, color: "#b45309", background: "#fef3c7" }, children: "archived" }),
|
|
3462
|
+
supersedeIndex.replacedBy.has(r.m.id) && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: { ...s2.tag, color: "#b45309", background: "#fef3c7" }, title: `\u5DF2\u88AB ${(supersedeIndex.replacedBy.get(r.m.id) ?? []).map((x) => `#${x.id.slice(0, 8)}`).join(", ")} \u66FF\u4EE3\uFF08\u65E7\u884C\u4FDD\u7559\u3001\u53EC\u56DE\u964D\u7EA7\uFF09`, children: "\u5DF2\u66FF\u6362" })
|
|
3146
3463
|
] }),
|
|
3147
3464
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("td", { style: { ...s2.td, minWidth: 0 }, children: [
|
|
3148
3465
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { title: r.m.text, style: expandedRows.has(r.m.id) ? s2.expanded : s2.clamp3, children: r.m.text }),
|
|
@@ -3159,7 +3476,11 @@ function EngramSection({ api, t }) {
|
|
|
3159
3476
|
" \xB7 ",
|
|
3160
3477
|
daysLeft2(r.m.expiresAt)
|
|
3161
3478
|
] }),
|
|
3162
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: s2.linkBtn, onClick: () => toggleExpand(r.m.id), children: expandedRows.has(r.m.id) ? "\u6536\u8D77" : "\u5C55\u5F00\u5168\u6587" })
|
|
3479
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("button", { style: s2.linkBtn, onClick: () => toggleExpand(r.m.id), children: expandedRows.has(r.m.id) ? "\u6536\u8D77" : "\u5C55\u5F00\u5168\u6587" }),
|
|
3480
|
+
r.m.supersedes && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("button", { style: s2.linkBtn, title: `\u6253\u5F00\u88AB\u66FF\u4EE3\u7684\u65E7\u8BB0\u5FC6 ${r.m.supersedes}`, onClick: () => openMemory(r.m.supersedes), children: [
|
|
3481
|
+
"\u66FF\u4EE3 #",
|
|
3482
|
+
r.m.supersedes.slice(0, 8)
|
|
3483
|
+
] })
|
|
3163
3484
|
] }),
|
|
3164
3485
|
r.m.tags.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { marginTop: 3, display: "flex", flexWrap: "wrap", gap: 4 }, children: r.m.tags.map((tag) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { style: s2.tag, children: tag }, tag)) })
|
|
3165
3486
|
] }),
|
|
@@ -3359,6 +3680,7 @@ ${r.m.text.slice(0, 60)}`)) void act(() => api.remove(r.m.id, r.m.workspace));
|
|
|
3359
3680
|
tasks,
|
|
3360
3681
|
nodes,
|
|
3361
3682
|
links,
|
|
3683
|
+
memories,
|
|
3362
3684
|
onClose: () => setDetail(null),
|
|
3363
3685
|
onNavigateMemory: openMemory,
|
|
3364
3686
|
onChanged: () => void refresh()
|
|
@@ -3375,10 +3697,12 @@ var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
|
3375
3697
|
var COMMON_FIELDS = [
|
|
3376
3698
|
{ key: "autoCapture", label: "\u81EA\u52A8\u6355\u83B7", hint: "\u96F6 LLM \u4ECE\u5DE5\u5177\u7ED3\u679C\u63D0\u53D6\u8BB0\u5FC6\uFF08git/\u5173\u952E\u6587\u4EF6/\u9519\u8BEF\uFF09", kind: "bool" },
|
|
3377
3699
|
{ key: "autoCapturePreferences", label: "\u504F\u597D\u6355\u83B7", hint: "\u7528\u6237\u7EA0\u6B63/\u504F\u597D\u5B66\u4E60\uFF1A\u68C0\u6D4B\u6D88\u606F\u91CC\u7684\u300C\u4E0D\u8981\u7528X/\u6539\u7528Y/prefer/never use\u300D\u53E5\u5F0F\uFF0C\u81EA\u52A8\u6C89\u6DC0\u4E3A preference \u8BB0\u5FC6\u5E76\u7F6E\u9876 [ENGRAM]\uFF08correx/PAHF \u5F0F\uFF0C\u96F6 LLM\uFF09", kind: "bool" },
|
|
3378
|
-
{ key: "boundaryPrune", label: "\u8FB9\u754C\u526A\u679D", hint: "ResultPack L1\uFF1Atodo \u5B8C\u6210/goal \u7EC8\u6001\u8FB9\u754C\u4E3B\u52A8\u526A\u6389\u8D85\u9608\u503C\u65E7\u5DE5\u5177\u7ED3\u679C\uFF08DSH \u786E\u5B9A\u6027 surface-replace\u3001\u507F\u8FD8\u95E8\u3001\u96F6 LLM\uFF1B\u9ED8\u8BA4\u5173\uFF09", kind: "bool" },
|
|
3700
|
+
{ key: "boundaryPrune", label: "\u8FB9\u754C\u526A\u679D", hint: "ResultPack L1\uFF1Atodo \u5B8C\u6210/goal \u7EC8\u6001\u8FB9\u754C\u4E3B\u52A8\u526A\u6389\u8D85\u9608\u503C\u65E7\u5DE5\u5177\u7ED3\u679C\uFF08DSH \u786E\u5B9A\u6027 surface-replace\u3001\u507F\u8FD8\u95E8\u3001\u96F6 LLM\uFF1B\u9ED8\u8BA4\u5F00\uFF0C\u5173=opt-out\uFF09", kind: "bool" },
|
|
3701
|
+
{ key: "boundaryPruneAdaptive", label: "\u526A\u679D\u81EA\u9002\u5E94", hint: "\u8D26\u672C\u5426\u51B3\uFF1A\u8BE5 workspace \u771F\u5B9E\u526A\u679D\u540E\u51C0\u6536\u76CA\u4E3A\u8D1F\uFF08\u22653 \u6B21\uFF09\u65F6\u81EA\u52A8\u505C\u6B62\u7EE7\u7EED\u526A\uFF1B\u8BC1\u636E\u53EA\u80FD\u5173\u3001\u4E0D\u4F1A\u81EA\u884C\u5F00", kind: "bool" },
|
|
3379
3702
|
{ key: "boundaryPruneThresholdChars", label: "\u526A\u679D\u9608\u503C(\u5B57\u7B26)", hint: "\u8986\u76D6\u5BBF\u4E3B 8192\uFF1A\u8BBE 2048 \u53EF\u66F4\u65E9\u5F00\u526A\uFF0C\u5E76\u914D L2 \u5F52\u6863\u627E\u56DE\u88AB\u526A\u4E2D\u6BB5\uFF1B\u7559\u7A7A=\u5BBF\u4E3B\u9ED8\u8BA4\u3002\u5EFA\u8BAE\u540C\u65F6\u628A\u4FDD\u7559\u8FB9\u7F18\u8C03\u5C0F\uFF08\u5982 1024/256\uFF09\u4EE5\u83B7\u5F97\u6700\u5927\u8282\u7701", kind: "num", min: 256, max: 16384, step: 256 },
|
|
3380
|
-
{ key: "resultPack", label: "\u7ED3\u679C\u5F52\u6863\u53EC\u56DE", hint: "ResultPack L2\uFF1A\u526A\u6389\u7684\u4E2D\u6BB5\u8131\u654F\u5F52\u6863\uFF0C\u8282\u70B9\u5C3E\u90E8\u9644 handle\uFF0C\u6A21\u578B\u53EF\u7528 result_recall(callId) \u6309\u9875\u53EC\u56DE\uFF08\u5B8C\u6574 ObservationPack\uFF1B\u9700\u4E0E\u8FB9\u754C\u526A\u679D\u4E00\u8D77\u5F00\uFF09", kind: "bool" },
|
|
3703
|
+
{ key: "resultPack", label: "\u7ED3\u679C\u5F52\u6863\u53EC\u56DE", hint: "ResultPack L2\uFF1A\u526A\u6389\u7684\u4E2D\u6BB5\u8131\u654F\u5F52\u6863\uFF0C\u8282\u70B9\u5C3E\u90E8\u9644 handle\uFF0C\u6A21\u578B\u53EF\u7528 result_recall(callId) \u6309\u9875\u53EC\u56DE\uFF08\u5B8C\u6574 ObservationPack\uFF1B\u9ED8\u8BA4\u5F00\uFF0C\u4FDD\u8BC1\u9ED8\u8BA4\u526A\u679D\u65E0\u635F\uFF1B\u9700\u4E0E\u8FB9\u754C\u526A\u679D\u4E00\u8D77\u5F00\uFF09", kind: "bool" },
|
|
3381
3704
|
{ key: "autoRecallOnStart", label: "\u4F1A\u8BDD\u542F\u52A8\u81EA\u52A8\u53EC\u56DE", hint: "\u65B0\u4F1A\u8BDD\u6309\u9996\u6761\u6D88\u606F\u81EA\u52A8\u628A\u6700\u76F8\u5173\u8BB0\u5FC6\u6CE8\u5165 [RECALL] \u5757\uFF08\u65E0\u9700\u6A21\u578B\u60F3\u8D77\u8C03 engram_recall\uFF09\uFF1B\u5173\u6389=\u56DE\u5230\u7EAF\u62C9\u53D6", kind: "bool" },
|
|
3705
|
+
{ key: "jitEnabled", label: "JIT \u63A8\u9001", hint: "\u9519\u8BEF\u590D\u53D1 / \u6587\u4EF6\u7126\u70B9 / goal \u5B8C\u6210\u65F6\uFF0C\u628A\u5DF2\u6709\u8BB0\u5FC6\u538B\u6210\u4E00\u884C\u63A8\u8FDB\u4E0A\u4E0B\u6587\uFF08append-only\u3001\u6BCF\u4F1A\u8BDD\u22643 \u884C\u3001\u65E0\u547D\u4E2D\u6C89\u9ED8\uFF1B\u6BCF\u6B21\u63A8\u9001\u6309\u524D\u7F00\u91CD\u5199\u8BA1\u5165\u8D26\u672C\uFF09", kind: "bool" },
|
|
3382
3706
|
{ key: "maxRecallPerSession", label: "\u6BCF\u4F1A\u8BDD\u53BB\u91CD\u4E0A\u9650", hint: "recall \u6BCF\u4F1A\u8BDD\u6700\u591A\u4FDD\u7559 N \u6761\uFF08\u8DE8\u4F1A\u8BDD\u53BB\u91CD\uFF09", kind: "num", min: 1, max: 10 },
|
|
3383
3707
|
{ key: "expireDays", label: "TTL\uFF08\u5929\uFF09", hint: "0 = \u4E0D\u8FC7\u671F", kind: "num", min: 0, max: 3650 },
|
|
3384
3708
|
{ key: "indexMaxChars", label: "\u7D22\u5F15\u5B57\u7B26\u4E0A\u9650", hint: "[ENGRAM] \u5757 token \u9884\u7B97", kind: "num", min: 0, max: 4e3 }
|