Brainby arc-labs/docs
Integration

LangChain

Use Brain as a LangChain chat-memory adapter — persist turns with encode, load relevant history with recall. LangChain.js and Python.

What you wire

LangChain's memory abstraction has two hooks:

  1. loadMemoryVariables — called before the LLM runs. Back it with recall to fetch the memories that answer the current input, and format them into the history variable your prompt template expects.
  2. saveContext — called after the LLM responds. Back it with encode to persist the turn so future calls can recall it.

Because recall returns a membership verdict (Single / Many / None) and not a token-budgeted block, the adapter joins the recalled memory texts itself. On None there is nothing to inject and history is empty.

TypeScript

import { BrainHttpClient } from '@brain-db/sdk';
import { BaseChatMemory } from 'langchain/memory';

class BrainMemory extends BaseChatMemory {
  private brain = new BrainHttpClient({ apiKey: process.env.BRAIN_API_KEY! });

  get memoryKeys() {
    return ['history'];
  }

  async loadMemoryVariables(input: { input: string }) {
    const answer = await this.brain.recall({ query: input.input, max_results: 6 });
    const history =
      answer.answer_kind === 'none' ? '' : answer.memories.map((m) => `- ${m.text}`).join('\n');
    return { history };
  }

  async saveContext(input: { input: string }, output: { output: string }) {
    await this.brain.encode({ text: input.input });
    await this.brain.encode({ text: `assistant: ${output.output}` });
  }
}

Use it like any other BaseChatMemory:

const chain = new ConversationChain({ llm: model, memory: new BrainMemory() });

Python

from brain_db_sdk import BrainHttpClient
from langchain.memory.chat_memory import BaseChatMemory


class BrainMemory(BaseChatMemory):
    brain = BrainHttpClient(os.environ["BRAIN_API_KEY"])

    @property
    def memory_variables(self):
        return ["history"]

    def load_memory_variables(self, inputs):
        answer = self.brain.recall(inputs["input"], max_results=6)
        history = (
            ""
            if answer.answer_kind == "none"
            else "\n".join(f"- {m.text}" for m in answer.memories)
        )
        return {"history": history}

    def save_context(self, inputs, outputs):
        self.brain.encode(inputs["input"])
        self.brain.encode(f"assistant: {outputs['output']}")

Using it as a retriever instead

If you want Brain to feed a RAG chain rather than act as chat memory, wrap recall in a retriever: call brain.recall({ query }) in _getRelevantDocuments (TS) / _get_relevant_documents (Python) and map each MemoryHit to a LangChain Document (pageContent = hit.text). The same membership shape applies — an empty document list means Brain returned None.

Was this page helpful?

On this page