Files
my_one_web/api/sessions.py
小白 99624184eb fix: 修复会话详情解析 JSONL 格式
- 正确解析 OpenClaw JSONL 会话文件格式
- 提取 type=message 类型的记录
- 解析 content 数组中的 text 和 thinking 内容
- 限制返回最近 30 条消息
2026-03-12 21:09:04 +08:00

138 lines
4.6 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
会话管理 API
作者:小白 🐶
"""
import os
import json
import glob
from datetime import datetime
from flask import jsonify, request
from . import api
SESSIONS_DIR = '/root/.openclaw/agents/main/sessions'
@api.route('/sessions')
def get_sessions():
"""获取会话列表"""
try:
sessions = []
for filepath in glob.glob(os.path.join(SESSIONS_DIR, '*.jsonl')):
if '.reset.' in filepath or filepath.endswith('.lock'):
continue
session_id = os.path.basename(filepath).replace('.jsonl', '')
stat = os.stat(filepath)
updated_at = stat.st_mtime
size = stat.st_size
messages_count = 0
try:
with open(filepath, 'r') as f:
messages_count = len([l for l in f.readlines() if l.strip()])
except:
pass
is_active = (datetime.now().timestamp() - updated_at) < 300
sessions.append({
'id': session_id,
'key': f'agent:main:session:{session_id}',
'updatedAt': int(updated_at * 1000),
'updatedTime': datetime.fromtimestamp(updated_at).strftime('%Y-%m-%d %H:%M:%S'),
'size': size,
'messagesCount': messages_count,
'status': 'active' if is_active else 'inactive'
})
sessions.sort(key=lambda x: x['updatedAt'], reverse=True)
return jsonify({
'success': True,
'data': {
'count': len(sessions),
'sessions': sessions
}
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@api.route('/sessions/<session_id>')
def get_session_detail(session_id):
"""获取会话详情"""
try:
filepath = os.path.join(SESSIONS_DIR, f'{session_id}.jsonl')
if not os.path.exists(filepath):
return jsonify({'success': False, 'error': '会话不存在'})
messages = []
with open(filepath, 'r') as f:
for line in f:
line = line.strip()
if not line:
continue
try:
record = json.loads(line)
# 只处理 message 类型的记录
if record.get('type') == 'message':
msg = record.get('message', {})
role = msg.get('role', 'unknown')
content_parts = msg.get('content', [])
# 提取文本内容
text_content = ''
for part in content_parts:
if isinstance(part, dict):
if part.get('type') == 'text':
text_content += part.get('text', '')
elif part.get('type') == 'thinking':
text_content += '[思考中...] '
elif isinstance(part, str):
text_content += part
if text_content.strip():
messages.append({
'role': role,
'content': text_content[:500],
'timestamp': record.get('timestamp', '')
})
except:
continue
# 只保留最近 30 条消息
messages = messages[-30:]
return jsonify({
'success': True,
'data': {
'id': session_id,
'messagesCount': len(messages),
'messages': messages
}
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})
@api.route('/sessions/<session_id>/kill', methods=['POST'])
def kill_session(session_id):
"""终止会话"""
try:
filepath = os.path.join(SESSIONS_DIR, f'{session_id}.jsonl')
if not os.path.exists(filepath):
return jsonify({'success': False, 'error': '会话不存在'})
backup_path = filepath + f'.reset.{datetime.now().isoformat()}'
os.rename(filepath, backup_path)
return jsonify({'success': True, 'message': '会话已终止'})
except Exception as e:
return jsonify({'success': False, 'error': str(e)})