mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-11-06 05:17:15 +00:00
Symptom: in a classic `hermes chat` session on the shared gateway, /cron
add|edit|pause|resume|run|remove still ran main's handler in the CLI
process, which called the cronjob tool there and wrote the profile's
cron/jobs.json from the client. Under strace, every write to jobs.json
came from the `chat --cli` process and none from the gateway.
Root cause: the one-gateway runtime (#106742) made the gateway the
owner of the profile's runtime state and of the ticker that fires cron
jobs. It left CLICommandsMixin._cron_* in the client, and the
gateway's slash.exec refused /cron for every local session except TUI
reads (2efe028116). That left the cron store with two writers.
Change:
- Move main's /cron handler (overview, list and every write) into
hermes_cli/cli_cron_lines.py as line builders (cron_command_lines),
with no other behaviour change. The CLI prints them when it has no
gateway session. The unused CLICommandsMixin._cron_list goes; its
test and eval read cron_list_lines directly.
- On the gateway, /cron is an owner command
(gateway/session_cron_commands.py). Bare /cron and `list` are reads
for every local session; that includes Desktop- and ACP-created
sessions, which main refused with unsupported_command. Every other
form is an admission-fenced control. An unclosed quote is refused as
invalid_params before pre_command fires. `/cron list -a` keeps the
list-all alias that the TUI read path accepted.
- A /cron write runs only when it arrives on a connection that is not
attached to the session: the classic CLI's own command socket
(GatewayConnection.call_until), which waits with no deadline. A
connection attached to the session keeps main's unsupported_command.
That is how Ink, Desktop and ACP send /cron: on their main
connection, which the gateway answers one request at a time and
which waits with a deadline, while a /cron run lasts as long as its
job. The gate is on the requesting connection, not on the surface
that created the session, so a classic CLI that resumed a TUI-made
session still writes (as on main), and Ink on a CLI-made session is
still refused.
- The classic CLI sends /cron to slash.exec
(gateway_setting_commands.GATEWAY_SETTINGS) with no deadline, on a
socket of its own (gateway_plugin_commands.call_unbounded, now shared
with plugin commands; its Ctrl+C handle is renamed
_gateway_command_wait). Ctrl+C prints the stopped line and
propagates.
- Regenerate the parity table. test_pre_command_in_gateway pinned the
old refusal of every classic CLI /cron; it now pins that the accepted
/cron forms fire pre_command once and a refused one (an unclosed
quote) fires nothing.
Why: the design contract allows one writer per owned store, and
clients only read and submit. The gateway already serves this
profile's cron store to its ticker and to Desktop (cron.manage). Now
the classic CLI's writes go through the same process.
Refs #134889 (T1)
Refs #139158