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
6 changes: 3 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

### Added

- **Unified databases (PRO-1618).** `hydradb database create <name> --type unified` provisions a database with ONE corpus instead of separate knowledge and memory corpora, and `database list` shows each database's type. The CLI reads a database's layout once per command from `GET /databases` (`details[].type`) and branches on that, never on a flag: a split database keeps every existing request and rendering exactly as it was, and a unified database never receives `type`.
- **Unified databases (PRO-1618).** `hydradb database create <name> --type unified` provisions a database with ONE corpus instead of separate knowledge and memory corpora, and `database list` shows each database's type. The CLI reads a database's layout once per command from `GET /databases` (`details[].type`) and branches on that, never on a flag: a split database keeps every existing request and rendering exactly as it was, and a unified database never receives `type`. The check has a 5-second budget and no retries. When it cannot answer (network, timeout, 429 or 5xx) the command warns on stderr and goes out in the split shape, as it did before layouts existed; if the database then refuses it as unified (`CORPUS_TYPE_UNSUPPORTED`), the command is redone in the unified shape. An auth or permission failure on the check is reported as it is. Without `--type`, `database create` leaves the layout to the server, and current servers make it unified.

On a unified database `query` is a JSON `POST /query` with no `type` and the answer is the four-key unified body (`chunks[]` with `context_id`, `score`, `content`, `enrichment` as a plain string and `enrichment_kind` beside it; `graph[]` with `origin`, `path_summary` and triplets; `forceful_relations[]`, whose `chunk` has the same shape; `llm_prompt`, a markdown document). The human view renders chunks, graph paths grouped by `origin` (query paths apart from chunk relation paths, each chunk relation listed under the returned chunk it hangs under, matched by `relation.chunk_id`) and, when there are any, the forceful relations; the new `--llm` flag prints the server-built markdown `llm_prompt` verbatim on stdout (feedback hint on stderr) so it can be piped into a model call; `--output json` prints the body verbatim, nothing added. `--follow-forceful-relations/--no-follow-forceful-relations` is forwarded. A parser detects the shape by the body (`llm_prompt`, or `graph`/`forceful_relations` as arrays, vs `chunk_content`/`graph_context`; a split body's `graph` and `forceful_relations` are objects), so a unified body that reaches the split path is still rendered as what it is.

`ingest` on a unified database is a JSON `POST /context/ingest` with the `context` list and one item of exactly one `--text` or `--conversation-file` (a JSON list of `{role, content, name?}` turns), plus `--context-id`, `--title`, `--enrich/--no-enrich`, `--instructions`, `--happened-at` (YYYY-MM-DD), `--attributes` and `--custom-attributes` (JSON objects), `--category`, repeatable `--forceful-relation` and `--acl`, and `--upsert/--no-upsert`. Every value is validated locally and named by turn or flag before a round trip. Files are refused on a unified database with a message pointing at `--text`; `--kind`, `--user-name` and `--markdown` are refused there too, and the unified-only options are refused on a split database. The 202's `results[].source_id` is rendered as the item's context id.
`ingest` on a unified database is a JSON `POST /context/ingest` with the `context` list and one item of exactly one `--text` or `--conversation-file` (a JSON list of `{role, content}` turns), plus `--context-id`, `--title`, `--user-name` (the item's `user_name`), `--enrich/--no-enrich`, `--instructions`, `--happened-at` (YYYY-MM-DD), `--attributes` and `--custom-attributes` (JSON objects), `--category`, repeatable `--forceful-relation` (sent as `forceful_relations.context_ids`) and `--acl`, and `--upsert/--no-upsert`. Every value is validated locally and named by turn or flag before a round trip, including the server's per-item caps (1 MiB of text, a 1024-byte title, 4000 characters of instructions, a context id of at most 100 characters with no commas). A turn carrying `name` is refused: the server takes a turn as exactly `{role, content}`. Files are refused on a unified database with a message pointing at `--text`; `--kind` and `--markdown` are refused there too, and the unified-only options are refused on a split database. The 202's `results[].id` is rendered as the item's context id (`source_id` is still read from older servers).

`list`, `delete`, `relations`, `subgraph` and `inspect` send no `type` on a unified database; an explicit `--kind` is refused there rather than silently dropped, and `delete` keeps its `knowledge` default on a split database. The deprecated aliases that hard-code a kind (`recall full`, `memories add`, `knowledge upload`, ...) are refused on a unified database with the same message. The pinned SDK cannot be relied on for any of this, so the unified calls (and `database create --type`) go over the wrapper's raw v2 path with the same headers, envelope unwrap and error translation as the SDK path. The conformance vectors gain `ingest-unified-json`.
`list`, `delete`, `relations`, `subgraph` and `inspect` send no `type` on a unified database; an explicit `--kind` is refused there rather than silently dropped, and `delete` keeps its `knowledge` default on a split database. The deprecated aliases that write with a hard-coded kind (`memories add`, `knowledge upload`, ...) are refused on a unified database with a message naming `hydradb ingest`; the read and delete aliases (`recall full`, `recall preferences`, `memories list`, `memories delete`, `knowledge delete`) chose that kind themselves, so on a unified database they drop it and act on the one corpus. `list` shows no per-item type column on a unified database. The unified query and `database create --type` are typed SDK calls; this needs `hydradb-sdk` 2.1.6, which knows the unified request and the four-key answer, so the pin moves from `>=2.1.4` to `>=2.1.6`. The unified ingest stays a JSON body on the wrapper's raw v2 path (same headers, envelope unwrap and error translation as the SDK path), because the shared `ingest-unified-json` conformance vector requires a JSON body and the SDK sends `context` only as a multipart form field. The conformance vectors gain `ingest-unified-json`.

- **`hydradb feedback` — report whether a query's results were actually useful.** `POST /feedback` had no CLI surface. It correlates on one key, the `request_id` from the query's `meta`, and nothing else about the original query is re-sent, so nothing has to be trusted from the client.

Expand Down
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ defaults to `--kind memory`, and file arguments are always knowledge sources.
| `--text` / `-t` | Text to ingest. Use `-` to read from stdin |
| `--title` | Optional title |
| `--source-id` | Client-assigned source identifier (the `--context-id` on a unified database) |
| `--user-name` | User name (split memory only) |
| `--user-name` | Who is speaking (split: memory only; unified: any item, sent as `user_name`) |
| `--infer` / `--no-infer` | Extract insights and build the knowledge graph (default on) |
| `--markdown` | Treat text as markdown (split memory only) |
| `--upsert` / `--no-upsert` | Update existing items with the same id (default on) |
Expand All @@ -325,13 +325,13 @@ echo "piped note" | hydradb ingest
apply to file ingest and are rejected rather than silently ignored.

On a **unified database** `ingest` sends one JSON context item (exactly one of
`--text` or `--conversation-file`) and never a `type`. Files, `--kind`,
`--user-name` and `--markdown` are refused there with a message; these options
apply there and are refused on a split database:
`--text` or `--conversation-file`) and never a `type`. Files, `--kind` and
`--markdown` are refused there with a message; `--user-name` names the speaker.
These options apply there and are refused on a split database:

| Option | Description |
|--------|-------------|
| `--conversation-file` | Path to a JSON list of `{role, content, name?}` turns (roles `user`, `assistant`, `system`) |
| `--conversation-file` | Path to a JSON list of `{role, content}` turns (roles `user`, `assistant`, `system`); name the user with `--user-name` |
| `--context-id` | Caller-assigned id for the item (server-generated when omitted) |
| `--enrich` / `--no-enrich` | Extract facts and graph relations for the item (default on; `--no-infer` means the same) |
| `--instructions` | Steer enrichment for this item |
Expand Down Expand Up @@ -401,7 +401,7 @@ Create and manage databases.

| Command | What it does | Key options |
|---------|--------------|-------------|
| `database create <database>` | Provisions a new database; `--type unified` gives it one corpus (no `--kind` on later commands) instead of the default `split` layout | `--type` |
| `database create <database>` | Provisions a new database; `--type split` or `--type unified` picks the layout. Without `--type` the server picks, and current servers pick `unified` | `--type` |
| `database list` | Lists all databases for the authenticated user, with each one's type (`split` or `unified`) | - |
| `database collections [database]` | Lists collections within a database | — |
| `database stats [database]` | Row-count statistics | — |
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ dependencies = [
# OpenAPI summary text and its CI auto-bumps the patch digit on merge, so a
# breaking rename can arrive as 2.1.2 -> 2.1.3. The wrapper is the firewall;
# the exact pin is what keeps that churn from reaching users (CONTRACT §2).
"hydradb-sdk>=2.1.4,<3",
"hydradb-sdk>=2.1.6,<3",
]

[project.scripts]
Expand Down
Loading