Skip to content

fix(providers): use chat completions for all Actual routes - #99523

Merged
SHL0MS merged 4 commits into
NousResearch:mainfrom
somewheresy:justin/e-1047-route-hermes-actual-provider-through-chat-completions-with
Sep 10, 2026
Merged

SHL0MS merged 4 commits into
NousResearch:mainfrom
somewheresy:justin/e-1047-route-hermes-actual-provider-through-chat-completions-with

Conversation

@somewheresy

@somewheresy somewheresy commented Aug 31, 2026 •

Copy link
Copy Markdown

Summary

Use /v1/chat/completions for every Actual generation path, including foreground chat, compaction, titles, async tasks, startup resolution, model switches, fallback chains, session restoration, and credential rotation. Store Actual provider settings in config.yaml and credentials in .env.

Motivation

The transport switch left multiple ways to select Responses: auxiliary wrappers, the hosted hostname mapping, persisted task/custom-provider modes, aliases, and runtime transitions. Bare endpoint overrides could also lose /v1. Environment-backed provider settings could override YAML during setup, credential resolution, or live key reloads.

Links

Approach

  • Recognize Actual by its provider aliases or the exact api.actual.inc hostname and enforce Chat Completions when resolving and changing runtimes.
  • Override stale Responses settings in Actual auxiliary tasks and custom providers targeting the hosted relay. Auxiliary overrides sharing the active Actual daemon also retain its protocol. Normalize bare Actual endpoints to /v1.
  • Guard the main Responses send site and the sync/async auxiliary adapter: a known Actual route raises before HTTP even if stale runtime state or a wrapper bypasses resolution. Preserve Actual identity on resolved auxiliary clients.
  • Remove the Actual-specific branch from the Responses transport. Preserve reasoning content, tool-turn replay, supported effort clamping, and one-shot --reasoning propagation.
  • Save endpoint selections in model.base_url. Prefer YAML during setup, discovery, credential-pool resolution, and live API-key reloads. Keep ACTUAL_BASE_URL as a legacy fallback; credentials remain in .env.
  • Preserve the hosted macOS TLS default and explicit TLS overrides.
  • Rebase onto upstream main at 872bafd58d.

Reviewer Focus

The HTTP harness in tests/agent/test_actual_auxiliary_routing.py exercises the real SDK, title generator, compressor, sync/async calls, provider resolution, and live agent transitions. A local server rejects inference routes other than /v1/chat/completions; hosted-route cases resolve api.actual.inc to that server. Coverage includes aliases, custom routes, keyed/keyless local endpoints, stale configuration, bare URLs, unsupported-model fallback, startup fallback, restored sessions, credential rotation, and live key reloads.

Regression cases reproduced the old alias/custom routing, startup fallback, and credential-rotation failures before their fixes. 1,900 tests pass across 109 files, including 121 Actual routing/configuration cases, after rebasing. The 18 forced-Responses cases reproduced outbound HTTP before the send guards and now verify that no HTTP request is sent; normal Actual requests still complete successfully. The suite also exercises the supported Codex Responses paths. Repository Ruff checks and the plugin-compatibility check pass. The routing/configuration review found no remaining material issues. Validation uses local HTTP integration tests; the live hosted Actual service was not exercised in this revision.

GitHub CI, Nix, and Docker workflows at commit 8a6b5b67a7 require upstream workflow approval before running. Current CI run. The PR has no merge conflicts.

Failure Modes

  • Stale title work is cancelled before any HTTP request.
  • Old Actual Responses settings cannot select /v1/responses, including after startup fallback, a model switch, or session restoration. Forced entry into the Responses transport raises a clear error before any HTTP request.
  • Unsupported-model recovery sends sync and async fallback requests through Chat Completions.
  • YAML endpoint selections survive stale environment URLs and API-key reloads. Invalid setup URL input preserves the configured endpoint.
  • Exact hostname checks reject lookalike hosts and URL-path spoofing.
  • Missing reasoning preserves final content; unsupported reasoning levels are clamped to Actual's supported vocabulary.

Breaking Changes

Actual routes now override saved Responses transport selections, including custom configurations targeting api.actual.inc. No config migration is required. ACTUAL_API_MODE was introduced only in an earlier revision of this unmerged PR; existing ACTUAL_BASE_URL settings remain a fallback.

Post-Merge Behavior

Merging triggers upstream CI and the Docker build/publish workflow. Existing Hermes processes receive the fix after updating and restarting. No Actual service deployment or new runtime flag is required. Release smoke: run hermes -z '<prompt>' --provider actual --model <model> --reasoning high, generate a title, and compact a conversation; verify outgoing generation requests use /v1/chat/completions.

Diagrams

flowchart LR
    Config[config.yaml provider and endpoint] --> Runtime[Actual route resolution]
    Key[.env API key] --> Runtime
    Legacy[Legacy URL fallback] --> Runtime
    Task[Auxiliary task or custom provider] --> Runtime
    Runtime --> Chat[Chat and startup]
    Runtime --> Aux[Titles, compaction, sync and async tasks]
    Runtime --> Changes[Switch, fallback, restore, key rotation]
    Chat --> API[POST /v1/chat/completions]
    Aux --> API
    Changes --> API
Loading

@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades labels Aug 31, 2026
@somewheresy
somewheresy force-pushed the justin/e-1047-route-hermes-actual-provider-through-chat-completions-with branch from 0527cfb to fbadfd9 Compare September 2, 2026 15:29
@somewheresy
somewheresy force-pushed the justin/e-1047-route-hermes-actual-provider-through-chat-completions-with branch from d181255 to 7cffb89 Compare September 10, 2026 18:41
@somewheresy somewheresy changed the title fix(providers): route Actual through chat completions fix(providers): route Actual tasks through chat completions Sep 10, 2026
@somewheresy
somewheresy force-pushed the justin/e-1047-route-hermes-actual-provider-through-chat-completions-with branch from 7cffb89 to 4135933 Compare September 10, 2026 19:01
@somewheresy somewheresy changed the title fix(providers): route Actual tasks through chat completions fix(providers): use chat completions for all Actual routes Sep 10, 2026
@SHL0MS
SHL0MS merged commit 2ddeba9 into NousResearch:main Sep 10, 2026
37 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint comp/cli CLI entry point, hermes_cli/, setup wizard comp/gateway Gateway runner, session dispatch, delivery comp/plugins Plugin system and bundled plugins P3 Low — cosmetic, nice to have sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants