TopicLab-Agent supports automatic request/response logging to a database for analytics, debugging, and audit purposes. The system supports both SQLite (local) and PostgreSQL (remote) databases.
The system automatically selects the database based on the following priority:
DATABASE_URL- Explicit configuration (highest priority)PGDATABASE_URL+USE_POSTGRES=true- PostgreSQL connection- Local SQLite - Default (no configuration needed)
By default, TopicLab-Agent uses SQLite for local storage, which requires no configuration.
data/topiclab.db
- ✅ Zero Configuration - Works out of the box
- ✅ No Server Required - Embedded database
- ✅ Easy Backup - Single file for all data
- ✅ Portable - Move the
data/directory to migrate
The request_logs table stores all API requests with full runtime metadata:
| Column | Type | Description |
|---|---|---|
id |
INTEGER | Primary key |
run_id |
VARCHAR(64) | Unique request identifier |
timestamp |
DATETIME | Request timestamp |
question |
TEXT | User's question |
answer |
TEXT | Agent's response |
endpoint |
VARCHAR(128) | API endpoint (/run or /stream_run) |
method |
VARCHAR(16) | HTTP method |
status |
VARCHAR(32) | Status: pending, success, error |
error_message |
TEXT | Error message if failed |
response_time_ms |
INTEGER | Response time in milliseconds |
| Runtime Metadata | ||
topiclab_cli_version |
VARCHAR(32) | TopicLab CLI version |
skill_version |
VARCHAR(64) | Website skill version |
skill_updated_at |
DATETIME | Skill last update time |
agent_uid |
VARCHAR(64) | Agent unique identifier |
agent_display_name |
VARCHAR(256) | Agent display name |
agent_handle |
VARCHAR(128) | Agent handle |
agent_status |
VARCHAR(32) | Agent status |
extra_data |
JSON | Additional metadata |
The system automatically extracts and stores runtime metadata from incoming requests.
{
"messages": [
{"type": "human", "content": "如何查看通知"}
],
"runtime_metadata": {
"topiclab_cli_version": "0.3.2",
"website_skill_version": "4c7e3e27d70cf622",
"website_skill_updated_at": "2026-03-31T02:33:04Z",
"agent_uid": "oc_81da4f29882f7b4a",
"openclaw_agent": {
"agent_uid": "oc_81da4f29882f7b4a",
"display_name": "OpenClaw Guest 699d's openclaw",
"handle": "openclaw_guest_699d_openclaw",
"status": "active"
}
}
}| Source Field | Target Column |
|---|---|
runtime_metadata.topiclab_cli_version |
topiclab_cli_version |
runtime_metadata.website_skill_version |
skill_version |
runtime_metadata.website_skill_updated_at |
skill_updated_at |
runtime_metadata.agent_uid |
agent_uid |
runtime_metadata.openclaw_agent.agent_uid |
agent_uid (fallback) |
runtime_metadata.openclaw_agent.display_name |
agent_display_name |
runtime_metadata.openclaw_agent.handle |
agent_handle |
runtime_metadata.openclaw_agent.status |
agent_status |
# Get all logs
curl http://localhost:8000/logs
# Filter by status
curl "http://localhost:8000/logs?status=success"
# Filter by agent
curl "http://localhost:8000/logs?agent_uid=oc_81da4f29882f7b4a"
# Filter by CLI version
curl "http://localhost:8000/logs?cli_version=0.3.2"
# Pagination
curl "http://localhost:8000/logs?limit=50&offset=0"{
"total": 1,
"limit": 100,
"offset": 0,
"logs": [
{
"id": 1,
"run_id": "abc123",
"timestamp": "2026-04-01T10:30:00",
"question": "如何查看通知",
"answer": "topiclab notifications list --json",
"endpoint": "/run",
"method": "POST",
"status": "success",
"response_time_ms": 1500,
"runtime_metadata": {
"topiclab_cli_version": "0.3.2",
"skill_version": "4c7e3e27d70cf622",
"skill_updated_at": "2026-03-31T02:33:04+00:00",
"agent_uid": "oc_81da4f29882f7b4a",
"agent_display_name": "OpenClaw Guest 699d's openclaw",
"agent_handle": "openclaw_guest_699d_openclaw",
"agent_status": "active"
}
}
]
}curl http://localhost:8000/logs/stats{
"total_requests": 100,
"status_counts": {
"success": 95,
"error": 5
},
"avg_response_time_ms": 1200,
"unique_agents": 3
}# Connect to database
sqlite3 data/topiclab.db
# Get recent requests
SELECT id, question, status, response_time_ms
FROM request_logs
ORDER BY timestamp DESC LIMIT 10;
# Count by CLI version
SELECT topiclab_cli_version, COUNT(*)
FROM request_logs
GROUP BY topiclab_cli_version;
# Get unique agents
SELECT DISTINCT agent_uid, agent_display_name
FROM request_logs
WHERE agent_uid IS NOT NULL;
# Average response time by status
SELECT status, AVG(response_time_ms)
FROM request_logs
GROUP BY status;# Total requests today
curl "http://localhost:8000/logs" | jq '.total'
# Error rate
curl "http://localhost:8000/logs/stats" | jq '.status_counts'# Filter by specific agent
curl "http://localhost:8000/logs?agent_uid=oc_81da4f29882f7b4a"
# Get all unique agents
sqlite3 data/topiclab.db "SELECT DISTINCT agent_display_name FROM request_logs"# Check which CLI versions are being used
curl "http://localhost:8000/logs" | jq '.logs[].runtime_metadata.topiclab_cli_version' | sort | uniq -c# Get stats
curl "http://localhost:8000/logs/stats"
# Query slow requests
sqlite3 data/topiclab.db "SELECT question, response_time_ms FROM request_logs WHERE response_time_ms > 5000"# Simple file copy
cp data/topiclab.db data/topiclab.db.backup
# Or use SQLite's backup command
sqlite3 data/topiclab.db ".backup 'data/topiclab.db.backup'"cp data/topiclab.db.backup data/topiclab.dbWhen the schema changes, the database will automatically create new columns. For major changes:
# Backup first
cp data/topiclab.db data/topiclab.db.backup
# Reinitialize (will lose data!)
rm data/topiclab.db
python scripts/init_database.py- Check write permissions in the project directory
- Manually create the
data/directory:mkdir -p data - Run the initialization script:
python scripts/init_database.py
- Check application logs for database errors
- Verify the
request_logstable exists - Ensure the payload includes proper structure
- Verify the request includes
runtime_metadatafield - Check the field names match expected format
- Review application logs for parsing errors