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:
| Field | Type | Description |
|---|---|---|
ID |
string | Unique record ID |
SessionID |
string | Session ID (empty for long-term) |
AgentID |
string | Agent identifier |
UserID |
string | Optional user scope |
Kind |
string | "short_term" or "long_term" |
Key |
string | Memory key |
Value |
any | Stored value (JSON-serializable) |
CreatedAt |
time.Time | Creation 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
}
| Method | Description |
|---|---|
Load |
Index all documents (idempotent) |
Search |
Return top-k relevant documents for a query |
Close |
Release 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:
- Call
Search(ctx, userMessage, 5)with the user’s message - Prepend “Relevant knowledge:” and the top documents to the system context
- 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 memoryGetMemory(ctx, agentID, key)— fetch by agent and keyListMemory(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)
}