Files
agent-base/scripts/export_agent_daily.py
ishenwei c474c9404b feat: add agent_name column to Message admin + export_agent_daily script
- Message list now shows agent_name via get_agent_name method
- New scripts/export_agent_daily.py for agent daily message export
  - Accepts --agent and --date (YYYY-MM-DD) arguments
  - Focuses on messages within target date (session may span multiple days)
  - Outputs Markdown with session info, messages, tool calls
2026-04-07 18:22:24 +08:00

176 lines
6.1 KiB
Python

#!/usr/bin/env python3
"""
Export agent daily messages to Markdown.
Usage:
python scripts/export_agent_daily.py --agent xingjiang --date 2026-04-07
python scripts/export_agent_daily.py --agent xingjiang --date 2026-04-07 --output /tmp/report.md
"""
import argparse
import json
import os
import sys
from datetime import date
# Add src to path for Django settings
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "src"))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "config.settings.production")
import django
django.setup()
from openclaw.models import Session, Message, ToolCall
def format_tool_args(args: dict) -> str:
"""Format tool arguments as pretty JSON."""
if not args:
return ""
return json.dumps(args, indent=2, ensure_ascii=False)
def export_agent_daily(agent_name: str, target_date: str, output_file=None):
"""
Export all messages for a specific agent on a specific date.
Sessions may span multiple days, but we focus on messages within the target date.
"""
target_date_obj = date.fromisoformat(target_date)
# Get sessions for this agent that have messages on the target date
sessions = Session.objects.filter(
agent_name=agent_name
).prefetch_related("messages", "messages__tool_calls").order_by("start_time")
daily_sessions = []
for session in sessions:
# Filter messages to only those on target date
day_messages = session.messages.filter(
timestamp__date=target_date_obj
).order_by("seq")
if day_messages.exists():
daily_sessions.append({
"session": session,
"messages": list(day_messages),
})
if not daily_sessions:
print(f"No messages found for agent {agent_name} on {target_date}", file=sys.stderr)
return
# Build Markdown output
lines = []
lines.append(f"# Agent Daily Report: {agent_name} - {target_date}")
lines.append("")
total_messages = sum(len(s["messages"]) for s in daily_sessions)
lines.append(f"**Total Sessions:** {len(daily_sessions)} ")
lines.append(f"**Total Messages:** {total_messages} ")
lines.append("")
role_label_map = {
"user": "User",
"assistant": "Assistant",
"tool": "Tool",
"toolResult": "Tool Result",
"system": "System",
}
for session_data in daily_sessions:
session = session_data["session"]
messages = session_data["messages"]
start_str = session.start_time.strftime("%Y-%m-%d %H:%M") if session.start_time else "N/A"
end_str = session.end_time.strftime("%H:%M") if session.end_time else " Ongoing"
lines.append(f"## Session: {session.session_id}")
lines.append(f"**Time:** {start_str} ~ {end_str} ")
lines.append(f"**Model:** {session.model_id or 'N/A'} ")
lines.append(f"**Tokens:** {session.total_tokens:,} | **Cost:** ${session.total_cost:.4f} ")
lines.append(f"**Messages:** {session.message_count} | **Tool Calls:** {session.tool_call_count} ")
lines.append("")
for msg in messages:
role_disp = role_label_map.get(msg.role, msg.role)
ts_str = msg.timestamp.strftime("%H:%M:%S")
lines.append(f"### [{msg.seq}] [{role_disp}] [{ts_str}]")
lines.append("")
# Content
content = msg.content_text.strip() if msg.content_text else ""
if content:
# Truncate very long content
if len(content) > 2000:
content = content[:2000] + "\n\n_[content truncated]_"
lines.append(f"**Content:**\n{content}")
else:
lines.append("**Content:** _(empty)_")
lines.append("")
# Tool call info
if msg.tool_name:
lines.append(f"**Tool:** `{msg.tool_name}` | **Exit:** {msg.exit_code} | **Duration:** {msg.duration_ms}ms")
lines.append("")
# Get tool calls for this message
tool_calls = msg.tool_calls.all()
if tool_calls.exists():
for tc in tool_calls:
args_str = format_tool_args(tc.arguments)
if args_str:
lines.append(f"**Arguments:**\n```json\n{args_str}\n```")
lines.append("")
if tc.result_text:
result = tc.result_text.strip()
if len(result) > 1000:
result = result[:1000] + "\n\n_[result truncated]_"
lines.append(f"**Result:**\n{result}")
lines.append("")
# Token info
if msg.tokens_total > 0:
lines.append(f"**Tokens:** {msg.tokens_total:,} (in: {msg.tokens_input}, out: {msg.tokens_output})")
if msg.is_error:
lines.append("⚠️ **Error**")
lines.append("")
lines.append("---")
lines.append("")
md_content = "\n".join(lines)
if output_file:
with open(output_file, "w", encoding="utf-8") as f:
f.write(md_content)
print(f"Report written to: {output_file}", file=sys.stderr)
else:
print(md_content)
def main():
parser = argparse.ArgumentParser(
description="Export agent daily messages to Markdown"
)
parser.add_argument("--agent", required=True, help="Agent name (e.g. xingjiang)")
parser.add_argument("--date", required=True, help="Target date (YYYY-MM-DD)")
parser.add_argument("--output", help="Output file path (default: stdout)")
args = parser.parse_args()
# Validate date format
try:
date.fromisoformat(args.date)
except ValueError:
print(f"Error: Invalid date format {args.date}. Use YYYY-MM-DD.", file=sys.stderr)
sys.exit(1)
export_agent_daily(args.agent, args.date, args.output)
if __name__ == "__main__":
main()