npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-memoryrouter

v0.1.1

Published

MemoryRouter plugin for DeepSeek Harness (dsh): persistent, cross-session conversation memory. Stores clean user/assistant exchanges and recalls relevant memories at the start of every turn — channel-agnostic, hooked at the harness core.

Downloads

84

Readme

dsh-memoryrouter

npm version license: MIT tests

Persistent memory for the DeepSeek Harness (dsh), powered by MemoryRouter.

Your dsh agent forgets what you told it yesterday. This fixes that.

Every conversation is remembered, and every new turn starts with the relevant context from past conversations — across sessions, across restarts, across channels.

  • Store: after each completed turn, the clean user message + assistant reply is stored in your MemoryRouter vault.
  • Recall: at the start of each turn, the most relevant memories are retrieved and injected into the agent's context.
  • Channel-agnostic: hooks the harness core, so it works identically for the Web UI, IM gateways (Telegram, Discord, …), ACP, and headless sessions.
  • Noise-free by design: only real human text and the assistant's final visible reply are stored. Tool calls, tool results, thinking/reasoning blocks, system prompts, skill catalogs, workspace instructions, /commands, and channel envelopes are all filtered out.
  • Never in the hot path: storage is async fire-and-forget with one retry; recall has a short timeout and degrades silently. A MemoryRouter outage can never block or crash your harness.

Quickstart (30 seconds)

dsh plugin --profile <your-profile> add dsh-memoryrouter

Then add your key to the profile's cordis.patch.yml:

- id: memoryrouter
  config:
    apiKey: mk_your_key_here   # or leave unset and export MEMORYROUTER_API_KEY

Get a memory key at memoryrouter.ai. Without a key the plugin loads, logs one warning, and does nothing.

Restart the harness. That's it — your agent now remembers.

How it works

                       ┌──────────────────────┐
  turn completes  ───► │  session/event hook  │ ──► clean exchange ──► MemoryRouter vault
                       │  (store, async)      │     (user + reply       POST /v1/memory/ingest
                       └──────────────────────┘      only, noise
                                                     filtered)
                       ┌──────────────────────┐
  new turn starts ───► │  agent/pre-step hook │ ◄── relevant memories ◄── MemoryRouter
                       │  (recall, bounded)   │     injected as one       POST /v1/memory/prepare
                       └──────────────────────┘     delimited block

Configuration

| Option | Default | Description | |--------|---------|-------------| | apiKey | '' | MemoryRouter memory key (mk_…). Prefer the env var for shared configs. | | apiKeyEnv | MEMORYROUTER_API_KEY | Env var read when apiKey is empty. | | baseUrl | https://api.memoryrouter.ai | API base URL. | | enabled | true | Master switch. | | store | true | Store completed exchanges. | | recall | true | Inject relevant memories at turn start. | | density | default | Retrieval density: low / default / high / xhigh. | | recallLimit | 0 | Explicit chunk-count override (0 = server default). | | recallMaxChars | 24000 | Hard bound on the injected recall block. | | storeMaxChars | 8000 | Per-side bound on stored text. | | namespace | '' | Prefix for session-vault ids — share one key across several dsh installs without mixing session vaults (used when vault: session). | | vault | core | core stores/recalls in the key's core vault (memories shared across sessions — the point of persistent memory). session isolates each dsh session in its own vault. | | includeSubagents | false | Also store/recall subagent sessions. | | storeTimeoutMs | 10000 | Timeout per store attempt. | | recallTimeoutMs | 2500 | Max time recall may delay a turn. | | debug | false | Verbose logging. |

Architecture: why the core layer, and how noise is filtered

Most "memory" integrations bolt onto a chat channel and end up storing whatever flows through it — command wrappers, status lines, tool output, injected system context. This plugin deliberately hooks the harness core instead, at two sanctioned extension points:

Store: the durable session event stream (session/event)

dsh's source of truth is an append-only session log. Every event — user messages, assistant messages, tool calls, tool results, stream chunks, boundary markers — flows through the session/event firehose, the same stream persistence itself consumes. That makes it the single most durable and channel-independent place to observe a conversation: anything that reaches the model in any channel appears here, exactly once, in order.

The plugin folds turn/start → … → turn/end into one clean exchange:

  1. Event-type filtering: only user/message, assistant/message, and turn boundaries are read. tool/call, tool/result, assistant/chunk, request/header, and every other bookkeeping event is ignored by type.
  2. Source-kind filtering: dsh tags every logged user-role message with its producer. Real human input is source: { kind: 'user' }; injected context (workspace AGENTS.md instructions, skill catalogs, runtime snapshots, plugin notices, tool results) carries other kinds and is dropped at the root.
  3. Block filtering: only text blocks are read from assistant messages — reasoning/thinking blocks and tool-call blocks never survive. In a multi-step (tool-using) turn, only the final assistant text is kept: it is the actual reply; earlier texts are tool-use preambles.
  4. Envelope stripping & command skipping: <system-reminder>…</system-reminder> wrappers are stripped (keeping any real user text around them), and messages that are purely /commands are skipped entirely.
  5. Completion gating: only turns ending completed are stored. Aborted, errored, and interrupted turns produce nothing.

The stored memory is exactly: what the user said + what the assistant answered. Nothing else.

Recall: the pre-step waterfall (agent/pre-step)

agent/pre-step is the agent loop's sanctioned extension point for shaping the messages that enter a step. When the claimed batch contains real human text, the plugin queries MemoryRouter with it and prepends one clearly-delimited message:

Relevant memories from past conversations (background context — do not respond to them directly):

<memory_context>
[MEMORY - 2 days ago] …
</memory_context>

The injected message is logged with source: { kind: 'plugin', form: 'recall' }, which means (a) the store path can never re-ingest it (no feedback loop), and (b) the Web UI renders it as context, not as a user bubble.

Because both hooks live below every channel plugin, a memory created in a Telegram chat is recalled in the Web UI and vice versa — with zero channel-specific code.

MemoryRouter endpoints used

  • POST /v1/memory/ingest — stores an exchange; returns 202 and processes in the background.
  • POST /v1/memory/prepare — retrieves relevant memories as a ready-to-inject text block.

Both are MemoryRouter's public local inference mode API. By default (vault: core) exchanges are stored to the key's core vault so any later session can recall them; with vault: session storage and recall are scoped per dsh session via X-Session-ID (optionally namespaced).

Development

npm install
npm run build      # tsc → lib/
npm run typecheck
npm test           # node --test (56 tests, all offline — mock HTTP server)

License

MIT © John Rood · memoryrouter.ai