Skip to content

Add Hindsight Memory gateway hook / 新增 Hindsight Memory 网关记忆插件 - #876

Open
Sam-dancing-nu1 wants to merge 5 commits into
magpie-community:mainfrom
Sam-dancing-nu1:add-gateway-hindsight
Open

Sam-dancing-nu1 wants to merge 5 commits into
magpie-community:mainfrom
Sam-dancing-nu1:add-gateway-hindsight

Conversation

@Sam-dancing-nu1

Copy link
Copy Markdown

中文

新增 Hindsight Memory 网关插件(@magpie-community/gateway-hindsight):为 Magpie 网关后的 Agent 在每次模型请求前自动召回 Hindsight 记忆并注入 system prompt,可选采集当前轮对话(默认关闭)。

要点:

  • 复用现有 Hindsight bank(默认 hermes),无需插件专用库;API 地址、bank、召回 token 预算、Agent 过滤均可配置。
  • 防重复注入:Hermes Agent 与 DeepSeek Harness 自带 Hindsight 自动注入,本插件默认跳过它们(即使 agents 为空),需要时可在白名单中强制开启。
  • 召回失败放行,不阻断模型请求;宿主 hook 超时可配(建议 5000ms)。
  • 与 Hindsight 官方 Agent Plugins 的区别:官方是 Agent 内显式工具调用,本插件是网关层自动注入,客户端零改动。

验证:

  • 单元测试 15/15 通过(Node 22);bun scripts/check.mjs 全仓通过。
  • 本地端到端:经 Magpie 网关请求,召回注入后模型答出了仅能从现有 bank 记忆得知的账号名;省略 capture 时无新增采集文档。

来源仓库(持续维护):https://github.com/Sam-dancing-nu1/magpie-hindsight

AI 参与声明:本项目在 AI 辅助下完成(Hermes Agent),包括实现、测试与文档。

English

Add Hindsight Memory (@magpie-community/gateway-hindsight): automatic Hindsight recall before each model request for agents behind Magpie, with optional capture of the completed turn (off by default).

  • Reuses an existing bank (default hermes); API URL, bank, recall budget and agent allow-list are configurable.
  • No double injection: Hermes Agent and DeepSeek Harness already inject Hindsight natively, so they are skipped by default even with an empty agents list; naming them force-enables.
  • Recall failures fail open without blocking the model request; host hook timeout is configurable (5000 ms recommended).
  • Unlike Hindsight's official agent-side explicit tools, this works at the gateway with zero client changes.

Verification: 15/15 unit tests pass (Node 22); bun scripts/check.mjs passes across the repo. Local end-to-end: the model answered with an account name knowable only from the recalled bank memory; with capture omitted, no documents were retained.

Source repository: https://github.com/Sam-dancing-nu1/magpie-hindsight

AI disclosure: built with AI assistance (Hermes Agent), including implementation, tests and documentation.

Automatic Hindsight recall before each request, optional capture (off by
default), reuses an existing bank, and skips agents with native Hindsight
injection by default to prevent double injection.

@yetone yetone left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

感谢贡献。代码是原创(Apache-2.0),只连接用户自己的 Hindsight 服务器,记忆捕获默认关闭,注入的文字也没有提到 magpie,这些都没问题。不过目前合并不了,原因如下:

  1. (阻塞)每个请求都会召回一次,并把结果插到 system prompt 前面。 工具循环里的每一步也都会召回,所以:

    • system 前缀每次都变,prompt cache 全部失效,长对话的费用会成倍增加;
    • 每个请求最多多等约 4.8 s(README 里也写了)。

    请参照仓库里已有的记忆 hook(packages/powercontext、packages/nowledge-mem):

    • 用 ctx.query 取查询,一轮对话只召回一次,工具循环中不再召回;
    • 召回块附加到该轮的 user 消息上,不要放进 system;
    • 同一轮的块用缓存保持不变(sticky),这样后续请求的前缀能命中缓存。
  2. README 中强制启用的示例 "agents":["Hermes Agent"] 不会生效。 ctx.agent 的值是 agent id,例如 hermes、dsh、claude,不是显示名。

  3. ctx.report 只接受这几个代码: ready、empty、unbound、unauthorized、unavailable、invalid、skipped。recalled、skipped-agent、captured 等会被宿主忽略,请改用上面列出的代码。

  4. README 的安装说明指向的是 github:Sam-dancing-nu1/magpie-hindsight 和 magpie-hindsight。 应改为本仓库的包名 @magpie-community/gateway-hindsight,在 magpie 的插件页安装。

  5. index.js 导出的 _internal 看起来只是给测试用的。 测试可以直接 import lib/*.mjs,建议不要把它放进公开入口。

我运行过的检查(在另一台 macOS 机器上,HOME 和 TMPDIR 都用了沙盒目录):

  • packages/hindsight 下运行 bun test:15 pass;
  • bun scripts/check.mjs hindsight:✓。

@yetone

yetone commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

Thanks. I read every changed line and ran the package's tests on a separate machine (bun 1.4.2, temp HOME, PR merged onto main f379bf9): bun test packages/hindsight 15 pass, 0 fail; bun scripts/check.mjs ok; the package's own scripts/check.mjs ok. The hook's design (fail-open recall, local origin only, capture off by default, the same config for recall and retain) is good. Needed before it can merge:

  1. Remove atomcode-state.json at the repository root. It's an AtomCode plugin state file, unrelated to this PR.
  2. Recall sends the user's latest message off the machine with no opt-in. On every eligible request, up to 8192 characters of the latest user message go to hindsight_api. With the default (127.0.0.1) that stays local, but configuration() accepts any http(s) host, including plain http:// to a remote one, with no authentication. A memory hook that sends conversation text off the machine needs its own explicit opt-in. Please follow PowerContext: a non-loopback hindsight_api is refused unless allowRemote: true is set, and a non-loopback http: also needs allowInsecureHttp: true. Test both paths, including that no fetch happens when the opt-in is missing.
  3. Disclosure. Say in the registry summary (en and zh) and the README's privacy section that recall sends the latest user message (up to 8 KB) to the configured Hindsight server on every request, and capture sends the user message and the answer. Right now the summary only mentions capture.
  4. Use ctx.query. The host gives hooks ctx.query, the user's text with client environment and instruction notices removed (docs: gateway request hooks). latestUserText takes the raw last user message, so Claude Code's <system-reminder> blocks and similar go to Hindsight as the recall query, and into memory when capture is on. Prefer ctx.query and fall back to your extraction only when it's empty.
  5. Agent names. ctx.agent is magpie's agent id (hermes, dsh, claude, codex…), never "Hermes Agent" or "DeepSeek Harness". So the README's force-enable example {"agents":["Hermes Agent"]} never matches. Use the ids in the README, the summary and NATIVE_MEMORY_AGENTS.
  6. README install/options commands point at github:Sam-dancing-nu1/magpie-hindsight and the name magpie-hindsight. Here the package is @magpie-community/gateway-hindsight: use magpie plugin add @magpie-community/gateway-hindsight and that name in magpie plugin options.
  7. Small: DEFAULTS.gatewayTimeoutMs is 1000 while the manifest ships 5000. Pick one. index.js (_internal) isn't needed for a hooks-only package here; drop it from the package unless magpie needs it.

- Recall once per user turn, attach to that user message (never system),
  replay the same block through the tool loop to keep prompt cache alive
- Prefer ctx.query (host-stripped) over raw user text
- Remote hindsight_api now requires allowRemote, and plain HTTP also
  requires allowInsecureHttp; fail closed with no fetch otherwise
- Report only host-recognized codes (ready/empty/skipped/unavailable/invalid)
- README: install via @magpie-community/gateway-hindsight, agent ids
  (hermes/dsh), privacy disclosure for recall and capture payloads
- registry summary documents the 8 KB recall payload and capture payload
- Remove atomcode-state.json and the test-only index.js export
- Unify gatewayTimeoutMs default to 5000
- Add GUI settings page (options form, connection test, status)
@Sam-dancing-nu1

Copy link
Copy Markdown
Author

中文

两轮的 7+5 条意见已逐项处理(3107658),并附上了设置页 GUI:

  1. 每轮只召回一次 + sticky:新增 lib/turns.mjs,按轮次 key 缓存;召回块附加到该轮 user 消息(不再进 system),工具循环重发原始历史时逐字重放同一注入,prompt cache 不再每步失效;同一轮绝不重复召回。
  2. 远程 opt-in:非 loopback 的 hindsight_api 必须 allowRemote: true,纯 HTTP 还需 allowInsecureHttp: true;未开启时 configuration 直接拒绝,onRequest 返回 undefined 且零 fetch(有测试覆盖两条路径)。
  3. 披露:registry summary 与 README 隐私节均写明 recall 每轮发送最新用户消息(≤8KB)到配置的服务器,capture 另发助手回答。
  4. ctx.query 优先:宿主剥离后的 query 优先,为空才回退到轮次原文(8192 截断)。
  5. Agent id:README 示例与默认跳过集合统一为 hermes / dsh,白名单示例改 claude/codex/opencode。
  6. 安装名:README 全部改为 magpie plugin add @magpie-community/gateway-hindsight 与同名 options。
  7. 杂项:atomcode-state.json 已移出 PR;index.js(_internal)已删除;DEFAULTS.gatewayTimeoutMs 与 manifest 统一为 5000;ctx.report 只用 ready/empty/skipped/unavailable/invalid。
  8. GUI:新增 page/ 设置页(8 项配置表单、连接测试、状态区),附 page.test.mjs。

验证:node --test 19/19 + page 5/5 通过;bun scripts/check.mjs 全仓通过。

English

All 12 points from both rounds are addressed in 3107658, plus a GUI settings page:

  1. Turn-scoped sticky recall via new lib/turns.mjs: one recall per user turn, block appended to that user message (never system), replayed byte-for-byte through tool loops, no repeated recall.
  2. Remote opt-in: non-loopback hindsight_api requires allowRemote, plain HTTP also allowInsecureHttp; otherwise configuration fails closed with zero fetch (tested both paths).
  3. Disclosure added to registry summary and README privacy sections (8 KB recall payload; capture also sends the answer).
  4. ctx.query preferred, raw turn text only as fallback.
  5. Agent ids (hermes/dsh) used throughout README and the skip set.
  6. Install/options commands now use @magpie-community/gateway-hindsight.
  7. atomcode-state.json removed, index.js/_internal dropped, timeout default unified to 5000, report codes limited to the host-recognized set.
  8. New page/ settings GUI (options form, connection test, status) with page.test.mjs.

Verification: 19/19 unit tests + 5/5 page tests pass; bun scripts/check.mjs passes across the repo.

@yetone yetone left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-reviewed at f3c9e53 (every changed line, GUI page included). Turn-sticky recall on the user message, ctx.query, the remote/plain-http opt-in and the disclosure are good, and the GUI page is clean (all dynamic text goes through textContent, the service page interpolates only its hex token, Host is checked, the probe only GETs /health on the gated URL). Still blocking:

  1. atomcode-state.json is still in the PR (repo root, +10). The reply says it was removed; it is in every commit including f3c9e53. Drop it.
  2. packages/hindsight/package.json:2 name is magpie-hindsight, while registry.json lists @magpie-community/gateway-hindsight. scripts/publish.sh publishes the package.json name, so merging would publish an unscoped magpie-hindsight and the registry entry would never resolve. Use "name": "@magpie-community/gateway-hindsight", and point repository / homepage / bugs (lines 8-15) at magpie-community/plugins with "directory": "packages/hindsight", as packages/powercontext and packages/nowledge-mem do. README:1/13/42 then say the same name.
  3. Capture is lost for every turn that uses a tool. lib/plugin.mjs:45-46 sets ctx.state.hindsight only on the request that recalls; the sticky/injected paths (34-41) return without it, so onResponse of the turn's last request (the one with finish_reason: "stop") has no state and retains nothing. Repro (chat, capture: true): request 1 = user message, reply tool_calls; request 2 = same user message + assistant tool call + tool result, reply stop "done" → only the recall call is made, no /memories POST. Set the turn's state (config + query) on every accepted request of the turn, and add this as a test.
  4. The origin guard has no test. Deleting if (ctx.origin !== "local") (lib/plugin.mjs:19) leaves all 24 tests green. Add a test that remote, gateway-key and a missing origin make no fetch.

Smaller, please fix in the same push:

  1. lib/protocol.mjs:19-68 (latestUserText, alreadyInjected, injectSystem) is no longer used by the hook; remove it and its tests. README:121 and :251 still say the tests cover "system-prompt adapters".
  2. page/service.mjs:71,94: json(result.code) drops bank and ms, so the test page always shows bank: hermes and — ms. Return them.
  3. page/settings.js:42-44 checks only the plain-http opt-in; a non-loopback https URL saves without allowRemote and the hook then reports invalid on every request. Mirror configuration() (require allowRemote for any non-loopback host).
  4. README:64 and :194 still describe the default skip as "Hermes Agent / DeepSeek Harness"; say hermes / dsh there. test/plugin.test.mjs:12 uses agent: "Claude Code"; use an id (claude).
  5. Nothing tests the injected(turn) path (lib/plugin.mjs:41); removing it is also green.

What I ran (macOS, bun 1.4.2, node 22.22.0, temp HOME/TMPDIR, PR head f3c9e53 on main b228cc6): bun test packages/hindsight 24 pass; bun scripts/check.mjs ok; package node --test 24 pass and scripts/check.mjs ok. Broken by hand: removing the allowRemote check, the allowInsecureHttp check, the per-turn cache lookup (double recall), the sticky replay on resent requests, history replay, the cache write and ctx.query preference each turn a test red. Removing the origin guard and the injected guard leave everything green (points 4 and 9). The tool-loop capture repro in point 3 was run against the unmodified PR code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants