mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-09 13:21:42 +00:00
opentui(phase3): launcher integration — HERMES_TUI_ENGINE dual-engine
hermes --tui launches the native OpenTUI engine (Bun) when HERMES_TUI_ENGINE=opentui (env) or display.tui_engine=opentui (config); Ink stays the default and the shipping path is untouched. - _resolve_tui_engine() (env > config > ink); refuses opentui on Windows/Termux (no Bun) -> falls back to ink with a notice. - _make_opentui_argv() -> [bun, src/entry.real.tsx] (no build step). - _bun_bin() with HERMES_BUN override. - Branch at top of _make_tui_argv BEFORE _ensure_tui_node (Bun-only host must not bootstrap Node). - Gate _launch_tui NODE_OPTIONS/--max-old-space-size on engine==ink (Bun is JSC; the V8 flag errors/ignores). Verified end-to-end via tmux: real hermes --tui -> Bun -> OpenTUI -> real Python gateway streamed a real reply. No-flag default still ink.
This commit is contained in:
parent
24f74eb888
commit
2bd9c9b881
741 changed files with 17733 additions and 79889 deletions
|
|
@ -606,63 +606,6 @@ class MemoryStore:
|
|||
raise RuntimeError(f"Failed to write memory file {path}: {e}")
|
||||
|
||||
|
||||
def _apply_write_gate(action: str, target: str, content: Optional[str],
|
||||
old_text: Optional[str]) -> Optional[str]:
|
||||
"""Evaluate the memory write gate. Returns a JSON tool-result string when
|
||||
the write should NOT proceed normally (blocked or staged), or None when the
|
||||
caller should perform the real write.
|
||||
|
||||
Only the mutating actions (add/replace/remove) are gated.
|
||||
"""
|
||||
if action not in {"add", "replace", "remove"}:
|
||||
return None
|
||||
|
||||
try:
|
||||
from tools import write_approval as wa
|
||||
except Exception:
|
||||
# If the gate module can't load, fail open (current behaviour) rather
|
||||
# than blocking all memory writes.
|
||||
return None
|
||||
|
||||
# Build a small inline summary/detail for the foreground approval prompt.
|
||||
label = "user profile" if target == "user" else "memory"
|
||||
if action == "add":
|
||||
summary = f"add to {label}"
|
||||
detail = content or ""
|
||||
elif action == "replace":
|
||||
summary = f"replace in {label}"
|
||||
detail = f"old: {old_text}\nnew: {content}"
|
||||
else: # remove
|
||||
summary = f"remove from {label}"
|
||||
detail = old_text or ""
|
||||
|
||||
decision = wa.evaluate_gate(wa.MEMORY, inline_summary=summary, inline_detail=detail)
|
||||
|
||||
if decision.allow:
|
||||
return None
|
||||
|
||||
if decision.blocked:
|
||||
return tool_error(decision.message, success=False)
|
||||
|
||||
# stage
|
||||
payload = {
|
||||
"action": action,
|
||||
"target": target,
|
||||
"content": content,
|
||||
"old_text": old_text,
|
||||
}
|
||||
record = wa.stage_write(
|
||||
wa.MEMORY, payload,
|
||||
summary=f"{summary}: {detail[:120]}",
|
||||
origin=wa.current_origin(),
|
||||
)
|
||||
return json.dumps(
|
||||
{"success": True, "staged": True, "pending_id": record["id"],
|
||||
"message": decision.message},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
|
||||
def memory_tool(
|
||||
action: str,
|
||||
target: str = "memory",
|
||||
|
|
@ -681,29 +624,21 @@ def memory_tool(
|
|||
if target not in {"memory", "user"}:
|
||||
return tool_error(f"Invalid target '{target}'. Use 'memory' or 'user'.", success=False)
|
||||
|
||||
# Validate required params BEFORE the gate so an invalid write is rejected
|
||||
# immediately instead of being staged and only failing at approve time.
|
||||
if action == "add" and not content:
|
||||
return tool_error("Content is required for 'add' action.", success=False)
|
||||
if action == "replace" and (not old_text or not content):
|
||||
missing = "old_text" if not old_text else "content"
|
||||
return tool_error(f"{missing} is required for 'replace' action.", success=False)
|
||||
if action == "remove" and not old_text:
|
||||
return tool_error("old_text is required for 'remove' action.", success=False)
|
||||
|
||||
# Approval gate: when on, stages the write (background/gateway) or prompts
|
||||
# inline (interactive CLI); when off (default) passes straight through.
|
||||
gate_result = _apply_write_gate(action, target, content, old_text)
|
||||
if gate_result is not None:
|
||||
return gate_result
|
||||
|
||||
if action == "add":
|
||||
if not content:
|
||||
return tool_error("Content is required for 'add' action.", success=False)
|
||||
result = store.add(target, content)
|
||||
|
||||
elif action == "replace":
|
||||
if not old_text:
|
||||
return tool_error("old_text is required for 'replace' action.", success=False)
|
||||
if not content:
|
||||
return tool_error("content is required for 'replace' action.", success=False)
|
||||
result = store.replace(target, old_text, content)
|
||||
|
||||
elif action == "remove":
|
||||
if not old_text:
|
||||
return tool_error("old_text is required for 'remove' action.", success=False)
|
||||
result = store.remove(target, old_text)
|
||||
|
||||
else:
|
||||
|
|
@ -717,23 +652,7 @@ def check_memory_requirements() -> bool:
|
|||
return True
|
||||
|
||||
|
||||
def apply_memory_pending(payload: Dict[str, Any], store: "MemoryStore") -> Dict[str, Any]:
|
||||
"""Replay a staged memory write directly against the store, bypassing the
|
||||
write gate. Called by the /memory approve handler.
|
||||
|
||||
Returns the store's result dict.
|
||||
"""
|
||||
action = payload.get("action")
|
||||
target = payload.get("target", "memory")
|
||||
content = payload.get("content") or ""
|
||||
old_text = payload.get("old_text") or ""
|
||||
if action == "add":
|
||||
return store.add(target, content)
|
||||
if action == "replace":
|
||||
return store.replace(target, old_text, content)
|
||||
if action == "remove":
|
||||
return store.remove(target, old_text)
|
||||
return {"success": False, "error": f"Unknown staged action '{action}'."}
|
||||
# =============================================================================
|
||||
# OpenAI Function-Calling Schema
|
||||
# =============================================================================
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue