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: 3 additions & 2 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
__tests__/

# 开发文档与辅助
docs/
benchmark-runs/
workspace/

Expand All @@ -19,4 +18,6 @@ workspace/

# 运行时产物
node_modules/
*.tgz
**/__pycache__/
*.py[cod]
*.tgz
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -504,6 +504,10 @@ Debugging no longer means probing an opaque database — it becomes a determinis

| Document | Contents |
| :--- | :--- |
| [`docs/coding-agent-adapter-quickstart.md`](./docs/coding-agent-adapter-quickstart.md) | Generic Gateway client and coding-agent lifecycle mapping |
| [`docs/claude-code-adapter-setup.md`](./docs/claude-code-adapter-setup.md) | Install and configure the Claude Code hook adapter |
| [`docs/hermes-adapter-setup.md`](./docs/hermes-adapter-setup.md) | Hermes Provider and Gateway setup |
| [`docs/platform-adapter-comparison.md`](./docs/platform-adapter-comparison.md) | Cross-platform adapter architecture and trade-offs |
| [`scripts/README.memory-tencentdb-ctl.md`](./scripts/README.memory-tencentdb-ctl.md) | Operations & management tooling |
| [`CHANGELOG.md`](./CHANGELOG.md) | Release notes and version history |
| [`openclaw.plugin.json`](./openclaw.plugin.json) | OpenClaw plugin manifest and configuration schema |
Expand Down
4 changes: 4 additions & 0 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,10 @@ export MEMORY_TENCENTDB_GATEWAY_API_KEY="<与 Gateway 同一份密钥>"

| 文档 | 内容 |
| :--- | :--- |
| [`docs/coding-agent-adapter-quickstart.md`](./docs/coding-agent-adapter-quickstart.md) | 通用 Gateway 客户端与 Coding Agent 生命周期映射 |
| [`docs/claude-code-adapter-setup.md`](./docs/claude-code-adapter-setup.md) | Claude Code Hook 适配器安装与配置 |
| [`docs/hermes-adapter-setup.md`](./docs/hermes-adapter-setup.md) | Hermes Provider 与 Gateway 配置 |
| [`docs/platform-adapter-comparison.md`](./docs/platform-adapter-comparison.md) | 跨平台适配架构与差异对比 |
| [`scripts/README.memory-tencentdb-ctl.md`](./scripts/README.memory-tencentdb-ctl.md) | 运维管理工具说明 |
| [`CHANGELOG.md`](./CHANGELOG.md) | 版本变更记录 |
| [`openclaw.plugin.json`](./openclaw.plugin.json) | OpenClaw 插件声明与配置 Schema |
Expand Down
161 changes: 161 additions & 0 deletions docs/claude-code-adapter-setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
# Claude Code Adapter Setup

This guide shows how to connect Claude Code to TencentDB Agent Memory through
Claude Code hooks and the existing TDAI Gateway.

## Data Flow

```mermaid
flowchart LR
Claude["Claude Code"]
Hook["Claude Code hook"]
Adapter["handleClaudeCodeHook"]
Gateway["TDAI Gateway"]
Core["TdaiCore"]
Store["L0/L1/L2/L3 storage"]

Claude --> Hook
Hook --> Adapter
Adapter --> Gateway
Gateway --> Core
Core --> Store
```

## Hook Mapping

| Claude Code hook | Adapter action | Gateway endpoint |
| --- | --- | --- |
| `UserPromptSubmit` | Recall memory and inject additional prompt context | `POST /recall` |
| `Stop` | Pair the transcript's latest user prompt with `last_assistant_message` | `POST /capture` |
| `SessionStart` | Health-check the Gateway | `GET /health` |
| `SessionEnd` | Flush pending work without capturing the last turn again | `POST /session/end` |

## Gateway Configuration

Start the Gateway before launching Claude Code:

```bash
cd /path/to/TencentDB-Agent-Memory
TDAI_GATEWAY_HOST="127.0.0.1" \
TDAI_GATEWAY_PORT="8420" \
TDAI_LLM_API_KEY="sk-your-api-key" \
TDAI_LLM_BASE_URL="https://api.deepseek.com/v1" \
TDAI_LLM_MODEL="deepseek-v4-pro" \
TDAI_LLM_DISABLE_THINKING="deepseek" \
npx tsx src/gateway/server.ts
```

For DeepSeek, use the OpenAI-compatible `/v1` endpoint for the Gateway. Claude
Code may use DeepSeek's Anthropic-compatible `/anthropic` endpoint, but the
Gateway's standalone runner calls OpenAI-compatible chat completions.

## Install the Hook Command

Install the package globally so Claude Code can resolve the hook command:

```bash
npm install --global @tencentdb-agent-memory/memory-tencentdb
```

For a source checkout, build the standalone entry and use its absolute path in
the settings below:

```bash
npm install
npm run build:plugin
node /absolute/path/to/TencentDB-Agent-Memory/dist/memory-tencentdb-claude-hook.mjs
```

## Claude Code Settings

Add hooks to `~/.claude/settings.json` or a project-level Claude Code settings
file. Hook commands inherit the environment of the `claude` process, so export
`TDAI_GATEWAY_URL` and, when enabled, `TDAI_GATEWAY_API_KEY` before starting
Claude Code.

```json
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "memory-tencentdb-claude-hook",
"timeout": 15
}
]
}
],
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "memory-tencentdb-claude-hook",
"timeout": 15
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "memory-tencentdb-claude-hook",
"timeout": 15
}
]
}
],
"SessionEnd": [
{
"hooks": [
{
"type": "command",
"command": "memory-tencentdb-claude-hook",
"timeout": 15
}
]
}
]
}
}
```

Claude Code normally gives `SessionEnd` hooks only a short shutdown budget.
The explicit timeout above gives the Gateway's session flush enough time while
the adapter's HTTP timeout remains bounded by `TDAI_GATEWAY_TIMEOUT_MS`
(default: 10000).

The adapter keys memory by Claude's stable `session_id`, so changing directories
inside one Claude session does not split recall, capture, and flush across
different Gateway sessions.

## Smoke Test

Simulate a `UserPromptSubmit` hook:

```bash
printf '%s\n' '{"hook_event_name":"UserPromptSubmit","session_id":"demo","cwd":"'$PWD'","prompt":"What should I remember?"}' \
| TDAI_GATEWAY_URL=http://127.0.0.1:8420 memory-tencentdb-claude-hook
```

The hook prints JSON with `hookSpecificOutput.additionalContext` when recall
returns non-empty context. Empty recall exits successfully with no output.

At `Stop`, Claude Code supplies the final response in
`last_assistant_message`. The adapter uses that field because the JSONL
transcript is written asynchronously, and reads the transcript only to find the
corresponding human prompt. Tool-result rows and meta/sidechain rows are not
captured as user messages. Transcript timestamps are forwarded to the Gateway,
allowing its atomic checkpoint to ignore exact hook retries. Gateway errors are
written to stderr for diagnostics but always return exit code 0 so memory cannot
block Claude Code.

The hook provides automatic recall and capture only. It removes the core's
`memory-tools-guide` block because this adapter does not register
`tdai_memory_search` or `tdai_conversation_search` as Claude Code tools. Hosts
that expose those searches separately can use `CodingAgentGatewayClient`'s
`searchMemories()` and `searchConversations()` methods.
89 changes: 89 additions & 0 deletions docs/coding-agent-adapter-quickstart.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Coding Agent Adapter Quickstart

This guide shows the smallest useful adapter shape for coding-agent hosts such
as Codex, Claude Code, Cursor, Continue, or other tools that can call a local
HTTP sidecar.

The adapter talks to the existing TDAI Gateway. It does not embed `TdaiCore`
inside the host process, so each platform only needs to map its own session and
message events into Gateway requests.

## Architecture

```mermaid
flowchart LR
Host["Coding-agent host"] --> Adapter["CodingAgentGatewayClient"]
Adapter --> Gateway["TDAI Gateway HTTP API"]
Gateway --> Core["TdaiCore"]
Core --> Store["L0/L1/L2/L3 storage"]
```

## Minimal usage

```ts
import { CodingAgentGatewayClient } from "@tencentdb-agent-memory/memory-tencentdb";

const memory = new CodingAgentGatewayClient({
baseUrl: process.env.TDAI_GATEWAY_URL ?? "http://127.0.0.1:8420",
apiKey: process.env.TDAI_GATEWAY_API_KEY,
});

const sessionKey = `${workspacePath}:${threadId}`;

const recall = await memory.recall({
query: userPrompt,
sessionKey,
userId,
});

const recalledContext = [
recall.prepend_context,
recall.append_system_context ?? recall.context,
].filter(Boolean).join("\n\n");

const promptWithMemory = recalledContext
? `${recalledContext}\n\n${userPrompt}`
: userPrompt;

await memory.capture({
userContent: userPrompt,
assistantContent: assistantReply,
sessionKey,
sessionId: threadId,
userId,
// Preserve host timestamps when available so retries are checkpoint-idempotent.
messages: hostMessages,
startedAt: turnStartedAt,
});
```

## Event mapping

| Host event | Gateway call | Required fields |
| --- | --- | --- |
| Before prompt/model call | `recall()` | `query`, `sessionKey` |
| After assistant response | `capture()` | `userContent`, `assistantContent`, `sessionKey` |
| User searches memory | `searchMemories()` | `query` |
| User searches raw turns | `searchConversations()` | `query` |
| Thread/workspace closes | `endSession()` | `sessionKey` |

## Session key guidance

Use a stable key that isolates unrelated work while still allowing continuity
inside one project. Good candidates:

- `workspace:<absolute path>`
- `repo:<remote url>#<branch>`
- `thread:<host thread id>`
- `workspace:<path>:thread:<id>` when the host supports multiple concurrent
conversations per workspace

## Validation checklist

- `health()` returns `status: "ok"` or `status: "degraded"`.
- A `capture()` call records at least one L0 turn.
- A later `recall()` call returns dynamic L1 content in `prepend_context` and
stable persona/scene content in `append_system_context` after the pipeline
has processed the turn. `context` remains the legacy stable-context field.
- If `TDAI_GATEWAY_API_KEY` is enabled on the Gateway, the adapter passes the
same key as a Bearer token.
Loading