9.3 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_CONFIG = "get_config" # Get config
SET_CONFIG = "set_config" # Set config
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"):
print(result["content"])
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_CONFIG - Get Config
Get current API configuration.
Request parameters:
body = {} # No parameters
Response data:
{
"api_key": str, # API Key
"base_url": str # API Base URL
}
5. SET_CONFIG - Set Config
Update API configuration (API Key and Base URL).
Request parameters:
body = {
"api_key": str, # API Key
"base_url": str, # API Base URL (default: https://api.deepseek.com)
"model": str # Model name (default: deepseek-chat)
}
Response data:
{
"status": "config_updated"
}
6. GET_HISTORY - Get Message History
Get saved message history.
Request parameters:
body = {} # No parameters
Response data:
{
"history": list # Message history list
}
7. SAVE_HISTORY - Save Message History
Save message history to memory.
Request parameters:
body = {
"messages": list # Message list
}
Response data:
{
"status": "history_saved"
}
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_config(data["api_key"], data.get("base_url"))
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 == "config":
result = client.update_config(data["api_key"], data.get("base_url"))
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 |