Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -853,6 +853,18 @@ result = agent.tool.use_agent(
"params": {"temperature": 1, "max_tokens": 4000}
}
)

# Use OrcaRouter as a named provider (OpenAI-compatible gateway)
os.environ["ORCAROUTER_API_KEY"] = "sk-orca-..."
result = agent.tool.use_agent(
prompt="Analyze this code",
system_prompt="You are a code review assistant.",
model_provider="orcarouter",
model_settings={
"model_id": "orcarouter/auto",
"params": {"temperature": 1, "max_tokens": 4000}
}
)
```

### A2A Client
Expand Down Expand Up @@ -1401,6 +1413,8 @@ The Mem0 Memory Tool supports three different backend configurations:
| STRANDS_MODEL_ID | Default model identifier for environment-based model selection | None |
| STRANDS_MAX_TOKENS | Maximum tokens for the nested agent model | None |
| STRANDS_TEMPERATURE | Sampling temperature for the nested agent model | None |
| ORCAROUTER_API_KEY | API key for the OrcaRouter provider | None |
| ORCAROUTER_BASE_URL | Base URL for the OrcaRouter provider | https://api.orcarouter.ai/v1 |


#### Elasticsearch Memory Tool
Expand Down
2 changes: 1 addition & 1 deletion src/strands_tools/think.py
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ def think(
exist in the parent agent's tool registry. Examples: ["calculator", "file_read", "retrieve"]
If not provided, inherits all tools from the parent agent.
model_provider: Model provider to use for the thinking cycles.
Options: "bedrock", "anthropic", "litellm", "llamaapi", "ollama", "openai", "github"
Options: "bedrock", "anthropic", "litellm", "llamaapi", "ollama", "openai", "github", "orcarouter"
Special values:
- None: Use parent agent's model (default, preserves original behavior)
- "env": Use environment variables to determine provider
Expand Down
2 changes: 1 addition & 1 deletion src/strands_tools/use_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,7 @@ def use_agent(
Examples: ["calculator", "file_read", "retrieve"]
If not provided, inherits all tools from the parent agent.
model_provider: Model provider to use for the nested agent.
Options: "bedrock", "anthropic", "litellm", "llamaapi", "ollama", "openai", "github"
Options: "bedrock", "anthropic", "litellm", "llamaapi", "ollama", "openai", "github", "orcarouter"
Special values:
- None: Use parent agent's model (default, preserves original behavior)
- "env": Use environment variables to determine provider
Expand Down
1 change: 1 addition & 0 deletions src/strands_tools/utils/models/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,5 @@
"writer",
"cohere",
"openai",
"orcarouter",
]
27 changes: 27 additions & 0 deletions src/strands_tools/utils/models/model.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,11 @@ def create_model(provider: str = None, config: dict[str, Any] = None) -> Model:

return OpenAIModel(**config)

elif provider == "orcarouter":
from strands.models.openai import OpenAIModel

return OpenAIModel(**config)

else:
# Try to load custom model provider
try:
Expand Down Expand Up @@ -284,6 +289,16 @@ def get_provider_config(provider: str) -> dict[str, Any]:
"params": {"max_tokens": int(os.getenv("STRANDS_MAX_TOKENS", "4000"))},
}

elif provider == "orcarouter":
return {
"client_args": {
"api_key": os.getenv("ORCAROUTER_API_KEY"),
"base_url": os.getenv("ORCAROUTER_BASE_URL", "https://api.orcarouter.ai/v1"),
},
"model_id": os.getenv("STRANDS_MODEL_ID", "orcarouter/auto"),
"params": {"max_tokens": int(os.getenv("STRANDS_MAX_TOKENS", "4000"))},
}

else:
raise ValueError(f"Unknown provider: {provider}")

Expand All @@ -304,6 +319,7 @@ def get_available_providers() -> list[str]:
"writer",
"cohere",
"github",
"orcarouter",
]


Expand Down Expand Up @@ -391,6 +407,17 @@ def get_provider_info(provider: str) -> dict[str, Any]:
"STRANDS_MAX_TOKENS",
],
},
"orcarouter": {
"name": "OrcaRouter",
"description": "Unified OpenAI-compatible gateway with zero-trust security for AI agents",
"default_model": "orcarouter/auto",
"env_vars": [
"ORCAROUTER_API_KEY",
"ORCAROUTER_BASE_URL",
"STRANDS_MODEL_ID",
"STRANDS_MAX_TOKENS",
],
},
}

return provider_info.get(provider, {"name": provider, "description": "Custom provider"})
2 changes: 1 addition & 1 deletion src/strands_tools/workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -978,7 +978,7 @@ def workflow(
• system_prompt (str): Custom system prompt for this task [OPTIONAL]
• tools (List[str]): Tool names available to this task [OPTIONAL]
• model_provider (str): Model provider for this task [OPTIONAL]
Options: "bedrock", "anthropic", "ollama", "openai", "github", "env"
Options: "bedrock", "anthropic", "ollama", "openai", "github", "orcarouter", "env"
• model_settings (Dict): Model configuration [OPTIONAL]
Example: {"model_id": "claude-sonnet-4", "params": {"temperature": 0.7}}
• dependencies (List[str]): Task IDs this task depends on [OPTIONAL]
Expand Down
43 changes: 43 additions & 0 deletions tests/test_model.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"""Tests for the model provider registry (strands_tools.utils.models.model)."""

from unittest.mock import patch

from strands_tools.utils.models.model import (
create_model,
get_available_providers,
get_provider_config,
get_provider_info,
)


def test_get_provider_config_orcarouter_defaults():
"""OrcaRouter provider should default to the OrcaRouter gateway base URL and auto model."""
config = get_provider_config("orcarouter")
assert config["client_args"]["base_url"] == "https://api.orcarouter.ai/v1"
assert config["model_id"] == "orcarouter/auto"


def test_get_provider_config_orcarouter_env_override(monkeypatch):
"""ORCAROUTER_API_KEY and ORCAROUTER_BASE_URL should be honored."""
monkeypatch.setenv("ORCAROUTER_API_KEY", "sk-orca-test")
monkeypatch.setenv("ORCAROUTER_BASE_URL", "https://custom.example/v1")
config = get_provider_config("orcarouter")
assert config["client_args"]["api_key"] == "sk-orca-test"
assert config["client_args"]["base_url"] == "https://custom.example/v1"


def test_get_available_providers_includes_orcarouter():
assert "orcarouter" in get_available_providers()


def test_get_provider_info_orcarouter():
info = get_provider_info("orcarouter")
assert info["name"] == "OrcaRouter"
assert "ORCAROUTER_API_KEY" in info["env_vars"]


def test_create_model_orcarouter_uses_openai_model():
"""The orcarouter provider is OpenAI-compatible and should build an OpenAIModel."""
with patch("strands.models.openai.OpenAIModel") as mock_cls:
create_model("orcarouter", {"model_id": "orcarouter/auto"})
mock_cls.assert_called_once_with(model_id="orcarouter/auto")
1 change: 1 addition & 0 deletions tests/test_use_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ def test_use_agent_with_all_model_providers(mock_parent_agent, mock_agent_result
"ollama",
"openai",
"github",
"orcarouter",
]

for provider in providers:
Expand Down
Loading