Skip to content

fix(delegate): resolve Portal model aliases before delegating to upstream API#28644

Open
JasonOA888 wants to merge 1 commit into
NousResearch:mainfrom
JasonOA888:fix/28023-resolve-delegation-model-alias
Open

fix(delegate): resolve Portal model aliases before delegating to upstream API#28644
JasonOA888 wants to merge 1 commit into
NousResearch:mainfrom
JasonOA888:fix/28023-resolve-delegation-model-alias

Conversation

@JasonOA888

Copy link
Copy Markdown
Contributor

Summary

Fixes #28023

Portal free-tier recommendations (e.g. nemotron-free, llama70b-free) and short aliases (e.g. sonnet, opus) are convenient for display but are NOT valid model IDs for upstream API calls. When such an alias lands in delegation.model (or is resolved from a runtime provider default), the delegation call fails with a 400 Bad Request from the upstream API.

Root Cause

_resolve_delegation_credentials() passes the configured model string through verbatim to the child agent. When the model is a Portal alias like nemotron-free, OpenRouter rejects it with:

{"error":{"message":"nemotron-free is not a valid model ID","code":400}}

Changes

Added _resolve_model_alias() in tools/delegate_tool.py which:

  1. Pass-through for fully-qualified model IDs (containing /) — no resolution needed
  2. Static catalog resolution via detect_static_provider_for_model() — reuses the same alias logic as /model switching
  3. Suffix stripping — removes -free/_free suffixes and retries (handles Portal aliases like nemotron-freenemotronnvidia/nemotron-3-super-120b-a12b)
  4. Graceful fallback — returns the original string with a warning log if resolution fails

Applied at all three return points in _resolve_delegation_credentials():

  • delegation.base_url path
  • No-provider path (child inherits from parent)
  • Provider-resolved path (via resolve_runtime_provider)

Testing

  • Syntax validation: ast.parse() passes
  • The resolution logic reuses existing detect_static_provider_for_model() which has its own test coverage

Files Changed

  • tools/delegate_tool.py — +71 lines (_resolve_model_alias + 3 call sites)

…ream API

Portal free-tier recommendations (e.g. nemotron-free, llama70b-free) and
short aliases (e.g. sonnet, opus) are convenient for display but are NOT
valid model IDs for upstream API calls. When such an alias lands in
delegation.model (or is resolved from a runtime provider default), the
delegation call fails with a 400 from the upstream API.

This adds _resolve_model_alias() which:
1. Passes through fully-qualified model IDs (containing /) unchanged
2. Tries detect_static_provider_for_model() to resolve known aliases
3. Strips -free/_free suffixes and retries resolution
4. Falls back to the original string with a warning log

Applied at all three return points in _resolve_delegation_credentials():
- base_url path
- no-provider path (inherit from parent)
- provider-resolved path

Closes NousResearch#28023
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists tool/delegate Subagent delegation provider/openrouter OpenRouter aggregator labels May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

P2 Medium — degraded but workaround exists provider/openrouter OpenRouter aggregator tool/delegate Subagent delegation type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] delegate_with_model / delegate_parallel sends unresolved free-tier model aliases to OpenRouter — all calls fail 400

2 participants