dsh-memory-palace 1.6.1 → 1.6.2-alpha.4

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 CHANGED
@@ -4,6 +4,9 @@
4
4
 
5
5
  [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [![Awesome DSH Plugin](https://awesome-dsh-plugin.com/badge.svg)](https://awesome-dsh-plugin.com)
6
6
 
7
+ > mian分支已适配**deepseek harness 0.1.2-alpha.2+**
8
+ > 旧版本已切换分支归档,见`dsh-v0.1.x`
9
+
7
10
  ## 特性
8
11
 
9
12
  - **人类可读的真源**:记忆全部存储在 Markdown 文件中(`MEMORY.md` + 每日日志 `YYYY-MM-DD.md`),任何编辑器可直接修改,数据永远属于你。
@@ -79,7 +82,7 @@ turn/end ──► 轻量兜底闸门
79
82
 
80
83
  ```bash
81
84
  dsh plugin --profile web add github:lovezi0/dsh-memory-palace
82
- # 锁定版本:dsh plugin --profile web add github:lovezi0/dsh-memory-palace#v1.6.1
85
+ # 锁定版本:dsh plugin --profile web add github:lovezi0/dsh-memory-palace#v1.6.2-alpha.4
83
86
  ```
84
87
 
85
88
  方式二:clone 后本地安装(开发 / 修改源码场景)
@@ -120,8 +123,15 @@ dsh plugin --profile web remove dsh-memory-palace
120
123
 
121
124
  ## 版本历史
122
125
 
126
+ - **1.6.2**
127
+ - **1.6.2.alpha.4**
128
+ - 🔥适配deepseek harness 0.1.2-alpha.4
129
+ - **1.6.2.alpha.2**
130
+ - 原1.6.0发布
123
131
  - **1.6.1**
124
132
  - 原1.6.0.alpha.1发布
133
+ - **1.6.0**
134
+ - 🔥适配deepseek harness 0.1.2-alpha.2
125
135
  - **1.6.0.alpha.1** *未发布npm*
126
136
  - 🔥新增混合模式(hybrid) *仍默认插件模式,建议切换至混合模式*
127
137
  - 🔥新增记忆子agent处理轮次会话日志
package/lib/client.js CHANGED
@@ -5,7 +5,8 @@ window.__ModuleLoader__.load({
5
5
  var exports = module.exports;
6
6
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
7
  let react = require("react");
8
- let _deepseek_ai_dsh_client_runtime_client = require("@deepseek-ai/dsh-client-runtime/client");
8
+ // v1.6.0-rc1:移除 require("@deepseek-ai/dsh-client-runtime/client")——该包在
9
+ // DSH 0.1.2-alpha.2 已整体删除(原变量赋值后零使用),平台 seed 表的 react 足够。
9
10
 
10
11
  const NS = "memory-palace";
11
12
 
@@ -214,8 +215,30 @@ window.__ModuleLoader__.load({
214
215
  }
215
216
 
216
217
 
218
+ // v1.6.0-rc1:模型枚举改走 ctx.remote.session.modelCatalog()——ApiProxy 包已在
219
+ // DSH 0.1.2-alpha.2 删除(旧 conn.api.llm.models 死了)。服务缺席 / 非 ok / 异常
220
+ // 一律降级为空列表,下拉只剩「复用当前会话模型」,UX 不变。
221
+ async function fetchModelOptions(ctx) {
222
+ try {
223
+ const remote = ctx && ctx.remote;
224
+ if (!remote || !remote.session || typeof remote.session.modelCatalog !== "function") return [];
225
+ const response = await remote.session.modelCatalog();
226
+ if (!response || !response.ok || !response.value) return [];
227
+ const opts = [];
228
+ for (const g of response.value.groups || []) {
229
+ for (const m of (g && g.models) || []) {
230
+ // m.id 已含 provider 前缀(如 nvidia/nemotron-3-ultra-550b-a55b),直接用,避免重复拼接
231
+ opts.push({ value: m.id, label: (g.name || g.id) + " / " + (m.name || m.id) });
232
+ }
233
+ }
234
+ return opts;
235
+ } catch (e) {
236
+ return [];
237
+ }
238
+ }
239
+
217
240
  function MemoryPalaceSection(props) {
218
- const { t, getConnection } = props;
241
+ const { t, fetchModels } = props;
219
242
  const [remote, setRemote] = react.useState({ value: null, user: {}, revision: undefined, loaded: false });
220
243
  const [draft, setDraft] = react.useState(() => projectDraft({ value: null }));
221
244
  const [dirty, setDirty] = react.useState(false);
@@ -224,7 +247,7 @@ window.__ModuleLoader__.load({
224
247
  const [validation, setValidation] = react.useState(null);
225
248
  const [modelOptions, setModelOptions] = react.useState([]);
226
249
 
227
- // 初始加载(从自有 route 读真实值,绕过 apiproxy allowlist)。
250
+ // 初始加载(从自有 route 读真实值)。
228
251
  react.useEffect(() => {
229
252
  let alive = true;
230
253
  (async () => {
@@ -250,18 +273,8 @@ window.__ModuleLoader__.load({
250
273
  let alive = true;
251
274
  (async () => {
252
275
  try {
253
- const conn = getConnection && getConnection();
254
- if (!conn || !conn.api || !conn.api.llm || typeof conn.api.llm.models !== "function") return;
255
- const r = await conn.api.llm.models({});
256
- const groups = (r && r.result && r.result.value && r.result.value.groups) || (r && r.groups) || [];
257
- const opts = [];
258
- for (const g of groups || []) {
259
- for (const m of (g && g.models) || []) {
260
- // m.id 已经包含 provider 前缀(如 nvidia/nemotron-3-ultra-550b-a55b),直接用,避免重复拼接
261
- opts.push({ value: m.id, label: g.name + " / " + m.name });
262
- }
263
- }
264
- if (alive) setModelOptions(opts);
276
+ const opts = await (fetchModels && fetchModels());
277
+ if (alive) setModelOptions(Array.isArray(opts) ? opts : []);
265
278
  } catch (e) {
266
279
  /* 枚举失败:保持空列表,下拉只剩「复用当前会话模型」 */
267
280
  }
@@ -860,14 +873,8 @@ window.__ModuleLoader__.load({
860
873
  // v1.1.3:设置读写走自有 route(/memory-palace/api),不再 bind settingsScope——
861
874
  // 非 loopback 下 settingsScope persistence=memory(set() no-op),保存永不落盘。
862
875
  const controller = new MemoryPalaceController(ctx);
863
- // v1.1.0:枚举已配置模型供「摘要模型」下拉(connection 服务,枚举失败则降级为空列表)。
864
- const getConnection = () => {
865
- try {
866
- return ctx.get("connection");
867
- } catch {
868
- return null;
869
- }
870
- };
876
+ // v1.6.0-rc1:枚举已配置模型改走 ctx.remote.session.modelCatalog()(ApiProxy 已删),
877
+ // 枚举失败则降级为空列表。
871
878
  ctx.slots.inject("settings.section", () => ctx.slots.register({
872
879
  name: "settings.section",
873
880
  id: "memory-palace",
@@ -875,7 +882,7 @@ window.__ModuleLoader__.load({
875
882
  label: () => t("nav"),
876
883
  locale: NS,
877
884
  inject: () => controller.inject()
878
- }, (props) => MemoryPalaceSection({ ...props, getConnection })));
885
+ }, (props) => MemoryPalaceSection({ ...props, fetchModels: () => fetchModelOptions(ctx) })));
879
886
  // v1.2.0:会话标题栏「记忆」按钮——headerUtilities 区(右对齐),order:-1 排在 Session log 左边。
880
887
  ctx.slots.inject("conversation.session.header.utilities", () => ctx.slots.register({
881
888
  name: "conversation.session.header.utilities",
@@ -886,7 +893,8 @@ window.__ModuleLoader__.load({
886
893
  }
887
894
 
888
895
  exports.apply = apply;
889
- exports.inject = ["slots", "locale", "connection"];
896
+ // v1.6.0-rc1:connection → remote + remote.session(模型枚举走 ctx.remote.session.modelCatalog)。
897
+ exports.inject = ["slots", "locale", "remote", "remote.session"];
890
898
  return module.exports;
891
899
  }
892
900
  });
@@ -0,0 +1,11 @@
1
+ // memory-palace v1.6.2-alpha.4 DSH 0.1.2-alpha.4 兼容层:Session.events getter 已被删除
2
+ // (宿主 27bf1039「distinguish event seqs from log offsets」顺带移除),替代 API 为
3
+ // snapshotEvents(from, toExclusive)——半开区间、from 含、返回冻结数组;运行时 seq 仍是
4
+ // 普通 number,wire/磁盘格式不变。旧版宿主(≤0.1.2-alpha.3)无此方法,回退 events + filter。
5
+ // 统一出口:调用方零分支,语义 =「取 seq >= fromSeq 的事件(升序)」。
6
+ export function eventsFrom(session, fromSeq = 0) {
7
+ if (typeof session?.snapshotEvents === "function") {
8
+ return session.snapshotEvents(fromSeq);
9
+ }
10
+ return (session?.events || []).filter((e) => e.seq >= fromSeq);
11
+ }
package/lib/distill.mjs CHANGED
@@ -5,6 +5,7 @@ import { join, dirname } from "node:path";
5
5
  import { BlockAssembler, createUserMessage } from "@deepseek-ai/dsh-llm";
6
6
  import { SUMMARY_PROMPT, DISTILL_PROMPT } from "./common/prompts.mjs";
7
7
  import { expandHome, readMdSync, toHomeShort, nowStamp, stripSmartTag } from "./common/text.mjs";
8
+ import { eventsFrom } from "./common/session.mjs";
8
9
  import { appendLineDedup, readNumberedMemory, applyMemoryOp } from "./common/records.mjs";
9
10
  import { runWithRetry, RETRY_CONSTANTS } from "./common/retry.mjs";
10
11
 
@@ -114,10 +115,9 @@ export function createDistill({ ctx, getConfig, paths, records, state }) {
114
115
  }
115
116
  const { provider, model } = resolved;
116
117
  // 2. 输入:取 seq >= fromSeq 的 surface 事件,投影成模型视角 Message[]。
118
+ // v1.6.2-alpha.4:eventsFrom 兼容层(宿主 0.1.2-alpha.4 删除 Session.events getter)。
117
119
  const SURFACE = new Set(["user/message", "assistant/message", "tool/result"]);
118
- const newEvents = (session.events || []).filter(
119
- (e) => e.seq >= fromSeq && SURFACE.has(e.type),
120
- );
120
+ const newEvents = eventsFrom(session, fromSeq).filter((e) => SURFACE.has(e.type));
121
121
  dbg("session core entry", { sessionId: session.id, fromSeq, eventsLen: newEvents.length });
122
122
  const hist = [];
123
123
  for (const e of newEvents) {
@@ -125,7 +125,7 @@ export function createDistill({ ctx, getConfig, paths, records, state }) {
125
125
  if (m) hist.push(m);
126
126
  }
127
127
  if (!hist.length) {
128
- dbgFail("no events in range", { fromSeq, eventsLen: (session.events || []).length, newEvents: newEvents.length, hasDerive: !!session.deriveEventMessage });
128
+ dbgFail("no events in range", { fromSeq, eventsLen: eventsFrom(session).length, newEvents: newEvents.length, hasDerive: !!session.deriveEventMessage });
129
129
  return { ok: false };
130
130
  }
131
131
  // 2.5 回喂存量记忆(v1.4.0 特性3):仅当 useFeedback 时,读取项目级 + 用户级 MEMORY.md 全文
@@ -10,6 +10,7 @@ import { writeFile, mkdir } from "node:fs/promises";
10
10
  import { join, dirname } from "node:path";
11
11
  import { BlockAssembler, createUserMessage, createToolResultMessage } from "@deepseek-ai/dsh-llm";
12
12
  import { todayISO, readMdSync } from "../common/text.mjs";
13
+ import { eventsFrom } from "../common/session.mjs";
13
14
  import { appendToSectionText, upsertSectionText, createSectionText, markEntryDeletedText, parseSections, locateSection } from "../common/sections.mjs";
14
15
  import { HYBRID_PROACTIVE, SUBAGENT_SYSTEM } from "./prompts.mjs";
15
16
 
@@ -66,10 +67,11 @@ async function streamTurn(ctx, params, timeoutMs) {
66
67
  }
67
68
 
68
69
  // 把本轮 surface 事件投影为消息数组(seq >= fromSeq;与 distillSessionCore 同源逻辑)。
70
+ // v1.6.2-alpha.4:eventsFrom 兼容层(宿主 0.1.2-alpha.4 删除 Session.events getter)。
69
71
  function projectTurnMessages(session, fromSeq) {
70
72
  const hist = [];
71
- for (const e of session.events || []) {
72
- if (e.seq < fromSeq || !SURFACE.has(e.type)) continue;
73
+ for (const e of eventsFrom(session, fromSeq)) {
74
+ if (!SURFACE.has(e.type)) continue;
73
75
  const m = session.deriveEventMessage ? session.deriveEventMessage(e) : null;
74
76
  if (m) hist.push(m);
75
77
  }
package/lib/index.js CHANGED
@@ -24,18 +24,21 @@
24
24
  // 硬约束——dsh 客户端模块系统不支持插件相对 require)
25
25
  import { join } from "node:path";
26
26
  import Schema from "@deepseek-ai/schemastery";
27
- import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
27
+ // v1.6.0-rc1:适配 DSH 0.1.2-alpha.2——dsh-settings 不再导出自由函数 installSettingsSection /
28
+ // settingsNamespace,设置节注册改用 SettingsProvider 实例方法 installSection(经 ctx.inject(["settings"]))。
28
29
  import { todayISO, expandHome, toHomeShort, readMdSync, budgetClip, stripSmartTag, stripDeletedLines, extractText, extractToolErrorText } from "./common/text.mjs";
29
30
  import { SCENE_KEYWORDS } from "./common/prompts.mjs";
30
31
  import { createPaths } from "./common/paths.mjs";
31
32
  import { createRecords } from "./common/records.mjs";
33
+ import { eventsFrom } from "./common/session.mjs";
32
34
  import { createDistill } from "./distill.mjs";
33
35
  import { registerTools } from "./tools.mjs";
34
36
  import { registerApi } from "./api.mjs";
35
37
  import { registerHybrid, HYBRID_PROACTIVE } from "./hybrid/index.mjs";
36
38
 
37
39
  export const name = "memory-palace";
38
- const MEMORY_PALACE_SETTINGS_NAMESPACE = settingsNamespace("memory-palace");
40
+ // v1.6.0-rc1:settingsNamespace() 已删除,namespace 直接用字符串(宿主侧做类型级校验)。
41
+ const MEMORY_PALACE_SETTINGS_NAMESPACE = "memory-palace";
39
42
 
40
43
  export const Config = Schema.object({
41
44
  enabled: Schema.boolean().default(true).description("启用 memory-palace 记忆注入与每日日志写入。"),
@@ -73,14 +76,10 @@ export const inject = ["systemPrompt", "tools", "llm", "webServer", "webRuntime"
73
76
  export function apply(ctx, config) {
74
77
  // 设置集成:在 DSH 设置页暴露 memory-palace 配置面板;运行时优先读用户设置覆盖层,
75
78
  // 未挂载 settings 服务时回退到 cordis 组合里的 config。
79
+ // v1.6.0-rc1:注册动作挪进下方 ctx.inject(["settings"]) 回调(installSection 是
80
+ // SettingsProvider 实例方法,须等 settings 服务挂载;其内部同步 setSource,时序与旧版等价)。
76
81
  let source = () => config;
77
82
  const baseEntry = { ...config };
78
- installSettingsSection(ctx, MEMORY_PALACE_SETTINGS_NAMESPACE, Config, baseEntry, {
79
- setSource: (next) => {
80
- source = next;
81
- },
82
- onChange: () => {},
83
- });
84
83
 
85
84
  // ---- v1.1.3:设置读写 route(真保存)----
86
85
  // client fetch 同源 /memory-palace/api/settings.get|update,绕过 settingsScope(persistence=memory no-op)
@@ -89,6 +88,15 @@ export function apply(ctx, config) {
89
88
  let settingsFace = null;
90
89
  ctx.inject(["settings"], (sctx) => {
91
90
  const ns = MEMORY_PALACE_SETTINGS_NAMESPACE;
91
+ // v1.6.0-rc1:设置节注册挪到此处(settings 服务就绪后)。installSection 内部会同步
92
+ // 执行 setSource(() => scope.get()),把 source 从 cordis config 切到用户设置覆盖层;
93
+ // owner=ctx 使插件卸载时宿主自动回退 setSource(() => entry)。与旧版自由函数时序等价。
94
+ sctx.settings.installSection(ctx, ns, Config, baseEntry, {
95
+ setSource: (next) => {
96
+ source = next;
97
+ },
98
+ onChange: () => {},
99
+ });
92
100
  const viewOf = () => {
93
101
  const descriptor = sctx.settings.describe({ redactSecrets: true }).find((candidate) => candidate.ns === ns);
94
102
  return descriptor === undefined
@@ -134,10 +142,10 @@ export function apply(ctx, config) {
134
142
  registerTools({ ctx, getConfig: () => source(), paths, records, state });
135
143
  registerApi({ ctx, paths, distill, state, getSettingsFace });
136
144
  // v1.6.0:hybrid 模式独立模块。必须【无条件注册】——apply() 同步段执行时 settings 服务
137
- // 尚未挂载(installSettingsSection 的 setSource 在 ctx.inject(["settings"]) 回调里才替换),
138
- // 此刻 source() 读的是 cordis 组合配置(默认 plugin),条件注册会导致设置页切 hybrid 后
139
- // 工具/子代理从未注册(v1.6.0 实装踩坑:settings.yaml memoryMode=hybrid 但 registerHybrid
140
- // 未执行 → 子代理 TypeError 被吞、日志全空)。
145
+ // 尚未挂载(v1.6.0-rc1 起设置节经 SettingsProvider.installSection 在 ctx.inject(["settings"])
146
+ // 回调里注册并同步 setSource),此刻 source() 读的是 cordis 组合配置(默认 plugin),
147
+ // 条件注册会导致设置页切 hybrid 后工具/子代理从未注册(v1.6.0 实装踩坑:settings.yaml
148
+ // memoryMode=hybrid 但 registerHybrid 未执行 → 子代理 TypeError 被吞、日志全空)。
141
149
  // 运行时分派靠 _settle / proactive 的热 source() 判断;工具注册无副作用(plugin/smart
142
150
  // 的 prompt 不引导使用,guards 白名单只拦 hybrid 工具)。
143
151
  const hybrid = registerHybrid({ ctx, getConfig: () => source(), paths, records, state });
@@ -291,10 +299,12 @@ export function apply(ctx, config) {
291
299
  // v1.1.3 修复:turnBuffer 字符上限(30k)仍可能截断超长工具型 request,导致 hasTool 误判为
292
300
  // false(tool 块被裁剪)→ 结算闸门误关 → 记忆整体丢失。智能模式闸门改用 session 事件增量
293
301
  // (真实完整信号,不依赖会被裁剪的 turnBuffer)。
294
- if (!baseGateOpen && state.activeSession && state.activeSession.events) {
302
+ // v1.6.2-alpha.4:宿主 0.1.2-alpha.4 删除 Session.events getter,事件读取统一走
303
+ // eventsFrom 兼容层(snapshotEvents 半开区间,旧宿主回退 events+filter)。
304
+ if (!baseGateOpen && state.activeSession) {
295
305
  const SURFACE = new Set(["user/message", "assistant/message", "tool/result"]);
296
- const newEvents = state.activeSession.events.filter(
297
- (e) => e.seq >= state.lastSummarizedSeq && SURFACE.has(e.type),
306
+ const newEvents = eventsFrom(state.activeSession, state.lastSummarizedSeq).filter(
307
+ (e) => SURFACE.has(e.type),
298
308
  );
299
309
  if (newEvents.some((e) => e.type === "tool/result")) baseGateOpen = true;
300
310
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-memory-palace",
3
- "version": "1.6.1",
3
+ "version": "1.6.2-alpha.4",
4
4
  "description": "把 WorkBuddy 的文件式记忆系统移植进 DeepSeek Harness:用户级 + 工作区的人类可读 Markdown 记忆(~/.deepseek-harness/MEMORY.md 与 <cwd>/.deepseek-harness/memory/)。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -30,24 +30,24 @@
30
30
  "client": {
31
31
  "platform": "web",
32
32
  "inject": [
33
- "@deepseek-ai/dsh-client-runtime",
34
33
  "@deepseek-ai/dsh-client-ui-settings",
34
+ "@deepseek-ai/dsh-client-ui-renderer",
35
35
  "@deepseek-ai/dsh-client-locale",
36
36
  "@deepseek-ai/dsh-client-connection",
37
- "@deepseek-ai/dsh-api-remotes"
37
+ "@deepseek-ai/dsh-api-remotes",
38
+ "@deepseek-ai/dsh-api-session-controller"
38
39
  ]
39
40
  }
40
41
  },
41
42
  "peerDependencies": {
42
43
  "@deepseek-ai/cordis": "*",
43
- "@deepseek-ai/dsh-fs": "^0.1.0-rc.6",
44
44
  "@deepseek-ai/dsh-llm": "*",
45
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6",
46
- "@deepseek-ai/dsh-tools": "^0.1.0-rc.6",
47
- "@deepseek-ai/schemastery": "^3.18.1"
45
+ "@deepseek-ai/dsh-settings": "^0.1.2-alpha.2",
46
+ "@deepseek-ai/dsh-tools": "^0.1.2-alpha.2",
47
+ "@deepseek-ai/schemastery": "^3.18.2"
48
48
  },
49
49
  "devDependencies": {
50
- "@deepseek-ai/dsh-settings": "^0.1.0-rc.6"
50
+ "@deepseek-ai/dsh-settings": "^0.1.2-alpha.2"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "node scripts/build.mjs",