
Security News
Open VSX Begins Implementing Pre-Publish Security Checks After Repeated Supply Chain Incidents
Following multiple malicious extension incidents, Open VSX outlines new safeguards designed to catch risky uploads earlier.
trpc.group/trpc-go/trpc-agent-go/examples/memory
Advanced tools
This example demonstrates intelligent memory management using the Runner orchestration component with streaming output, session management, and comprehensive memory tool calling functionality.
Important: This example has been updated to use the new two-step memory integration approach. The old llmagent.WithMemory() method is no longer supported.
llmagent.WithMemory(memoryService) - automatic memory tool registrationllmagent.WithTools(memoryService.Tools()) - manual tool registrationrunner.WithMemoryService(memoryService) - service management in runnerThis change provides better separation of concerns and explicit control over memory tool registration.
This implementation showcases the essential features for building AI applications with persistent memory capabilities:
This implementation follows principles for better separation of concerns and explicit control:
llmagent.WithTools(memoryService.Tools())runner.WithMemoryService(memoryService)The memory functionality is integrated using a two-step approach:
// Create memory service with default tools enabled
memoryService := memoryinmemory.NewMemoryService(
// Disable specific tools if needed
memoryinmemory.WithToolEnabled(memory.DeleteToolName, false),
// Use custom tool implementations
memoryinmemory.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Create LLM agent with manual memory tool registration
llmAgent := llmagent.New(
agentName,
llmagent.WithModel(modelInstance),
llmagent.WithTools(memoryService.Tools()), // Step 1: Register memory tools
)
// Create runner with memory service
runner := runner.NewRunner(
appName,
llmAgent,
runner.WithSessionService(sessionService),
runner.WithMemoryService(memoryService), // Step 2: Set memory service in runner
)
By default, the following memory tools are enabled:
| Tool Name | Default Status | Description |
|---|---|---|
memory_add | β Enabled | Add a new memory entry |
memory_update | β Enabled | Update an existing memory |
memory_search | β Enabled | Search memories by query |
memory_load | β Enabled | Load recent memories |
memory_delete | β Disabled | Delete a memory entry |
memory_clear | β Disabled | Clear all memories for a user |
Memory tools automatically get appName and userID from the execution context at runtime:
appName and userID in the context valuesThis design provides:
The following memory tools are manually registered via memoryService.Tools():
| Tool Name | Description | Parameters |
|---|---|---|
memory_add | Add a new memory entry | memory (string, required), topics (array of strings, optional) |
memory_update | Update an existing memory | memory_id (string, required), memory (string, required), topics (array of strings, optional) |
memory_delete | Delete a memory entry | memory_id (string, required) |
memory_clear | Clear all memories for a user | None |
memory_search | Search memories by query | query (string, required) |
memory_load | Load recent memories | limit (number, optional, default: 10) |
| Variable | Description | Default Value |
|---|---|---|
OPENAI_API_KEY | API key for the model service (required) | `` |
OPENAI_BASE_URL | Base URL for the model API endpoint | https://api.openai.com/v1 |
| Variable | Description | Default Value |
|---|---|---|
REDIS_ADDR | Redis server address | localhost:6379 |
PG_HOST | PostgreSQL host | localhost |
PG_PORT | PostgreSQL port | 5432 |
PG_USER | PostgreSQL user | postgres |
PG_PASSWORD | PostgreSQL password | my-secret-pw |
PG_DATABASE | PostgreSQL database name | postgres |
MYSQL_HOST | MySQL host | localhost |
MYSQL_PORT | MySQL port | 3306 |
MYSQL_USER | MySQL user | root |
MYSQL_PASSWORD | MySQL password | `` |
MYSQL_DATABASE | MySQL database name | trpc_agent_go |
| Argument | Description | Default Value |
|---|---|---|
-model | Name of the model to use | deepseek-chat |
-memory | Memory service: inmemory, redis, mysql, or postgres | inmemory |
-soft-delete | Enable soft delete for MySQL/PostgreSQL memory service | false |
-streaming | Enable streaming mode for responses | true |
cd examples/memory
export OPENAI_API_KEY="your-api-key-here"
go run .
export OPENAI_API_KEY="your-api-key"
go run . -model gpt-4o
If you have MODEL_NAME set in your environment:
source ~/.bashrc && go run . -model "$MODEL_NAME"
Choose between streaming and non-streaming responses:
# Default streaming mode (real-time character output)
go run .
# Non-streaming mode (complete response at once)
go run . -streaming=false
# Combined with other options
go run . -model gpt-4o -streaming=false
When to use each mode:
-streaming=true, default): Best for interactive chat where you want to see responses appear in real-time, providing immediate feedback and better user experience.-streaming=false): Better for automated scripts, batch processing, or when you need the complete response before processing it further.The example supports four memory service backends: in-memory, Redis, MySQL, and PostgreSQL, while always using in-memory session service for simplicity:
# Default in-memory memory service
go run .
# Redis memory service (using default or environment variable)
go run . -memory redis
# MySQL memory service (using environment variables)
export MYSQL_HOST=localhost
export MYSQL_PORT=3306
export MYSQL_USER=root
export MYSQL_PASSWORD=password
export MYSQL_DATABASE=trpc_agent_go
go run . -memory mysql
# PostgreSQL memory service (using environment variables)
export PG_HOST=localhost
export PG_PORT=5432
export PG_USER=postgres
export PG_PASSWORD=my-secret-pw
export PG_DATABASE=postgres
go run . -memory postgres
Available service combinations:
| Memory Service | Session Service | Status | Description |
|---|---|---|---|
inmemory | inmemory | β Ready | Default configuration |
redis | inmemory | β Ready | Redis memory + in-memory session |
mysql | inmemory | β Ready | MySQL memory + in-memory session (env vars required) |
postgres | inmemory | β Ready | PostgreSQL memory + in-memory session (env vars required) |
To see all available command line options:
go run . --help
Output:
Usage of ./memory_example:
-memory string
Name of the memory service to use inmemory / redis / mysql / postgres (default "inmemory")
-model string
Name of the model to use (default "deepseek-chat")
-soft-delete
Enable soft delete for MySQL/PostgreSQL memory service (default false)
-streaming
Enable streaming mode for responses (default true)
Note: Database connection parameters (host, port, user, password, database) are configured via environment variables. See the Environment Variables section above for details.
The memory service comes with sensible defaults:
// Default enabled tools: add, update, search, load
// Default disabled tools: delete, clear
memoryService := memoryinmemory.NewMemoryService()
// You can enable disabled tools if needed:
// memoryService := memoryinmemory.NewMemoryService(
// memoryinmemory.WithToolEnabled(memory.DeleteToolName, true),
// memoryinmemory.WithToolEnabled(memory.ClearToolName, true),
// )
You can enable or disable specific tools:
memoryService := memoryinmemory.NewMemoryService(
// Enable disabled tools
memoryinmemory.WithToolEnabled(memory.DeleteToolName, true),
memoryinmemory.WithToolEnabled(memory.ClearToolName, true),
// Or disable enabled tools
memoryinmemory.WithToolEnabled(memory.AddToolName, false),
)
Notes:
memory_add, memory_update, memory_search, and memory_load are enabled; memory_delete and memory_clear are disabled. Control them with WithToolEnabled(...). The builderβs enabledTools argument reflects this list.defaultPrompt.// Redis service: enable delete tool.
memoryService, err := memoryredis.NewService(
memoryredis.WithRedisClientURL("redis://localhost:6379"),
memoryredis.WithToolEnabled(memory.DeleteToolName, true),
)
if err != nil {
// Handle error appropriately.
}
You can override default tool implementations with custom ones:
import (
"context"
"fmt"
"trpc.group/trpc-go/trpc-agent-go/memory"
toolmemory "trpc.group/trpc-go/trpc-agent-go/memory/tool"
"trpc.group/trpc-go/trpc-agent-go/tool"
"trpc.group/trpc-go/trpc-agent-go/tool/function"
)
// Custom clear tool with enhanced logging.
func customClearMemoryTool() tool.Tool {
clearFunc := func(ctx context.Context, _ *toolmemory.ClearMemoryRequest) (*toolmemory.ClearMemoryResponse, error) {
// Get memory service and user info from invocation context.
memSvc, err := toolmemory.GetMemoryServiceFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("custom clear tool: %w", err)
}
appName, userID, err := toolmemory.GetAppAndUserFromContext(ctx)
if err != nil {
return nil, fmt.Errorf("custom clear tool: %w", err)
}
if err := memSvc.ClearMemories(ctx, memory.UserKey{AppName: appName, UserID: userID}); err != nil {
return nil, fmt.Errorf("custom clear tool: failed to clear memories: %w", err)
}
return &toolmemory.ClearMemoryResponse{Message: "π All memories cleared successfully with custom magic! β¨"}, nil
}
return function.NewFunctionTool(
clearFunc,
function.WithName(memory.ClearToolName),
function.WithDescription("π§Ή Custom clear tool: Clear all memories for the user with extra sparkle! β¨"),
)
}
// Use custom tool
memoryService := memoryinmemory.NewMemoryService(
memoryinmemory.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Or register the custom tool for Redis service.
memoryService, err := memoryredis.NewService(
memoryredis.WithRedisClientURL("redis://localhost:6379"),
memoryredis.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
if err != nil {
// Handle error appropriately.
}
Custom tools use the ToolCreator pattern to avoid circular dependencies:
type ToolCreator func() tool.Tool
// Example custom tool
func myCustomAddTool() tool.Tool {
// Implementation that gets memory service from context
return function.NewFunctionTool(/* ... */)
}
// Register custom tool
memoryService := memoryinmemory.NewMemoryService(
memoryinmemory.WithCustomTool(memory.AddToolName, myCustomAddTool),
)
When you share information or ask about memories in a new session, you'll see:
π§ Memory tool calls initiated:
β’ memory_add (ID: call_abc123)
Args: {"memory":"User's name is John and they like coffee","topics":["name","preferences"]}
π Executing memory tools...
β
Memory tool response (ID: call_abc123): {"success":true,"message":"Memory added successfully","memory":"User's name is John and they like coffee","topics":["name","preferences"]}
π€ Assistant: I'll remember that your name is John and you like coffee!
When using custom tools in a new session, you'll see enhanced output:
π§Ή [Custom Clear Tool] Clearing memories with extra sparkle... β¨
π§ Memory tool calls initiated:
β’ memory_clear (ID: call_def456)
Args: {}
π Executing memory tools...
β
Memory tool response (ID: call_def456): {"success":true,"message":"π All memories cleared successfully with custom magic! β¨"}
π€ Assistant: All your memories have been cleared with extra sparkle! β¨
π€ You: /new
π Started new memory session!
Previous: memory-session-1703123457
Current: memory-session-1703123458
(Memory and conversation history have been reset)
π€ You: What do you remember about me?
π€ Assistant: Let me check what I remember about you.
π§ Memory tool calls initiated:
β’ memory_search (ID: call_ghi789)
Args: {"query":"John"}
π Executing memory tools...
β
Memory tool response (ID: call_ghi789): {"success":true,"query":"John","count":0,"results":[]}
I don't have any memories about you yet. Could you tell me something about yourself so I can remember it for future conversations?
The interface is simple and intuitive:
π§ Multi Turn Chat with Memory
Model: gpt-4o-mini
Memory Service: inmemory
Streaming: true
Available tools: memory_add, memory_update, memory_search, memory_load
(memory_delete, memory_clear disabled by default)
==================================================
β
Memory chat ready! Session: memory-session-1703123456
Memory Service: inmemory
π‘ Special commands:
/memory - Show user memories
/new - Start a new session
/exit - End the conversation
π€ You: Hello! My name is John and I like coffee.
π€ Assistant: Hello John! Nice to meet you. I'll remember that you like coffee.
π€ You: /new
π Started new memory session!
Previous: memory-session-1703123456
Current: memory-session-1703123457
(Memory and conversation history have been reset)
π€ You: What do you remember about me?
π€ Assistant: Let me check what I remember about you.
π§ Memory tool calls initiated:
β’ memory_search (ID: call_def456)
Args: {"query":"John"}
π Executing memory tools...
β
Memory tool response (ID: call_def456): {"success":true,"query":"John","count":1,"results":[{"id":"abc123","memory":"User's name is John and they like coffee","topics":["name","preferences"],"created":"2025-01-28 20:30:00"}]}
Based on my memory, I know:
- Your name is John
- You like coffee
π€ You: /exit
π Goodbye!
/memory - Ask the agent to show stored memories/new - Start a new session (resets conversation context and memory)/exit - End the conversationNote: Use /new to reset the session when you want to test memory persistence. In the same session, the LLM maintains conversation context, so memory tools may not be called if the information is already in the conversation history.
The LLM agent automatically decides when to store important information about users based on the conversation context.
The agent can search for and retrieve relevant memories when users ask questions or need information recalled.
Memories are stored in-memory and persist across conversation turns within the same session.
All memory operations are clearly displayed, showing:
Custom tools can provide enhanced functionality:
memoryinmemory.NewMemoryService() for in-memory storagememoryredis.NewService() for Redis-based storagememorymysql.NewService() for MySQL-based storagememorypostgres.NewService() for PostgreSQL-based storageThe memory tools are manually registered for explicit control:
// Create memory service with custom configuration
memoryService := memoryinmemory.NewMemoryService(
memoryinmemory.WithToolEnabled(memory.DeleteToolName, false),
memoryinmemory.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Create LLM agent with manual memory tool registration
llmAgent := llmagent.New(
agentName,
llmagent.WithModel(modelInstance),
llmagent.WithTools(memoryService.Tools()), // Step 1: Register memory tools
)
// Create runner with memory service
runner := runner.NewRunner(
appName,
llmAgent,
runner.WithSessionService(sessionService),
runner.WithMemoryService(memoryService), // Step 2: Set memory service
)
Memory tools are created lazily when first requested:
sync.RWMutex for concurrent accessCustom tools use a factory pattern to avoid circular dependencies:
// ToolCreator type for creating tools
type ToolCreator func() tool.Tool
// Default tool creators
var defaultEnabledTools = map[string]ToolCreator{
memory.AddToolName: toolmemory.NewAddTool,
memory.UpdateToolName: toolmemory.NewUpdateTool,
// ... other tools
}
// Custom tool registration
memoryinmemory.WithCustomTool(memory.ClearToolName, customClearMemoryTool)
Default Tools:
Custom Tools: You can override default tools with custom implementations. Refer to the customClearMemoryTool example above, and follow the same pattern (imports + context helpers) for add/update/delete/search/load.
User Input β Runner β Agent β Memory Tools β Memory Service β Response
The example now supports Redis-based memory service for persistent storage:
// Redis memory service
memoryService, err := memoryredis.NewService(
memoryredis.WithRedisClientURL("redis://localhost:6379"),
memoryredis.WithToolEnabled(memory.DeleteToolName, false),
memoryredis.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Session service always uses in-memory for simplicity
sessionService := sessioninmemory.NewSessionService()
Benefits of Redis support:
To use Redis memory service, you need a running Redis instance:
# Start Redis with Docker (recommended for testing)
docker run -d --name redis-memory -p 6379:6379 redis:7-alpine
Usage examples:
# Connect to default Redis (localhost:6379)
go run . -memory redis
# Connect to custom Redis address via environment variable
export REDIS_ADDR=localhost:6380
go run . -memory redis
# Connect to Redis with authentication via environment variable
export REDIS_ADDR=redis://username:password@localhost:6379
go run . -memory redis
The example supports MySQL-based memory service for persistent relational storage:
// MySQL memory service
// DSN is built from environment variables: MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE
memoryService, err := memorymysql.NewService(
memorymysql.WithMySQLClientDSN("user:password@tcp(localhost:3306)/dbname?parseTime=true&charset=utf8mb4"),
memorymysql.WithToolEnabled(memory.DeleteToolName, false),
memorymysql.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Session service always uses in-memory for simplicity
sessionService := sessioninmemory.NewSessionService()
Benefits of MySQL support:
To use MySQL memory service, you need a running MySQL instance:
# Start MySQL with Docker (recommended for testing)
docker run -d --name mysql-memory \
-e MYSQL_ROOT_PASSWORD=password \
-e MYSQL_DATABASE=memory_db \
-p 3306:3306 \
mysql:8.0
# Wait for MySQL to be ready
docker exec mysql-memory mysqladmin ping -h localhost -u root -ppassword
Usage examples:
# Minimal setup (using defaults)
export MYSQL_PASSWORD=password
go run . -memory mysql
# Custom configuration
export MYSQL_HOST=localhost
export MYSQL_PORT=3306
export MYSQL_USER=root
export MYSQL_PASSWORD=password
export MYSQL_DATABASE=memory_db
go run . -memory mysql
# Using environment variables
export MYSQL_HOST=localhost
export MYSQL_PORT=3307
export MYSQL_USER=root
export MYSQL_PASSWORD=password
export MYSQL_DATABASE=memory_db
go run . -memory mysql
# Connect with custom table name (via code configuration)
# See memorymysql.WithTableName() option in the code
Connection String:
The MySQL connection string is automatically built from environment variables:
[username[:password]@][protocol[(address)]]/dbname?parseTime=true&charset=utf8mb4
Common connection parameters:
parseTime=true - Parse DATE and DATETIME to time.Time (required)charset=utf8mb4 - Character setTable Schema:
The MySQL memory service automatically creates the following table structure:
CREATE TABLE IF NOT EXISTS memories (
id BIGINT AUTO_INCREMENT PRIMARY KEY,
app_name VARCHAR(255) NOT NULL,
user_id VARCHAR(255) NOT NULL,
memory_id VARCHAR(64) NOT NULL,
memory_data JSON NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
INDEX idx_app_user (app_name, user_id),
UNIQUE INDEX idx_app_user_memory (app_name, user_id, memory_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
The example supports PostgreSQL-based memory service for persistent relational storage:
// PostgreSQL memory service
memoryService, err := memorypostgres.NewService(
memorypostgres.WithHost("localhost"),
memorypostgres.WithPort(5432),
memorypostgres.WithUser("postgres"),
memorypostgres.WithPassword("password"),
memorypostgres.WithDatabase("dbname"),
memorypostgres.WithSoftDelete(true),
memorypostgres.WithToolEnabled(memory.DeleteToolName, false),
memorypostgres.WithCustomTool(memory.ClearToolName, customClearMemoryTool),
)
// Session service always uses in-memory for simplicity
sessionService := sessioninmemory.NewSessionService()
Benefits of PostgreSQL support:
deleted_at fieldTo use PostgreSQL memory service, you need a running PostgreSQL instance:
# Start PostgreSQL with Docker (recommended for testing)
docker run -d --name postgres-memory \
-e POSTGRES_USER=postgres \
-e POSTGRES_PASSWORD=password \
-e POSTGRES_DB=memory_db \
-p 5432:5432 \
postgres:15-alpine
# Wait for PostgreSQL to be ready
docker exec postgres-memory pg_isready -U postgres
Usage examples:
# Minimal setup (using defaults)
export PG_PASSWORD=password
go run . -memory postgres
# Custom configuration
export PG_HOST=localhost
export PG_PORT=5432
export PG_USER=postgres
export PG_PASSWORD=password
export PG_DATABASE=memory_db
go run . -memory postgres
# Using environment variables
export PG_HOST=localhost
export PG_PORT=5433
export PG_USER=postgres
export PG_PASSWORD=password
export PG_DATABASE=memory_db
go run . -memory postgres
# Connect with soft delete enabled
export PG_HOST=localhost
export PG_PORT=5432
export PG_USER=postgres
export PG_PASSWORD=password
export PG_DATABASE=memory_db
go run . -memory postgres -soft-delete
# Connect with custom table name (via code configuration)
# See memorypostgres.WithTableName() option in the code
Connection String:
The PostgreSQL connection string is automatically built from environment variables:
host=localhost port=5432 dbname=memory_db sslmode=disable user=postgres password=password
Common connection parameters:
sslmode=disable - Disable SSL (for local development, default)sslmode=require - Require SSL connectionTable Schema:
The PostgreSQL memory service automatically creates the following table structure:
CREATE TABLE IF NOT EXISTS memories (
id BIGSERIAL PRIMARY KEY,
app_name VARCHAR(255) NOT NULL,
user_id VARCHAR(255) NOT NULL,
memory_id VARCHAR(64) NOT NULL,
memory_data JSONB NOT NULL,
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
deleted_at TIMESTAMP NULL DEFAULT NULL,
CONSTRAINT idx_app_user_memory UNIQUE (app_name, user_id, memory_id)
);
CREATE INDEX IF NOT EXISTS idx_app_user ON memories(app_name, user_id);
CREATE INDEX IF NOT EXISTS idx_deleted_at ON memories(deleted_at);
Soft Delete:
When soft delete is enabled:
deleted_at timestamp instead of physically removing rowsWHERE deleted_at IS NULL)WithSoftDelete(true) option to enable soft delete behaviorThis example demonstrates how to:
Future enhancements could include:
FAQs
Unknown package
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Following multiple malicious extension incidents, Open VSX outlines new safeguards designed to catch risky uploads earlier.

Research
/Security News
Threat actors compromised four oorzc Open VSX extensions with more than 22,000 downloads, pushing malicious versions that install a staged loader, evade Russian-locale systems, pull C2 from Solana memos, and steal macOS credentials and wallets.

Security News
Lodash 4.17.23 marks a security reset, with maintainers rebuilding governance and infrastructure to support long-term, sustainable maintenance.