Skip to main content
AgentWorkflow is the SDK contract for rollout behavior. You subclass it, implement one async run() method, and create one sample either by returning its message history or by calling the current policy through an Osmosis-supported agent integration that registers the sample source. The workflow should answer one question: given this dataset prompt, what should the agent do before the grader scores the result?

Base Class

The SDK shape is:
run() is called once for each workflow execution. Construct any per-execution agent or session objects inside the method and run the agent. Then either return the sample directly or let the integration register the resulting conversation with the active RolloutContext.

Workflow return value

run() accepts three shapes, all normalized to a single sample: Supported integrations register a sample source for you, so most workflows return None: OsmosisStrandsAgent registers its Strands history, while OsmosisMemorySession registers an OpenAI Agents SDK session. Return AgentWorkflowOutput when you build the message history yourself:
AgentWorkflowOutput.info is reserved and is not currently passed to graders. Use metrics for finite numeric sample measurements and ctx.artifacts_dir for files.
AgentWorkflowOutput rejects unknown top-level fields and non-finite metric values (NaN, inf, -inf). The same validation runs across Local and Harbor/container execution.

AgentWorkflowContext

The ctx object gives the workflow its input and config: If your dataset row contains system_prompt, user_prompt, and ground_truth, the prompt fields are assembled into ctx.prompt. The reference answer is not passed to the workflow; it is exposed to your grader as ctx.label. The same metadata object is available on both AgentWorkflowContext and GraderContext, so workflows and graders can read the same per-row context.
Keep task answers out of AgentWorkflow.run(). The workflow should produce behavior; the Grader should decide whether that behavior deserves reward.

Writing Artifacts

Use ctx.artifacts_dir to write files that shouldn’t be embedded in the sample payload — logs, traces, screenshots, or other large or binary outputs. Each rollout gets its own directory, but it’s None when the environment can’t provision one, so guard with if ctx.artifacts_dir: before writing to it — an unguarded write raises and fails the workflow.
After the rollout finishes, collected files appear alongside its sample in the run’s Artifacts panel on the Osmosis Platform, mirroring the layout you write under ctx.artifacts_dir. Artifact collection never affects rewards or rollout status.

Saved Trajectories

Rollout servers created with create_rollout_server() save finished samples as ATIF (Agent Trajectory Interchange Format) documents alongside run artifacts. Persistence is best-effort and never changes reward or rollout status. Calling LocalBackend.run_workflow() or another backend method directly in a custom harness does not install this server lifecycle; that harness must save any trajectory it needs. Files land next to the artifacts directory on the platform-managed host:
RolloutSample.messages preserves the framework-native history that graders read. For ATIF persistence, built-in integrations make a separate, best-effort normalized copy in trajectory_messages; normalization failure leaves the native sample intact and skips trajectory persistence. Explicit workflow output uses its returned messages for both views when they can be copied.
If you build a custom sample source whose native history isn’t already OpenAI chat-completions-shaped, set RolloutSample.trajectory_messages on the returned sample to control what gets persisted (an explicit None skips trajectory saving for that sample).
ATIF includes usage, model, and timestamp data only when the source messages or server report provide those fields. Missing metadata stays absent; the SDK does not fabricate it.

Model Routing Requirement

LLM calls inside run() must route through the RolloutContext installed by the execution backend. The training cluster uses the rollout-scoped chat-completions URL from this context to serve the current policy, collect traces, and connect the reward to the sample.
Use one of the supported integrations: Do not call litellm, the OpenAI SDK, or another provider SDK directly with a hard-coded policy model from run(). Direct calls bypass the rollout context and are not compatible with training.

Strands Pattern

For Strands, pass ctx.prompt directly as messages and call invoke_async():
Constructing OsmosisStrandsAgent inside run() binds it to the active rollout context and registers the agent as a sample source. See Strands Integration for tool examples, migration steps, and details about OsmosisRolloutModel.

OpenAI Agents Pattern

For OpenAI Agents, construct an OsmosisAgent, attach OpenAI Agents ModelSettings, create one OsmosisMemorySession, and pass that session to Runner.run():
The session is what records the OpenAI Agents SDK conversation for grading. Create it inside run() so it registers with the current RolloutContext. See OpenAI Agents Integration for session behavior, tracing notes, and migration steps.

Custom Configuration

Custom configs extend AgentWorkflowConfig. Define a module-level config instance in your rollout entrypoint and pass it to the backend:
Pass the config instance explicitly to the backend constructor, for example LocalBackend(workflow=SearchWorkflow, workflow_config=search_workflow_config). Eval and training TOML files do not currently set workflow config fields directly. BaseConfig allows extra fields, so simple rollout configs usually do not need additional Pydantic boilerplate.

Tool-Using Workflows

Tool use belongs inside your agent framework, not in the backend. Define tools the way your framework expects, pass them into the Osmosis-wrapped agent, and let the integration record the resulting messages. For example, a Strands workflow can keep its tool list in config:

Entry Point Wiring

Workflow classes and config objects require explicit wiring. Select them in the backend constructor and expose that backend through the rollout server:
Multiple concrete AgentWorkflow subclasses can exist in the same module; only the class passed as workflow runs. Submit preflight imports the entrypoint once to surface import-time errors and does not inspect the module namespace; see Files in a Rollout for when that import is skipped and what it executes locally.

Next Steps

Strands Integration

Build a Strands-based rollout with tools and OsmosisStrandsAgent.

OpenAI Agents Integration

Build an OpenAI Agents SDK rollout with OsmosisAgent and OsmosisMemorySession.

Grader

Define reward logic for the sample your workflow produces.

Evaluation

Submit an evaluation run to test your workflow and grader before a training run.
Last modified on August 10, 2026