Merge branch 'main' into bb/gui

This commit is contained in:
emozilla
2026-05-20 16:01:41 -04:00
72 changed files with 2726 additions and 742 deletions
+13 -1
View File
@@ -901,7 +901,19 @@ def init_agent(
hermes_home = get_hermes_home()
agent.logs_dir = hermes_home / "sessions"
agent.logs_dir.mkdir(parents=True, exist_ok=True)
agent.session_log_file = agent.logs_dir / f"session_{agent.session_id}.json"
# Per-session JSON snapshot writer (~/.hermes/sessions/session_{sid}.json)
# is opt-in via sessions.write_json_snapshots (default False). state.db
# is canonical — the snapshot is only useful for external tooling that
# reads the JSON files directly. See run_agent._save_session_log.
agent._session_json_enabled = False
try:
from hermes_cli.config import load_config as _load_sess_cfg
_sess_cfg = (_load_sess_cfg().get("sessions") or {})
agent._session_json_enabled = bool(_sess_cfg.get("write_json_snapshots", False))
except Exception:
pass
# logs_dir is retained unconditionally for request_dump_*.json (debug
# breadcrumb path written by agent_runtime_helpers.dump_api_request_debug).
# Track conversation messages for session logging
agent._session_messages: List[Dict[str, Any]] = []
-2
View File
@@ -387,8 +387,6 @@ def compress_context(
_SESSION_ID.set(agent.session_id)
except Exception:
pass
# Update session_log_file to point to the new session's JSON file
agent.session_log_file = agent.logs_dir / f"session_{agent.session_id}.json"
agent._session_db_created = False
agent._session_db.create_session(
session_id=agent.session_id,
-5
View File
@@ -1454,7 +1454,6 @@ def run_conversation(
}
messages.append(continue_msg)
agent._session_messages = messages
agent._save_session_log(messages)
restart_with_length_continuation = True
break
@@ -3086,7 +3085,6 @@ def run_conversation(
if not agent.quiet_mode:
agent._vprint(f"{agent.log_prefix}↻ Codex response incomplete; continuing turn ({agent._codex_incomplete_retries}/3)")
agent._session_messages = messages
agent._save_session_log(messages)
continue
agent._codex_incomplete_retries = 0
@@ -3411,7 +3409,6 @@ def run_conversation(
# Save session log incrementally (so progress is visible even if interrupted)
agent._session_messages = messages
agent._save_session_log(messages)
# Continue loop for next response
continue
@@ -3578,7 +3575,6 @@ def run_conversation(
interim_msg["_thinking_prefill"] = True
messages.append(interim_msg)
agent._session_messages = messages
agent._save_session_log(messages)
continue
# ── Empty response retry ──────────────────────
@@ -3712,7 +3708,6 @@ def run_conversation(
}
messages.append(continue_msg)
agent._session_messages = messages
agent._save_session_log(messages)
continue
codex_ack_continuations = 0
+20 -5
View File
@@ -112,17 +112,31 @@ class ChatCompletionsTransport(ProviderTransport):
def convert_messages(
self, messages: list[dict[str, Any]], **kwargs
) -> list[dict[str, Any]]:
"""Messages are already in OpenAI format — sanitize Codex leaks only.
"""Messages are already in OpenAI format — strip internal fields
that strict chat-completions providers reject with HTTP 400/422.
Strips Codex Responses API fields (``codex_reasoning_items`` /
``codex_message_items`` on the message, ``call_id``/``response_item_id``
on tool_calls) that strict chat-completions providers reject with 400/422.
Strips:
- Codex Responses API fields: ``codex_reasoning_items`` /
``codex_message_items`` on the message, ``call_id`` /
``response_item_id`` on ``tool_calls`` entries.
- ``tool_name`` on tool-result messages — written by
``make_tool_result_message()`` for the SQLite FTS index, but not
part of the Chat Completions schema. Strict providers (Fireworks,
Moonshot/Kimi) reject any payload containing it with
``Extra inputs are not permitted, field: 'messages[N].tool_name'``.
Permissive providers (OpenRouter, MiniMax) silently ignore the
field, which masked the bug for months.
"""
needs_sanitize = False
for msg in messages:
if not isinstance(msg, dict):
continue
if "codex_reasoning_items" in msg or "codex_message_items" in msg:
if (
"codex_reasoning_items" in msg
or "codex_message_items" in msg
or "tool_name" in msg
):
needs_sanitize = True
break
tool_calls = msg.get("tool_calls")
@@ -145,6 +159,7 @@ class ChatCompletionsTransport(ProviderTransport):
continue
msg.pop("codex_reasoning_items", None)
msg.pop("codex_message_items", None)
msg.pop("tool_name", None)
tool_calls = msg.get("tool_calls")
if isinstance(tool_calls, list):
for tc in tool_calls: