4.1 KiB
4.1 KiB
Copilot Instructions for TJWaterAgent
Overview
- TJWaterAgent is a Bun + TypeScript backend service.
- Main entrypoint:
src/server.ts - Chat API base path:
/api/v1/agent/chat - Persistent storage is PostgreSQL-first. Historical file storage only remains for one-time migration and external result payload files.
Core identity model
sessionId= durable chat thread identifier exposed to clients and used for persistence.runtimeSessionId= temporary opencode runtime execution identifier for a single active request.- Do not reintroduce
conversationId/clientSessionIdnaming for the durable thread id. UsesessionId.
Persistence design
Canonical PostgreSQL tables:
conversationsconversation_statesconversation_turnsruntime_sessionslearning_statesresult_refsmemories
conversations
Stores durable thread metadata:
session_id- actor / owner / project fields
parent_session_idtitlestatus- streaming lifecycle fields:
is_streamingactive_runtime_session_idstreaming_started_at
is_streaming is persisted so the frontend can recover streaming state after refresh. Stream cleanup must be guarded by active_runtime_session_id so an old stream cannot clear a newer one.
conversation_states
Stores frontend-facing session UI state:
messagesbranch_groupsis_title_manually_edited
conversation_turns
Stores transcript turns as one row per turn:
- keyed by
turn_id - linked by
session_id - ordered by deterministic
turn_index
Do not fall back to legacy transcript files in runtime code.
runtime_sessions
Stores runtime binding context for internal tools and learning review/gate flows:
runtime_session_idsession_id- actor / project / trace fields
allow_learning_writelearning_modereleased_at
This replaces the old alias-based tool_session_contexts model.
result_refs
result_refs is metadata-only in PostgreSQL:
- metadata lives in PG
- payload body lives outside PG via
payload_pathor futureobject_key
Most payloads are large, so do not inline them into PostgreSQL.
memories
Durable memory is stored in PG, not markdown files.
Runtime flow
- Client sends/loads a
session_id. ChatSessionBridgebinds that durablesessionIdto a freshruntimeSessionId.- Internal tools call back into the server using
runtimeSessionId. - Transcript, memory, learning state, and result refs persist against
sessionId. - Stream start sets
conversations.is_streaming = true; stream completion clears it only if the runtime id still matches.
Important files
src/server.ts- bootstrap, internal tool endpoints, app wiringsrc/chat/sessionBridge.ts-sessionIdvsruntimeSessionIdbindingsrc/db/index.ts- PostgreSQL bootstrap and schema migration/cleanupsrc/conversations/store.ts- durable session metadata + streaming statesrc/conversations/stateStore.ts- UI state persistencesrc/history/store.ts- transcript persistencesrc/session/runtimeSessionStore.ts- runtime session persistencesrc/results/store.ts- metadata-only result refs + external payload filessrc/results/resolver.ts- result ref normalization and retrievalsrc/learning/orchestrator.ts/src/learning/stateStore.ts- learning review pipelinesrc/memory/store.ts- persistent memory storescripts/migrate-file-storage-to-postgres.ts- one-time migration from legacy file storage
Compatibility rules
- Runtime code should target the canonical schema only.
- Legacy column/table handling belongs only in
src/db/index.tsbootstrap migration orscripts/migrate-file-storage-to-postgres.ts. - Do not add back file-based runtime persistence or compatibility reads unless a migration explicitly requires it.
Validation
Useful commands:
bun run check
PGHOST=... PGPORT=... PGUSER=... PGPASSWORD=... PGDATABASE=agent PGSSLMODE=disable bun test tests/conversations/store.test.ts tests/history/store.test.ts tests/session/runtimeSessionStore.test.ts tests/results/store.test.ts tests/routes/chatSession.test.ts