Files
my_one_web/api/sessions.py
小白 a0cf95a960 fix: 修复会话管理 API
- 改用直接读取会话文件方式替代命令调用
- 修复 sessions_list 命令不存在的错误
- 实现会话列表、详情、终止功能
2026-03-12 21:01:59 +08:00

174 lines
5.4 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/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 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
# 读取最后几行获取会话信息
try:
with open(filepath, 'r') as f:
lines = f.readlines()
total_tokens = 0
channel = 'unknown'
# 解析最后一条消息获取信息
if lines:
try:
last_line = lines[-1].strip()
if last_line:
data = json.loads(last_line)
if 'usage' in data:
total_tokens = data['usage'].get('total_tokens', 0)
except:
pass
messages_count = len([l for l in lines if l.strip()])
except:
messages_count = 0
total_tokens = 0
# 判断是否活跃5分钟内更新
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,
'totalTokens': total_tokens,
'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:
data = json.loads(line)
# 提取消息
if 'messages' in data:
for msg in data['messages']:
messages.append({
'role': msg.get('role', 'unknown'),
'content': msg.get('content', '')[:500], # 截断内容
'timestamp': data.get('created', 0)
})
elif 'content' in data:
messages.append({
'role': data.get('role', 'unknown'),
'content': data.get('content', '')[:500]
})
except:
continue
# 只保留最近 20 条消息
messages = messages[-20:]
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')
lockfile = filepath + '.lock'
if not os.path.exists(filepath):
return jsonify({
'success': False,
'error': '会话不存在'
})
# 重命名为备份文件而不是直接删除
backup_path = filepath + f'.reset.{datetime.now().isoformat()}'
os.rename(filepath, backup_path)
# 删除锁文件
if os.path.exists(lockfile):
os.remove(lockfile)
return jsonify({
'success': True,
'message': '会话已终止'
})
except Exception as e:
return jsonify({
'success': False,
'error': str(e)
})