mirror of
https://github.com/jxxghp/MoviePilot.git
synced 2026-10-29 19:37:54 +08:00
54 lines
2.8 KiB
Python
54 lines
2.8 KiB
Python
"""
|
|
代码执行的模型输出投影,工具失败与内核状态各自如实报告。
|
|
"""
|
|
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from app.adapters.system.code.output import SPILL_BYTES, STDERR_BYTES, project_stdout, read_cell_stdout
|
|
from app.agent.policy.sanitizer import sanitize_archived_text
|
|
|
|
_ANSI = re.compile(r'\x1b(?:\[[0-?]*[ -/]*[@-~]|\][^\x07]*(?:\x07|\x1b\\))')
|
|
|
|
|
|
def render_result(payload: dict[str, Any], *, directory: Path, output_directory: Path,
|
|
reused: bool, state_reset: bool, elapsed: float) -> dict[str, Any]:
|
|
"""
|
|
完整 stdout 脱敏后才落盘,内核退出后仍能从独立输出目录继续读取。
|
|
"""
|
|
source = read_cell_stdout(payload, directory) + str(payload.get('raw_stdout') or '')
|
|
source_captured = len(source.encode('utf-8'))
|
|
stdout = sanitize_archived_text(_ANSI.sub('', source))
|
|
preview, metadata = project_stdout(stdout, output_directory)
|
|
stderr = sanitize_archived_text(_ANSI.sub('', str(payload.get('stderr') or '') + str(payload.get('raw_stderr') or '')))
|
|
trace = sanitize_archived_text(str(payload.get('traceback') or ''))
|
|
status = payload.get('status', 'error')
|
|
result: dict[str, Any] = {
|
|
'status': 'error' if status == 'error' else 'success',
|
|
'output': preview,
|
|
'exit_code': 1 if status == 'error' else 0,
|
|
'duration_seconds': round(elapsed, 2),
|
|
'kernel': {'mode': 'session', 'reused': reused, 'state_reset': state_reset,
|
|
'execution_count': int(payload.get('execution_count', 0)), 'ended': status == 'exit'},
|
|
**metadata,
|
|
}
|
|
if stderr or trace:
|
|
errors = (stderr + trace).encode('utf-8', errors='replace')
|
|
raw_errors = str(payload.get('raw_stderr') or '').encode('utf-8')
|
|
truncated = (len(errors) > STDERR_BYTES or bool(payload.get('stderr_clipped'))
|
|
or int(payload.get('raw_stderr_bytes', 0)) > len(raw_errors))
|
|
result.update(stderr=errors[:STDERR_BYTES].decode('utf-8', errors='ignore'), stderr_truncated=truncated)
|
|
result['output'] += '\n[stderr]\n' + result['stderr']
|
|
if status == 'error':
|
|
result['error'] = result.get('stderr') or 'Python cell 执行异常。'
|
|
captured_total = int(payload.get('stdout_bytes_total', 0)) + int(payload.get('raw_stdout_bytes', 0))
|
|
if payload.get('stdout_clipped') or captured_total > source_captured:
|
|
result['stdout_source_bytes_total'] = captured_total
|
|
result['stdout_spill_capped'] = captured_total > SPILL_BYTES
|
|
result['stdout_capture_incomplete'] = captured_total > source_captured
|
|
if result['stdout_capture_incomplete']:
|
|
result['stdout_truncated'] = True
|
|
result['warning'] = '部分输出超过捕获预算,无法恢复全部正文;现有 spill 仅包含已保留部分。'
|
|
return result
|