# klieo-memory-pgvector

PostgreSQL + [pgvector](https://github.com/pgvector/pgvector) implementation of
klieo-core's `LongTermMemory` (and `FilterableLongTermMemory`). Sibling to
`klieo-memory-qdrant` — same trait surface, different store. Targets Aurora
PostgreSQL Serverless v2 but works against any Postgres with the `vector`
extension.

## Schema

One table per deployment (`<prefix>_v1`, default `klieo_facts_v1`):

| column        | type           | purpose                              |
|---------------|----------------|--------------------------------------|
| `fact_id`     | `uuid` (PK)    | caller-facing `FactId`               |
| `text`        | `text`         | fact body                            |
| `metadata`    | `jsonb`        | caller's opaque JSON                 |
| `embedding`   | `vector(dim)`  | `Embedder::embed(text)`              |
| `scope_kind`  | `text`         | `workspace` \| `agent` \| `global`   |
| `scope_value` | `text`         | scope owner (empty for global)       |

Indexes: HNSW on `embedding` (`vector_cosine_ops`) for ANN recall, and
`(scope_kind, scope_value)` for the scope filter. Provisioned lazily on the
first `remember` (so process starts don't race on DDL); the embedding
dimension is fixed at first write.

`metadata` is `jsonb` (not a string) so relational joins from domain keys
(Versicherungsnummer, Vertrag, GeVo-Typ) to facts remain possible against the
same table — that join layer is a separate component, intentionally out of
this crate.

## Usage

```rust,no_run
# async fn example() {
use klieo_memory_pgvector::{MemoryPgvector, PgvectorConfig, DummyEmbedder};
use std::sync::Arc;

// Capability-shaped default (DummyEmbedder):
let mem = MemoryPgvector::connect("postgres://localhost/klieo").await.unwrap();

// Real embedder + config:
let cfg = PgvectorConfig::new("postgres://aurora.internal/klieo?sslmode=require")
    .with_table_prefix("triage")
    .with_embedder_id("titan-v2");
let mem = MemoryPgvector::new(cfg, Arc::new(DummyEmbedder)).await.unwrap();
let _ = mem.long_term;
# }
```

## TLS / credentials

Carried by the connection URL (`?sslmode=require`), standard libpq behaviour —
not a separate config knob. The table prefix is validated as a lowercase SQL
identifier before it is interpolated into DDL.

## Permissions

The first `remember` runs `CREATE EXTENSION IF NOT EXISTS vector` — the role
needs permission to create the extension (on Aurora, `rds_superuser`), or an
operator must pre-create it.

## Embeddings

Model-agnostic via the shared `Embedder` trait. Pair with a Bedrock Titan
`Embedder` on the AWS estate; `DummyEmbedder` (zero-vector, FIFO recall) is the
default for tests/dev.
