jenkins c089a5ec2a hermes(runtime): emit artifacts and web sources from real tool output
HUX-04/HUX-08: after a successful tool execution the hux-runtime plugin
now registers freshly written files as typed artifacts (create or
immutable version by conversation-scoped title, bounded to 1 MiB,
deterministic idempotency keys) and records up to three deduplicated
web sources from real network/web_search output. Emitters are fail-open
and can never break the tool result. Delivered through the plugin
ConfigMap; 95% branch coverage; quality contract updated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BvMSXH8VH2tMWXanb8SJdf
2026-08-24 04:35:12 -03:00

2.7 KiB

HUX runtime integration

This plugin wraps Hermes's real tool_execution middleware boundary. It is inert unless HUX_RUNTIME_ENABLED=1; HUX_TOOL_ENFORCEMENT=1 additionally requires every exact tool call to be released by HUX before next_call runs.

The process needs these read-only files:

  • HUX_SUBJECT_FILE: router-published usr_<64 lowercase hex> binding;
  • HUX_WORKER_KEY_FILE: mode 0400, used only for worker-trust loopback calls;
  • HUX_CONTEXT_KEY_FILE: the WebUI-created, owner-only, single-link 32-byte context key. Chat and the runtime use the same hux.context.id.v1 helper.

Set HUX_TENANT_SLOT=slot-N, HUX_BASE_URL=http://127.0.0.1:8790, and a bounded HUX_TIMEOUT_SECONDS (default 3). The HUX service and plugin must be in the same pod. HUX_PROJECT_SOURCE defaults to profile:default and must match the source used by WebUI context creation. No HUX port belongs in a Service or ingress.

Every turn first calls the worker-trust, idempotent POST /hux/v1/context/bootstrap. The sidecar must verify every supplied ID against the same context key before registering the deterministic project, session, and conversation. Deployment remains default-off until that route is present in the converged backend.

Hermes currently exposes interruption through on_session_end(interrupted=True) but does not give plugins the authoritative process-registry state or reverted side-effect list required by hux_hook.on_stop. The plugin therefore records a failed/interrupted run and never claims cancellation. A real bridge requires a new post-interrupt hook fired only after the runtime has killed and reaped every registered tool process, with run_id, session_id, turn_id, process_registry_empty, and redacted side-effect receipts.

Quality registration must include services/hermes/plugins/hux-runtime/*.py as source and testing/tests/test_hermes_hux_runtime_plugin.py as its focused test. The current focused gate is 54 passing tests with every production file above 95% line and branch coverage.

Post-tool emitters (HUX-04 / HUX-08)

emitters.sync_after_tool runs only after a successful tool execution and never raises into the tool path. A successful write_files tool whose arguments name a real, non-symlink file of at most 1 MiB creates (or, when a same-titled artifact already exists in the conversation, appends an immutable version to) a typed artifact through the loopback API; the service's secret scrubbing and restricted forcing still apply. A successful network or web_search tool records up to three deduplicated web sources found in the first 64 KiB of real tool output. Both use deterministic idempotency keys, so retries never duplicate records.