Skip to main content

Memory & Knowledge

Chronos provides two complementary mechanisms for context: Memory (user-specific facts and session state) and Knowledge (RAG over documents). Both are automatically injected into the agent's context during Chat and ChatWithSession.

Memory Store

The memory.Store provides short-term (session-scoped) and long-term (persistent) memory on top of storage.Storage.

Creating a Store

store := memory.NewStore(agentID, backend)

backend must implement storage.Storage (e.g., SQLite or PostgreSQL adapter).

Short-Term Memory

Session-scoped working memory. Values are tied to a session and typically cleared when the session ends.

err := memStore.SetShortTerm(ctx, sessionID, "current_topic", "weather")
if err != nil {
log.Fatal(err)
}

// List all short-term memories for this agent
records, err := memStore.ListShortTerm(ctx)

Long-Term Memory

Cross-session persistent memory. Use for facts about the user that should persist across conversations.

err := memStore.SetLongTerm(ctx, "user_preference_timezone", "America/Los_Angeles")
if err != nil {
log.Fatal(err)
}

// List all long-term memories
records, err := memStore.ListLongTerm(ctx)

Retrieval

value, err := memStore.Get(ctx, "user_preference_timezone")

MemoryRecord

Under the hood, memories are stored as storage.MemoryRecord:

FieldTypeDescription
IDstringUnique record ID
SessionIDstringSession ID (empty for long-term)
AgentIDstringAgent identifier
UserIDstringOptional user scope
Kindstring"short_term" or "long_term"
KeystringMemory key
ValueanyStored value (JSON-serializable)
CreatedAttime.TimeCreation timestamp

Memory Manager

The memory.Manager uses an LLM to autonomously extract facts from conversations and store them as long-term memories. It also formats memories for context injection.

Creating a Manager

mgr := memory.NewManager(agentID, userID, memStore, provider)

provider is a model.Provider used for extraction and optimization. The manager calls it to decide what to remember.

ExtractMemories

Analyzes a conversation and stores memorable facts as long-term memories. The LLM returns a JSON array of {key, value} objects; only clear, factual information is extracted.

messages := []model.Message{
{Role: model.RoleUser, Content: "My name is Alice and I live in Berlin."},
{Role: model.RoleAssistant, Content: "Nice to meet you, Alice!"},
}
err := mgr.ExtractMemories(ctx, messages)

The agent automatically calls ExtractMemories after each Chat and ChatWithSession turn when a MemoryManager is configured.

GetUserMemories

Returns all long-term memories formatted for context injection. The agent uses this to prepend "User memories:" to the system context.

memCtx, err := mgr.GetUserMemories(ctx)
// memCtx: "User memories:\n- user_name: Alice\n- user_location: Berlin\n"

OptimizeMemories

Asks the LLM to deduplicate and compress existing long-term memories. Useful when the memory store grows large.

err := mgr.OptimizeMemories(ctx)

Runs only when there are at least 5 long-term memories.

Agentic Memory Tools

MemoryTools() returns tool definitions that let the model manage memory directly during conversation: remember, forget, and recall.

Each MemoryTool has Name, Description, and Handler. Convert to tool.Definition by adding Parameters (JSON Schema) and Permission:

builder := agent.New("agent", "Agent").WithModel(provider).WithMemoryManager(mgr)
for _, mt := range mgr.MemoryTools() {
var params map[string]any
switch mt.Name {
case "remember":
params = map[string]any{
"type": "object",
"properties": map[string]any{
"key": map[string]any{"type": "string", "description": "Memory key"},
"value": map[string]any{"type": "string", "description": "Fact to store"},
},
"required": []string{"key", "value"},
}
case "forget":
params = map[string]any{
"type": "object",
"properties": map[string]any{
"key": map[string]any{"type": "string", "description": "Memory key to remove"},
},
"required": []string{"key"},
}
default: // recall
params = map[string]any{"type": "object", "properties": map[string]any{}}
}
builder = builder.AddTool(&tool.Definition{
Name: mt.Name,
Description: mt.Description,
Parameters: params,
Permission: tool.PermAllow,
Handler: mt.Handler,
})
}
a, err := builder.Build()

The remember tool stores a fact; forget removes by key; recall lists all stored memories.

Knowledge (RAG)

The knowledge.Knowledge interface supports document indexing and similarity search for RAG.

Interface

type Knowledge interface {
Load(ctx context.Context) error
Search(ctx context.Context, query string, topK int) ([]Document, error)
Close() error
}
MethodDescription
LoadIndex all documents (idempotent)
SearchReturn top-k relevant documents for a query
CloseRelease resources

Document

type Document struct {
ID string
Content string
Metadata map[string]any
Score float32
}

VectorKnowledge

VectorKnowledge implements Knowledge using a storage.VectorStore and model.EmbeddingsProvider:

kb := knowledge.NewVectorKnowledge(
"docs", // collection name
1536, // embedding dimension (e.g., text-embedding-3-small)
vectorStore,
embedder,
"text-embedding-3-small",
)

kb.AddDocuments(
knowledge.Document{ID: "1", Content: "Chronos is a Go-based agentic framework."},
knowledge.Document{ID: "2", Content: "Agents use the builder pattern for configuration."},
)

err := kb.Load(ctx)
if err != nil {
log.Fatal(err)
}

docs, err := kb.Search(ctx, "How do I configure an agent?", 5)

Automatic Injection

When an agent has Knowledge configured, Chat and ChatWithSession automatically:

  1. Call Search(ctx, userMessage, 5) with the user's message
  2. Prepend "Relevant knowledge:" and the top documents to the system context
  3. Let the model use this context when generating the response

Storage Integration

Memory records are persisted via storage.Storage. Implementations must support:

  • PutMemory(ctx, *MemoryRecord) — upsert a memory
  • GetMemory(ctx, agentID, key) — fetch by agent and key
  • ListMemory(ctx, agentID, kind) — list by agent and kind (short_term/long_term)
  • DeleteMemory(ctx, id) — remove by ID

SQLite and PostgreSQL adapters implement these methods.

Complete Example: Memory and Knowledge

package main

import (
"context"
"fmt"
"log"
"os"

"github.com/spawn08/chronos/engine/model"
"github.com/spawn08/chronos/sdk/agent"
"github.com/spawn08/chronos/sdk/knowledge"
"github.com/spawn08/chronos/sdk/memory"
"github.com/spawn08/chronos/storage/adapters/sqlite"
)

func main() {
ctx := context.Background()

store, err := sqlite.New("memory.db")
if err != nil {
log.Fatal(err)
}
defer store.Close()
if err := store.Migrate(ctx); err != nil {
log.Fatal(err)
}

provider := model.NewOpenAI(os.Getenv("OPENAI_API_KEY"))

memStore := memory.NewStore("demo-agent", store)
memMgr := memory.NewManager("demo-agent", "user-1", memStore, provider)

// Optional: add some long-term memories manually
_ = memStore.SetLongTerm(ctx, "favorite_color", "blue")

// Optional: RAG knowledge base (requires VectorStore + EmbeddingsProvider)
// kb := knowledge.NewVectorKnowledge(...)
// kb.AddDocuments(...)
// _ = kb.Load(ctx)

a, err := agent.New("demo-agent", "Demo Agent").
WithModel(provider).
WithStorage(store).
WithMemory(memStore).
WithMemoryManager(memMgr).
// WithKnowledge(kb).
WithSystemPrompt("You are a helpful assistant. Use the user's memories to personalize responses.").
Build()
if err != nil {
log.Fatal(err)
}

// First turn: user shares a fact
resp1, err := a.ChatWithSession(ctx, "session-1", "My name is Bob and I work in San Francisco.")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp1.Content)

// Second turn: agent recalls the fact (extracted by MemoryManager)
resp2, err := a.ChatWithSession(ctx, "session-1", "What do you know about me?")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp2.Content)
}

Complete Example: VectorKnowledge with Qdrant

package main

import (
"context"
"fmt"
"log"
"os"

"github.com/spawn08/chronos/engine/model"
"github.com/spawn08/chronos/sdk/agent"
"github.com/spawn08/chronos/sdk/knowledge"
"github.com/spawn08/chronos/storage/adapters/qdrant"
)

func main() {
ctx := context.Background()

qdrantStore := qdrant.New("http://localhost:6333")
defer qdrantStore.Close()

embedder := model.NewOpenAIEmbeddings(os.Getenv("OPENAI_API_KEY"))
provider := model.NewOpenAI(os.Getenv("OPENAI_API_KEY"))

kb := knowledge.NewVectorKnowledge(
"docs",
1536,
qdrantStore,
embedder,
"text-embedding-3-small",
)
defer kb.Close()

kb.AddDocuments(
knowledge.Document{ID: "1", Content: "Chronos agents use the builder pattern."},
knowledge.Document{ID: "2", Content: "Memory is stored in short-term and long-term stores."},
knowledge.Document{ID: "3", Content: "VectorKnowledge uses embeddings for RAG search."},
)
if err := kb.Load(ctx); err != nil {
log.Fatal(err)
}

a, err := agent.New("rag-agent", "RAG Agent").
WithModel(provider).
WithKnowledge(kb).
WithSystemPrompt("Answer using the provided knowledge. Cite sources when relevant.").
Build()
if err != nil {
log.Fatal(err)
}

resp, err := a.Chat(ctx, "How does Chronos handle memory?")
if err != nil {
log.Fatal(err)
}
fmt.Println(resp.Content)
}