Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
301 changes: 293 additions & 8 deletions agent/transports/hermes_tools_mcp_server.py

Large diffs are not rendered by default.

6 changes: 6 additions & 0 deletions hermes_cli/codex_runtime_plugin_migration.py
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,12 @@ def _build_hermes_tools_mcp_entry() -> dict:
}
if env:
out["env"] = env
# Session-id delivery: a NAME, never a value (burn-in rule — a literal id
# written at migrate time would be frozen into config.toml and name the
# wrong session forever). Codex snapshots the names listed here from its
# own process env at MCP spawn, so the shim's own-lineage exclusion
# follows the ACTIVE session (#26604 keep_open resolution, option (a)).
out["env_vars"] = ["HERMES_SESSION_ID"]
# Generous timeouts — browser_navigate or delegate_task can take a
# while; we don't want codex's MCP client to give up too early.
out["startup_timeout_sec"] = 30.0
Expand Down
14 changes: 14 additions & 0 deletions hermes_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
_COMPRESSION_CHILD_SQL,
_FTS_CJK_TRIGGERS,
_FTS_TRIGGERS,
_fts_object_missing,
_LISTABLE_CHILD_SQL,
_PREVIEW_RAW_SELECT,
_ephemeral_child_sql,
Expand Down Expand Up @@ -4205,6 +4206,19 @@ def _do(conn):
)
self._execute_write(_do)

def update_claude_sdk_session_id(
self, session_id: str, sdk_session_id: Optional[str]
) -> None:
"""Persist (or clear, with None) the claude-agent-sdk session id used
to resume the SDK conversation across gateway restarts and
agent-cache eviction (#25267 continuity)."""
def _do(conn):
conn.execute(
"UPDATE sessions SET claude_sdk_session_id = ? WHERE id = ?",
(sdk_session_id, session_id),
)
self._execute_write(_do)

def update_system_prompt(
self, session_id: str, system_prompt: Optional[str]
) -> None:
Expand Down
8 changes: 8 additions & 0 deletions hermes_state_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,13 @@ def _sql_session_last_active_by_id(session_id_expr: str) -> str:
FTS_STORAGE_VERSION = 1


def _fts_object_missing(exc: BaseException) -> bool:
"""True when an FTS probe failure means the table/module is ABSENT
(disable search) rather than transiently unavailable (keep it on)."""
msg = str(exc).lower()
return "no such table" in msg or "no such module" in msg


# Cap on user-controlled FTS5 query input before regex/sanitizer processing.
# Search queries do not need to be arbitrarily large, and bounding them keeps
# sanitizer/runtime behavior predictable under adversarial input.
Expand Down Expand Up @@ -206,6 +213,7 @@ def _sql_session_last_active_by_id(session_id_expr: str) -> str:
model TEXT,
model_config TEXT,
system_prompt TEXT,
claude_sdk_session_id TEXT,
system_prompt_hash TEXT,
parent_session_id TEXT,
started_at REAL NOT NULL,
Expand Down
6 changes: 5 additions & 1 deletion hermes_state_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -1299,8 +1299,12 @@ def _run_trigram_search(
with self._read_ctx() as conn:
try:
tri_cursor = conn.execute(tri_sql, tri_params)
except sqlite3.OperationalError:
except sqlite3.OperationalError as exc:
# Query failed at runtime — let the caller fall back.
# A missing tokenizer is permanent: log it once instead of
# silently retrying on every CJK query.
if self._is_trigram_unavailable_error(exc):
self._warn_trigram_unavailable(exc)
return None
return [dict(row) for row in tri_cursor.fetchall()]

Expand Down
Loading
Loading