Skip to main content
Strands Agents is an AWS agent framework for building tool-using agents. Use the Osmosis Strands integration when you want Strands tools, Strands message handling, and a direct migration path from an existing strands.Agent. The osmosis-ai package includes strands-agents[litellm], so starter rollouts can use Strands without adding another dependency.

Integration Objects

ObjectPurpose
OsmosisStrandsAgentDrop-in replacement for Strands Agent that registers samples with the active rollout context
OsmosisRolloutModelPlaceholder model that resolves to the current Osmosis policy at runtime
OsmosisStrandsAgent preserves normal Strands constructor arguments such as tools, system_prompt, messages, and callback handlers.

Quick Example

from osmosis_ai.rollout import AgentWorkflow, AgentWorkflowContext
from osmosis_ai.rollout.integrations.agents.strands import (
    OsmosisRolloutModel,
    OsmosisStrandsAgent,
)


class StrandsWorkflow(AgentWorkflow):
    async def run(self, ctx: AgentWorkflowContext) -> None:
        agent = OsmosisStrandsAgent(
            name="assistant",
            model=OsmosisRolloutModel(params={"temperature": 1.0}),
            messages=ctx.prompt,
            callback_handler=None,
        )
        await agent.invoke_async()
ctx.prompt is already the ready-to-use input for the current sample. If your dataset row contains system_prompt and user_prompt, the SDK assembles those fields before your workflow runs.

Tools

Define Strands tools normally with @tool, then pass them to OsmosisStrandsAgent:
from strands import tool
from osmosis_ai.rollout import AgentWorkflow, AgentWorkflowContext
from osmosis_ai.rollout.integrations.agents.strands import (
    OsmosisRolloutModel,
    OsmosisStrandsAgent,
)


@tool
def search(query: str) -> str:
    """Search for information."""
    return f"Results for: {query}"


class SearchWorkflow(AgentWorkflow):
    async def run(self, ctx: AgentWorkflowContext) -> None:
        agent = OsmosisStrandsAgent(
            name="search-agent",
            model=OsmosisRolloutModel(params={"temperature": 1.0}),
            tools=[search],
            system_prompt="You are a helpful assistant.",
            messages=ctx.prompt,
            callback_handler=None,
        )
        await agent.invoke_async()
For most tool-using agents, one invoke_async() call is enough because Strands handles the model-tool loop internally. Add an outer loop only when you need extra stopping conditions or a hard cap across repeated invocations.

OsmosisRolloutModel

OsmosisRolloutModel does not take a model_id. The SDK uses the placeholder model id openai/osmosis-rollout at runtime, and Osmosis routes it to the current policy. Use the params dict for sampling options:
model = OsmosisRolloutModel(
    params={
        "temperature": 1.0,
        "max_tokens": 1024,
    }
)
Construct OsmosisStrandsAgent inside AgentWorkflow.run() or another path where the execution backend has already installed an active RolloutContext. Constructing it at module import time will fail because no rollout context exists yet.

How Sample Collection Works

When constructed with an OsmosisRolloutModel, OsmosisStrandsAgent performs these steps:
1

Read the rollout context

It reads the active RolloutContext from the current execution scope and raises RuntimeError if none is available.
2

Choose a sample ID

It derives a sample ID from the agent’s name, agent_id, or a generated UUID.
3

Resolve the model

It calls model.for_sample(sample_id, rollout_ctx) to create a real LiteLLM model connected to the Osmosis chat completions endpoint.
4

Register the agent

It registers itself with the rollout context so the backend can collect the Strands message history as a RolloutSample.
5

Initialize Strands Agent

It delegates to the normal Strands Agent constructor with the resolved model. Tools, prompts, messages, and callbacks pass through unchanged.

Complete Example

from strands import tool
from osmosis_ai.rollout import (
    AgentWorkflow,
    AgentWorkflowContext,
    Grader,
    GraderContext,
)
from osmosis_ai.rollout.integrations.agents.strands import (
    OsmosisRolloutModel,
    OsmosisStrandsAgent,
)


@tool
def calculator(expression: str) -> str:
    """Evaluate a math expression."""
    return str(eval(expression))


class MathWorkflow(AgentWorkflow):
    async def run(self, ctx: AgentWorkflowContext) -> None:
        agent = OsmosisStrandsAgent(
            name="math-agent",
            model=OsmosisRolloutModel(params={"temperature": 1.0}),
            tools=[calculator],
            system_prompt="You are a math assistant. Use the calculator tool.",
            messages=ctx.prompt,
            callback_handler=None,
        )
        await agent.invoke_async()


def _last_text(sample) -> str:
    if not sample.messages:
        return ""
    content = sample.messages[-1].get("content", "")
    if isinstance(content, str):
        return content
    if isinstance(content, list):
        return next((b["text"] for b in content if isinstance(b, dict) and "text" in b), "")
    return ""


class MathGrader(Grader):
    async def grade(self, ctx: GraderContext) -> None:
        for sample_id, sample in ctx.samples.items():
            answer = _last_text(sample)
            reward = 1.0 if ctx.label and ctx.label.strip() in answer else 0.0
            ctx.set_sample_reward(sample_id, reward)

Migrating from Strands Agent

If you already have a Strands agent, migrate it in four steps:
1

Replace the agent import

Replace from strands import Agent with:
from osmosis_ai.rollout.integrations.agents.strands import OsmosisStrandsAgent
2

Replace the model

Replace your fixed LiteLLM model with an Osmosis placeholder:
from osmosis_ai.rollout.integrations.agents.strands import OsmosisRolloutModel

model = OsmosisRolloutModel(params={"temperature": 1.0})
Drop the model_id; the training cluster decides which policy to serve.
3

Swap the agent class

Replace Agent(...) with OsmosisStrandsAgent(...). Keep tools, system prompt, messages, and callbacks the same.
4

Wrap in AgentWorkflow

Move the agent construction and await agent.invoke_async() call into AgentWorkflow.run().

Strands vs OpenAI Agents

Choose Strands whenChoose OpenAI Agents when
Your tools are already Strands @tool functionsYour workflow already uses Runner.run and OpenAI Agents SDK sessions
You want Strands message traces in sample.messagesYou want persisted Responses API-style session items in sample.messages
You are migrating from strands.AgentYou are migrating from OpenAI Agents SDK Agent
See OpenAI Agents Integration for the OpenAI Agents SDK path.

Next Steps

Building AgentWorkflows

Review the shared workflow contract.

Building Graders

Score the samples produced by your Strands agent.

Evaluation

Submit an evaluation run for your Strands rollout.

OpenAI Agents Integration

Compare the OpenAI Agents SDK integration.