Strands Agents

The SDK’s OpenAIModel with one base URL and one key, in Python and TypeScript. Claude, GPT and DeepSeek agents with tools.

Checked 2026-10-19

·All guides·Models

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.

shell
pip install 'strands-agents[openai]'
agent.py
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.

shell
npm install @strands-agents/sdk openai zod
agent.ts
import { 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.

structured.py
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.

stream.py
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

ModelModel idInput / 1MOutput / 1MDeveloper list, in / out
Claude Sonnet 5.5claude-sonnet-5-5$1.20$3.00$2.00 / $10.00
GPT-6.1 Solgpt-6.1-sol$0.60$3.00$2.00 / $10.00
DeepSeek V4 Pro 0813deepseek-v4-pro-0813$0.792$1.188$1.32 / $3.96
Claude Opus 5.5claude-opus-5-5$2.80$10.00$4.00 / $20.00
Gemini 3.1 Pro Previewgemini-3.1-pro-preview$1.20$7.20$2.00 / $12.00
Kimi K3kimi-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:

shell
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 is No API key was sent.
  • A 404 with No such route. means base_url lost its /v1.
  • A 404 with No such model means the model_id is not in the catalog. Copy it from the Models page.
  • A 402 with the code insufficient_balance means the prepaid balance ran out. Requests work again after a top-up.

Questions

Yes. The SDK's OpenAIModel provider passes client_args to the OpenAI client, so a base_url of https://api.uplinkswitch.com/v1 and an UplinkSwitch key are all it needs. In TypeScript the same values go in clientConfig and apiKey.

Yes. Through OpenAIModel, claude-sonnet-5-5 and claude-opus-5-5 answer in the OpenAI format, tool calls included. In our run Claude Sonnet 5.5 called the word_count tool and answered 5.

strands-agents 1.61.1 for Python and @strands-agents/sdk 1.21.0 for TypeScript, on 2026-10-19.

structured_output_model, passed to the agent call, returned the object on Claude Sonnet 5.5, GPT-6.1 Sol and DeepSeek V4 Pro. The older Agent.structured_output() method is deprecated in Strands and returned the object only on GPT-6.1 Sol in our run.

Each model call is a separate request, and the Usage page of the console lists every one with its token counts and charge.