Agent Memory
Memory allows agents to maintain context across conversations and recall relevant information from past interactions.
Memory Types
Ductape agents support two types of memory:
| Type | Scope | Storage | Use Case |
|---|---|---|---|
| Short-Term | Current conversation | In-memory | Context within a session |
| Long-Term | All conversations | Vector database | Recall across sessions |
Short-Term Memory
Short-term memory maintains the conversation history within a single session.
Configuration
- TypeScript
- Java
- Go
- .NET
const agent = await ductape.agents.define({
// ...
memory: {
shortTerm: {
maxMessages: 50, // Max messages to keep
truncationStrategy: 'summarize', // How to handle overflow
includeToolResults: true, // Include tool outputs
},
},
});
Map<String, Object> agent = ductape.agents.define(Map.of(
// ...
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 50, // Max messages to keep
"truncationStrategy", "summarize", // How to handle overflow
"includeToolResults", true, // Include tool outputs
)
)
));
agent := client.agents.define({
// ...
memory: {
shortTerm: {
"maxMessages": 50, // Max messages to keep
"truncationStrategy": "summarize", // How to handle overflow
"includeToolResults": true, // Include tool outputs
},
},
});
var agent = await ductape.agents.define({
// ...
memory: {
shortTerm: {
["maxMessages"] = 50, // Max messages to keep
["truncationStrategy"] = "summarize", // How to handle overflow
["includeToolResults"] = true, // Include tool outputs
},
},
});
Options
| Option | Type | Default | Description |
|---|---|---|---|
maxMessages | number | 50 | Maximum messages to retain |
truncationStrategy | string | 'summarize' | How to handle overflow |
includeToolResults | boolean | true | Include tool outputs in history |
summarizeAfter | number | - | Summarize after N messages |
Truncation Strategies
FIFO (First In, First Out)
Removes oldest messages when limit is reached:
- TypeScript
- Java
- Go
- .NET
memory: {
shortTerm: {
maxMessages: 20,
truncationStrategy: 'fifo',
},
}
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 20,
"truncationStrategy", "fifo"
)
)
memory: {
shortTerm: {
"maxMessages": 20,
"truncationStrategy": "fifo",
},
}
memory: {
shortTerm: {
["maxMessages"] = 20,
["truncationStrategy"] = "fifo",
},
}
Sliding Window
Keeps a percentage of recent messages:
- TypeScript
- Java
- Go
- .NET
memory: {
shortTerm: {
maxMessages: 50,
truncationStrategy: 'sliding_window', // Keeps ~80% of maxMessages
},
}
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 50,
"truncationStrategy", "sliding_window", // Keeps ~80% of maxMessages
)
)
memory: {
shortTerm: {
"maxMessages": 50,
"truncationStrategy": "sliding_window", // Keeps ~80% of maxMessages
},
}
memory: {
shortTerm: {
["maxMessages"] = 50,
["truncationStrategy"] = "sliding_window", // Keeps ~80% of maxMessages
},
}
Summarize (Recommended)
Compresses older messages into summaries:
- TypeScript
- Java
- Go
- .NET
memory: {
shortTerm: {
maxMessages: 50,
truncationStrategy: 'summarize',
summarizeAfter: 30, // Start summarizing after 30 messages
},
}
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 50,
"truncationStrategy", "summarize",
"summarizeAfter", 30, // Start summarizing after 30 messages
)
)
memory: {
shortTerm: {
"maxMessages": 50,
"truncationStrategy": "summarize",
"summarizeAfter": 30, // Start summarizing after 30 messages
},
}
memory: {
shortTerm: {
["maxMessages"] = 50,
["truncationStrategy"] = "summarize",
["summarizeAfter"] = 30, // Start summarizing after 30 messages
},
}
Long-Term Memory
Long-term memory uses vector databases to store and retrieve information across sessions.
Setup
- Create a vector database configuration:
- TypeScript
- Java
- Go
- .NET
import { VectorDBType, DistanceMetric } from '@ductape/sdk';
await ductape.vector.create({
name: 'Agent Memory Store',
tag: 'agent-memory',
type: VectorDBType.PINECONE,
dimensions: 1536,
metric: DistanceMetric.COSINE,
envs: [
{
slug: 'dev',
endpoint: 'https://dev-index.pinecone.io',
apiKey: process.env.PINECONE_API_KEY,
index: 'agent-memories',
},
],
});
import Map.of( VectorDBType, DistanceMetric ) from '@ductape/sdk';
ductape.vector.create(Map.of(
"name", "Agent Memory Store",
"tag", "agent-memory",
type: VectorDBType.PINECONE,
"dimensions", 1536,
metric: DistanceMetric.COSINE,
envs: [
Map.of(
"slug", "dev",
"endpoint", "https://dev-index.pinecone.io",
apiKey: System.getenv("PINECONE_API_KEY"),
"index", "agent-memories"
),
]
));
import { VectorDBType, DistanceMetric } from '@ductape/sdk';
client.vector.create({
"name": "Agent Memory Store",
"tag": "agent-memory",
type: VectorDBType.PINECONE,
"dimensions": 1536,
metric: DistanceMetric.COSINE,
envs: [
{
"slug": "dev",
"endpoint": "https://dev-index.pinecone.io",
apiKey: os.Getenv("PINECONE_API_KEY"),
"index": "agent-memories",
},
],
});
import { VectorDBType, DistanceMetric } from '@ductape/sdk';
await ductape.vector.create({
["name"] = "Agent Memory Store",
["tag"] = "agent-memory",
type: VectorDBType.PINECONE,
["dimensions"] = 1536,
metric: DistanceMetric.COSINE,
envs: [
{
["slug"] = "dev",
["endpoint"] = "https://dev-index.pinecone.io",
apiKey: Environment.GetEnvironmentVariable("PINECONE_API_KEY"),
["index"] = "agent-memories",
},
],
});
- Configure the agent with long-term memory:
- TypeScript
- Java
- Go
- .NET
const agent = await ductape.agents.define({
// ...
memory: {
shortTerm: {
maxMessages: 50,
truncationStrategy: 'summarize',
},
longTerm: {
enabled: true,
vectorStore: 'agent-memory', // Reference to vector config
retrieveTopK: 5,
minSimilarity: 0.7,
autoStore: true,
namespace: 'support-agent',
},
},
});
Map<String, Object> agent = ductape.agents.define(Map.of(
// ...
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 50,
"truncationStrategy", "summarize"
),
longTerm: Map.of(
"enabled", true,
"vectorStore", "agent-memory", // Reference to vector config
"retrieveTopK", 5,
"minSimilarity", 0.7,
"autoStore", true,
"namespace", "support-agent"
)
)
));
agent := client.agents.define({
// ...
memory: {
shortTerm: {
"maxMessages": 50,
"truncationStrategy": "summarize",
},
longTerm: {
"enabled": true,
"vectorStore": "agent-memory", // Reference to vector config
"retrieveTopK": 5,
"minSimilarity": 0.7,
"autoStore": true,
"namespace": "support-agent",
},
},
});
var agent = await ductape.agents.define({
// ...
memory: {
shortTerm: {
["maxMessages"] = 50,
["truncationStrategy"] = "summarize",
},
longTerm: {
["enabled"] = true,
["vectorStore"] = "agent-memory", // Reference to vector config
["retrieveTopK"] = 5,
["minSimilarity"] = 0.7,
["autoStore"] = true,
["namespace"] = "support-agent",
},
},
});
Long-Term Memory Options
| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | false | Enable long-term memory |
vectorStore | string | - | Tag of vector database config |
retrieveTopK | number | 5 | Number of memories to retrieve |
minSimilarity | number | 0.7 | Minimum similarity threshold (0-1) |
autoStore | boolean | false | Automatically store interactions |
namespace | string | - | Namespace for memory isolation |
How It Works
- Before each response, the agent queries the vector store for relevant memories
- Retrieved memories are added to the system prompt as context
- After interactions (if autoStore is enabled), important information is stored
User Input
↓
┌─────────────────────┐
│ Query Vector DB │ ← "What's relevant to this input?"
│ for memories │
└─────────────────────┘
↓
┌─────────────────────┐
│ Add memories to │ ← Context injection
│ system prompt │
└─────────────────────┘
↓
┌─────────────────────┐
│ Generate response │
└─────────────────────┘
↓
┌─────────────────────┐
│ Store important │ ← If autoStore enabled
│ information │
└─────────────────────┘
Memory Isolation
By Session
Isolate memories per user or conversation:
- TypeScript
- Java
- Go
- .NET
// Run with sessionId
const result = await ductape.agents.run({
tag: 'support-agent',
input: 'Remember that I prefer email communication',
sessionId: 'user-123', // Isolates memory to this user
});
// Later, same user
const result2 = await ductape.agents.run({
tag: 'support-agent',
input: 'What are my preferences?',
sessionId: 'user-123', // Will recall preferences
});
// Run with sessionId
Map<String, Object> result = ductape.agents().run(Map<String, Object>.of(
"tag", "support-agent",
"input", "Remember that I prefer email communication",
"sessionId", "user-123", // Isolates memory to this user
));
// Later, same user
Map<String, Object> result2 = ductape.agents().run(Map<String, Object>.of(
"tag", "support-agent",
"input", "What are my preferences?",
"sessionId", "user-123", // Will recall preferences
));
// Run with sessionId
result := client.agents.run({
"tag": "support-agent",
"input": "Remember that I prefer email communication",
"sessionId": "user-123", // Isolates memory to this user
});
// Later, same user
result2 := client.agents.run({
"tag": "support-agent",
"input": "What are my preferences?",
"sessionId": "user-123", // Will recall preferences
});
// Run with sessionId
var result = await ductape.agents.run({
["tag"] = "support-agent",
["input"] = "Remember that I prefer email communication",
["sessionId"] = "user-123", // Isolates memory to this user
});
// Later, same user
var result2 = await ductape.agents.run({
["tag"] = "support-agent",
["input"] = "What are my preferences?",
["sessionId"] = "user-123", // Will recall preferences
});
By Namespace
Use namespaces for broader isolation:
- TypeScript
- Java
- Go
- .NET
memory: {
longTerm: {
enabled: true,
vectorStore: 'agent-memory',
namespace: `org-${organizationId}`, // Isolate by organization
},
}
memory: Map.of(
longTerm: Map.of(
"enabled", true,
"vectorStore", "agent-memory",
namespace: `org-$Map.of(organizationId)`, // Isolate by organization
)
)
memory: {
longTerm: {
"enabled": true,
"vectorStore": "agent-memory",
namespace: `org-${organizationId}`, // Isolate by organization
},
}
memory: {
longTerm: {
["enabled"] = true,
["vectorStore"] = "agent-memory",
namespace: `org-${organizationId}`, // Isolate by organization
},
}
Manual Memory Operations
Store Information
Use ctx.remember() in tool handlers:
- TypeScript
- Java
- Go
- .NET
{
tag: 'save-preference',
description: 'Save a user preference',
parameters: {
preference: { type: 'string', required: true },
category: { type: 'string', required: true },
},
handler: async (ctx, params) => {
await ctx.remember({
content: params.preference,
metadata: {
type: 'preference',
category: params.category,
userId: ctx.sessionId,
timestamp: new Date().toISOString(),
},
});
return { saved: true };
},
}
Map.of(
"tag", "save-preference",
"description", "Save a user preference",
parameters: Map.of(
preference: Map.of( "type", "string", "required", true ),
category: Map.of( "type", "string", "required", true )
),
handler: async (ctx, params) => Map.of(
ctx.remember(Map.of(
content: params.preference,
metadata: Map.of(
"type", "preference",
category: params.category,
userId: ctx.sessionId,
timestamp: Instant.now().toISOString()
)
));
return Map.of( "saved", true );
)
)
import "context"
{
"tag": "save-preference",
"description": "Save a user preference",
parameters: {
preference: { "type": "string", "required": true },
category: { "type": "string", "required": true },
},
handler: async (ctx, params) => {
ctx.remember({
content: params.preference,
metadata: {
"type": "preference",
category: params.category,
userId: ctx.sessionId,
timestamp: new Date().toISOString(),
},
});
return { "saved": true };
},
}
{
["tag"] = "save-preference",
["description"] = "Save a user preference",
parameters: {
preference: { ["type"] = "string", ["required"] = true },
category: { ["type"] = "string", ["required"] = true },
},
handler: async (ctx, params) => {
await ctx.remember({
content: params.preference,
metadata: {
["type"] = "preference",
category: params.category,
userId: ctx.sessionId,
timestamp: DateTime.UtcNow.toISOString(),
},
});
return { ["saved"] = true };
},
}
Retrieve Information
Use ctx.recall() in tool handlers:
- TypeScript
- Java
- Go
- .NET
{
tag: 'get-preferences',
description: 'Get user preferences',
parameters: {
category: { type: 'string' },
},
handler: async (ctx, params) => {
const memories = await ctx.recall({
query: `${params.category || 'user'} preferences`,
topK: 10,
filter: {
type: 'preference',
userId: ctx.sessionId,
},
minScore: 0.6,
});
return {
preferences: memories.matches.map((m) => ({
content: m.metadata?.content,
category: m.metadata?.category,
relevance: m.score,
})),
};
},
}
Map.of(
"tag", "get-preferences",
"description", "Get user preferences",
parameters: Map.of(
category: Map.of( "type", "string" )
),
handler: async (ctx, params) => Map.of(
Map<String, Object> memories = ctx.recall(Map.of(
query: `$Map.of(params.category || 'user') preferences`,
"topK", 10,
filter: Map.of(
"type", "preference",
userId: ctx.sessionId
),
"minScore", 0.6
));
return Map.of(
preferences: memories.matches.map((m) => (Map.of(
content: m.metadata?.content,
category: m.metadata?.category,
relevance: m.score
)))
);
)
)
import "context"
{
"tag": "get-preferences",
"description": "Get user preferences",
parameters: {
category: { "type": "string" },
},
handler: async (ctx, params) => {
memories := ctx.recall({
query: `${params.category || 'user'} preferences`,
"topK": 10,
filter: {
"type": "preference",
userId: ctx.sessionId,
},
"minScore": 0.6,
});
return {
preferences: memories.matches.map((m) => ({
content: m.metadata?.content,
category: m.metadata?.category,
relevance: m.score,
})),
};
},
}
{
["tag"] = "get-preferences",
["description"] = "Get user preferences",
parameters: {
category: { ["type"] = "string" },
},
handler: async (ctx, params) => {
var memories = await ctx.recall({
query: `${params.category || 'user'} preferences`,
["topK"] = 10,
filter: {
["type"] = "preference",
userId: ctx.sessionId,
},
["minScore"] = 0.6,
});
return {
preferences: memories.matches.map((m) => ({
content: m.metadata?.content,
category: m.metadata?.category,
relevance: m.score,
})),
};
},
}
Memory Patterns
Customer Context
Remember customer information across interactions:
- TypeScript
- Java
- Go
- .NET
const agent = await ductape.agents.define({
tag: 'customer-agent',
name: 'Customer Service Agent',
systemPrompt: `You are a customer service agent.
Use your memory to provide personalized service.
Remember important details about customers for future interactions.`,
memory: {
shortTerm: { maxMessages: 30 },
longTerm: {
enabled: true,
vectorStore: 'customer-memory',
autoStore: true,
},
},
tools: [
{
tag: 'note-customer-issue',
description: 'Record a customer issue for future reference',
parameters: {
issue: { type: 'string', required: true },
resolution: { type: 'string' },
severity: { type: 'string', enum: ['low', 'medium', 'high'] },
},
handler: async (ctx, params) => {
await ctx.remember({
content: `Customer issue: ${params.issue}. Resolution: ${params.resolution || 'Pending'}`,
metadata: {
type: 'customer_issue',
customerId: ctx.sessionId,
severity: params.severity,
resolved: !!params.resolution,
timestamp: new Date().toISOString(),
},
});
return { recorded: true };
},
},
],
});
Map<String, Object> agent = ductape.agents.define(Map.of(
"tag", "customer-agent",
"name", "Customer Service Agent",
systemPrompt: `You are a customer service agent.
Use your memory to provide personalized service.
Remember important details about customers for future interactions.`,
memory: Map.of(
shortTerm: Map.of( "maxMessages", 30 ),
longTerm: Map.of(
"enabled", true,
"vectorStore", "customer-memory",
"autoStore", true
)
),
tools: [
Map.of(
"tag", "note-customer-issue",
"description", "Record a customer issue for future reference",
parameters: Map.of(
issue: Map.of( "type", "string", "required", true ),
resolution: Map.of( "type", "string" ),
severity: Map.of( "type", "string", enum: ['low', 'medium', 'high'] )
),
handler: async (ctx, params) => Map.of(
ctx.remember(Map.of(
content: `Customer issue: $Map.of(params.issue). Resolution: $Map.of(params.resolution || 'Pending')`,
metadata: Map.of(
"type", "customer_issue",
customerId: ctx.sessionId,
severity: params.severity,
resolved: !!params.resolution,
timestamp: Instant.now().toISOString()
)
));
return Map.of( "recorded", true );
)
),
]
));
import "context"
agent := client.agents.define({
"tag": "customer-agent",
"name": "Customer Service Agent",
systemPrompt: `You are a customer service agent.
Use your memory to provide personalized service.
Remember important details about customers for future interactions.`,
memory: {
shortTerm: { "maxMessages": 30 },
longTerm: {
"enabled": true,
"vectorStore": "customer-memory",
"autoStore": true,
},
},
tools: [
{
"tag": "note-customer-issue",
"description": "Record a customer issue for future reference",
parameters: {
issue: { "type": "string", "required": true },
resolution: { "type": "string" },
severity: { "type": "string", enum: ['low', 'medium', 'high'] },
},
handler: async (ctx, params) => {
ctx.remember({
content: `Customer issue: ${params.issue}. Resolution: ${params.resolution || 'Pending'}`,
metadata: {
"type": "customer_issue",
customerId: ctx.sessionId,
severity: params.severity,
resolved: !!params.resolution,
timestamp: new Date().toISOString(),
},
});
return { "recorded": true };
},
},
],
});
var agent = await ductape.agents.define({
["tag"] = "customer-agent",
["name"] = "Customer Service Agent",
systemPrompt: `You are a customer service agent.
Use your memory to provide personalized service.
Remember important details about customers for future interactions.`,
memory: {
shortTerm: { ["maxMessages"] = 30 },
longTerm: {
["enabled"] = true,
["vectorStore"] = "customer-memory",
["autoStore"] = true,
},
},
tools: [
{
["tag"] = "note-customer-issue",
["description"] = "Record a customer issue for future reference",
parameters: {
issue: { ["type"] = "string", ["required"] = true },
resolution: { ["type"] = "string" },
severity: { ["type"] = "string", enum: ['low', 'medium', 'high'] },
},
handler: async (ctx, params) => {
await ctx.remember({
content: `Customer issue: ${params.issue}. Resolution: ${params.resolution || 'Pending'}`,
metadata: {
["type"] = "customer_issue",
customerId: ctx.sessionId,
severity: params.severity,
resolved: !!params.resolution,
timestamp: DateTime.UtcNow.toISOString(),
},
});
return { ["recorded"] = true };
},
},
],
});
Knowledge Base Search
Use memory as a searchable knowledge base:
- TypeScript
- Java
- Go
- .NET
const agent = await ductape.agents.define({
tag: 'knowledge-agent',
name: 'Knowledge Base Agent',
systemPrompt: `You are a helpful assistant with access to a knowledge base.
Search for relevant information before answering questions.`,
memory: {
shortTerm: { maxMessages: 20 },
longTerm: {
enabled: true,
vectorStore: 'knowledge-base',
retrieveTopK: 5,
minSimilarity: 0.75,
},
},
tools: [
{
tag: 'search-knowledge',
description: 'Search the knowledge base for relevant information',
parameters: {
query: { type: 'string', required: true },
category: { type: 'string' },
},
handler: async (ctx, params) => {
const results = await ctx.recall({
query: params.query,
topK: 10,
filter: params.category ? { category: params.category } : undefined,
minScore: 0.7,
});
if (results.matches.length === 0) {
return { found: false, message: 'No relevant information found' };
}
return {
found: true,
results: results.matches.map((m) => ({
title: m.metadata?.title,
content: m.metadata?.content,
relevance: m.score,
})),
};
},
},
],
});
Map<String, Object> agent = ductape.agents.define(Map.of(
"tag", "knowledge-agent",
"name", "Knowledge Base Agent",
systemPrompt: `You are a helpful assistant with access to a knowledge base.
Search for relevant information before answering questions.`,
memory: Map.of(
shortTerm: Map.of( "maxMessages", 20 ),
longTerm: Map.of(
"enabled", true,
"vectorStore", "knowledge-base",
"retrieveTopK", 5,
"minSimilarity", 0.75
)
),
tools: [
Map.of(
"tag", "search-knowledge",
"description", "Search the knowledge base for relevant information",
parameters: Map.of(
query: Map.of( "type", "string", "required", true ),
category: Map.of( "type", "string" )
),
handler: async (ctx, params) => Map.of(
Map<String, Object> results = ctx.recall(Map.of(
query: params.query,
"topK", 10,
filter: params.category ? Map.of( category: params.category ) : undefined,
"minScore", 0.7
));
if (results.matches.length === 0) Map.of(
return Map.of( "found", false, "message", "No relevant information found" );
)
return Map.of(
"found", true,
results: results.matches.map((m) => (Map.of(
title: m.metadata?.title,
content: m.metadata?.content,
relevance: m.score
)))
);
)
),
]
));
import "context"
agent := client.agents.define({
"tag": "knowledge-agent",
"name": "Knowledge Base Agent",
systemPrompt: `You are a helpful assistant with access to a knowledge base.
Search for relevant information before answering questions.`,
memory: {
shortTerm: { "maxMessages": 20 },
longTerm: {
"enabled": true,
"vectorStore": "knowledge-base",
"retrieveTopK": 5,
"minSimilarity": 0.75,
},
},
tools: [
{
"tag": "search-knowledge",
"description": "Search the knowledge base for relevant information",
parameters: {
query: { "type": "string", "required": true },
category: { "type": "string" },
},
handler: async (ctx, params) => {
results := ctx.recall({
query: params.query,
"topK": 10,
filter: params.category ? { category: params.category } : undefined,
"minScore": 0.7,
});
if (results.matches.length === 0) {
return { "found": false, "message": "No relevant information found" };
}
return {
"found": true,
results: results.matches.map((m) => ({
title: m.metadata?.title,
content: m.metadata?.content,
relevance: m.score,
})),
};
},
},
],
});
var agent = await ductape.agents.define({
["tag"] = "knowledge-agent",
["name"] = "Knowledge Base Agent",
systemPrompt: `You are a helpful assistant with access to a knowledge base.
Search for relevant information before answering questions.`,
memory: {
shortTerm: { ["maxMessages"] = 20 },
longTerm: {
["enabled"] = true,
["vectorStore"] = "knowledge-base",
["retrieveTopK"] = 5,
["minSimilarity"] = 0.75,
},
},
tools: [
{
["tag"] = "search-knowledge",
["description"] = "Search the knowledge base for relevant information",
parameters: {
query: { ["type"] = "string", ["required"] = true },
category: { ["type"] = "string" },
},
handler: async (ctx, params) => {
var results = await ctx.recall({
query: params.query,
["topK"] = 10,
filter: params.category ? { category: params.category } : undefined,
["minScore"] = 0.7,
});
if (results.matches.length === 0) {
return { ["found"] = false, ["message"] = "No relevant information found" };
}
return {
["found"] = true,
results: results.matches.map((m) => ({
title: m.metadata?.title,
content: m.metadata?.content,
relevance: m.score,
})),
};
},
},
],
});
Conversation Summaries
Store conversation summaries for long-term context:
- TypeScript
- Java
- Go
- .NET
const agent = await ductape.agents.define({
tag: 'summary-agent',
name: 'Agent with Summaries',
systemPrompt: 'You are a helpful assistant that remembers past conversations.',
memory: {
shortTerm: {
maxMessages: 30,
truncationStrategy: 'summarize',
},
longTerm: {
enabled: true,
vectorStore: 'conversation-summaries',
autoStore: true,
},
},
tools: [
{
tag: 'summarize-conversation',
description: 'Save a summary of the current conversation',
parameters: {
summary: { type: 'string', required: true },
topics: { type: 'array', items: { type: 'string' } },
},
handler: async (ctx, params) => {
await ctx.remember({
content: params.summary,
metadata: {
type: 'conversation_summary',
sessionId: ctx.sessionId,
topics: params.topics,
timestamp: new Date().toISOString(),
},
});
return { saved: true };
},
},
],
});
Map<String, Object> agent = ductape.agents.define(Map.of(
"tag", "summary-agent",
"name", "Agent with Summaries",
"systemPrompt", "You are a helpful assistant that remembers past conversations.",
memory: Map.of(
shortTerm: Map.of(
"maxMessages", 30,
"truncationStrategy", "summarize"
),
longTerm: Map.of(
"enabled", true,
"vectorStore", "conversation-summaries",
"autoStore", true
)
),
tools: [
Map.of(
"tag", "summarize-conversation",
"description", "Save a summary of the current conversation",
parameters: Map.of(
summary: Map.of( "type", "string", "required", true ),
topics: Map.of( "type", "array", items: Map.of( "type", "string" ) )
),
handler: async (ctx, params) => Map.of(
ctx.remember(Map.of(
content: params.summary,
metadata: Map.of(
"type", "conversation_summary",
sessionId: ctx.sessionId,
topics: params.topics,
timestamp: Instant.now().toISOString()
)
));
return Map.of( "saved", true );
)
),
]
));
import "context"
agent := client.agents.define({
"tag": "summary-agent",
"name": "Agent with Summaries",
"systemPrompt": "You are a helpful assistant that remembers past conversations.",
memory: {
shortTerm: {
"maxMessages": 30,
"truncationStrategy": "summarize",
},
longTerm: {
"enabled": true,
"vectorStore": "conversation-summaries",
"autoStore": true,
},
},
tools: [
{
"tag": "summarize-conversation",
"description": "Save a summary of the current conversation",
parameters: {
summary: { "type": "string", "required": true },
topics: { "type": "array", items: { "type": "string" } },
},
handler: async (ctx, params) => {
ctx.remember({
content: params.summary,
metadata: {
"type": "conversation_summary",
sessionId: ctx.sessionId,
topics: params.topics,
timestamp: new Date().toISOString(),
},
});
return { "saved": true };
},
},
],
});
var agent = await ductape.agents.define({
["tag"] = "summary-agent",
["name"] = "Agent with Summaries",
["systemPrompt"] = "You are a helpful assistant that remembers past conversations.",
memory: {
shortTerm: {
["maxMessages"] = 30,
["truncationStrategy"] = "summarize",
},
longTerm: {
["enabled"] = true,
["vectorStore"] = "conversation-summaries",
["autoStore"] = true,
},
},
tools: [
{
["tag"] = "summarize-conversation",
["description"] = "Save a summary of the current conversation",
parameters: {
summary: { ["type"] = "string", ["required"] = true },
topics: { ["type"] = "array", items: { ["type"] = "string" } },
},
handler: async (ctx, params) => {
await ctx.remember({
content: params.summary,
metadata: {
["type"] = "conversation_summary",
sessionId: ctx.sessionId,
topics: params.topics,
timestamp: DateTime.UtcNow.toISOString(),
},
});
return { ["saved"] = true };
},
},
],
});
Best Practices
1. Choose Appropriate Similarity Thresholds
- TypeScript
- Java
- Go
- .NET
// Strict - only very relevant memories
minSimilarity: 0.85
// Balanced - good relevance with some flexibility
minSimilarity: 0.7
// Lenient - cast a wider net
minSimilarity: 0.5
// Strict - only very relevant memories
"minSimilarity", 0.85
// Balanced - good relevance with some flexibility
"minSimilarity", 0.7
// Lenient - cast a wider net
"minSimilarity", 0.5
// Strict - only very relevant memories
"minSimilarity": 0.85
// Balanced - good relevance with some flexibility
"minSimilarity": 0.7
// Lenient - cast a wider net
"minSimilarity": 0.5
// Strict - only very relevant memories
["minSimilarity"] = 0.85
// Balanced - good relevance with some flexibility
["minSimilarity"] = 0.7
// Lenient - cast a wider net
["minSimilarity"] = 0.5
2. Limit Retrieved Memories
Too many memories can confuse the agent:
- TypeScript
- Java
- Go
- .NET
// Good - focused context
retrieveTopK: 3
// Acceptable - broader context
retrieveTopK: 5
// Risky - may overwhelm
retrieveTopK: 20
// Good - focused context
"retrieveTopK", 3
// Acceptable - broader context
"retrieveTopK", 5
// Risky - may overwhelm
"retrieveTopK", 20
// Good - focused context
"retrieveTopK": 3
// Acceptable - broader context
"retrieveTopK": 5
// Risky - may overwhelm
"retrieveTopK": 20
// Good - focused context
["retrieveTopK"] = 3
// Acceptable - broader context
["retrieveTopK"] = 5
// Risky - may overwhelm
["retrieveTopK"] = 20
3. Use Meaningful Metadata
- TypeScript
- Java
- Go
- .NET
await ctx.remember({
content: 'User prefers dark mode',
metadata: {
type: 'preference', // Categorical
category: 'ui', // Subcategory
userId: ctx.sessionId, // Ownership
importance: 'high', // Priority
timestamp: new Date().toISOString(), // Time
source: 'explicit', // How it was learned
},
});
ctx.remember(Map.of(
"content", "User prefers dark mode",
metadata: Map.of(
"type", "preference", // Categorical
"category", "ui", // Subcategory
userId: ctx.sessionId, // Ownership
"importance", "high", // Priority
timestamp: Instant.now().toISOString(), // Time
"source", "explicit", // How it was learned
)
));
ctx.remember({
"content": "User prefers dark mode",
metadata: {
"type": "preference", // Categorical
"category": "ui", // Subcategory
userId: ctx.sessionId, // Ownership
"importance": "high", // Priority
timestamp: new Date().toISOString(), // Time
"source": "explicit", // How it was learned
},
});
await ctx.remember({
["content"] = "User prefers dark mode",
metadata: {
["type"] = "preference", // Categorical
["category"] = "ui", // Subcategory
userId: ctx.sessionId, // Ownership
["importance"] = "high", // Priority
timestamp: DateTime.UtcNow.toISOString(), // Time
["source"] = "explicit", // How it was learned
},
});
4. Clean Up Old Memories
Periodically remove outdated information:
- TypeScript
- Java
- Go
- .NET
// In a maintenance job
await ductape.vector.deleteVectors({
tag: 'agent-memory',
filter: {
timestamp: { $lt: thirtyDaysAgo },
type: 'temporary',
},
});
// In a maintenance job
ductape.vector.deleteVectors(Map.of(
"tag", "agent-memory",
filter: Map.of(
timestamp: Map.of( $lt: thirtyDaysAgo ),
"type", "temporary"
)
));
// In a maintenance job
client.vector.deleteVectors({
"tag": "agent-memory",
filter: {
timestamp: { $lt: thirtyDaysAgo },
"type": "temporary",
},
});
// In a maintenance job
await ductape.vector.deleteVectors({
["tag"] = "agent-memory",
filter: {
timestamp: { $lt: thirtyDaysAgo },
["type"] = "temporary",
},
});
Next Steps
- Human-in-the-Loop - Add approval features
- Vectors - Learn more about vector databases
- Examples - See memory patterns in action