- 修正 PROCESS_MESSAGE 响应数据访问路径 (result['content'] -> result['data']['content']) - 添加 CLEAR_HISTORY 文档说明 (基于 SAVE_HISTORY 空消息实现) - 添加 test_clear_history 和 test_send_message_is_alias 测试用例 - 优化 BackendClient 历史相关方法的返回值处理
12 KiB
BackendServer API Documentation
This document describes the backend server's API interfaces for developers extending other connection methods (such as HTTP interface, WebSocket, etc.).
Overview
TrulyMEM backend uses Packet Communication Protocol, implemented via queue.Queue for thread-safe communication. The backend runs in an independent thread, processing requests from clients.
Core Components
| Component | Description |
|---|---|
BackendServer |
Backend server, runs in independent thread |
BackendClient |
Client wrapper, provides convenient methods |
PacketType |
Request type enum |
Packet |
Data packet (request) |
PacketResponse |
Data packet response |
Request Types (PacketType)
class PacketType(Enum):
PROCESS_MESSAGE = "process_message" # Process message
EXECUTE_TOOL = "execute_tool" # Execute tool
GET_STATUS = "get_status" # Get status
GET_SETTINGS = "get_settings" # Get all settings (api_config + tool_limits)
SET_SETTINGS = "set_settings" # Set all settings (api_config + tool_limits)
GET_HISTORY = "get_history" # Get history
SAVE_HISTORY = "save_history" # Save history
SHUTDOWN = "shutdown" # Shutdown service
Data Packet Format
Packet
@dataclass
class Packet:
id: str # Unique identifier
type: PacketType # Request type
body: Dict[str, Any] # Request parameters
response_queue: queue.Queue # Response queue (optional)
created_at: float # Creation time
PacketResponse
@dataclass
class PacketResponse:
id: str # Corresponding request ID
success: bool # Success flag
data: Any = None # Returned data
error: Optional[str] = None # Error message
API Interface Details
1. PROCESS_MESSAGE - Process Message
Send user message, AI will process and return reply (may contain tool calls).
Request parameters:
body = {
"user_input": str # User input message
}
Response data:
{
"success": True,
"content": str, # AI reply content
"tool_calls": [ # Tool call records
{
"name": str, # Tool name
"arguments": dict,# Tool parameters
"result": str # Tool execution result
}
],
"rejected_tools": [ # Rejected tool calls
(str, str) # (tool name, rejection reason)
]
}
Example:
from core import BackendServer, BackendClient
server = BackendServer(db_path="graph_memory.db", use_embedded_db=True)
server.start(api_key="your-api-key")
client = BackendClient(server)
result = client.process_message("Hello, please remember my name is Xiao Ming")
if result.get("success"):
# Response data is in "data" field
print(result["data"]["content"])
# Tool calls: result["data"]["tool_calls"]
# Rejected tools: result["data"]["rejected_tools"]
2. EXECUTE_TOOL - Execute Tool
Directly execute specified memory tools.
Note
: Tools called directly from frontend are NOT limited in number, only tool calls initiated by the model are limited.
Request parameters:
body = {
"tool_name": str, # Tool name
"arguments": dict # Tool parameters
}
Response data:
{
"success": True,
"result": str # Tool execution result
}
Example:
result = client.execute_tool("memory_recall", {"query_intent": "user information"})
3. GET_STATUS - Get Status
Get backend running status.
Request parameters:
body = {} # No parameters
Response data:
{
"running": bool, # Whether backend is running
"config": dict, # Current config
"graph_initialized": bool, # Whether graph database is initialized
"client_initialized": bool # Whether API client is initialized
}
4. GET_SETTINGS - Get All Settings
Get current API config and tool limits (all at once).
Request parameters:
body = {} # No parameters
Response data:
{
"api_config": {
"api_key": str, # API Key
"base_url": str, # API Base URL
"model": str # Model name
},
"tool_limits": {
"persona_query_max": int, # Persona graph query limit
"persona_update_max": int, # Persona graph update limit
"task_query_max": int, # Working memory query limit
"task_update_max": int, # Working memory update limit
"memory_query_max": int, # General memory query limit
"memory_update_max": int # General memory update limit
}
}
Example:
result = client.get_settings()
api_config = result["data"]["api_config"]
tool_limits = result["data"]["tool_limits"]
5. SET_SETTINGS - Set All Settings
Update API config and tool limits (all at once).
Request parameters:
body = {
"api_config": {
"api_key": str, # API Key
"base_url": str, # API Base URL (default: https://api.deepseek.com)
"model": str # Model name (default: deepseek-chat)
},
"tool_limits": {
"persona_query_max": int, # Persona query limit (≥1)
"persona_update_max": int, # Persona update limit (≥1)
"task_query_max": int, # Working memory query limit (≥1)
"task_update_max": int, # Working memory update limit (≥1)
"memory_query_max": int, # General memory query limit (≥1)
"memory_update_max": int # General memory update limit (≥1)
}
}
Response data:
{
"status": "settings_updated"
}
Example:
result = client.update_settings(
api_config={
"api_key": "sk-xxxxx",
"base_url": "https://api.deepseek.com",
"model": "deepseek-chat"
},
tool_limits={
"persona_query_max": 2,
"task_query_max": 5,
"memory_query_max": 30
}
)
6. GET_HISTORY - Get Message History
Get saved message history (from database, for UI display only, not used in model inference).
Request parameters:
body = {} # No parameters
Response data:
{
"history": list # Message history list [{"role": "user/assistant", "content": "..."}]
}
Notes:
- Message history is stored in database
chat_recordstable - Returns up to 500 most recent records
- History messages are only for UI display, not used in model inference
7. SAVE_HISTORY - Save Message History
Save message history to database (automatically saved after each message processing, user message and AI response saved separately).
Request parameters:
body = {
"messages": list # Message list [{"role": "...", "content": "..."}]
}
Response data:
{
"status": "history_saved"
}
Notes:
- Messages are automatically saved to database
chat_recordstable - System automatically keeps only 500 most recent records, older records are deleted
- Each call to
PROCESS_MESSAGEwill automatically save user message and AI response - Clear History: Passing empty messages list
messages=[]clears history,client.clear_history()method is implemented based on this
8. SHUTDOWN - Shutdown Service
Shutdown backend server.
Request parameters:
body = {} # No parameters
Response data:
{
"status": "shutdown"
}
Usage Examples
Basic Usage
from core import BackendServer, BackendClient
# 1. Create and start backend
# config_file default: ~/.trulymem/config.json
server = BackendServer(
db_path="graph_memory.db",
use_embedded_db=True,
config_file=None # Optional, custom config path
)
server.start(
api_key="your-api-key",
base_url="https://api.deepseek.com",
model="deepseek-chat" # Optional, model name
)
# 2. Create client
client = BackendClient(server)
# 3. Send message
result = client.process_message("Hello")
if result.get("success"):
print(result["content"])
# 4. Shutdown
client.shutdown()
Using Packet Protocol
import queue
from core import BackendServer, Packet, PacketType
server = BackendServer(config_file=None)
server.start(api_key="your-key", model="deepseek-chat")
# Create request packet
response_queue = queue.Queue()
packet = Packet(
id="req-001",
type=PacketType.PROCESS_MESSAGE,
body={"user_input": "Hello"},
response_queue=response_queue
)
# Send request
result = server.send(packet)
print(result.body)
# Shutdown
server.shutdown()
Extension Guide
Extend to HTTP API
from flask import Flask, request, jsonify
from core import BackendServer, BackendClient
app = Flask(__name__)
server = BackendServer()
client = BackendClient(server)
@app.route("/message", methods=["POST"])
def send_message():
data = request.json
result = client.process_message(data["message"])
return jsonify(result)
@app.route("/config", methods=["POST"])
def update_config():
data = request.json
result = client.update_settings(
api_config=data.get("api_config", {}),
tool_limits=data.get("tool_limits", {})
)
return jsonify(result)
@app.route("/status", methods=["GET"])
def get_status():
result = client.get_status()
return jsonify(result)
if __name__ == "__main__":
server.start()
app.run(port=8080)
Extend to WebSocket
import asyncio
import websockets
import json
from core import BackendServer, BackendClient
server = BackendServer()
client = BackendClient(server)
async def handler(websocket):
async for message in websocket:
data = json.loads(message)
msg_type = data.get("type")
if msg_type == "message":
result = client.process_message(data["content"])
elif msg_type == "settings":
result = client.update_settings(
api_config=data.get("api_config", {}),
tool_limits=data.get("tool_limits", {})
)
elif msg_type == "status":
result = client.get_status()
else:
result = {"success": False, "error": "unknown type"}
await websocket.send(json.dumps(result))
async def main():
server.start()
async with websockets.serve(handler, "localhost", 8765):
await asyncio.Future()
asyncio.run(main())
Thread Safety Notes
BackendServerusesthreading.Lockto protect shared resources- All requests pass through
queue.Queue, thread-safe - Responses return through each request's independent response queue
- Default timeout: 30 seconds
Tool Call Limits
Limit Scope
| Call Method | Limited | Description |
|---|---|---|
| Model-initiated tool calls | ✅ Limited | Triggered via PROCESS_MESSAGE, model automatically calls tools |
| Frontend direct tool calls | ❌ Not limited | Called directly via EXECUTE_TOOL |
Limit Rules (Model-initiated only)
| Category | Operation | Per-Turn Limit |
|---|---|---|
| Persona graph | Query | 1 time |
| Persona graph | Modify | 1 time |
| Working memory chain | Query | 4 times |
| Working memory chain | Modify | 2 times |
| General memory | Query | 20 times |
| General memory | Modify | 10 times |
Reset Mechanism
- Counter resets automatically on each
PROCESS_MESSAGEcall - Frontend direct
EXECUTE_TOOLcalls do NOT reset the counter
Error Handling
All APIs return unified format:
# Success
{
"success": True,
"data": {...}
}
# Failure
{
"success": False,
"error": "Error description"
}
Common errors:
| Error Message | Description |
|---|---|
API Key not configured |
API Key not set |
timeout |
Request timeout |
Tool call rejected: ... |
Tool call rate exceeded limit |