Updated semantic, and added entities/relationship implementation
This commit is contained in:
@@ -38,7 +38,8 @@ src/
|
||||
│ └── index.js # Session + episode CRUD and FTS search
|
||||
├── semantic/
|
||||
│ └── index.js # Qdrant collection management, upsert, search, delete
|
||||
├── entities/ # Entity + relationship CRUD (upcoming)
|
||||
├── entities/
|
||||
│ └── index.js # Entity + relationship CRUD
|
||||
└── index.js # Express app + route definitions
|
||||
```
|
||||
|
||||
@@ -100,6 +101,15 @@ Qdrant and SQLite work as a pair — neither operates in isolation:
|
||||
2. IDs are used to fetch full content from SQLite
|
||||
3. Results are ranked and assembled into a context package
|
||||
|
||||
## Entity Layer
|
||||
|
||||
Entities and relationships are stored in SQLite with two key constraints:
|
||||
|
||||
- `UNIQUE(name, type)` on entities — ensures no duplicates; upsert updates existing records
|
||||
- `UNIQUE(from_id, to_id, label)` on relationships — prevents duplicate edges
|
||||
- `ON DELETE CASCADE` on both `from_id` and `to_id` — deleting an entity automatically
|
||||
removes all relationships where it appears on either end
|
||||
|
||||
## Endpoints
|
||||
|
||||
### Health
|
||||
@@ -132,7 +142,7 @@ Qdrant and SQLite work as a pair — neither operates in isolation:
|
||||
| POST | /episodes | Create a new episode |
|
||||
| GET | /episodes/search?q=&limit= | Full-text search across episodes |
|
||||
| GET | /episodes/:id | Get episode by ID |
|
||||
| GET | /sessions/:id/episodes?limit=&offset= | Get episodes for a session |
|
||||
| GET | /sessions/:id/episodes?limit=&offset= | Get paginated episodes for a session |
|
||||
| DELETE | /episodes/:id | Delete an episode |
|
||||
|
||||
**POST /episodes body:**
|
||||
@@ -146,4 +156,58 @@ Qdrant and SQLite work as a pair — neither operates in isolation:
|
||||
}
|
||||
```
|
||||
|
||||
> Semantic (Qdrant) and entity REST endpoints will be documented as they are built out.
|
||||
> Note: `/episodes/search` must be defined before `/episodes/:id` in Express to prevent
|
||||
> the word `search` being captured as an ID parameter.
|
||||
|
||||
### Entities
|
||||
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| POST | /entities | Upsert an entity (creates or updates by name + type) |
|
||||
| GET | /entities/by-type/:type | Get all entities of a given type |
|
||||
| GET | /entities/:id | Get entity by internal ID |
|
||||
| DELETE | /entities/:id | Delete entity (cascades to relationships) |
|
||||
|
||||
**POST /entities body:**
|
||||
```json
|
||||
{
|
||||
"name": "NexusAI",
|
||||
"type": "project",
|
||||
"notes": "My AI memory project",
|
||||
"metadata": {}
|
||||
}
|
||||
```
|
||||
|
||||
> Note: `/entities/by-type/:type` must be defined before `/entities/:id` in Express to
|
||||
> prevent `by-type` being captured as an ID parameter.
|
||||
|
||||
### Relationships
|
||||
|
||||
| Method | Path | Description |
|
||||
|---|---|---|
|
||||
| POST | /relationships | Upsert a relationship between two entities |
|
||||
| GET | /entities/:id/relationships | Get all relationships originating from an entity |
|
||||
| DELETE | /relationships | Delete a specific relationship |
|
||||
|
||||
**POST /relationships body:**
|
||||
```json
|
||||
{
|
||||
"fromId": 1,
|
||||
"toId": 2,
|
||||
"label": "uses",
|
||||
"metadata": {}
|
||||
}
|
||||
```
|
||||
|
||||
**DELETE /relationships body:**
|
||||
```json
|
||||
{
|
||||
"fromId": 1,
|
||||
"toId": 2,
|
||||
"label": "uses"
|
||||
}
|
||||
```
|
||||
|
||||
> Relationships are identified by the composite key `(fromId, toId, label)`. Delete uses
|
||||
> the request body rather than URL params as this three-part key is awkward to express
|
||||
> cleanly in a path.
|
||||
Reference in New Issue
Block a user