feat: L4 session archiver + scheduler cron integration

- Add compress_session.py: compress raw model_responses into L4 archives
- Integrate 12h silent cron into scheduler.check() (runs before TASKS dir check)
- Whitelist compress_session.py in .gitignore (archives excluded)
- llmcore: refactor SSE warn handling, max_retries default 2->1
- scheduler: remove unused health_check(), INTERVAL 60->120
This commit is contained in:
Liang Jiaqing
2026-04-11 15:55:35 +08:00
parent a737523f0a
commit de8adf76a9
4 changed files with 276 additions and 59 deletions

View File

@@ -1,4 +1,4 @@
import os, json, socket as _socket, logging
import os, json, time as _time, socket as _socket, logging
from datetime import datetime, timedelta
# 端口锁防止重复启动bind失败时agentmain会直接崩溃退出
@@ -8,7 +8,7 @@ except NameError:
_lock = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM)
_lock.bind(('127.0.0.1', 45762)); _lock.listen(1)
INTERVAL = 60
INTERVAL = 120
ONCE = False
_dir = os.path.dirname(os.path.abspath(__file__))
@@ -27,6 +27,7 @@ if not _logger.handlers:
# 默认最大延迟窗口(小时),超过此时间不触发
DEFAULT_MAX_DELAY = 6
_l4_t = 0 # last L4 archive time
def _parse_cooldown(repeat):
"""解析repeat为冷却时间(比实际周期略短,防漂移)"""
@@ -56,6 +57,18 @@ def _last_run(tid, done_files):
return latest
def check():
# L4 archive cron (silent, every 12h)
global _l4_t
if _time.time() - _l4_t > 43200:
_l4_t = _time.time()
try:
import sys; sys.path.insert(0, os.path.join(_dir, '../memory/L4_raw_sessions'))
from compress_session import batch_process
r = batch_process(dry_run=False)
print(f'[L4 cron] {r}')
except Exception as e:
_logger.error(f'L4 archive failed: {e}')
if not os.path.isdir(TASKS): return None
now = datetime.now()
os.makedirs(DONE, exist_ok=True)
@@ -109,50 +122,5 @@ def check():
f'先读 scheduled_task_sop 了解执行流程,然后执行以下任务:\n\n'
f'{prompt}\n\n'
f'完成后将执行报告写入 {rpt}')
return None
def health_check():
"""检查所有定时任务的健康状态,返回结构化报告"""
if not os.path.isdir(TASKS):
return {'error': 'TASKS directory not found'}
now = datetime.now()
os.makedirs(DONE, exist_ok=True)
done_files = set(os.listdir(DONE))
results = []
for f in sorted(os.listdir(TASKS)):
if not f.endswith('.json'): continue
tid = f[:-5]
try:
task = json.loads(open(os.path.join(TASKS, f), encoding='utf-8').read())
except Exception as e:
results.append({'task': tid, 'status': 'ERROR', 'detail': f'JSON parse: {e}'})
continue
enabled = task.get('enabled', False)
repeat = task.get('repeat', 'daily')
sched = task.get('schedule', '00:00')
last = _last_run(tid, done_files)
cooldown = _parse_cooldown(repeat)
# 判断健康状态
if not enabled:
status = 'DISABLED'
elif last is None:
status = 'NEVER_RUN'
elif repeat == 'once':
status = 'COMPLETED' if last else 'PENDING'
else:
# 检查是否超过预期间隔的1.5倍
expected_gap = cooldown * 1.25 # 略大于冷却时间
if (now - last) > expected_gap:
status = 'OVERDUE'
else:
status = 'HEALTHY'
results.append({
'task': tid, 'status': status, 'enabled': enabled,
'repeat': repeat, 'schedule': sched,
'last_run': last.strftime('%Y-%m-%d %H:%M') if last else None,
'cooldown_hours': cooldown.total_seconds() / 3600,
})
return results
return None