# Agent tools

> tdai_memory_search and tdai_conversation_search (OpenClaw) plus Hermes memory_tencentdb_* tool schemas: parameters, hybrid/embedding/keyword strategies, combined 3-call-per-turn limit, and response shapes.

- Repository: TencentCloud/TencentDB-Agent-Memory
- GitHub: https://github.com/TencentCloud/TencentDB-Agent-Memory
- Human docs: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a
- Complete Markdown: https://grok-wiki.com/public/docs/tencentcloud-tencentdb-agent-memory-5a33bbf5540a/llms-full.txt

## Source Files

- `index.ts`
- `src/core/tools/memory-search.ts`
- `src/core/tools/conversation-search.ts`
- `openclaw.plugin.json`
- `hermes-plugin/memory/memory_tencentdb/__init__.py`
- `src/gateway/types.ts`

---

---
title: "Agent tools"
description: "tdai_memory_search and tdai_conversation_search (OpenClaw) plus Hermes memory_tencentdb_* tool schemas: parameters, hybrid/embedding/keyword strategies, combined 3-call-per-turn limit, and response shapes."
---

OpenClaw registers **`tdai_memory_search`** (L1) and **`tdai_conversation_search`** (L0) via `api.registerTool()`. Hermes exposes the same Gateway-backed search under **`memory_tencentdb_memory_search`** and **`memory_tencentdb_conversation_search`**. Both hosts call `TdaiCore.searchMemories` / `searchConversations`, which run hybrid FTS + embedding search with automatic degradation and Reciprocal Rank Fusion (RRF).

## Host surfaces

| Host | L1 tool | L0 tool | How results return |
|------|---------|---------|-------------------|
| OpenClaw plugin | `tdai_memory_search` | `tdai_conversation_search` | Tool `content[].text` (markdown-ish lines) + `details` |
| Hermes `memory_tencentdb` | `memory_tencentdb_memory_search` | `memory_tencentdb_conversation_search` | JSON string from `handle_tool_call` (Gateway body) |
| Gateway HTTP | `POST /search/memories` | `POST /search/conversations` | JSON `{ results, total, strategy? }` |

`openclaw.plugin.json` declares `contracts.tools`: `["tdai_memory_search", "tdai_conversation_search"]`.

Hermes does **not** serve the `tdai_*` names. Older transcripts that call `tdai_memory_search` through Hermes get `{"error":"Unknown tool: …"}`.

```text
OpenClaw agent                  Hermes agent
     │                               │
     ├─ tdai_memory_search           ├─ memory_tencentdb_memory_search
     └─ tdai_conversation_search     └─ memory_tencentdb_conversation_search
              │                               │
              ▼                               ▼
         TdaiCore (in-process)         HTTP client → Gateway
              │                               │
              └──────────► executeMemorySearch / executeConversationSearch
```

## Registration and availability

### OpenClaw

Tools register only when **`recall.enabled` or `capture.enabled`** is true. If both are false, neither tool is registered.

### Hermes

`get_tool_schemas()` returns both schemas when:

- the provider is initialized / Gateway is available, or
- `MEMORY_TENCENTDB_GATEWAY_CMD` or `MEMORY_TENCENTDB_GATEWAY_PORT` is set (pre-init optimistic registration so routing works before `initialize()` finishes).

Otherwise it returns `[]`.

Tool execution goes through `MemoryTencentdbSdkClient` → `POST /search/memories` or `POST /search/conversations` (default base `http://127.0.0.1:8420`).

## Combined 3-call-per-turn limit

OpenClaw soft-limits the two tools **together** to **3 calls per turn**:

1. **Tool descriptions** — both tools include: *“Limit: tdai_memory_search and tdai_conversation_search share a combined limit of 3 calls per turn. Stop searching after 3 total attempts.”*
2. **Auto-recall guide** — when recall injects context, `<memory-tools-guide>` tells the model the same combined cap: first miss may retry with different keywords/tools; after 3 total attempts, stop and answer from what is already known.

There is **no hard enforcer** in `execute` yet. Registration comments mark a planned `before_tool_call` + early-return hard limit as TODO. Enforcement today is prompt-only.

Hermes tool descriptions and `system_prompt_block()` name the tools and purpose but **do not** encode the 3-call combined limit.

## Search strategies

Agent tools do **not** take a `strategy` argument. Strategy is chosen from runtime capability and which path returns hits:

| Reported `strategy` | When |
|---------------------|------|
| `hybrid` | FTS and embedding both return ≥1 candidate; lists merged with RRF (`k = 60`) |
| `embedding` | Only vector path has hits (or both empty and embedding is configured) |
| `fts` | Only FTS/keyword path has hits |
| `none` | Empty query, missing store, or neither embedding nor FTS available |

Behavior notes:

- FTS and embedding run **in parallel**.
- Over-fetch: `candidateK = limit * 3` (conversation search with `session_key` uses `limit * 4` before filter).
- Secondary filters (`type`, `scene`, `session_key`) apply **after** merge, then results are trimmed to `limit`.
- Single-path failure is non-fatal; the other path can still succeed.
- If neither embedding nor FTS is available, tools return empty results with a `message` asking for an embedding provider (e.g. `embedding.provider = openai_compatible`) or FTS support.

This is separate from **auto-recall** `recall.strategy` (`hybrid` / `embedding` / `keyword` in config). Tool code reports keyword-only path as `fts`, not `keyword`.

## `tdai_memory_search` / `memory_tencentdb_memory_search`

Searches **L1** structured long-term memories (preferences, events, instructions).

### Parameters

| Parameter | Type | Required | Default / bounds | OpenClaw | Hermes schema |
|-----------|------|----------|------------------|----------|---------------|
| `query` | string | yes | — | yes | yes |
| `limit` | number / integer | no | default `5`, clamp `[1, 20]` | yes | yes |
| `type` | string enum | no | — | `persona` \| `episodic` \| `instruction` | same |
| `scene` | string | no | substring match on `scene_name` (case-insensitive) | yes | **not in schema** (Gateway/client support `scene`; Hermes tool path does not pass it) |

OpenClaw clamps with `Math.min(Math.max(Number(params.limit) || 5, 1), 20)`. Hermes uses `_coerce_limit`: accepts int/float/numeric strings, rejects bool, clamps `[1, 20]`, falls back to `5` on garbage.

### Internal result items

| Field | Meaning |
|-------|---------|
| `id` | L1 `record_id` |
| `content` | Memory text |
| `type` | Memory type |
| `priority` | Priority; `< 0` treated as global instruction in formatter |
| `scene_name` | Scene association |
| `score` | Native score, or RRF score when `hybrid` |
| `created_at` / `updated_at` | Mapped from `timestamp_start` / `timestamp_end` |

### Formatted text (OpenClaw + Gateway `results`)

```text
Found N matching memories:

- **[type]** (priority: P) [scene: name] (score: 0.123)
  <content>
```

Empty: `No matching memories found.`  
Config/capability failure may return the embedding/FTS configuration message instead.

### OpenClaw tool return

```json
{
  "content": [{ "type": "text", "text": "<formatted string>" }],
  "details": { "count": 3, "strategy": "hybrid" }
}
```

On exception: text `Memory search failed: …`, `details: { error }`.

### Hermes tool return

JSON-serialized Gateway body, typically:

```json
{
  "results": "<formatted string>",
  "total": 3,
  "strategy": "hybrid"
}
```

Errors: missing `query`, Gateway disconnected, circuit breaker open, or `Tool call failed: …` as `{"error":"…"}`.

## `tdai_conversation_search` / `memory_tencentdb_conversation_search`

Searches **L0** raw conversation messages when structured L1 is insufficient (exact wording, timeline, dialogue context).

### Parameters

| Parameter | Type | Required | Default / bounds | OpenClaw | Hermes schema |
|-----------|------|----------|------------------|----------|---------------|
| `query` | string | yes | — | yes | yes |
| `limit` | number / integer | no | default `5`, clamp `[1, 20]` | yes | yes |
| `session_key` | string | no | exact match on `session_key` after merge | yes | **not in schema** (Gateway/client support it; Hermes tool path does not pass it) |

### Internal result items

| Field | Meaning |
|-------|---------|
| `id` | L0 `record_id` |
| `session_key` | Session id |
| `role` | `user` or `assistant` |
| `content` | Single message text (`message_text`) |
| `score` | Native or RRF score |
| `recorded_at` | Timestamp |

### Formatted text

```text
Found N matching message(s):

---
**[role]** Session: <session_key> [recorded_at] (score: 0.123)

<message content>
```

Empty: `No matching conversation messages found.`

### OpenClaw tool return

```json
{
  "content": [{ "type": "text", "text": "<formatted string>" }],
  "details": { "count": 2 }
}
```

Note: conversation tool `details` does **not** include `strategy` (unlike memory search). Failures use text `Conversation search failed: …`.

### Hermes / Gateway response

```json
{
  "results": "<formatted string>",
  "total": 2
}
```

Gateway conversation search response type has no `strategy` field (memory search does).

## Gateway HTTP bridge

Agent tools and HTTP share the same core methods.

:::endpoint POST /search/memories L1 memory search
**Body**

- `query` (string, required)
- `limit` (number, optional)
- `type` (string, optional)
- `scene` (string, optional)

**200 response**

- `results` (string) — formatted text from `formatSearchResponse`
- `total` (number)
- `strategy` (string)

**400** — missing `query` → `{ "error": "Missing required field: query" }`
:::

:::endpoint POST /search/conversations L0 conversation search
**Body**

- `query` (string, required)
- `limit` (number, optional)
- `session_key` (string, optional)

**200 response**

- `results` (string) — formatted text from `formatConversationSearchResponse`
- `total` (number)

**400** — missing `query`
:::

Auth and CORS follow Gateway config (`TDAI_GATEWAY_API_KEY`, etc.). Hermes attaches `Authorization: Bearer …` when `MEMORY_TENCENTDB_GATEWAY_API_KEY` (or fallback) is set.

## Limit and type coercion

| Rule | OpenClaw | Hermes |
|------|----------|--------|
| Default `limit` | `5` | `5` (`_DEFAULT_SEARCH_LIMIT`) |
| Max `limit` | `20` | `20` (`_MAX_SEARCH_LIMIT`) |
| Min `limit` | `1` | `1` |
| Non-numeric / bool `limit` | `Number(...) \|\| 5` then clamp | warn + default `5` (bool rejected) |

Missing required `query`:

- OpenClaw: empty string → empty result set (`strategy: "none"`).
- Hermes: explicit `{"error":"Missing required parameter: query"}`.

## Failure modes

| Condition | Behavior |
|-----------|----------|
| Both recall and capture disabled (OpenClaw) | Tools not registered |
| Vector store missing | Empty results, `strategy: "none"` |
| No embedding and no FTS | Empty + configuration `message` |
| Embedding or FTS throws mid-search | That path empty; other path may still win |
| Hermes Gateway down / not connected | JSON error + hint; recovery may run in background |
| Hermes circuit breaker open | `{"error":"… circuit breaker open."}` |
| OpenClaw execute exception | Soft fail text to the model; metrics report `success: false` |

## When to use which tool

| Need | Tool |
|------|------|
| Preferences, rules, structured facts (L1) | Memory search |
| Exact past wording, raw turns, timeline (L0) | Conversation search |
| Full scene dossier after navigation paths appear | Host `read_file` on scene paths (OpenClaw guide), not these search tools |

Auto-recall already injects a short L1 slice plus persona/scene navigation when enabled; tools are for **on-demand drill-down** when that slice is not enough. Truncated recall lines point agents at `tdai_memory_search` / `tdai_conversation_search`.

## Related pages

<CardGroup>
  <Card title="Gateway HTTP API" href="/gateway-http-api">
    Full route list including `/search/memories` and `/search/conversations` request and error envelopes.
  </Card>
  <Card title="Memory layers" href="/memory-layers">
    L0 conversation vs L1 atom layers that these tools query.
  </Card>
  <Card title="Storage backends" href="/storage-backends">
    FTS5, embeddings, BM25, and hybrid RRF used by the search engines.
  </Card>
  <Card title="Configure embedding" href="/configure-embedding">
    Embedding provider setup and keyword-only degradation when provider is `none`.
  </Card>
  <Card title="TdaiCore and host adapters" href="/tdai-core-adapters">
    How OpenClaw tools and Gateway handlers share `TdaiCore.searchMemories` / `searchConversations`.
  </Card>
  <Card title="Hermes setup" href="/hermes-setup">
    Install `memory_tencentdb` and verify Gateway tool routing.
  </Card>
</CardGroup>
