Strands Agents
The SDK’s OpenAIModel with one base URL and one key, in Python and TypeScript. Claude, GPT and DeepSeek agents with tools.
Python
Strands ships an OpenAI provider, and UplinkSwitch speaks the OpenAI format for every model. Install the SDK with the openai extra, create a key in the console and export it as UPLINKSWITCH_API_KEY.
pip install 'strands-agents[openai]'import os
from strands import Agent, tool
from strands.models.openai import OpenAIModel
model = OpenAIModel(
client_args={
"api_key": os.environ["UPLINKSWITCH_API_KEY"],
"base_url": "https://api.uplinkswitch.com/v1",
"default_headers": {
"HTTP-Referer": "https://uplinkswitch.ai",
"X-Title": "Strands Agents",
},
},
model_id="claude-sonnet-5-5",
params={"max_tokens": 1000},
)
@tool
def word_count(text: str) -> int:
"""Count the words in a piece of text."""
return len(text.split())
agent = Agent(model=model, tools=[word_count])
agent("How many words are in 'the quick brown fox jumps'? Use the word_count tool.")base_url stops at /v1, and model_id is the id from the Models page. params goes into every request, so max_tokens and temperature belong there.client_args goes to the OpenAI client, and its two custom headers name the app in our request log. Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro each called word_count and answered 5 in our run.
TypeScript
The TypeScript SDK takes the key as apiKey and the base URL inside clientConfig, which also carries the defaultHeaders that name the app in our request log. api: 'chat' keeps it on Chat Completions.
npm install @strands-agents/sdk openai zodimport { Agent, tool } from '@strands-agents/sdk';
import { OpenAIModel } from '@strands-agents/sdk/models/openai';
import { z } from 'zod';
const model = new OpenAIModel({
api: 'chat',
apiKey: process.env.UPLINKSWITCH_API_KEY,
clientConfig: {
baseURL: 'https://api.uplinkswitch.com/v1',
defaultHeaders: {
'HTTP-Referer': 'https://uplinkswitch.ai',
'X-Title': 'Strands Agents',
},
},
modelId: 'gpt-6.1-sol',
});
const wordCount = tool({
name: 'word_count',
description: 'Count the words in a piece of text.',
inputSchema: z.object({ text: z.string() }),
callback: (input) => input.text.split(/\s+/).length,
});
const agent = new Agent({ model, tools: [wordCount] });
const result = await agent.invoke("How many words are in 'the quick brown fox jumps'?");
console.log(String(result));Structured output
Pass a Pydantic model as structured_output_model on the call. Strands turns it into a tool, and the validated object lands on result.structured_output.
from pydantic import BaseModel
class Capital(BaseModel):
country: str
capital: str
result = Agent(model=model)("What is the capital of France?", structured_output_model=Capital)
print(result.structured_output)
# country='France' capital='Paris'All three models returned the object this way. The deprecated Agent.structured_output() sends response_format instead; with it, Claude Sonnet 5.5 and DeepSeek V4 Pro answered in plain text.
Streaming
stream_async yields text events as the model writes. With the default callback handler, a plain agent(...) call prints the same stream to the terminal.
import asyncio
async def main():
agent = Agent(model=model, callback_handler=None)
async for event in agent.stream_async("Count from 1 to 5."):
if "data" in event:
print(event["data"], end="", flush=True)
asyncio.run(main())Models and prices
| Model | Model id | Input / 1M | Output / 1M | Developer list, in / out |
|---|---|---|---|---|
| Claude Sonnet 5.5 | claude-sonnet-5-5 | $1.20 | $3.00 | $2.00 / $10.00 |
| GPT-6.1 Sol | gpt-6.1-sol | $0.60 | $3.00 | $2.00 / $10.00 |
| DeepSeek V4 Pro 0813 | deepseek-v4-pro-0813 | $0.792 | $1.188 | $1.32 / $3.96 |
| Claude Opus 5.5 | claude-opus-5-5 | $2.80 | $10.00 | $4.00 / $20.00 |
| Gemini 3.1 Pro Preview | gemini-3.1-pro-preview | $1.20 | $7.20 | $2.00 / $12.00 |
| Kimi K3 | kimi-k3 | $0.90 | $4.50 | $3.00 / $15.00 |
USD per million tokens, live from GET /v1/catalog.
An agent sends the whole conversation on every model call, so input tokens add up fast. A task of five calls that together send 20,000 input tokens and get 1,500 back costs $0.0285 on Claude Sonnet 5.5, against $0.055 at Anthropic's list price, and $0.0176 on DeepSeek V4 Pro 0813. Credit is prepaid from $10 with no subscription.
Check it
Confirm the key before you start an agent:
curl https://api.uplinkswitch.com/v1/models \
-H "Authorization: Bearer $UPLINKSWITCH_API_KEY" \
-H "HTTP-Referer: https://uplinkswitch.ai" \
-H "X-Title: Strands Agents"A list of model ids means the key works. The snippets on this page ran against the live API on 2026-10-19: the Python agent with its tool on Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro with strands-agents 1.61.1, the TypeScript agent on GPT-6.1 Sol with @strands-agents/sdk 1.21.0, plus streaming and structured output.
Errors
- A 401 with
The API key is not valid.means the key is wrong or revoked; with no key the message isNo API key was sent. - A 404 with
No such route.meansbase_urllost its/v1. - A 404 with
No such modelmeans themodel_idis not in the catalog. Copy it from the Models page. - A 402 with the code
insufficient_balancemeans the prepaid balance ran out. Requests work again after a top-up.