-
-
Notifications
You must be signed in to change notification settings - Fork 0
1.5 data
3F state lives in four stores, each chosen for its access shape:
| Store | Holds | Accessed via |
|---|---|---|
| PostgreSQL 16 | Conversations, dead-letter envelopes, per-session config | Prisma 7 |
| MinIO | Raw image payloads (bytes) | S3 API (modules/minio) |
| KeyDB | Queue state, pub/sub, cancellation markers, ephemeral caches | BullMQ / ioredis |
| Qdrant | Long-term memory records + the AI's cognition document | REST (modules/qdrant) |
The generated client lives at server/src/generated/prisma (checked-in build artifact of prisma generate, produced during image builds and the install step). Prisma 7's prisma-client generator is used; the datasource URL comes from environment (POSTGRES_URL via prisma.config.ts).
One row per exchange request: composite key (sessionId, conversationId, requestId), optional title, and JSON content holding the full exchange (prompt, messages, phases, structured results). Indexed by (sessionId, conversationId) for session-scoped loading — this is what lets the dashboard reopen a conversation exactly where it left off.
Persisted dead-letter envelopes keyed by requestId:
- identity:
queueName,jobId; - status lifecycle:
DlqStatus—Failed→Active→Cleared→Removed; - context:
payload(JSON),retryConfig,failureHistory,failedReason; - bookkeeping:
attemptsMade/totalAttempts,failedAt,nextRetryAt.
See 1.3 for how records arrive here and 1.1 for the DLQ API that manages them.
Per-session workbench configuration (key sessionId): selectedModel, preprocessing (JSON), providerOverrides (JSON), and the memory space ids memoryPartition / memoryCognition — the user-set memory overrides (see the memory section below). This is the server-side state behind the SysCtl area (see 2-dashboard): overrides set in the UI are persisted here and applied by the harness on the next request.
Media the user has already been shown inside a conversation, keyed by deterministic identity: image entries carry a normalized content fingerprint (fp:) or storage hash (sh:), video entries carry canonical provider keys. Written at respond time from the guarded final data; read at sanitize time so media-list follow-ups never repeat already-shown content. Rows are purged when their conversation or session is deleted.
Per-provider override rows (key provider): serper, brightData, youtube, sources, ollama, memory. values holds the provider config (API keys encrypted at rest — see the secrets cipher below). The memory row carries the memory system variables (cognitionLimit — the cognition profile character cap), written by PUT /memory-overrides and layered over the MEMORY_COGNITION_LIMIT env baseline.
A named playlist scoped to one conversation (composite key (sessionId, conversationId, name)). videos is a JSON array of VideoGalleryItem; the active playlist is the queue. Rows are purged when their conversation is deleted. Backed by the /api/v1/playlists controller (see 1.1).
Cached end-of-day OHLCV bar for one ticker and trading date (composite key (ticker, date)): open/high/low/close, optional adjustedClose, volume, fetchedAt. Final bars are immutable; the repository re-fetches the most recent days so late updates (post-close uploads, restated adjusted closes) propagate.
Ledger of the [from, to) date windows already fetched per ticker (composite key (ticker, fromDate, toDate)). Trading days skip weekends/holidays, so coverage cannot be derived from the bars alone — requests only backfill intervals not in this ledger. Together the two tables back the /api/v1/stock-data endpoints (see 1.1).
Images uploaded with POST /harness are stored per conversation, addressed by content hash:
storage/:sessionId/:conversationId/:hash
Properties:
-
Dedup by construction — the dashboard sends known hashes in
sessionMetadata; the storage API exposes anexistsprobe, so identical images are never re-uploaded or re-stored. - Stable addressing — hash-as-key makes payloads idempotent and replay-safe (DLQ reinstatement can re-reference the original bytes).
-
Lifecycle — whole-conversation deletion is one call (
DELETE /storage/:sessionId/:conversationId).
MinioHealthIndicator participates in /health/ready; bucket bootstrap happens at startup.
Configuration (server/keydb.conf, mounted into the container): password-protected (requirepass redis for dev), 500 MB memory ceiling, 2 I/O threads, RDB persistence. It backs:
- BullMQ structures (waiting/active/failed sets, delayed jobs);
- Socket.IO adapter state for multi-instance room routing;
- Lightweight runtime markers (cancellation, overrides cache).
Everything on KeyDB is rebuildable — the durable truth is PostgreSQL + MinIO. Wiping the keydb_data volume mid-session costs, at most, in-flight queued jobs (and those get re-instated, see 1.3).
Feature-gated (MEMORY_ENABLED, default off). One collection per embedding model (name suffixed with the model; vector size probed from the live model at bootstrap, Cosine distance). Payload keyword indexes cover every filtered field; the two space identity keys carry Qdrant's is_tenant multitenancy marker.
One point = one record whose payload text IS the record (no chunk layer — the transcript already lives in HarnessConversation). Point ids are deterministic (sha256 of a seed), so re-stating a record overwrites it in place. Every point belongs to exactly one space, folded into the identity key:
-
memory_partition— the user's fact space: statements the user made or asked to remember (preferences, contact details, notable gathered facts). Written two ways: the agenticmemoryRemembertool (sync store) and the background vectorize pipeline (extract → embed → store, one job per turn-side, rolesuser/assistant). -
memory_cognition— the AI's cognition space: the assistant's derived, accumulated understanding of the user in two forms. (1) ONE structured profile document per cognition key (tags['cognition','profile']): stable identity and durable traits —name,language,timezone,expertise[],goals[],communication{style,detailLevel,formality},preferences{},likes[],dislikes[],interests[]— rewritten wholesale by thememory-profilevectorize-queue job after every answered turn, serialized JSON capped by thememoryCognitionLimitsystem variable (env baselineMEMORY_COGNITION_LIMIT, default 5000, clamped 500–32000; runtime override viaPUT /memory-overrides, persisted globally in theprovider_overridesrowmemory). (2) Derived insight records (tags['cognition','insight'], ≤500 chars each, id seeded on the text so repeats overwrite): the DEPTH behind profile topics — the profile doubles as the routing map: its lean topic values ("cars", "Linux") token-match against the prompt at respond time (word-boundary, deterministic — no extra model call) and sharpen the insight query for the hot facet (likes.carsstyle paths are stored on each insight for observability); probe fires only when insights exist. Both personalize every answer as marked private system context (never quoted as user-stated facts; disclosed plainly when asked); the user can also wipe the space (memoryDeletewithcognition=true— purges profile + insights).
Reads: MemorySearchService embeds the query as the full text AND per-sentence variants, merges hits by best score — sentence-dense records are matched on their strongest segment. Records have no exposed ids: exact-text equality is the deletion identity.
Retention/deletion: sysctl prune (DELETE /qdrant/memory) wipes a partition (facts AND cognition) or one conversation (facts only — cognition transcends conversations by design); DELETE /qdrant/text deletes by filters (exact text / contains / tags / conversation / request, capped at 50 matches per call) or the cognition space (cognition=true — batched purge of profile + insights). Unscoped deletes are rejected.
Provider API keys stored in HarnessProviderOverride are encrypted at rest with AES-256-GCM (modules/secrets, SecretsCipherService, keyed by TRIPLEF_SECRETS_KEY). The provider-overrides API returns masked keys and decrypts only when a provider actually needs the value, so secrets never appear in plaintext in the database or the UI.
modules/sharp generates image variants before model consumption — resized/normalized derivatives that improve vision-model throughput and OCR quality without touching the stored original. Effective settings are configurable per session (HarnessConfig.preprocessing), pushed from the dashboard's PProc/SysCtl controls; the server treats client overrides as the effective config on the next request.