This document explains the three persistence paths used by chat, how they differ, and how they work together.
Not all knowledge belongs in the same store. The agent now uses three separate memory layers:
-
Conversation memory (JDBC chat memory)
- Stores recent message history for a chat thread.
- Scope:
chatId(UUID), effectively tied to a specific connection chat. - Purpose: preserve dialog continuity and follow-up context.
-
RAG training memory (embeddings)
- Stores schema DDL, query examples, and documentation as embeddings.
- Scope: connection-specific training corpus.
- Purpose: semantic retrieval for SQL generation quality.
-
Business rule memory (feedback-driven SQL guardrails)
- Stores learned SQL constraints from user corrections/teachings.
- Scope: strictly connection-scoped and schema-compatible.
- Purpose: deterministic protection against bad joins/filters.
- Schema descriptions and terminology.
- Query examples (NL -> SQL).
- General documentation that improves retrieval.
- Deterministic instructions such as:
- use table A instead of table B
- must join on
group_id - must include
type='CREDIT'andmode='SUBSCRIPTION'
- Thread-local conversational context.
- Temporary clarification turns and follow-up references.
FeedbackServicestores feedback events.- For learnable types (
CORRECTION,TEACHING,COLUMN_VALUES), it callsBusinessRuleMemoryService.learnFromFeedback(...). - Rules are persisted as
BrainRulerows with SQL rule types:SQL_REQUIRED_TABLESQL_PROHIBITED_TABLESQL_REQUIRED_PREDICATESQL_REQUIRED_JOIN_KEY
ChatServicecallsBusinessRuleMemoryService.resolveApplicableGuardrails(connectionId, question, schema).- Rule selection is constrained by:
- connection id
- schema compatibility (when schema is available)
- question token overlap
ChatServiceappendsbuildGuardrailContext(...)output into feedback context.- This gives the model explicit, connection-scoped SQL constraints.
- Before execution,
ChatServicevalidates SQL viaevaluateSql(...). - If guardrails are violated, execution is blocked and SQL repair/refinement loops run.
- Every corrected candidate is re-validated against the same guardrails.
If a user teaches:
- "For subscription revenue, use
ACCOUNTSandACCOUNTS_LEDGER, join ongroup_id, and filtertype=CREDITandmode=SUBSCRIPTION"
Then for matching questions on that connection, the agent:
- adds those constraints to prompt context
- rejects SQL that uses disallowed joins/tables
- keeps iterating until SQL passes guardrail checks or attempts are exhausted
Business rules are intentionally generic and schema-aware:
- No hardcoded table assumptions across all connections.
- Main chat-path code must also stay schema-agnostic: no customer-specific table names, column names, SQL fragments, or prompt-to-table shortcuts in classifier, planner, resolver, composer, or execution logic.
- Rules are only applied when they fit the active connection and (if available) current schema.
- This prevents leaking business logic between unrelated databases.
GET /api/memory/status- Shows JDBC chat memory availability and effective window.
POST /api/feedback/*- Captures user feedback used for long-term learning.
GET /api/business-rules/connection/{connectionId}- Returns active rules, applicable guardrails, and rendered guardrail context.
POST /api/business-rules/connection/{connectionId}/learn- Manually ingest rule text.
app.chat.memory.max-messages- Message window size for JDBC chat memory.
app.chat.sql-fix.max-attempts- Max SQL correction/refinement retries.
app.chat.auto-learn-feedback.enabled- Enables auto-learning from explicit user corrections.
app.chat.auto-learn.max-feedback-context-chars- Caps feedback+guardrail context length injected into prompts.
db.query-timeout-seconds- JDBC statement timeout used during query execution.
Core tests covering this flow:
BusinessRuleMemoryServiceTestFeedbackServiceTestBusinessRuleControllerIntegrationTest
Connection integration coverage (including configured test connection):
ConnectionControllerIntegrationTestSlowQueryControllerIntegrationTest