Skip to content

nemoclaw inference set breaks Hermes sandboxes for Anthropic providers (Hermes sync drops the anthropic-messages wire mode) #4746

@jahubba

Description

@jahubba

Description

nemoclaw inference set --provider anthropic-prod (and --provider compatible-anthropic-endpoint) leaves a Hermes-type sandbox unable to run any inference: every agent turn is rejected by the OpenShell L7 policy with

[OCSF] NET:OPEN [MED] DENIED inference.local:443 [reason:connection not allowed by policy: POST /chat/completions]

and the agent surfaces a 403 to the user on every channel message. The same providers work for OpenClaw-type sandboxes.

Expected: after nemoclaw inference set --provider anthropic-prod --model claude-sonnet-4-6, the Hermes agent's inference calls succeed through inference.local.

Root cause

Two related drops of the wire-format information on the Hermes sync path:

  1. patchHermesInferenceConfig discards route.inferenceApi (src/lib/actions/inference-set.ts). It writes only model.default, model.base_url, and a hardcoded model.provider: "custom". Compare patchOpenClawInferenceConfig, which propagates api: route.inferenceApi into the provider config — that's why OpenClaw works and Hermes doesn't.

  2. getSandboxInferenceConfig defaults compatible-anthropic-endpoint to the OpenAI wire (src/lib/inference/config.ts). The guard reads inferenceApi === "openai-completions", but inferenceApi is initialized to preferredInferenceApi || "openai-completions" — so a null preference (the Hermes sync never passes one) silently selects the managed/OpenAI branch for an Anthropic-wire provider.

Downstream mechanics: Hermes resolves the transport of a custom provider via base-URL heuristics (hermes_cli/providers.pyapi.anthropic.com or a /anthropic suffix → anthropic_messages); https://inference.local/v1 matches nothing, so Hermes emits POST /chat/completions. Onboarding registers both providers as providerType: "anthropic" (src/lib/onboard/providers.ts), whose L7 policy only permits the Anthropic wire (/v1/messages). Mismatch → every call denied.

Hermes natively supports the missing key: model.api_mode: anthropic_messages is honored for custom providers (its auth flow even cleans up stale api_mode values on provider switches, confirming it's a supported config surface).

Reproduction Steps

  1. Onboard a Hermes sandbox (e.g. the NemoHermes path), any initial provider.
  2. openshell provider create --name anthropic-prod --type anthropic --credential ANTHROPIC_API_KEY
  3. nemoclaw inference set --provider anthropic-prod --model claude-sonnet-4-6 (with --no-verify if the gateway host cannot probe api.anthropic.com)
  4. Message the agent on any channel, or from inside the sandbox:
    curl -sk https://inference.local/v1/chat/completions -H 'content-type: application/json' -d '{"model":"claude-sonnet-4-6","max_tokens":10,"messages":[{"role":"user","content":"ping"}]}'
  5. Observe the L7 denial in nemoclaw <name> logs and the agent failing to answer.

/sandbox/.hermes/config.yaml after step 3 shows the synced block:

model:
  default: claude-sonnet-4-6
  base_url: https://inference.local   # anthropic route
  provider: custom                    # → Hermes speaks /chat/completions
  # (no api_mode — the bug)

Proposed fix

  • patchHermesInferenceConfig: when route.inferenceApi === "anthropic-messages", also write model.api_mode: "anthropic_messages"; delete the key on non-anthropic routes so a stale wire mode never survives a provider switch.
  • getSandboxInferenceConfig: keep compatible-anthropic-endpoint on the OpenAI wire only for an explicit preferredInferenceApi === "openai-completions", not the null-default.

PR with both fixes + unit tests to follow.

Environment

  • NemoClaw v0.0.55 (also present on current main), Hermes Agent v2026.5.16 sandbox (nemohermes)
  • Host: Linux 5.15 (Jetson, aarch64), Node v22.22.3, Docker + OpenShell gateway
  • Workaround in the meantime: use the compatible-endpoint (OpenAI-wire) profile pointed at Anthropic's OpenAI-compatible endpoint (OPENAI_BASE_URL=https://api.anthropic.com/v1) — consistent on both sides of the gateway, verified working.

Metadata

Metadata

Assignees

No one assigned

    Labels

    area: inferenceInference routing, serving, model selection, or outputsarea: sandboxOpenShell sandbox lifecycle, runtime, config, or recoveryintegration: hermesHermes integration behaviorprovider: anthropicAnthropic or Claude provider behavior

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions