"""Auto-generated Hermes session-kernel runner. One exec cell per request."""
import contextlib
import io
import json
import os
import sys
import traceback
_SENTINEL = os.environ["HERMES_KERNEL_SENTINEL"]
_CAPTURE_LIMIT = 1000000
_SPILL_DIR = os.environ.get("HERMES_KERNEL_SPILL_DIR", "")
_SPILL_CAP = 5000000
# The persistent cell namespace. `__name__` is `__main__` so scripts behave
# like the per-call path; builtins resolve normally through exec.
GLOBALS = {"__name__": "__main__", "__builtins__": __builtins__}
_real_stdout = sys.stdout
def _bounded(text, spill_name=None):
"""Clip to the inline cap; spill the FULL text to disk when clipping.
Returns (clipped_text, clipped?, spill_path_or_empty). Spill is
best-effort — a failed write degrades to plain clipping.
"""
if len(text) <= _CAPTURE_LIMIT:
return text, False, ""
spill_path = ""
if _SPILL_DIR and spill_name:
try:
spill_path = os.path.join(_SPILL_DIR, spill_name)
with open(spill_path, "w", encoding="utf-8", errors="replace") as f:
f.write(text[:_SPILL_CAP])
if len(text) > _SPILL_CAP:
f.write("\n\n[... spill capped ...]")
except Exception:
spill_path = ""
return text[: _CAPTURE_LIMIT], True, spill_path
def _reply(payload):
body = json.dumps(payload, ensure_ascii=False).encode("utf-8")
_real_stdout.buffer.write(
("\n" + _SENTINEL + " " + str(len(body)) + "\n").encode("utf-8")
)
_real_stdout.buffer.write(body)
_real_stdout.buffer.flush()
def main():
execution_count = 0
for line in sys.stdin:
line = line.strip()
if not line:
continue
try:
request = json.loads(line)
except ValueError:
continue
execution_count += 1
out, err = io.StringIO(), io.StringIO()
status = "ok"
trace = ""
try:
with contextlib.redirect_stdout(out), contextlib.redirect_stderr(err):
exec(compile(request["code"], "<cell>", "exec"), GLOBALS)
except SystemExit as exc:
status = "exit"
trace = "SystemExit: " + repr(exc.code)
except BaseException:
status = "error"
trace = traceback.format_exc()
stdout_text, stdout_clipped, stdout_spill = _bounded(
out.getvalue(), "cell_%06d_stdout.txt" % execution_count
)
stderr_text, stderr_clipped, _ = _bounded(err.getvalue())
_reply(
{
"id": request.get("id", ""),
"status": status,
"stdout": stdout_text,
"stderr": stderr_text,
"stdout_clipped": stdout_clipped,
"stderr_clipped": stderr_clipped,
"stdout_spill_path": stdout_spill,
"traceback": trace,
"execution_count": execution_count,
}
)
if status == "exit":
break
if __name__ == "__main__":
main()