diff --git a/python/samples/02-agents/providers/README.md b/python/samples/02-agents/providers/README.md index 4f0946a2864..8ecbd6c0b5a 100644 --- a/python/samples/02-agents/providers/README.md +++ b/python/samples/02-agents/providers/README.md @@ -15,5 +15,6 @@ This directory groups provider-specific samples for Agent Framework. | [`mistral/`](mistral/) | Mistral AI embedding generation with configurable models and output dimensions. | | [`ollama/`](ollama/) | Local Ollama samples using `OllamaChatClient` (recommended) plus OpenAI-compatible Ollama setup, including reasoning and multimodal examples. | | [`openai/`](openai/) | OpenAI provider samples for Chat and Chat Completion clients, including tools, structured output, sessions, MCP, web search, and multimodal tasks. | +| [`orcarouter/`](orcarouter/) | OrcaRouter gateway samples using the OpenAI-compatible Chat Completions and Responses clients pointed at the gateway, including tool calling and streaming. | Each folder has its own README with setup requirements and file-by-file details. diff --git a/python/samples/02-agents/providers/orcarouter/README.md b/python/samples/02-agents/providers/orcarouter/README.md new file mode 100644 index 00000000000..4e233154d6f --- /dev/null +++ b/python/samples/02-agents/providers/orcarouter/README.md @@ -0,0 +1,39 @@ +# OrcaRouter Examples + +This folder contains examples demonstrating how to use OrcaRouter with the Agent Framework. + +OrcaRouter is an OpenAI-compatible AI gateway built for both models and agents. Like OpenRouter, +it exposes a provider/model namespace across many models — but it also combines adaptive routing, +automatic failover, observability, guardrails, and agent-tool governance behind the same endpoint. +You can use it through the OpenAI-compatible Chat Completions API or the Responses API, so no +OrcaRouter-specific client package is required. + +## Prerequisites + +1. **Create an OrcaRouter account**: Sign up at [orcarouter.ai](https://www.orcarouter.ai) and + obtain an API key. +2. **Pick a model**: Choose a model served by the gateway, for example `orcarouter/fusion`. + List available models with: + ```bash + curl -H "Authorization: Bearer $ORCAROUTER_API_KEY" https://api.orcarouter.ai/v1/models + ``` + +## Examples + +| File | Description | +|------|-------------| +| [`orcarouter_agent_with_openai_chat_client.py`](orcarouter_agent_with_openai_chat_client.py) | Agent with tool calling using the OpenAI Chat Completions client pointed at the OrcaRouter gateway. Shows both streaming and non-streaming responses. | +| [`orcarouter_agent_with_responses_client.py`](orcarouter_agent_with_responses_client.py) | Agent using the OpenAI Responses client (`OpenAIChatClient`) pointed at the OrcaRouter gateway. Shows both streaming and non-streaming responses. | + +## Configuration + +Set the following environment variables: + +- `ORCAROUTER_API_KEY`: Your OrcaRouter API key +- `ORCAROUTER_BASE_URL`: The OrcaRouter gateway base URL with `/v1/` suffix (optional, defaults to `https://api.orcarouter.ai/v1`) + - Example: `export ORCAROUTER_BASE_URL="https://api.orcarouter.ai/v1"` +- `ORCAROUTER_MODEL`: The model name to use (optional, defaults to `orcarouter/fusion`) + - Example: `export ORCAROUTER_MODEL="orcarouter/fusion"` + +The examples fall back to sensible defaults for `ORCAROUTER_BASE_URL` and `ORCAROUTER_MODEL`, so only +`ORCAROUTER_API_KEY` is strictly required. diff --git a/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_openai_chat_client.py b/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_openai_chat_client.py new file mode 100644 index 00000000000..edad2f8bac4 --- /dev/null +++ b/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_openai_chat_client.py @@ -0,0 +1,99 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import os +from random import randint +from typing import Annotated + +from agent_framework import Agent, tool +from agent_framework.openai import OpenAIChatCompletionClient +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() + +""" +OrcaRouter with OpenAI Chat Completion Client Example + +This sample demonstrates using OrcaRouter models through the OpenAI Chat +Completion client by pointing the base URL at the OrcaRouter gateway. +OrcaRouter is an OpenAI-compatible AI gateway for models and agents: like +OpenRouter it exposes a provider/model namespace across many models, but it +also combines adaptive routing, automatic failover, observability, +guardrails, and agent-tool governance behind the same endpoint. + +Environment Variables: +- ORCAROUTER_API_KEY: Your OrcaRouter API key +- ORCAROUTER_BASE_URL: The OrcaRouter gateway base URL + (e.g., "https://api.orcarouter.ai/v1") +- ORCAROUTER_MODEL: The model name to use (e.g., "orcarouter/fusion") +""" + + +# NOTE: approval_mode="never_require" is for sample brevity. Use "always_require" in production; +# see samples/02-agents/tools/function_tool_with_approval.py +# and samples/02-agents/tools/function_tool_with_approval_and_sessions.py. +@tool(approval_mode="never_require") +def get_weather( + location: Annotated[str, "The location to get the weather for."], +) -> str: + """Get the weather for a given location.""" + conditions = ["sunny", "cloudy", "rainy", "stormy"] + return f"The weather in {location} is {conditions[randint(0, 3)]} with a high of {randint(10, 30)}°C." + + +def _client() -> OpenAIChatCompletionClient: + """Create an OpenAI Chat Completion client pointed at the OrcaRouter gateway.""" + return OpenAIChatCompletionClient( + api_key=os.getenv("ORCAROUTER_API_KEY"), + base_url=os.getenv("ORCAROUTER_BASE_URL", "https://api.orcarouter.ai/v1"), + model=os.getenv("ORCAROUTER_MODEL", "orcarouter/fusion"), + ) + + +async def non_streaming_example() -> None: + """Example of non-streaming response (get the complete result at once).""" + print("=== Non-streaming Response Example ===") + + agent = Agent( + client=_client(), + name="WeatherAgent", + instructions="You are a helpful weather agent.", + tools=[get_weather], + ) + + query = "What's the weather like in Seattle?" + print(f"User: {query}") + result = await agent.run(query) + print(f"Agent: {result}\n") + + +async def streaming_example() -> None: + """Example of streaming response (get results as they are generated).""" + print("=== Streaming Response Example ===") + + agent = Agent( + client=_client(), + name="WeatherAgent", + instructions="You are a helpful weather agent.", + tools=[get_weather], + ) + + query = "What's the weather like in Portland?" + print(f"User: {query}") + print("Agent: ", end="", flush=True) + async for chunk in agent.run(query, stream=True): + if chunk.text: + print(chunk.text, end="", flush=True) + print("\n") + + +async def main() -> None: + print("=== OrcaRouter with OpenAI Chat Completion Client Agent Example ===") + + await non_streaming_example() + await streaming_example() + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_responses_client.py b/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_responses_client.py new file mode 100644 index 00000000000..3f3e8505a3b --- /dev/null +++ b/python/samples/02-agents/providers/orcarouter/orcarouter_agent_with_responses_client.py @@ -0,0 +1,82 @@ +# Copyright (c) Microsoft. All rights reserved. + +import asyncio +import os + +from agent_framework import Agent +from agent_framework.openai import OpenAIChatClient +from dotenv import load_dotenv + +# Load environment variables from .env file +load_dotenv() + +""" +OrcaRouter with OpenAI Responses Chat Client Example + +This sample demonstrates using OrcaRouter models through the OpenAI Responses +client by pointing the base URL at the OrcaRouter gateway. In addition to the +OpenAI-compatible Chat Completions API, the gateway also exposes the Responses +API (``/responses``) behind the same endpoint, so ``OpenAIChatClient`` can be +used directly with OrcaRouter. + +Environment Variables: +- ORCAROUTER_API_KEY: Your OrcaRouter API key +- ORCAROUTER_BASE_URL: The OrcaRouter gateway base URL + (e.g., "https://api.orcarouter.ai/v1") +- ORCAROUTER_MODEL: The model name to use (e.g., "orcarouter/fusion") +""" + + +def _client() -> OpenAIChatClient: + """Create an OpenAI Responses client pointed at the OrcaRouter gateway.""" + return OpenAIChatClient( + api_key=os.getenv("ORCAROUTER_API_KEY"), + base_url=os.getenv("ORCAROUTER_BASE_URL", "https://api.orcarouter.ai/v1"), + model=os.getenv("ORCAROUTER_MODEL", "orcarouter/fusion"), + ) + + +async def non_streaming_example() -> None: + """Example of non-streaming response (get the complete result at once).""" + print("=== Non-streaming Response Example ===") + + agent = Agent( + client=_client(), + name="Assistant", + instructions="You are a helpful assistant.", + ) + + query = "What is the capital of France?" + print(f"User: {query}") + result = await agent.run(query) + print(f"Agent: {result}\n") + + +async def streaming_example() -> None: + """Example of streaming response (get results as they are generated).""" + print("=== Streaming Response Example ===") + + agent = Agent( + client=_client(), + name="Assistant", + instructions="You are a helpful assistant.", + ) + + query = "Write a haiku about the ocean." + print(f"User: {query}") + print("Agent: ", end="", flush=True) + async for chunk in agent.run(query, stream=True): + if chunk.text: + print(chunk.text, end="", flush=True) + print("\n") + + +async def main() -> None: + print("=== OrcaRouter with OpenAI Responses Chat Client Agent Example ===") + + await non_streaming_example() + await streaming_example() + + +if __name__ == "__main__": + asyncio.run(main())