summary system backend implementation

This commit is contained in:
Storme-bit
2026-04-19 06:50:24 -07:00
parent 15c1bec609
commit 2769f436fa
10 changed files with 210 additions and 106 deletions

View File

@@ -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