Grounding LLM Responses in Application State
The CognitiveBridge pattern: injecting arousal, conflict, surprise, and memory state into system prompts so LLM responses are shaped by what the application knows.
By default, LLMs respond based purely on the conversation history and their training. They don't know whether your application is under load, whether the user seems confused, or what the system's memory banks contain. The CognitiveBridge pattern bridges this gap — it extracts application state and injects it into every system prompt as structured context.
The Problem
Suppose you're building a conversational interface over a knowledge base. The LLM can answer questions, but it doesn't know:
- Whether it just retrieved weak or strong evidence
- Whether the current query is semantically similar to recent ones (low surprise) or completely novel (high surprise)
- Whether internal signals suggest the user is confused or on track
- What facts have been explicitly taught to the system
All of this information exists in your application — but without explicit injection, the LLM is blind to it.
CognitiveBridge Architecture
The bridge sits between the user message and the LLM call:
class CognitiveBridge:
def __init__(self, model, mechanisms, memories, encoder, llm, base_system_prompt):
self.model = model # cognitive neural network
self.memories = memories # dict of memory blocks
self.encoder = encoder # text → vector
self.llm = llm # LLM client
self.base_prompt = base_system_prompt
self._history = []
self._knowledge = [] # durable facts
def turn(self, user_message: str) -> str:
# 1. Encode
embedding = self.encoder.encode(user_message)
# 2. Run cognitive model
output = self.model.forward(embedding)
# 3. Extract state
state = StateExtractor.extract(self.model, self.memories)
# 4. Update neuromodulators from state
self._update_neuromodulators(state)
# 5. Build enriched system prompt
system = self._build_system_prompt(state)
# 6. Call LLM
self._history.append({"role": "user", "content": user_message})
response = self.llm.send(system, self._history)
self._history.append({"role": "assistant", "content": response})
return responseExtracting Cognitive State
@dataclass
class CognitiveState:
arousal: float # 0-1: how activated/engaged the system is
conflict: float # 0-1: disagreement between internal signals
surprise: float # 0-1: how unexpected the current input is
uncertainty: float # 0-1: confidence in the retrieved evidence
memory_load: float # 0-1: how full working memory is
class StateExtractor:
@staticmethod
def extract(model, memories) -> CognitiveState:
# Arousal: mean activation magnitude across blocks
activations = [block.out for block in model.blocks if hasattr(block, 'out')]
arousal = float(np.mean([np.abs(a).mean() for a in activations if a is not None]))
# Conflict: variance across parallel processing streams
if len(activations) > 1:
stacked = np.stack([a.mean(0) for a in activations], axis=0)
conflict = float(np.var(stacked, axis=0).mean())
else:
conflict = 0.0
# Surprise: distance from working memory baseline
wm = memories.get("working")
if wm is not None:
baseline = wm.buffer.mean(0)
current = activations[-1].mean(0) if activations else baseline
surprise = float(np.mean((current - baseline) ** 2))
else:
surprise = 0.0
return CognitiveState(
arousal=np.clip(arousal, 0, 1),
conflict=np.clip(conflict, 0, 1),
surprise=np.clip(surprise, 0, 1),
uncertainty=1.0 - np.clip(arousal, 0, 1),
memory_load=wm.ptr / wm.capacity if wm else 0.0,
)Building the Enriched System Prompt
def _build_system_prompt(self, state: CognitiveState) -> str:
directive = StateInterpreter.interpret(state)
knowledge_section = ""
if self._knowledge:
facts = "\n".join(f"- {fact}" for fact in self._knowledge)
knowledge_section = f"\n\n[Known Facts]\n{facts}"
state_section = f"""
[Internal Cognitive State]
- Arousal: {state.arousal:.2f} (system engagement level)
- Conflict: {state.conflict:.2f} (internal signal disagreement)
- Surprise: {state.surprise:.2f} (input novelty)
- Memory load: {state.memory_load:.0%} capacity used
- Directive: {directive}"""
return self.base_prompt + knowledge_section + state_sectionStateInterpreter: Translating Numbers to Language
class StateInterpreter:
@staticmethod
def interpret(state: CognitiveState) -> str:
parts = []
if state.arousal > 0.7:
parts.append("System is highly engaged — prioritize depth over breadth.")
elif state.arousal < 0.3:
parts.append("System is in low-arousal mode — be concise and direct.")
if state.conflict > 0.6:
parts.append("High internal conflict — acknowledge uncertainty in your response.")
if state.surprise > 0.7:
parts.append("Novel input detected — do not assume prior context applies.")
if state.memory_load > 0.8:
parts.append("Memory near capacity — prioritize most recent context.")
return " ".join(parts) if parts else "Normal operating state."Teaching Durable Facts
The bridge supports injecting facts that persist across every subsequent call:
bridge.teach("The user's project uses Next.js 15 App Router")
bridge.teach("Prefer TypeScript over JavaScript in all code examples")
bridge.teach("The database is Neon PostgreSQL with Drizzle ORM")
# Every system prompt now includes these facts verbatim
response = bridge.turn("How do I add a new API route?")This is distinct from retrieval — taught facts are always included, not ranked. Use it for ground truths and preferences that should never be filtered out.
Why This Matters
Without this pattern, the LLM is an oracle consulted in isolation. With it, the LLM becomes an output layer for a stateful application — one that knows its own arousal, uncertainty, and memory state, and can communicate that to the model through the system prompt.
The practical result: responses that hedge appropriately when internal confidence is low, that stay focused when arousal is high, and that leverage explicitly taught knowledge without requiring retrieval.