Commit graph

8037 commits

Author SHA1 Message Date
saitsuki
e701cdc86e fix(gateway): end finalized expired sessions as reset 2026-07-17 04:51:39 -07:00
Teknium
78b9d98d76 fix(codex): surface nested error envelope in Responses type=error SSE frames
Port from anomalyco/opencode#36130: the Responses spec carries streaming
error details at the top level of the error frame, but the official OpenAI
SDK and several OpenAI-compatible proxies wrap them in an HTTP-style nested
envelope ({"type": "error", "error": {code, message, param}}).

_raise_stream_error only read top-level fields, so nested-envelope frames
collapsed to the generic 'stream emitted error event' placeholder with
code=None — the error classifier never saw the provider's real failure
reason, misrouting rate-limit / context-overflow / entitlement errors into
the generic retry path.

Top-level fields keep precedence; the envelope is a fallback. Null-tolerant
for spec-compliant frames with explicit nulls.
2026-07-17 04:51:14 -07:00
Teknium
4dc2b7be0f fix(mcp): preserve concurrent OAuth manager refresh 2026-07-17 04:50:47 -07:00
Teknium
cf3ae7c59c fix(mcp): preserve live OAuth state during reauth 2026-07-17 04:50:47 -07:00
Teknium
ebd737f4d9 fix(mcp): close hosted OAuth lifecycle gaps 2026-07-17 04:50:47 -07:00
Teknium
6045529724 fix(mcp): harden hosted OAuth across profiles and clients 2026-07-17 04:50:47 -07:00
Ben Barclay
11eaa77daf fix(mcp): serialize hosted oauth reauthorization 2026-07-17 04:50:47 -07:00
Ben Barclay
b09f1ba770 fix(mcp): reject invalid dashboard oauth callbacks 2026-07-17 04:50:47 -07:00
Ben Barclay
05dea7be04 fix(mcp): complete OAuth through hosted dashboards 2026-07-17 04:50:47 -07:00
Teknium
14ea8de763 fix(agent): harden non-finite wait recovery
Only advertise finite watchdog deadlines that are still in the future, exercise the full MoA heartbeat path, and register the salvaged contributor attribution.
2026-07-17 04:46:59 -07:00
发飙的公牛
1a5d2a12d8 fix: handle infinite Codex wait deadlines 2026-07-17 04:46:59 -07:00
Teknium
6dcbcd0277
refactor(console): remove hosted-context command blocking from Hermes Console (#66144)
The dashboard console previously ran under a 'hosted' context that
blocked most commands (auth add, config set model.*, mcp add --command,
cron --script, ...) behind an allowlist + line-policy layer. With the
full Hermes CLI now built into the dashboard, that policy layer is
redundant gatekeeping: the console gets the same command surface
everywhere.

Removed:
- ConsoleContext/contexts plumbing on ConsoleCommand + engine
- EXPECTED_HOSTED_PATHS allowlist + _mark_hosted
- _enforce_hosted_line_policy + HOSTED_CONFIG_* allow/block tables
- _dashboard_console_context() and the context field on the ready frame
- hosted-context tests; context badge in HermesConsoleModal

Kept (mechanical, not policy): shell-syntax rejection, the
interactive/server command blocks (gateway, dashboard, mcp serve, ...),
mutating-command confirmations, output caps, and command timeouts.
2026-07-17 04:33:34 -07:00
Teknium
60419dfb4b fix(codex): reconcile app-server bridge with #38835, gate commentary on show_commentary
Follow-ups on top of @xxxigm's salvaged bridge (#33294):

- Remove the now-dead narrow item/started-only mapper from #38835
  (_codex_note_to_tool_progress) — the full bridge supersedes it and
  keeps the same tool-name contract; its tests are repointed at the
  bridge helpers.
- Preserve main's request_routing/approval-bypass wiring on the
  CodexAppServerSession constructor (landed after the PR was filed).
- Gate agentMessage interim delivery on display.show_commentary so the
  app-server runtime honors the same toggle as the codex_responses
  commentary channel (tool progress is unaffected).
- Add json import (bridge helpers use json.dumps) and modernize the
  wiring test's stub agent for main's usage-accounting attributes.
2026-07-17 04:32:56 -07:00
xxxigm
68d5368f38 test(codex): regression coverage for app-server event bridge (#33200)
42 tests across five suites:

* ``TestCodexItemToToolName`` / ``TestCodexItemToArgs`` /
  ``TestCodexItemToPreview`` / ``TestCodexItemCompletionPayload`` —
  pin the per-type mapping so the synthetic tool name + args the
  UI sees match what ``CodexEventProjector`` writes into messages.
* ``TestStreamDeltaDispatch`` / ``TestToolProgressDispatch`` /
  ``TestAgentMessageInterimDispatch`` — drive each Codex
  notification shape through the bridge and assert the right
  agent callback fires with the right arguments (including the
  duration / is_error / result kwargs the gateway renders).
* ``TestBridgeRobustness`` — defensive paths: non-dict
  notifications, missing params, raising callbacks (must not
  tear down the codex turn loop), and agents without callbacks
  registered (cron / gateway-less contexts).
* ``TestBridgeWiredInRuntime`` — integration guard that
  ``run_codex_app_server_turn`` actually constructs the session
  with ``on_event=<bridge>``, preventing a future refactor from
  silently regressing live progress visibility again.
2026-07-17 04:32:56 -07:00
slow4cyl
bd208a6d77 test(cron): public save_jobs()/load_jobs() post-import HERMES_HOME regression
Review follow-up: the store-internals tests proved _current_cron_store()
resolves lazily, but not that the PUBLIC job I/O honors it. This exercises
save_jobs()/load_jobs() after a late env repoint and asserts the
import-time jobs.json stays byte-identical to a planted sentinel.
2026-07-17 16:08:56 +05:30
slow4cyl
65d6bd2b9f fix(cron): patched compatibility constants take precedence over a repointed env
Review follow-up: tests that monkeypatch CRON_DIR/JOBS_FILE/OUTPUT_DIR (the
documented process-wide compatibility surface) were bypassed by the lazy
env fallback — 3 file-permission tests, the cross-process lock test, and
the heartbeat roundtrip regressed. _current_cron_store() now snapshots the
constants at import and honors any deliberate re-point of them ahead of
the env resolution, so the precedence is: use_cron_store() override >
patched constants > fresh HERMES_HOME > import defaults. Adds a test
pinning constants-beat-env; the late-env sentinel behavior is unchanged.
tests/cron: failure set byte-identical to unpatched main on this box
(the 5 regressions gone); 138 pass in the touched files.
2026-07-17 16:08:56 +05:30
slow4cyl
5c121f157f fix(cron): resolve the no-override store fallback lazily so late env repoints can't write the real jobs file
Complements ec0227b43 (context-scoped cron store): the ContextVar override
is the right tool for deliberate cross-profile scoping, but with no
override active, _current_cron_store() returned the import-time constants —
so a HERMES_HOME set AFTER cron.jobs import (the filed incident: test
fixtures patching the env too late) still read/wrote the user's real
jobs.json. The fallback now resolves the active profile home fresh via
get_hermes_home() (context-local override, then env) and scopes the store
to it; when the home is unchanged since import, the exact module-level
constants are returned as before (zero change in the common path, and they
remain the documented compatibility surface). use_cron_store() still wins.

Three tests: late env repoint scopes the store; unchanged home returns the
import-time constants identically; an active use_cron_store() override
beats the env.
2026-07-17 16:08:56 +05:30
Teknium
0f102fa4dc
feat(browser): store full snapshots on truncation; make eval denylist opt-in (#65923)
* feat(browser): store full snapshots on truncation; make eval denylist opt-in

Two harness fixes motivated by BU_Bench results where fixed-verb + lossy
observation cost Hermes heavily vs code-driven browser agents:

1. Snapshot truncation no longer loses content. When a snapshot exceeds
   the 8000-char threshold, the complete accessibility tree is saved to
   cache/web (same truncate-and-store pattern as web_extract) and the
   truncated view / LLM summary includes the file path plus a ready-made
   read_file call. Element refs beyond the cut are recoverable without
   re-snapshotting. Stored copies are force-redacted and capped at 2MB;
   content-hash filenames dedupe repeated snapshots of the same page.

2. The browser_console(expression=...) sensitive-primitive denylist is
   now opt-in via browser.restrict_evaluate (default false). The
   names-based denylist blocked legitimate DOM extraction — any selector
   or expression containing 'fetch', 'cookie', 'input', etc. — which
   crippled the agent's only programmatic page-inspection path. The
   SSRF/private-URL egress guards in _browser_eval are independent of
   this policy and remain always-on. browser.allow_unsafe_evaluate keeps
   its meaning (bypass the denylist) for configs that already set it.

* test: update None-guard test for stored-snapshot pointer in _extract_relevant_content

test_normal_content_returned pinned the exact return value; the summary
now carries a pointer to the stored full snapshot. Assert the summary
passes through and the pointer is present instead.

* feat(browser): align snapshot threshold with web_extract's 15k char budget

SNAPSHOT_SUMMARIZE_THRESHOLD 8000 -> 15000, matching
web_tools.DEFAULT_EXTRACT_CHAR_LIMIT so the snapshot and web_extract
truncate-and-store paths give the model the same per-page budget.
_truncate_snapshot's default max_chars now follows the constant.
Invariant test added; docs (en+zh) and CLI tip updated.
2026-07-16 23:41:26 -07:00
Teknium
779019ef7d feat(agent): add display.show_commentary toggle for Codex commentary channel
Commentary delivery is on by default; users who find the extra mid-turn
narration noisy can set display.show_commentary: false to restore the
previous behavior (commentary routed to the reasoning channel, visible
only with show_reasoning).

- hermes_cli/config.py: display.show_commentary default true
- agent/agent_init.py: wire config -> agent.show_commentary
- run_agent.py: gate structured commentary extraction on the flag
- agent/codex_runtime.py: gate live-stream commentary callback (falls
  back to legacy reasoning-channel routing when off)
- docs + 2 tests (interim path off, live stream fallback)

Also adds AUTHOR_MAP entries for davidrobertson and 100yenadmin.
2026-07-16 23:27:12 -07:00
Eva
7041c56cdf feat(agent): stream Codex commentary separately 2026-07-16 23:27:12 -07:00
Eva
b008131b54 fix(agent): harden Codex commentary interim delivery 2026-07-16 23:27:12 -07:00
David Robertson
a15397d61a fix(agent): redact Codex interim commentary 2026-07-16 23:27:12 -07:00
David Robertson
136ade2ed5 fix(agent): surface Codex commentary items as interim messages 2026-07-16 23:27:12 -07:00
cresslank
34837597d2 fix(auth): make xAI OAuth pools multi-account resilient
Keep each xAI OAuth auth-add login as an independent manual device-code pool entry and recognize xAI personal-team spending-limit 403 responses as billing exhaustion. Preserve the structured top-level error message so the failed credential is quarantined and the next healthy account is selected without attempting a pointless token refresh.

Route direct xAI HTTP consumers through the credential pool as well. Proactive and 401-reactive refreshes update the exact issuing manual entry, preserve validated xAI base URL overrides, and serialize single-use refresh-token rotation across concurrent pool instances.
2026-07-17 11:37:25 +05:30
Thatgfsj
ef1c622105 fix(title): prevent stale background title generation from reloading unloaded Ollama models
Add a runtime_validator callback to generate_title() / auto_title_session()
/ maybe_auto_title(). Callers snapshot the session's model+provider when
spawning the background titler; the validator runs right before the LLM
request and skips it silently when the live runtime no longer matches —
so a stale title request can't reload a model that strict_single_load
already evicted after a user model switch. Fail-open: a raising validator
never disables titling.

Wired at all four call sites (cli, gateway, tui_gateway, acp_adapter).

Surgical reapply of PR #19137 (base was 8k+ commits stale; the original
patch predates the pinned-language prompts, the atomic-write helper, and
the moved TUI/ACP call sites). Original work by @Thatgfsj. Closes #19027.
2026-07-16 23:07:13 -07:00
Steven Seagondollar
ed2f48b2e6 fix(titles): use active runtime for gateway sessions 2026-07-16 22:54:09 -07:00
Teknium
7facf63ae7 fix(title): reconcile atomic auto-title writes with collision dedup retry
Combines the two salvaged fixes so they compose instead of conflict:
_persist_session_title (#50575) now writes through set_auto_title_if_empty
(#51483) when the store provides it — the collision-dedup retry and the
manual-/title race protection apply together. Predicate failure (a manual
title landed while generation was in flight) returns None: nothing written,
no callback. Legacy stores without the atomic method keep the plain
set_session_title path, including the vanished-session RuntimeError.

Tests cover both store shapes plus the race-skip path; E2E verified against
a real SQLite SessionDB (collision -> 'Weekly Report #2', manual title
preserved, cron dedup, blank guard). AUTHOR_MAP entry for rasitakyol.
2026-07-16 22:39:47 -07:00
Trevor Gordon
9bf5822a2f fix(cron): robust session title generation (#50535, #50536, #50537) 2026-07-16 22:39:47 -07:00
Raşit Akyol
d05cd7c1ef fix(agent): make auto-title write atomic 2026-07-16 22:39:47 -07:00
Raşit Akyol
f725cf830f fix(agent): avoid overwriting manual session titles 2026-07-16 22:39:47 -07:00
Teknium
b170f522a4 test(honcho): align observer-resolution test with post-#62290 call shape
The salvaged test from PR #62982 asserted search_query=None as an explicit
kwarg; current _fetch_peer_context omits search_query when None.
2026-07-16 22:25:22 -07:00
liuhao1024
e5bebe2cad fix(plugins): rebuild Honcho client when timeout config changes
The Honcho client singleton cached the HTTP timeout at first build.
In long-lived processes (gateway, dashboard), changing the timeout
via config.yaml or HONCHO_TIMEOUT had no effect until restart.

Track the resolved timeout alongside the cached client and compare
on each get_honcho_client() call. When the timeout differs, reset
the singleton so the next call rebuilds with the new value.

Fixes #57347
2026-07-16 22:25:22 -07:00
Hermes Pi
73a4574ede fix(honcho): preserve profiles for local IP config 2026-07-16 22:25:22 -07:00
RainbowAndSun
b08a13cd33 test: add prefetch_context observer-resolution test for ai_observe_others
Verify that get_prefetch_context queries user context through the
assistant observer when _ai_observe_others is enabled, matching
the fix that routes _fetch_session_context through
_resolve_observer_target.
2026-07-16 22:25:22 -07:00
fjlaowan1983
af550a7053 fix(honcho): reject whitespace-only search/reasoning queries
Strip query before validation; add regression tests (aligns upstream #11192).

Made-with: Cursor
2026-07-16 22:25:22 -07:00
Teknium
8222b16785 fix(title): follow-ups for salvaged #37349 — lazy config import, guard ordering, config example
- Make the config imports lazy inside _auto_title_enabled(), matching the
  existing _title_language() pattern (title_generator is imported from agent
  code paths where a module-level hermes_cli import risks circularity).
- Check the enabled flag after the cheap first-exchange guard in
  maybe_auto_title so config isn't read on every turn of a long session.
- Repoint the two new tests at the real import site.
- Document the key in cli-config.yaml.example and merge the enabled flag
  into the existing title_generation block in configuration.md.
- AUTHOR_MAP entry for the contributor.
2026-07-16 22:24:45 -07:00
Danny Huang
e20c3c1c29 fix: honor disabled title generation config 2026-07-16 22:24:45 -07:00
Gille
7cb2d2cd4a
fix(auth): detect configured providers absent from registry (#66017)
* fix: detect env-var-configured providers absent from PROVIDER_REGISTRY

is_provider_explicitly_configured() only checked PROVIDER_REGISTRY (a
manually-maintained dict) for env-var names. Providers that exist solely
in the models.dev catalog — e.g. openrouter — were never recognised as
explicitly configured, so they were filtered out of the desktop model
picker even when their API key was set in .env.

Add a fallback to get_provider() (which reads the models.dev catalog)
when PROVIDER_REGISTRY returns None. Both ProviderConfig and ProviderDef
expose .auth_type and .api_key_env_vars with the same shape.

* test: keep OpenRouter provider gate assertion behavioral

* chore(release): map salvaged OpenRouter contributor

---------

Co-authored-by: zzpigpinggai <zzpigpinggai@users.noreply.github.com>
2026-07-16 22:56:45 -04:00
Gille
1f7d2be22f
fix(install): detect Git Bash Mandatory ASLR failures (#64651) 2026-07-16 22:46:46 -04:00
brooklyn!
dfb76d36d5
fix(desktop): put Hermes-managed Node on PATH for install/rebuild (#66002)
Desktop launch and the update-chain rebuild install npm deps whose child
scripts shell out to a bare `node` (e.g. electron-winstaller's
select-7z-arch.js). When launched from the desktop updater chain
(Desktop -> hermes-setup -> hermes update) the shell PATH customizations are
lost, so the install dies with `'node' is not recognized` / `node: not found`.

- cmd_gui: wrap the npm-install env with with_hermes_node_path(_nixos_build_env())
  so managed Node is prepended even on a stripped PATH — mirrors the idiom
  already used by the update deps refresh. (The original fix merged nixos_env
  on TOP of the managed env, whose full os.environ copy clobbered the managed
  PATH back to bare; wrapping fixes that merge order.)
- _cmd_update_impl: spawn the `desktop --build-only` subprocess with
  with_hermes_node_path() so the child starts with managed Node from the outset.

Regression test: the desktop install env now prepends the managed Node dir
ahead of a bare updater PATH instead of passing env=None.

Co-authored-by: F4TB0Yz <jfduarte09@gmail.com>
2026-07-16 20:45:05 -04:00
Devorun
bd00212337
fix(dashboard): drop _HERMES_GATEWAY when spawning hermes actions (#52482)
The web dashboard runs inside the gateway process, so `os.environ` carries
`_HERMES_GATEWAY=1`. `_spawn_hermes_action` spread that into the subprocess env,
so a spawned `hermes gateway restart` (dashboard "Enable webhooks", Telegram QR
apply) tripped the in-process restart-loop guard and exited 1 — the gateway
never restarted, but the dashboard reported `restart_started: true` because it
only checks that the spawn succeeded.

Scrub `_HERMES_GATEWAY` from the spawned action's env, matching what the
gateway's own restart watcher already does (gateway/run.py).

Fixes #52470. Adds a test asserting the spawned env drops the loop-guard var
while keeping HERMES_NONINTERACTIVE.
2026-07-16 19:52:53 -04:00
xxxigm
d4c3f98140
fix(dashboard): unblock basic auth plugin when setting password interactively (#54489) (#63786)
* fix(dashboard): unblock basic auth plugin during interactive password setup

When the dashboard prompts for username/password on a non-loopback bind,
also remove the bundled basic provider from plugins.disabled so
discover_plugins(force=True) can register it (#54489).

* test(dashboard): cover basic auth plugin blocked by plugins.disabled

Regression harness for #54489: credentials in config are not enough when
the bundled basic provider is on the deny-list.
2026-07-16 19:49:39 -04:00
rayoo
921c17af88
fix(dashboard): scope chat attach tokens by session (#60745) 2026-07-16 19:48:47 -04:00
amanning3390
311a5b0a55 feat(kimi): discover K3 on coding endpoint 2026-07-16 13:33:02 -07:00
Erosika
8d1c96fd2f fix(memory): align external prefetch guard with fail-open contracts 2026-07-16 12:48:48 -07:00
LeonSGP43
d77c455d7d fix(memory): fail fast on stuck external prefetch 2026-07-16 12:48:48 -07:00
Erosika
2ad6ab17e3 fix(honcho): enforce recall latency and budget contracts 2026-07-16 12:48:48 -07:00
Erosika
e8957babf4 feat(honcho): make latency-adding paths configurable
queryRewrite (default off) gates the latest-message rewrite so the
extra auxiliary LLM call is opt-in. firstTurnBaseWait and
firstTurnDialecticWait expose the turn-1 bounded waits in seconds
(0 disables). All three resolve host-block-first like every other
field. Also pins per-host timeout resolution with tests.
2026-07-16 12:48:48 -07:00
Erosika
e7fb51d5ac refactor(memory): make query rewrite provider-agnostic
Move query_rewrite from the honcho plugin to plugins/memory/ and
rename the auxiliary task key honcho_query_rewrite ->
memory_query_rewrite so any memory provider can use the same
rewrite path and model/timeout config block. No behavior change.
2026-07-16 12:48:48 -07:00
Erosika
8ab4cb9d0d fix(honcho): gate the stalled-init prefetch wait to the first turn 2026-07-16 12:48:48 -07:00