diff --git a/src/openclaw/admin.py b/src/openclaw/admin.py index 5b24f69..0328896 100644 --- a/src/openclaw/admin.py +++ b/src/openclaw/admin.py @@ -1,4 +1,9 @@ +from datetime import date + from django.contrib import admin +from django.db.models import Prefetch +from django.template.response import TemplateResponse + from openclaw.models import Session, Message, ToolCall @@ -28,6 +33,73 @@ class ToolCallInline(admin.TabularInline): return False +def daily_conversation_view(request): + """Admin standalone view for date-range conversation browsing.""" + start_str = request.GET.get("start") + end_str = request.GET.get("end") + agent_filter = request.GET.get("agent", "") + + start_date = start_str if start_str else date.today().isoformat() + end_date = end_str if end_str else date.today().isoformat() + + agents = list( + Session.objects.values_list("agent_name", flat=True) + .distinct() + .order_by("agent_name") + ) + + sessions_qs = Session.objects.filter( + start_time__date__gte=start_date, + start_time__date__lte=end_date, + ).order_by("start_time") + + if agent_filter: + sessions_qs = sessions_qs.filter(agent_name=agent_filter) + + messages_prefetch = Prefetch( + "messages", + queryset=Message.objects.order_by("seq"), + ) + sessions_qs = sessions_qs.prefetch_related(messages_prefetch) + + role_labels = { + "user": "User", + "assistant": "Assistant", + "toolResult": "Tool Result", + } + + session_list = [] + for session in sessions_qs: + messages = [] + for msg in session.messages.all(): + messages.append({ + "timestamp": msg.timestamp, + "role": msg.role, + "content_text": msg.content_text, + "tool_name": msg.tool_name, + "get_role_label": role_labels.get(msg.role, msg.role), + }) + session_list.append({ + "session_id": session.session_id, + "agent_name": session.agent_name, + "model_id": session.model_id, + "total_tokens": session.total_tokens, + "start_time": session.start_time, + "messages": messages, + }) + + context = { + **admin.site.each_context(request), + "start_date": start_date, + "end_date": end_date, + "selected_agent": agent_filter, + "agents": agents, + "sessions": session_list, + "title": "Daily Conversation View", + } + return TemplateResponse(request, "admin/openclaw/daily_view.html", context) + + @admin.register(Session) class SessionAdmin(admin.ModelAdmin): list_display = ( @@ -51,6 +123,14 @@ class SessionAdmin(admin.ModelAdmin): "pushed_at", ) + def get_urls(self): + from django.urls import path + urls = super().get_urls() + custom_urls = [ + path("daily/", admin.site.admin_view(daily_conversation_view), name="openclaw_daily"), + ] + return custom_urls + urls + @admin.register(Message) class MessageAdmin(admin.ModelAdmin): diff --git a/src/openclaw/templates/admin/openclaw/daily_view.html b/src/openclaw/templates/admin/openclaw/daily_view.html new file mode 100644 index 0000000..c4d60f9 --- /dev/null +++ b/src/openclaw/templates/admin/openclaw/daily_view.html @@ -0,0 +1,43 @@ +{% extends "admin/base_site.html" %} +{% block content %} +
Model: {{ session.model_id or 'N/A' }} | Tokens: {{ session.total_tokens }} | + Start: {{ session.start_time|default:"N/A" }}
+ + {% for msg in session.messages %} + + {% empty %} +No messages.
+ {% endfor %} +