summary system backend implementation
This commit is contained in:
@@ -58,7 +58,7 @@ Six core tables:
|
||||
- **entities** — named things the system learns about (people, places, concepts)
|
||||
- **relationships** — directional labeled links between entities
|
||||
- **summaries** — condensed episode groups for efficient context retrieval
|
||||
- **projects** — named groupings of sessions with `name`, `description`, `colour`, `icon`, `isolated`, `notes`
|
||||
- **projects** — named groupings of sessions with `name`, `description`, `colour`, `icon`, `isolated`, `notes`, `system_prompt`
|
||||
|
||||
### Migrations
|
||||
|
||||
@@ -71,6 +71,7 @@ try { db.exec(`ALTER TABLE sessions ADD COLUMN project_id INTEGER REFERENCES pro
|
||||
try { db.exec(`CREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id)`); } catch {}
|
||||
try { db.exec(`ALTER TABLE projects ADD COLUMN isolated INTEGER NOT NULL DEFAULT 0`); } catch {}
|
||||
try { db.exec(`ALTER TABLE projects ADD COLUMN notes TEXT`); } catch {}
|
||||
try { db.exec(`ALTER TABLE projects ADD COLUMN system_prompt TEXT`); } catch {}
|
||||
```
|
||||
|
||||
New migrations are always appended here — never modify the schema file for
|
||||
@@ -92,29 +93,15 @@ keep the FTS index automatically in sync with the episodes table.
|
||||
|
||||
Both `updateSession` and `updateProject` build their `SET` clause dynamically
|
||||
from only the fields passed — prevents partial updates from overwriting fields
|
||||
that weren't touched:
|
||||
that weren't touched.
|
||||
|
||||
`updateProject` allowlist:
|
||||
```js
|
||||
// updateProject example
|
||||
function updateProject(id, fields = {}) {
|
||||
const allowed = ['name', 'description', 'colour', 'icon', 'isolated', 'notes'];
|
||||
const updates = [];
|
||||
const values = [];
|
||||
for (const key of allowed) {
|
||||
if (fields[key] !== undefined) {
|
||||
updates.push(`${key} = ?`);
|
||||
values.push(fields[key] ?? null);
|
||||
}
|
||||
}
|
||||
if (updates.length === 0) return getProject(id);
|
||||
values.push(id);
|
||||
db.prepare(`UPDATE projects SET ${updates.join(', ')} WHERE id = ?`).run(...values);
|
||||
return getProject(id);
|
||||
}
|
||||
const allowed = ['name', 'description', 'colour', 'icon', 'isolated', 'notes', 'system_prompt'];
|
||||
```
|
||||
|
||||
This means saving just `{ notes: "..." }` won't touch `name`, `colour`, or
|
||||
any other field.
|
||||
This means saving just `{ notes: "..." }` or `{ system_prompt: "..." }` won't
|
||||
touch any other field.
|
||||
|
||||
## Qdrant / Semantic Layer
|
||||
|
||||
@@ -183,8 +170,10 @@ After extraction, each entity is:
|
||||
Qdrant collection with `{ name, type, notes, projectId }` as payload —
|
||||
`projectId` scopes entities to their project for isolated retrieval
|
||||
|
||||
The Qdrant payload stores enough information to reconstruct entity context
|
||||
at retrieval time without a SQLite roundtrip.
|
||||
`extractAndStoreEntities` receives `projectId` from `createEpisode`, which
|
||||
receives it from the episode route, which receives it from orchestration's
|
||||
`createEpisode` call. This ensures entities are tagged with the correct
|
||||
project scope at extraction time.
|
||||
|
||||
## Project Delete Behaviour
|
||||
|
||||
|
||||
Reference in New Issue
Block a user