---
title: "Strands Agents with an OpenAI-compatible model provider"
canonical: https://uplinkswitch.ai/guides/strands-agents
generated: 2026-11-04T07:23:47.011Z
source: https://uplinkswitch.ai/guides/strands-agents
base_url: https://api.uplinkswitch.com/v1
---

[›uplinkswitch](https://uplinkswitch.ai/)

[api.uplinkswitch.com/v1](https://uplinkswitch.ai/models)[Console](https://uplinkswitch.ai/console)

[›uplinkswitch](https://uplinkswitch.ai/)

# 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](https://uplinkswitch.ai/guides)·[Models](https://uplinkswitch.ai/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](https://uplinkswitch.ai/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](https://uplinkswitch.ai/models). `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

| Model | Model id | Input / 1M | Output / 1M | Developer list, in / out |
| --- | --- | --- | --- | --- |
| [Claude Sonnet 5.5](https://uplinkswitch.ai/models/claude-sonnet-5-5) | `claude-sonnet-5-5` | $1.20 | $3.00 | $2.00 / $10.00 |
| [GPT-6.1 Sol](https://uplinkswitch.ai/models/gpt-6.1-sol) | `gpt-6.1-sol` | $0.60 | $3.00 | $2.00 / $10.00 |
| [DeepSeek V4 Pro 0813](https://uplinkswitch.ai/models/deepseek-v4-pro-0813) | `deepseek-v4-pro-0813` | $0.792 | $1.188 | $1.32 / $3.96 |
| [Claude Opus 5.5](https://uplinkswitch.ai/models/claude-opus-5-5) | `claude-opus-5-5` | $2.80 | $10.00 | $4.00 / $20.00 |
| [Gemini 3.1 Pro Preview](https://uplinkswitch.ai/models/gemini-3.1-pro-preview) | `gemini-3.1-pro-preview` | $1.20 | $7.20 | $2.00 / $12.00 |
| [Kimi K3](https://uplinkswitch.ai/models/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:

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](https://uplinkswitch.ai/models).
-   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.

## Related

-   [SDK setup](https://uplinkswitch.ai/guides/sdks)
-   [LangChain setup](https://uplinkswitch.ai/guides/langchain)
-   [Vercel AI SDK setup](https://uplinkswitch.ai/guides/vercel-ai-sdk)
-   [Claude Sonnet 5.5](https://uplinkswitch.ai/models/claude-sonnet-5-5)
-   [GPT-6.1 Sol](https://uplinkswitch.ai/models/gpt-6.1-sol)
-   [DeepSeek V4 Pro](https://uplinkswitch.ai/models/deepseek-v4-pro-0813)
-   [Model catalog](https://uplinkswitch.ai/models)
-   [LLM API price index](https://uplinkswitch.ai/pricing-index)
