Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/test-integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
filters: |
adk:
- 'integrations/adk/typescript/**'
deepseek-harness:
- 'integrations/deepseek-harness/typescript/**'
mastra:
- 'integrations/mastra/typescript/**'
vercel-ai:
Expand Down Expand Up @@ -93,6 +95,9 @@ jobs:
matrix:
package: ${{ fromJSON(needs.detect-changes.outputs.typescript) }}
node-version: ["20", "22"]
exclude:
- package: deepseek-harness
node-version: "20"
steps:
- uses: actions/checkout@v4
- name: Test TypeScript integration
Expand Down
1 change: 1 addition & 0 deletions integrations/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ Current packages:
| `ag2/python` | `zep-ag2` (PyPI) | `zep_ag2` |
| `autogen/python` | `zep-autogen` (PyPI) | `zep_autogen` |
| `crewai/python` | `zep-crewai` (PyPI) | `zep_crewai` |
| `deepseek-harness/typescript` | `@getzep/zep-deepseek-harness` (npm) | `@getzep/zep-deepseek-harness` |
| `langgraph/python` | `zep-langgraph` (PyPI) | `zep_langgraph` |
| `livekit/python` | `zep-livekit` (PyPI) | `zep_livekit` |
| `mastra/typescript` | `@getzep/zep-mastra` (npm) | `@getzep/zep-mastra` |
Expand Down
1 change: 1 addition & 0 deletions integrations/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ New to Zep? Sign up at [getzep.com](https://www.getzep.com) and create an API ke
|-----------|----------|---------|----------|
| AG2 | Python | `zep-ag2` | [`ag2/python/`](ag2/python/) |
| CrewAI | Python | [`zep-crewai`](https://pypi.org/p/zep-crewai) | [`crewai/python/`](crewai/python/) |
| DeepSeek Harness | TypeScript | `@getzep/zep-deepseek-harness` | [`deepseek-harness/typescript/`](deepseek-harness/typescript/) |
| Google ADK | Python | [`zep-adk`](https://pypi.org/p/zep-adk) | [`adk/python/`](adk/python/) |
| Google ADK | TypeScript | `@getzep/zep-adk` | [`adk/typescript/`](adk/typescript/) |
| Google ADK | Go | `github.com/getzep/zep/integrations/adk/go` | [`adk/go/`](adk/go/) |
Expand Down
15 changes: 15 additions & 0 deletions integrations/deepseek-harness/typescript/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

## 0.1.0 (2026-08-13)

### Added

- DeepSeek Harness Cordis plugin and installable bundle.
- Context Block recall through `agent/pre-step`, recorded as durable
source-attributed context.
- Completed-turn persistence through `session/event`, excluding injected
context, tool results, and intermediate assistant tool-call preambles.
- Lazy user/thread provisioning, per-session thread derivation, configurable
identity and context formatting, duplicate-write protection, and fail-open
Zep error handling.
- Programmatic `ZepMemoryRuntime` and `installZepMemory` APIs.
148 changes: 148 additions & 0 deletions integrations/deepseek-harness/typescript/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Zep Memory for DeepSeek Harness

`@getzep/zep-deepseek-harness` adds durable long-term memory to
[DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness).

It uses the Harness's native lifecycle:

- `agent/pre-step` retrieves the user's Zep Context Block on each genuine user
turn and adds it as a source-attributed, durable `user/message`.
- `session/event` persists direct user input and the final assistant response
after a successful `turn/end`.
- Zep user and thread resources are provisioned lazily and idempotently.
- Zep errors fail open: they are logged without conversation content and never
stop the agent loop.

The injected Context Block is intentionally logged. DeepSeek Harness requires
all model-visible input to be reconstructable from the session log; modifying a
model request directly would violate that invariant.

## Install

DeepSeek Harness plugins are installed into a profile:

```bash
dsh plugin --profile headless add @getzep/zep-deepseek-harness
```

Set the values read by the bundled patch:

```bash
export ZEP_API_KEY="your-zep-api-key"
export ZEP_USER_ID="stable-user-id"
```

The bundle adds this row:

```yaml
- insert:
- id: zep-memory
name: '@getzep/zep-deepseek-harness'
config:
apiKey: !!js process.env.ZEP_API_KEY
userId: !!js process.env.ZEP_USER_ID
```

See [SETUP.md](SETUP.md) for the complete setup.

## Behavior

### Recall

Recall happens once at the start of a genuine user turn. Tool-loop steps and
plugin-generated context do not trigger additional retrieval. The plugin calls
`thread.getUserContext`, formats the Context Block, and appends it to the
downstream pre-step decision with this source:

```ts
{
kind: "plugin",
plugin: "zep-memory",
form: "snapshot"
}
```

This keeps memory visible to the model, session replay, compaction, and UI
consumers without pretending that it was human input.

### Persistence

On a completed or max-token turn, the plugin sends one batch to
`thread.addMessages` containing:

1. Direct human messages from the turn.
2. The final assistant text from the turn.

Injected contexts, tool results, reasoning blocks, and intermediate tool-call
preambles are excluded. Duplicate `turn/end` notifications for the same live
session do not cause duplicate writes.

Zep graph ingestion is asynchronous. Memory written in one turn may not be
available immediately in the next turn.

## Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `apiKey` | `string` | required | Zep Cloud API key. |
| `userId` | `string` | required | Stable Zep user id. |
| `threadId` | `string` | Harness session id | Fixed thread id. Use only when this plugin instance serves one session. |
| `threadIdPrefix` | `string` | `""` | Prefix for session-derived thread ids. |
| `firstName` | `string` | — | User identity metadata. |
| `lastName` | `string` | — | User identity metadata. |
| `email` | `string` | — | User identity metadata. |
| `userMessageName` | `string` | — | Name on persisted user messages. |
| `assistantMessageName` | `string` | `"Assistant"` | Name on persisted assistant messages. |
| `contextTemplate` | `string` | `Relevant long-term memory from Zep:\n\n{context}` | Injected context wrapper; must contain `{context}` exactly once. |
| `contextTemplateId` | `string` | — | Custom Zep Context Block template id. |
| `recall` | `boolean` | `true` | Enable Context Block retrieval. |
| `persist` | `boolean` | `true` | Enable completed-turn persistence. |

By default, every Harness session gets a separate Zep thread under the same
user graph. This preserves conversational relevance while allowing recall from
the user's whole graph. Set `threadId` only for a deployment that deliberately
maps the plugin to one conversation.

## Programmatic use

When another plugin already owns a shared `ZepClient`, install the listeners
without creating another client:

```ts
import { ZepClient } from "@getzep/zep-cloud";
import {
ZepMemoryRuntime,
installZepMemory,
} from "@getzep/zep-deepseek-harness";

const runtime = new ZepMemoryRuntime({
client: new ZepClient({ apiKey: process.env.ZEP_API_KEY! }),
userId: "user-123",
firstName: "Ada",
lastName: "Lovelace",
});

installZepMemory(ctx, runtime);
```

The caller owns the supplied client. Listener registrations and pending-write
drain are attached to the Cordis plugin lifecycle.

## Development

```bash
npm install
npm run lint
npm run typecheck
npm test
npm run build
```

## Compatibility

- DeepSeek Harness `0.1.0-rc.6`
- Zep Cloud JavaScript SDK `3.28.0`
- Node.js `^22.19.0 || >=24`

DeepSeek Harness is in developer preview and may make breaking plugin API
changes. This package pins its tested release-candidate range accordingly.
75 changes: 75 additions & 0 deletions integrations/deepseek-harness/typescript/SETUP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
# Setup

## 1. Create a Zep account and API key

1. Sign up at [getzep.com](https://www.getzep.com).
2. Open the [Zep dashboard](https://app.getzep.com).
3. Create or select a project and create an API key.

## 2. Install the plugin

Install the package into the DeepSeek Harness profile that should use memory:

```bash
dsh plugin --profile headless add @getzep/zep-deepseek-harness
```

Replace `headless` with `web` or another profile name as needed. The package
contains a Harness bundle, so installation activates its `zep-memory` Cordis
row automatically.

## 3. Configure identity

The bundled row reads:

```bash
export ZEP_API_KEY="your-zep-api-key"
export ZEP_USER_ID="stable-id-for-the-human-user"
```

Use a stable application user id, not a random id per process. For stronger
identity resolution, update the profile's `cordis.patch.yml` row:

```yaml
- id: zep-memory
name: '@getzep/zep-deepseek-harness'
config:
apiKey: !!js process.env.ZEP_API_KEY
userId: !!js process.env.ZEP_USER_ID
firstName: Ada
lastName: Lovelace
email: ada@example.com
threadIdPrefix: dsh-
```

Do not commit an API key to YAML. `!!js process.env.ZEP_API_KEY` resolves it
from the process environment when the plugin loads.

By default, the Harness session id becomes the Zep thread id. Every session
therefore gets its own thread while sharing the user's graph. Set a fixed
`threadId` only when one plugin instance is intentionally scoped to one
conversation.

## 4. Run Harness

```bash
dsh --profile headless "Remember that I prefer aisle seats."
```

After Zep has ingested the turn, start or continue a session for the same
`ZEP_USER_ID` and ask what the agent remembers. Zep ingestion is asynchronous,
so a just-written fact may not be available immediately.

## 5. Verify the package

From this integration directory:

```bash
npm install
npm run lint
npm run typecheck
npm test
npm run build
```

The tests use a mocked Zep client and require no credentials.
6 changes: 6 additions & 0 deletions integrations/deepseek-harness/typescript/cordis.patch.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- insert:
- id: zep-memory
name: '@getzep/zep-deepseek-harness'
config:
apiKey: !!js process.env.ZEP_API_KEY
userId: !!js process.env.ZEP_USER_ID
9 changes: 9 additions & 0 deletions integrations/deepseek-harness/typescript/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// @ts-check
import eslint from "@eslint/js";
import tseslint from "typescript-eslint";

export default tseslint.config(
{ ignores: ["dist/**", "node_modules/**"] },
eslint.configs.recommended,
...tseslint.configs.recommended,
);
9 changes: 9 additions & 0 deletions integrations/deepseek-harness/typescript/examples/cordis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
- insert:
- id: zep-memory
name: '@getzep/zep-deepseek-harness'
config:
apiKey: !!js process.env.ZEP_API_KEY
userId: !!js process.env.ZEP_USER_ID
firstName: Ada
lastName: Lovelace
threadIdPrefix: dsh-
Loading
Loading