- on_text_delta dropped whitespace-only deltas, so concatenating the `text`
events no longer reproduced the answer (a newline between paragraphs was
lost). Only None/"" (the turn-end sentinel) is skipped now.
- The emitter was attached only after credentials + agent init succeeded, so a
missing key or unknown provider exited 1 with an EMPTY stdout and the
provider error rendered through ChatConsole (stdout). The emitter is now
built before _ensure_runtime_credentials/_init_agent; that path closes the
protocol with init + a failed `result` (exit_code 1, error) and the
credential error goes to stderr whenever stdout is machine-readable
(tool_progress_mode == "off", i.e. -Q and stream-json).
- _tool_started was keyed by tool name, so concurrent same-name calls
clobbered each other's start time; key on tool_call_id when the caller
passes one and surface it on tool_use/tool_result.
Live: `hermes chat -q … --format stream-json` with no provider and with a dead
custom base_url both yield pure JSONL (`system` + `result`, exit 1).
Adds a --format flag to hermes chat single-query mode. stream-json
emits newline-delimited JSON events (init, text, tool_use, tool_result,
result envelope with token stats + exit code) to stdout for CI
pipelines and external tooling. Session ID stays on stderr.
Salvaged from PR #12278 by @ProDrifterDK onto current main, including
the follow-up commit enforcing the single-query contract (implies
quiet, rejects --tui, emits a final result record with exit code 130
on interrupt).