[nu-demo] hero_agent reads OPENROUTER_API_KEYS (plural) — no fallback to singular #136

Closed
opened 2026-04-23 23:16:06 +00:00 by mik-tf · 1 comment
Owner

Symptom

hero_agent chat fails with:

LLM API error 401 No cookie auth credentials found

even though OPENROUTER_API_KEY is set in the env (the Hero-wide convention).

Root cause

hero_agent/crates/hero_agent/src/config.rs:85:

env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEYS")

reads only OPENROUTER_API_KEYS (plural, comma-separated). It does NOT try OPENROUTER_API_KEY (singular) as a fallback. The aibroker secret store and every other place in the hero stack uses the singular form, so operators naturally set only the singular and hero_agent gets no keys at all.

Demo workaround (applied 2026-04-23)

Patched the hero_agent action env to set BOTH OPENROUTER_API_KEY and OPENROUTER_API_KEYS to the same value.

Proper fix

In config.rs, the key lookup should accept a fallback chain like ["OPENROUTER_API_KEYS", "OPENROUTER_API_KEY"], split the result on comma, and use whichever is present. Extend env_csv (or add env_csv_with_fallback) to support this. Apply the same pattern for any other provider env var hero_agent reads.

Filed 2026-04-23 nu-shell demo bring-up. Signed-off-by: mik-tf

## Symptom hero_agent chat fails with: ``` LLM API error 401 No cookie auth credentials found ``` even though `OPENROUTER_API_KEY` is set in the env (the Hero-wide convention). ## Root cause `hero_agent/crates/hero_agent/src/config.rs:85`: ``` env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEYS") ``` reads only `OPENROUTER_API_KEYS` (plural, comma-separated). It does NOT try `OPENROUTER_API_KEY` (singular) as a fallback. The aibroker secret store and every other place in the hero stack uses the singular form, so operators naturally set only the singular and hero_agent gets no keys at all. ## Demo workaround (applied 2026-04-23) Patched the hero_agent action env to set BOTH `OPENROUTER_API_KEY` and `OPENROUTER_API_KEYS` to the same value. ## Proper fix In `config.rs`, the key lookup should accept a fallback chain like `["OPENROUTER_API_KEYS", "OPENROUTER_API_KEY"]`, split the result on comma, and use whichever is present. Extend `env_csv` (or add `env_csv_with_fallback`) to support this. Apply the same pattern for any other provider env var hero_agent reads. Filed 2026-04-23 nu-shell demo bring-up. Signed-off-by: mik-tf
Author
Owner

Fixed in hero_agent commit cec24b4 on development.

Change at crates/hero_agent/src/config.rs:84:

-openrouter_keys: env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEYS"),
+// Plural takes precedence (comma-separated rotation); falls back
+// to singular OPENROUTER_API_KEY (canonical OpenRouter SDK name)
+// so operators who only set the standard env var still work.
+openrouter_keys: env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEY"),

Root cause was simple: both args to env_csv(primary, fallback) were the same string "OPENROUTER_API_KEYS", so the fallback was a no-op duplicate. Operators who only exported the canonical OpenRouter SDK env var name OPENROUTER_API_KEY ended up with openrouter_keys = [] and chat failing 401 even though the key was present.

Resolution table:

OPENROUTER_API_KEYS OPENROUTER_API_KEY Result
set (CSV) any plural CSV used (rotation path preserved)
unset set singular treated as 1-element CSV → one key in the list
unset unset empty Vec (preserved)

Aligns with service_agent.nu:76 which already forwards the singular env var under the plural action-env name — so after this fix hero_agent works with either name on the operator side.

Verification: cargo fmt --check -p hero_agent clean; cargo check -p hero_agent passes.

Meta-tracker: home#193.

Signed-off-by: mik-tf

Fixed in hero_agent commit `cec24b4` on `development`. Change at `crates/hero_agent/src/config.rs:84`: ```diff -openrouter_keys: env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEYS"), +// Plural takes precedence (comma-separated rotation); falls back +// to singular OPENROUTER_API_KEY (canonical OpenRouter SDK name) +// so operators who only set the standard env var still work. +openrouter_keys: env_csv("OPENROUTER_API_KEYS", "OPENROUTER_API_KEY"), ``` Root cause was simple: both args to `env_csv(primary, fallback)` were the same string `"OPENROUTER_API_KEYS"`, so the fallback was a no-op duplicate. Operators who only exported the canonical OpenRouter SDK env var name `OPENROUTER_API_KEY` ended up with `openrouter_keys = []` and chat failing 401 even though the key was present. Resolution table: | `OPENROUTER_API_KEYS` | `OPENROUTER_API_KEY` | Result | |----------------------|----------------------|--------| | set (CSV) | any | plural CSV used (rotation path preserved) | | unset | set | singular treated as 1-element CSV → one key in the list | | unset | unset | empty Vec (preserved) | Aligns with `service_agent.nu:76` which already forwards the singular env var under the plural action-env name — so after this fix hero_agent works with either name on the operator side. Verification: `cargo fmt --check -p hero_agent` clean; `cargo check -p hero_agent` passes. Meta-tracker: home#193. Signed-off-by: mik-tf
Sign in to join this conversation.
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/home#136
No description provided.