Add relay_json module, update dialogue and file_ops, update local settings

This commit is contained in:
2026-07-31 01:27:20 -06:00
parent 96afc351ac
commit c4e805defd
5 changed files with 257 additions and 22 deletions
+26 -16
View File
@@ -52,6 +52,8 @@ import json
from pathlib import Path
from typing import Optional
from . import relay_json
_PREFIXES = ("filectl", "file")
# Keeps a runaway read/write/list from blowing up the tool_result relay (and,
@@ -95,17 +97,23 @@ def parse(command: str) -> Optional[dict]:
if not rest or rest.lower() in ("help", "-h", "--help"):
return {"action": "help"}
# Lenient on purpose — see relay_json. A stray quote in machine-written
# JSON should not cost a turn, but the repair is reported back so the model
# is told it sent something broken while it can still learn from it.
try:
payload = json.loads(rest)
except json.JSONDecodeError as exc:
raise FileOpError(f"couldn't parse filectl JSON ({exc}); usage:\n{HELP}") from exc
payload, repairs = relay_json.loads(rest)
except relay_json.RelayJsonError as exc:
raise FileOpError(f"couldn't parse filectl JSON {exc}\nusage:\n{HELP}") from exc
if not isinstance(payload, dict):
raise FileOpError(f"filectl payload must be a JSON object; usage:\n{HELP}")
op = str(payload.get("op") or "help").lower()
# Carried on the action so execute() can tell the model what it got wrong;
# a silent repair would fix today's call and guarantee tomorrow's.
tag = {"_repairs": repairs} if repairs else {}
if op == "help":
return {"action": "help"}
return {"action": "help", **tag}
if op == "list":
path = _required_str(payload, "path")
@@ -114,7 +122,7 @@ def parse(command: str) -> Optional[dict]:
raise FileOpError('"pattern" must be a non-empty string')
return {
"action": "list", "path": path,
"pattern": pattern, "recursive": bool(payload.get("recursive")),
"pattern": pattern, "recursive": bool(payload.get("recursive")), **tag,
}
if op == "read":
@@ -122,14 +130,14 @@ def parse(command: str) -> Optional[dict]:
return {
"action": "read", "path": path,
"start": _line_number(payload.get("start"), "start"),
"end": _line_number(payload.get("end"), "end"),
"end": _line_number(payload.get("end"), "end"), **tag,
}
if op == "write":
path = _required_str(payload, "path")
if payload.get("content") is None:
raise FileOpError('write needs "content"')
return {"action": "write", "path": path, "content": str(payload["content"])}
return {"action": "write", "path": path, "content": str(payload["content"]), **tag}
if op == "edit":
path = _required_str(payload, "path")
@@ -138,7 +146,7 @@ def parse(command: str) -> Optional[dict]:
old, new = str(payload["old"]), str(payload["new"])
if old == new:
raise FileOpError("old and new text are identical — nothing to edit")
return {"action": "edit", "path": path, "old": old, "new": new}
return {"action": "edit", "path": path, "old": old, "new": new, **tag}
raise FileOpError(f"unknown filectl op {op!r}; usage:\n{HELP}")
@@ -175,14 +183,16 @@ def execute(action: dict) -> str:
if kind == "help":
return HELP
if kind == "list":
return _do_list(action)
if kind == "read":
return _do_read(action)
if kind == "write":
return _do_write(action)
if kind == "edit":
return _do_edit(action)
return "[filectl] ok"
output = _do_list(action)
elif kind == "read":
output = _do_read(action)
elif kind == "write":
output = _do_write(action)
elif kind == "edit":
output = _do_edit(action)
else:
output = "[filectl] ok"
return output + relay_json.repair_note(action.get("_repairs") or [])
def _resolve(path_str: str) -> Path: