@hydradb/mcp 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +167 -0
- package/README.md +92 -34
- package/dist/adapters.d.ts +27 -16
- package/dist/adapters.js +58 -54
- package/dist/adapters.js.map +1 -1
- package/dist/config.d.ts +2 -0
- package/dist/config.js +27 -1
- package/dist/config.js.map +1 -1
- package/dist/context.d.ts +43 -3
- package/dist/context.js +374 -34
- package/dist/context.js.map +1 -1
- package/dist/descriptions.d.ts +57 -28
- package/dist/descriptions.js +203 -49
- package/dist/descriptions.js.map +1 -1
- package/dist/hydra/client.d.ts +69 -8
- package/dist/hydra/client.js +102 -20
- package/dist/hydra/client.js.map +1 -1
- package/dist/hydra/errors.js +91 -6
- package/dist/hydra/errors.js.map +1 -1
- package/dist/hydra/index.d.ts +2 -2
- package/dist/hydra/index.js +1 -1
- package/dist/hydra/index.js.map +1 -1
- package/dist/index.js +97 -10
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +18 -1
- package/dist/server.js +998 -106
- package/dist/server.js.map +1 -1
- package/dist/tool-names.d.ts +2 -1
- package/dist/tool-names.js +2 -0
- package/dist/tool-names.js.map +1 -1
- package/dist/types.d.ts +8 -51
- package/dist/types.js +6 -5
- package/dist/types.js.map +1 -1
- package/package.json +11 -6
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.2.0] - 2026-08-14
|
|
9
|
+
|
|
10
|
+
### ⚠️ Migration required if you call the old tool names
|
|
11
|
+
|
|
12
|
+
The seven deprecated `hydra_db_*` tool aliases are **no longer registered by
|
|
13
|
+
default**. If your `mcp.json` still calls them, add one environment variable:
|
|
14
|
+
|
|
15
|
+
```json
|
|
16
|
+
"env": { "HYDRADB_MCP_LEGACY_TOOLS": "1" }
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Everything else in this release is backward compatible. This is called out first
|
|
20
|
+
because a minor version bump under-signals it: the change is breaking for anyone
|
|
21
|
+
who has not migrated to the canonical names.
|
|
22
|
+
|
|
23
|
+
The reason is not only the ~3,500 tokens per conversation the alias manifest
|
|
24
|
+
costs (44% of it). The alias names are systematically better literal matches for
|
|
25
|
+
how users phrase requests than the canonical names — "search my memory" matches
|
|
26
|
+
`hydra_db_search` exactly while `hydradb_query` needs a synonym step — and
|
|
27
|
+
picking one costs real capability, since `hydra_db_ingest_conversation` cannot
|
|
28
|
+
set `kind`, `overwrite`, `title`, `infer` or `is_markdown`.
|
|
29
|
+
|
|
30
|
+
Migration table:
|
|
31
|
+
|
|
32
|
+
| Deprecated | Use instead |
|
|
33
|
+
|---|---|
|
|
34
|
+
| `hydra_db_search` | `hydradb_query` |
|
|
35
|
+
| `hydra_db_store`, `hydra_db_ingest_conversation` | `hydradb_ingest` |
|
|
36
|
+
| `hydra_db_list_memories`, `hydra_db_list_sources` | `hydradb_list` |
|
|
37
|
+
| `hydra_db_fetch_content` | `hydradb_inspect` |
|
|
38
|
+
| `hydra_db_delete_memory` | `hydradb_delete` |
|
|
39
|
+
|
|
40
|
+
### Other breaking changes
|
|
41
|
+
|
|
42
|
+
- `kind` is now **required** on `hydradb_list`. It previously defaulted to
|
|
43
|
+
`memory`, so `hydradb_list({})` returned memories only and read as the complete
|
|
44
|
+
inventory — a caller asking "what does Hydra DB have?" never saw the knowledge
|
|
45
|
+
corpus that `hydradb_query` searches by default.
|
|
46
|
+
- `hydradb_query` now returns a single context block instead of a summary
|
|
47
|
+
followed by full context. Every chunk body was previously sent twice.
|
|
48
|
+
- `hydradb_query` defaults to `detail: "compact"`, which trims each chunk body to
|
|
49
|
+
~600 characters and omits surrounding-context blocks. Pass `detail: "full"` for
|
|
50
|
+
the previous rendering.
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- **`hydradb_status`** — check whether ingested sources have finished indexing.
|
|
55
|
+
Ingestion is asynchronous, so a query issued immediately after a save can
|
|
56
|
+
legitimately return nothing; this distinguishes "still indexing" from "the save
|
|
57
|
+
failed".
|
|
58
|
+
- **Pagination** on `hydradb_list` (`page`, `page_size`), with the response
|
|
59
|
+
stating how much of the corpus it covered.
|
|
60
|
+
- **`kind` on `hydradb_ingest`** — knowledge can now be created, not just
|
|
61
|
+
searched, listed, inspected and deleted.
|
|
62
|
+
- **Bulk delete** — `hydradb_delete` accepts `ids`, reporting partial removals
|
|
63
|
+
as partial.
|
|
64
|
+
- **New query parameters**: `source_ids` (search inside specific documents),
|
|
65
|
+
`metadata_filters`, `num_related_chunks`, `operator`, `mode: "auto"`,
|
|
66
|
+
`detail`.
|
|
67
|
+
- **New ingest parameters**: `metadata`, `observation_date`, `overwrite`.
|
|
68
|
+
- **`offset`/`limit`/`expiry_seconds`** on `hydradb_inspect`.
|
|
69
|
+
- **`structuredContent`** on `hydradb_list`, `hydradb_ingest` and
|
|
70
|
+
`hydradb_delete`, alongside the existing text.
|
|
71
|
+
- **Lifecycle handling** — SIGINT/SIGTERM drain in-flight tool calls before
|
|
72
|
+
closing; unhandled rejections and uncaught exceptions are logged and exit
|
|
73
|
+
non-zero.
|
|
74
|
+
- **New environment variables**: `HYDRADB_TIMEOUT_SECONDS` (default 30),
|
|
75
|
+
`HYDRADB_MAX_RETRIES` (default 2), `HYDRADB_MCP_LEGACY_TOOLS` (default off).
|
|
76
|
+
|
|
77
|
+
### Fixed
|
|
78
|
+
|
|
79
|
+
Most of these returned a success-shaped result while losing or inventing data,
|
|
80
|
+
so neither the caller nor the user learned anything had gone wrong.
|
|
81
|
+
|
|
82
|
+
- **Nothing ever emitted an ID.** Query results carried no value that
|
|
83
|
+
`hydradb_inspect` or `hydradb_delete` would accept, and ingest returned a
|
|
84
|
+
preview of the caller's own text instead of the id the server assigned. Recall
|
|
85
|
+
and follow-up could not compose, and correcting a stored memory was
|
|
86
|
+
unreachable in both directions.
|
|
87
|
+
- **A delete that removed nothing reported "not found or already deleted"** — a
|
|
88
|
+
cause never observed, and the reassuring one. A caller that guessed an id read
|
|
89
|
+
it as confirmation that the user's data was gone.
|
|
90
|
+
- **The memory listing presented page one as the entire store.** With 4,000
|
|
91
|
+
memories stored, it answered "50 memories:" and page 2 was unreachable through
|
|
92
|
+
the MCP entirely. The source listing printed the corpus-wide total above a
|
|
93
|
+
single page.
|
|
94
|
+
- **Per-item ingest failures were discarded.** The server reports which item
|
|
95
|
+
failed and why; the tool reported bare counts, so the only recovery was to
|
|
96
|
+
re-ingest everything — which, since a reused `source_id` replaces, could
|
|
97
|
+
destroy the item that had succeeded.
|
|
98
|
+
- **Generated conversation ids collided.** `mcp-conversation-${Date.now()}` has
|
|
99
|
+
millisecond resolution, and with `upsert` hardcoded on, a collision silently
|
|
100
|
+
replaced the earlier conversation and reported success.
|
|
101
|
+
- **`hydradb_list` ignored `source_ids` for memories** — accepted, validated, and
|
|
102
|
+
dropped in silence.
|
|
103
|
+
- **Raw JSON envelopes reached the prompt.** When ingest stored the serialised
|
|
104
|
+
source record, the renderer emitted ids and tenant identifiers where the
|
|
105
|
+
content should have been.
|
|
106
|
+
- **Graph relations went missing.** `source_chunk_ids` — the primary
|
|
107
|
+
chunk-to-relation mapping — was dropped by the response adapter, so relations
|
|
108
|
+
linked only that way were never rendered.
|
|
109
|
+
- **`mode: "url"` could not work.** `presignedUrl` was never read, so the one
|
|
110
|
+
mode whose purpose is a download link returned "(no text content)".
|
|
111
|
+
- **`hydradb_inspect` could end a session.** Binary content was inlined as
|
|
112
|
+
base64, so a 1 MB scanned PDF became roughly 350k tokens in one call. Binary is
|
|
113
|
+
now never inlined, and text output is bounded.
|
|
114
|
+
- **Error bodies were unbounded and unfiltered.** A CDN or proxy error page
|
|
115
|
+
reached the caller whole. Now structured-first, capped, and scrubbed of
|
|
116
|
+
credential-shaped material.
|
|
117
|
+
- **No timeout was configured**, so a failing endpoint could occupy a caller for
|
|
118
|
+
~3 minutes; and `extra.signal` was never forwarded, so a cancelled tool call
|
|
119
|
+
left the request in flight.
|
|
120
|
+
- **Failures were inconsistently flagged.** A server-*refused* delete and a
|
|
121
|
+
failed inspect returned success-shaped results, so a client branching on
|
|
122
|
+
`isError` misread them.
|
|
123
|
+
- **Every untitled note was titled "MCP Memory"**, and title is the only
|
|
124
|
+
per-chunk label rendered in search results.
|
|
125
|
+
- **`npm test` could pass having run zero tests** on Node 18 and 20 — `/bin/sh`
|
|
126
|
+
does not expand `**`, and CI was running a different command.
|
|
127
|
+
|
|
128
|
+
### Changed
|
|
129
|
+
|
|
130
|
+
- Tool descriptions now say **when** to call each tool — recall before
|
|
131
|
+
answering, save what the user reveals — with worked examples. Nothing
|
|
132
|
+
previously did, which is the difference between a memory product and a
|
|
133
|
+
note-taking tool.
|
|
134
|
+
- Parameter descriptions explain the decision each informs rather than restating
|
|
135
|
+
the type.
|
|
136
|
+
- All four MCP behaviour hints (`readOnlyHint`, `destructiveHint`,
|
|
137
|
+
`idempotentHint`, `openWorldHint`) are declared on every tool. `destructiveHint`
|
|
138
|
+
could not previously be set at all, and the spec defaults it to *true* for
|
|
139
|
+
non-readonly tools — so `hydradb_ingest` read as destructive.
|
|
140
|
+
- Overlapping chunks whose content is wholly contained in another are suppressed,
|
|
141
|
+
and extra context is deduplicated by content rather than id.
|
|
142
|
+
- `max_results` now bounds what is rendered, not just what is requested.
|
|
143
|
+
- The recall renderer reads SDK types directly; the snake_case mirror and its
|
|
144
|
+
adapters are gone (−112 lines).
|
|
145
|
+
- Ingest input is bounded (1M characters, 500 turns).
|
|
146
|
+
- `moduleResolution` is `NodeNext`, so the SDK's `exports` subpaths resolve.
|
|
147
|
+
- The `lint` CI job runs an actual linter; the publish workflow smoke-tests the
|
|
148
|
+
built package and asserts the tarball contents.
|
|
149
|
+
|
|
150
|
+
## [1.1.1] - 2026-07
|
|
151
|
+
|
|
152
|
+
### Fixed
|
|
153
|
+
|
|
154
|
+
- `hydradb_query` no longer pins `kind: "memory"`, which had made every ingested
|
|
155
|
+
knowledge source unreachable from the MCP.
|
|
156
|
+
- The server reports its real version instead of a hardcoded `1.0.0`.
|
|
157
|
+
|
|
158
|
+
## [1.1.0] - 2026-07
|
|
159
|
+
|
|
160
|
+
### Added
|
|
161
|
+
|
|
162
|
+
- Canonical HydraDB tool vocabulary (`hydradb_*`), with the previous `hydra_db_*`
|
|
163
|
+
names kept as deprecated aliases.
|
|
164
|
+
|
|
165
|
+
[1.2.0]: https://github.com/hydra-db/hydradb-mcp/releases/tag/v1.2.0
|
|
166
|
+
[1.1.1]: https://github.com/hydra-db/hydradb-mcp/releases/tag/v1.1.1
|
|
167
|
+
[1.1.0]: https://github.com/hydra-db/hydradb-mcp/releases/tag/v1.1.0
|
package/README.md
CHANGED
|
@@ -4,72 +4,127 @@ MCP (Model Context Protocol) server for [Hydra DB](https://hydradb.com), the sta
|
|
|
4
4
|
|
|
5
5
|
## Available Tools
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
`
|
|
10
|
-
|
|
7
|
+
| Tool | What it does |
|
|
8
|
+
|---|---|
|
|
9
|
+
| `hydradb_query` | Search memories and knowledge together, with knowledge-graph context |
|
|
10
|
+
| `hydradb_ingest` | Save a note, a document, or a conversation |
|
|
11
|
+
| `hydradb_list` | Enumerate one family — every memory, or every knowledge source |
|
|
12
|
+
| `hydradb_inspect` | Fetch one source's full content by id |
|
|
13
|
+
| `hydradb_delete` | Remove one or more items by id, irreversibly |
|
|
14
|
+
| `hydradb_status` | Check whether an ingested source has finished indexing |
|
|
15
|
+
|
|
16
|
+
Ids flow between these: `hydradb_query` and `hydradb_list` emit them;
|
|
17
|
+
`hydradb_inspect`, `hydradb_delete` and `hydradb_status` accept them.
|
|
18
|
+
|
|
19
|
+
### Deprecated aliases
|
|
20
|
+
|
|
21
|
+
The previous `hydra_db_*` tool names are **no longer registered by default** as
|
|
22
|
+
of 1.2.0. If your `mcp.json` still calls them, set:
|
|
11
23
|
|
|
12
|
-
|
|
24
|
+
```
|
|
25
|
+
HYDRADB_MCP_LEGACY_TOOLS=1
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
| Deprecated alias | Use instead |
|
|
13
29
|
|---|---|
|
|
14
|
-
| `
|
|
15
|
-
| `
|
|
16
|
-
| `
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
30
|
+
| `hydra_db_search` | `hydradb_query` |
|
|
31
|
+
| `hydra_db_store`, `hydra_db_ingest_conversation` | `hydradb_ingest` |
|
|
32
|
+
| `hydra_db_list_memories`, `hydra_db_list_sources` | `hydradb_list` |
|
|
33
|
+
| `hydra_db_fetch_content` | `hydradb_inspect` |
|
|
34
|
+
| `hydra_db_delete_memory` | `hydradb_delete` |
|
|
19
35
|
|
|
20
36
|
### **hydradb_query**
|
|
21
37
|
|
|
22
|
-
|
|
38
|
+
Searches **both** memories and ingested knowledge sources. Returns matching
|
|
39
|
+
chunks with their source id, a relevance score, and knowledge-graph context.
|
|
23
40
|
|
|
24
41
|
| Parameter | Type | Required | Description |
|
|
25
42
|
|-----------|------|----------|-------------|
|
|
26
|
-
| `query` | string | Yes |
|
|
27
|
-
| `
|
|
28
|
-
| `
|
|
29
|
-
| `
|
|
43
|
+
| `query` | string | Yes | What you want to know, as a question or topic |
|
|
44
|
+
| `kind` | string | No | `memory`, `knowledge`, or `all` (default: `all`) |
|
|
45
|
+
| `max_results` | number | No | Maximum chunks to return (1-50, default: 10) |
|
|
46
|
+
| `mode` | string | No | `fast`, `thinking` (default), or `auto` |
|
|
47
|
+
| `detail` | string | No | `compact` (default) trims each chunk; `full` returns them whole |
|
|
48
|
+
| `graph_context` | boolean | No | Include knowledge-graph relations (default: true) |
|
|
49
|
+
| `operator` | string | No | `or` (default), `and`, or `phrase` for exact strings |
|
|
50
|
+
| `source_ids` | array | No | Restrict the search to these sources |
|
|
51
|
+
| `metadata_filters` | object | No | Exact-match filters over stored metadata |
|
|
52
|
+
| `num_related_chunks` | number | No | Adjacent chunks to attach per match (0-5, default: 0) |
|
|
30
53
|
|
|
31
54
|
### **hydradb_ingest**
|
|
32
55
|
|
|
33
|
-
|
|
56
|
+
Saves information so it outlives the session. Provide **exactly one** of `text`
|
|
57
|
+
or `turns`.
|
|
34
58
|
|
|
35
59
|
| Parameter | Type | Required | Description |
|
|
36
60
|
|-----------|------|----------|-------------|
|
|
37
|
-
| `text` | string | No\* |
|
|
38
|
-
| `
|
|
39
|
-
| `
|
|
40
|
-
| `
|
|
41
|
-
| `
|
|
42
|
-
| `
|
|
43
|
-
| `
|
|
44
|
-
|
|
45
|
-
|
|
61
|
+
| `text` | string | No\* | A note, fact, decision, or document body |
|
|
62
|
+
| `turns` | array | No\* | Conversation turns, each with `user` and `assistant` |
|
|
63
|
+
| `kind` | string | No | `memory` (default) or `knowledge` for a document |
|
|
64
|
+
| `title` | string | No | Label shown in later search results — always set it |
|
|
65
|
+
| `source_id` | string | No | Identifier for this entry. **Reusing one REPLACES what is stored under it** |
|
|
66
|
+
| `overwrite` | boolean | No | Allow that replacement (default: true) |
|
|
67
|
+
| `infer` | boolean | No | Extract insights and graph entities (default: true) |
|
|
68
|
+
| `is_markdown` | boolean | No | Chunk on markdown structure (default: false) |
|
|
69
|
+
| `metadata` | object | No | Key/value metadata, matchable later via `metadata_filters` |
|
|
70
|
+
| `observation_date` | string | No | When the fact was true (RFC3339), vs when it was stored |
|
|
71
|
+
| `user_name` | string | No | What to call the user, used with `turns` (default: `User`) |
|
|
72
|
+
|
|
73
|
+
\* Passing both is an error; passing neither is an error.
|
|
74
|
+
|
|
75
|
+
Ingestion is **asynchronous** — content is not searchable the instant it is
|
|
76
|
+
saved. Use `hydradb_status` to confirm.
|
|
46
77
|
|
|
47
78
|
### **hydradb_list**
|
|
48
79
|
|
|
49
|
-
|
|
80
|
+
Enumerates one family at a time. These are separate corpora: listing memories
|
|
81
|
+
tells you nothing about which knowledge sources exist.
|
|
50
82
|
|
|
51
83
|
| Parameter | Type | Required | Description |
|
|
52
84
|
|-----------|------|----------|-------------|
|
|
53
|
-
| `kind` | string |
|
|
54
|
-
| `
|
|
85
|
+
| `kind` | string | **Yes** | `memory` or `knowledge` |
|
|
86
|
+
| `ids` | array | No | Restrict to these ids |
|
|
87
|
+
| `source_ids` | array | No | Deprecated alias for `ids` |
|
|
88
|
+
| `page` | number | No | Page to return, 1-indexed (default: 1) |
|
|
89
|
+
| `page_size` | number | No | Items per page (1-100) |
|
|
90
|
+
|
|
91
|
+
The response reports how many of the total it showed and how to reach the rest.
|
|
55
92
|
|
|
56
93
|
### **hydradb_inspect**
|
|
57
94
|
|
|
58
|
-
|
|
95
|
+
Fetches one source's full content by id.
|
|
59
96
|
|
|
60
97
|
| Parameter | Type | Required | Description |
|
|
61
98
|
|-----------|------|----------|-------------|
|
|
62
|
-
| `
|
|
63
|
-
| `
|
|
99
|
+
| `id` | string | Yes | The source id, from `hydradb_query` or `hydradb_list` |
|
|
100
|
+
| `source_id` | string | No | Deprecated alias for `id` |
|
|
101
|
+
| `mode` | string | No | `content` (default), `url` for a download link, or `both` |
|
|
102
|
+
| `offset` | number | No | Character offset to read from (default: 0) |
|
|
103
|
+
| `limit` | number | No | Maximum characters to return (max 20000) |
|
|
104
|
+
| `expiry_seconds` | number | No | How long a `url` link stays valid |
|
|
105
|
+
|
|
106
|
+
Long sources come back in slices, and binary sources are never inlined — you get
|
|
107
|
+
their type and size, and `mode: "url"` returns a download link.
|
|
64
108
|
|
|
65
109
|
### **hydradb_delete**
|
|
66
110
|
|
|
67
|
-
|
|
111
|
+
Removes items by id. Irreversible.
|
|
112
|
+
|
|
113
|
+
| Parameter | Type | Required | Description |
|
|
114
|
+
|-----------|------|----------|-------------|
|
|
115
|
+
| `ids` | array | No\* | The ids to delete — accepts several at once |
|
|
116
|
+
| `id` | string | No\* | A single id |
|
|
117
|
+
| `kind` | string | No | `memory` (default) or `knowledge` |
|
|
118
|
+
|
|
119
|
+
\* Provide one of them.
|
|
120
|
+
|
|
121
|
+
### **hydradb_status**
|
|
122
|
+
|
|
123
|
+
Checks whether ingested sources have finished indexing.
|
|
68
124
|
|
|
69
125
|
| Parameter | Type | Required | Description |
|
|
70
126
|
|-----------|------|----------|-------------|
|
|
71
|
-
| `
|
|
72
|
-
| `kind` | string | No | Which family the ID belongs to: `memory` or `knowledge` (default: `memory`) |
|
|
127
|
+
| `ids` | array | Yes | The source ids to check |
|
|
73
128
|
|
|
74
129
|
## Configuration
|
|
75
130
|
|
|
@@ -87,6 +142,9 @@ Delete a memory or knowledge source from Hydra DB by its ID. This action is irre
|
|
|
87
142
|
| `HYDRADB_COLLECTION` | Collection (sub-tenant) for partitioning | `hydra-db-mcp` |
|
|
88
143
|
| `HYDRADB_BASE_URL` | Base URL override | `https://api.hydradb.com` |
|
|
89
144
|
| `HYDRADB_LOG_LEVEL` | Log level: DEBUG, INFO, WARN, ERROR | `ERROR` |
|
|
145
|
+
| `HYDRADB_TIMEOUT_SECONDS` | Per-attempt request timeout | `30` |
|
|
146
|
+
| `HYDRADB_MAX_RETRIES` | Retries per request (0 disables) | `2` |
|
|
147
|
+
| `HYDRADB_MCP_LEGACY_TOOLS` | Register the deprecated `hydra_db_*` tools | *off* |
|
|
90
148
|
|
|
91
149
|
The legacy `HYDRA_DB_*` names — `HYDRA_DB_API_KEY`, `HYDRA_DB_TENANT_ID`,
|
|
92
150
|
`HYDRA_DB_SUB_TENANT_ID`, `HYDRA_DB_BASE_URL`, `HYDRA_DB_LOG_LEVEL` — remain
|
package/dist/adapters.d.ts
CHANGED
|
@@ -1,29 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Adapters
|
|
3
|
-
* snake_case shapes this server already renders.
|
|
2
|
+
* Adapters over responses the SDK does not fully type.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* Note: with `skipValidation`, the SDK transforms known fields to camelCase but
|
|
11
|
-
* leaves the untyped triplet innards (`relation`/`source`/`target`) as raw
|
|
12
|
-
* snake_case — which is exactly what `formatTriplet` reads — so triplets pass
|
|
13
|
-
* through untouched.
|
|
4
|
+
* The recall adapters that used to live here are gone: `src/context.ts` now
|
|
5
|
+
* reads the SDK payload directly, so the snake_case mirror they translated into
|
|
6
|
+
* no longer exists. What remains is the listing layer, which is a different
|
|
7
|
+
* thing entirely — see `toMemoryList` — plus the ingest result, which is read
|
|
8
|
+
* for its per-item errors.
|
|
14
9
|
*/
|
|
15
10
|
import type { HydraDB as SDK } from "@hydradb/sdk";
|
|
16
|
-
import type { AddMemoryResponse
|
|
17
|
-
/** SDK retrieval result → the legacy `RecallResponse` fed to `buildRecalledContext`. */
|
|
18
|
-
export declare function toRecallResponse(data: SDK.SearchV2RetrievalResult): RecallResponse;
|
|
19
|
-
/** SDK ingest result → the legacy `AddMemoryResponse` (success/failed counts). */
|
|
11
|
+
import type { AddMemoryResponse } from "./types.js";
|
|
20
12
|
export declare function toAddMemoryResponse(data: SDK.IngestionV2SourceUploadResponse): AddMemoryResponse;
|
|
21
13
|
export interface MemoryListItem {
|
|
22
14
|
memory_id: string;
|
|
23
15
|
memory_content: string;
|
|
24
16
|
}
|
|
17
|
+
/**
|
|
18
|
+
* How much of the corpus a listing actually covered.
|
|
19
|
+
*
|
|
20
|
+
* The server returns this alongside every listing and both adapters used to
|
|
21
|
+
* discard it, which is what let one page be presented as the whole store.
|
|
22
|
+
*/
|
|
23
|
+
export interface PageInfo {
|
|
24
|
+
/** Total rows across all pages, when the server reported one. */
|
|
25
|
+
total?: number;
|
|
26
|
+
page?: number;
|
|
27
|
+
page_size?: number;
|
|
28
|
+
total_pages?: number;
|
|
29
|
+
has_next?: boolean;
|
|
30
|
+
}
|
|
31
|
+
export interface MemoryList {
|
|
32
|
+
memories: MemoryListItem[];
|
|
33
|
+
page: PageInfo;
|
|
34
|
+
}
|
|
25
35
|
/** SDK list result → memory rows. Field names vary across v2 records, so read defensively. */
|
|
26
|
-
export declare function toMemoryList(data: SDK.ListV2SourceListResponse):
|
|
36
|
+
export declare function toMemoryList(data: SDK.ListV2SourceListResponse): MemoryList;
|
|
27
37
|
export interface SourceListItem {
|
|
28
38
|
id: string;
|
|
29
39
|
title?: string;
|
|
@@ -32,6 +42,7 @@ export interface SourceListItem {
|
|
|
32
42
|
export interface SourceList {
|
|
33
43
|
sources: SourceListItem[];
|
|
34
44
|
total: number;
|
|
45
|
+
page: PageInfo;
|
|
35
46
|
}
|
|
36
47
|
/** SDK list result → knowledge source rows + total. */
|
|
37
48
|
export declare function toSourceList(data: SDK.ListV2SourceListResponse): SourceList;
|
package/dist/adapters.js
CHANGED
|
@@ -1,67 +1,39 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Adapters
|
|
3
|
-
* snake_case shapes this server already renders.
|
|
2
|
+
* Adapters over responses the SDK does not fully type.
|
|
4
3
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The recall adapters that used to live here are gone: `src/context.ts` now
|
|
5
|
+
* reads the SDK payload directly, so the snake_case mirror they translated into
|
|
6
|
+
* no longer exists. What remains is the listing layer, which is a different
|
|
7
|
+
* thing entirely — see `toMemoryList` — plus the ingest result, which is read
|
|
8
|
+
* for its per-item errors.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* SDK ingest result item → `MemoryResultItem`.
|
|
9
12
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
13
|
+
* `results` used to be hardcoded empty in `toAddMemoryResponse`, which discarded
|
|
14
|
+
* every per-item `status`/`error`/`errorCode`/`relationsError` the server sent.
|
|
15
|
+
* The caller was left with bare counts — "1 success, 2 failed" with no reason,
|
|
16
|
+
* no code and no way to tell WHICH item failed — so its only rational recovery
|
|
17
|
+
* was to re-ingest everything, which (a reused `source_id` replaces) can destroy
|
|
18
|
+
* the item that succeeded.
|
|
14
19
|
*/
|
|
15
|
-
function
|
|
16
|
-
return {
|
|
17
|
-
// Triplet innards are already raw snake_case (untyped in the SDK schema).
|
|
18
|
-
triplets: (path.triplets ?? []),
|
|
19
|
-
relevancy_score: path.relevancyScore ?? 0,
|
|
20
|
-
combined_context: path.combinedContext ?? null,
|
|
21
|
-
group_id: path.groupId ?? null,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
function toVectorChunk(chunk) {
|
|
20
|
+
function toMemoryResultItem(item) {
|
|
25
21
|
return {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
document_metadata: chunk.additionalMetadata ?? null,
|
|
35
|
-
tenant_metadata: chunk.metadata ?? null,
|
|
36
|
-
extra_context_ids: chunk.extraContextIds ?? null,
|
|
37
|
-
layout: chunk.layout ?? null,
|
|
22
|
+
source_id: item.id ?? "",
|
|
23
|
+
title: item.filename ?? null,
|
|
24
|
+
status: item.status ?? "unknown",
|
|
25
|
+
// The server sends "" rather than omitting these on success; normalise to
|
|
26
|
+
// null so callers can test presence instead of emptiness.
|
|
27
|
+
error: item.error || null,
|
|
28
|
+
error_code: item.errorCode || null,
|
|
29
|
+
relations_error: item.relationsError || null,
|
|
38
30
|
};
|
|
39
31
|
}
|
|
40
|
-
/** SDK retrieval result → the legacy `RecallResponse` fed to `buildRecalledContext`. */
|
|
41
|
-
export function toRecallResponse(data) {
|
|
42
|
-
const graph = data.graphContext;
|
|
43
|
-
const additional = {};
|
|
44
|
-
for (const [id, chunk] of Object.entries(data.additionalContext ?? {})) {
|
|
45
|
-
additional[id] = toVectorChunk(chunk);
|
|
46
|
-
}
|
|
47
|
-
return {
|
|
48
|
-
chunks: (data.chunks ?? []).map(toVectorChunk),
|
|
49
|
-
graph_context: graph
|
|
50
|
-
? {
|
|
51
|
-
query_paths: (graph.queryPaths ?? []).map(toScoredPath),
|
|
52
|
-
chunk_relations: (graph.chunkRelations ?? []).map(toScoredPath),
|
|
53
|
-
chunk_id_to_group_ids: graph.chunkIdToGroupIds ?? {},
|
|
54
|
-
}
|
|
55
|
-
: undefined,
|
|
56
|
-
additional_context: additional,
|
|
57
|
-
};
|
|
58
|
-
}
|
|
59
|
-
/** SDK ingest result → the legacy `AddMemoryResponse` (success/failed counts). */
|
|
60
32
|
export function toAddMemoryResponse(data) {
|
|
61
33
|
return {
|
|
62
34
|
success: data.success ?? false,
|
|
63
35
|
message: data.message ?? "",
|
|
64
|
-
results: [],
|
|
36
|
+
results: (data.results ?? []).map(toMemoryResultItem),
|
|
65
37
|
success_count: data.successCount ?? 0,
|
|
66
38
|
failed_count: data.failedCount ?? 0,
|
|
67
39
|
};
|
|
@@ -79,23 +51,54 @@ function asRecords(value) {
|
|
|
79
51
|
? value
|
|
80
52
|
: undefined;
|
|
81
53
|
}
|
|
54
|
+
function num(record, ...keys) {
|
|
55
|
+
for (const key of keys) {
|
|
56
|
+
const value = record[key];
|
|
57
|
+
if (typeof value === "number")
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Pagination metadata, read defensively for the same reason the rows are: the
|
|
64
|
+
* SDK types this response as `{ inner?: … }` while the live API returns at top
|
|
65
|
+
* level, and neither shape is guaranteed to carry every field.
|
|
66
|
+
*/
|
|
67
|
+
function toPageInfo(container, rowCount) {
|
|
68
|
+
const meta = container.pagination ?? {};
|
|
69
|
+
const total = num(container, "total") ?? num(meta, "total");
|
|
70
|
+
return {
|
|
71
|
+
total: total ?? rowCount,
|
|
72
|
+
page: num(meta, "page"),
|
|
73
|
+
page_size: num(meta, "page_size", "pageSize"),
|
|
74
|
+
total_pages: num(meta, "total_pages", "totalPages"),
|
|
75
|
+
has_next: typeof meta.has_next === "boolean"
|
|
76
|
+
? meta.has_next
|
|
77
|
+
: typeof meta.hasNext === "boolean"
|
|
78
|
+
? meta.hasNext
|
|
79
|
+
: undefined,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
82
|
/** SDK list result → memory rows. Field names vary across v2 records, so read defensively. */
|
|
83
83
|
export function toMemoryList(data) {
|
|
84
84
|
// Memory listings surface at top-level `user_memories` — not under an
|
|
85
85
|
// `.inner` wrapper, and not under `sources` (that is the knowledge shape).
|
|
86
86
|
const d = data;
|
|
87
|
+
const container = (asRecords(d.user_memories) ? d : d.inner) ?? d;
|
|
87
88
|
const records = asRecords(d.user_memories) ??
|
|
88
89
|
asRecords(d.inner?.user_memories) ??
|
|
89
90
|
[];
|
|
90
|
-
|
|
91
|
+
const memories = records.map((record) => ({
|
|
91
92
|
memory_id: str(record, "memory_id", "id", "source_id") ?? "",
|
|
92
93
|
memory_content: str(record, "memory_content", "content", "text", "memory", "title") ?? "",
|
|
93
94
|
}));
|
|
95
|
+
return { memories, page: toPageInfo(container, memories.length) };
|
|
94
96
|
}
|
|
95
97
|
/** SDK list result → knowledge source rows + total. */
|
|
96
98
|
export function toSourceList(data) {
|
|
97
99
|
// Knowledge listings surface at top-level `sources`, not under `.inner`.
|
|
98
100
|
const d = data;
|
|
101
|
+
const container = (asRecords(d.sources) ? d : d.inner) ?? d;
|
|
99
102
|
const records = asRecords(d.sources) ??
|
|
100
103
|
asRecords(d.inner?.sources) ??
|
|
101
104
|
[];
|
|
@@ -108,6 +111,7 @@ export function toSourceList(data) {
|
|
|
108
111
|
return {
|
|
109
112
|
sources,
|
|
110
113
|
total: typeof total === "number" ? total : sources.length,
|
|
114
|
+
page: toPageInfo(container, sources.length),
|
|
111
115
|
};
|
|
112
116
|
}
|
|
113
117
|
//# sourceMappingURL=adapters.js.map
|
package/dist/adapters.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"adapters.js","sourceRoot":"","sources":["../src/adapters.ts"],"names":[],"mappings":"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"}
|
package/dist/config.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export interface HydraDBConfig {
|
|
|
12
12
|
database: string;
|
|
13
13
|
collection: string;
|
|
14
14
|
baseUrl?: string;
|
|
15
|
+
timeoutSeconds?: number;
|
|
16
|
+
maxRetries?: number;
|
|
15
17
|
}
|
|
16
18
|
export type EnvSource = Record<string, string | undefined>;
|
|
17
19
|
export type WarnFn = (message: string) => void;
|
package/dist/config.js
CHANGED
|
@@ -50,6 +50,32 @@ export function resolveConfig(env = process.env, warn = defaultWarn) {
|
|
|
50
50
|
const collection = readEnv(env, "HYDRADB_COLLECTION", "HYDRA_DB_SUB_TENANT_ID", warn) ??
|
|
51
51
|
DEFAULT_COLLECTION;
|
|
52
52
|
const baseUrl = readEnv(env, "HYDRADB_BASE_URL", "HYDRA_DB_BASE_URL", warn);
|
|
53
|
-
|
|
53
|
+
// Included only when actually set, so the resolved config says what the
|
|
54
|
+
// environment said rather than carrying a row of undefined knobs.
|
|
55
|
+
const timeoutSeconds = positiveInt(env.HYDRADB_TIMEOUT_SECONDS);
|
|
56
|
+
const maxRetries = nonNegativeInt(env.HYDRADB_MAX_RETRIES);
|
|
57
|
+
return {
|
|
58
|
+
apiKey,
|
|
59
|
+
database,
|
|
60
|
+
collection,
|
|
61
|
+
baseUrl,
|
|
62
|
+
...(timeoutSeconds != null ? { timeoutSeconds } : {}),
|
|
63
|
+
...(maxRetries != null ? { maxRetries } : {}),
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Numeric overrides are ignored rather than fatal when malformed.
|
|
68
|
+
*
|
|
69
|
+
* A typo'd timeout should not stop the server from starting — falling back to
|
|
70
|
+
* the built-in default keeps it running, and the alternative (exit 1 on a
|
|
71
|
+
* cosmetic env var) is worse than the misconfiguration.
|
|
72
|
+
*/
|
|
73
|
+
function positiveInt(raw) {
|
|
74
|
+
const value = Number(raw);
|
|
75
|
+
return raw != null && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
76
|
+
}
|
|
77
|
+
function nonNegativeInt(raw) {
|
|
78
|
+
const value = Number(raw);
|
|
79
|
+
return raw != null && Number.isInteger(value) && value >= 0 ? value : undefined;
|
|
54
80
|
}
|
|
55
81
|
//# sourceMappingURL=config.js.map
|