Skip to content

Port Hermes Gateway activity events to main#90

Merged
madtank merged 4 commits intomainfrom
codex/hermes-gateway-events-port
Apr 23, 2026
Merged

Port Hermes Gateway activity events to main#90
madtank merged 4 commits intomainfrom
codex/hermes-gateway-events-port

Conversation

@madtank
Copy link
Copy Markdown
Member

@madtank madtank commented Apr 23, 2026

Summary

  • ports PR feat(examples/hermes): emit AX_GATEWAY_EVENT phase events for tool calls #84 onto current main so Gateway-managed Hermes sentinel runtimes emit structured AX_GATEWAY_EVENT status and tool activity lines
  • redirects Hermes terminal chatter away from Gateway reply capture so only phase events and the final response are posted
  • extracts concise activity text from tool arguments for richer frontend processing bubbles

Supersedes #84.

Verification

  • uv run ruff check ax_cli/ examples/hermes_sentinel/hermes_bridge.py
  • uv run ruff format --check ax_cli/ examples/hermes_sentinel/hermes_bridge.py
  • uv run pytest -q tests/test_gateway_commands.py
  • uv run pytest -q
  • git diff --check

anvil and others added 4 commits April 23, 2026 23:34
The hermes_sentinel bridge was final-reply-only: no tool_call, no status,
no AX_GATEWAY_EVENT lines, so Gateway-managed hermes runtimes produced
blank phase bubbles in the UI even though the underlying AIAgent emits
tool_progress callbacks internally.

This pipes hermes's `tool_progress_callback` (AIAgent constructor param,
fires before each tool with (name, args_preview, args_dict)) into
AX_GATEWAY_EVENT `tool_start` / `tool_result` pairs so the UI chip shows
what the agent is doing in real time. Also emits `status` events for
started → thinking → completed / error phases wrapping the run, and
normalizes any run_conversation exception into a clean `error` status
event instead of letting the traceback escape to stderr (which Gateway
would otherwise post as the reply body).

Protocol consumed by Gateway runtime (see ax_cli/gateway.py):
- `AX_GATEWAY_EVENT {"kind":"status","status":"...","message":"..."}`
- `AX_GATEWAY_EVENT {"kind":"tool_start","tool_name":"...","tool_call_id":"...","status":"tool_call",...}`
- `AX_GATEWAY_EVENT {"kind":"tool_result","tool_name":"...","tool_call_id":"...","status":"tool_complete",...}`
Unprefixed stdout continues to accumulate into the final reply body.

Validated on dev.paxai.app: dev_sentinel registered with this bridge,
phase sequence reaches the pending bubble via agent_processing SSE.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…minal chatter doesn't leak into reply

Hermes's AIAgent prints progress animations ("deliberating...", tool
previews, "💻 $ pwd", "ಠ_ಠ computing...", etc.) to stdout even with
quiet_mode=True. Gateway captures unprefixed stdout as the reply body,
so the bubble was receiving Hermes's terminal chatter instead of the
actual final_response — e.g. "[tool] ٩(๑❛ᴗ❛๑)۶ deliberating... ┊ 💻 $
pwd 7.4s" as the user-visible reply.

Fix: capture _real_stdout before the run, redirect sys.stdout/sys.stderr
to /dev/null during run_conversation, emit AX_GATEWAY_EVENT lines and
the final reply via a dedicated writer bound to _real_stdout. Clean
separation: hermes's internal prints get swallowed, our phase events
and the real reply reach Gateway exactly once.

Validated on dev.paxai.app (dev_sentinel msg bf2c87b6):

    reply_sent | pong  cwd: `/home/ax-agent/agents/dev_sentinel`

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Instead of chip reading a generic "@x is using terminal...", surface the
specific command/file so the user sees what the agent is actually doing:

  terminal   + {command:"pwd"}    → "$ pwd"
  read_file  + {path:"AGENTS.md"} → "reading AGENTS.md"
  write_file + {path:"notes.md"}  → "writing notes.md"
  edit_file                       → "editing <path>"
  search/grep                     → "searching <pattern>"
  web_search                      → "web search: <query>"
  fetch                           → "fetching <url>"
  unknown tool                    → first scalar arg or "using <tool>"

Truncated to 80 chars at the emitter so the chip stays short.

Validated on dev.paxai.app (msg 71d14a1b multi-tool run):
  activity="reading /home/ax-agent/agents/dev_sentinel/AGENTS.md"
  activity="$ pwd"

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@madtank madtank merged commit b91f9b9 into main Apr 23, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant