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
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.
AgentWorkflowContext
Thectx 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.
Writing Artifacts
Usectx.artifacts_dir to write files that shouldn’t be embedded in the sample payload, such as 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.
ctx.artifacts_dir. Artifact collection never affects rewards or rollout status.
Write artifacts off the event loop with asyncio.to_thread, as shown above. In managed runs, ctx.artifacts_dir can be backed by remote storage, so closing a file may wait for its upload. A synchronous write then blocks every rollout on the server and delays result polling.
Saved Trajectories
Rollout servers created withcreate_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.
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.
Live Trajectory Previews
Live trajectory previews are disabled unless the hosting environment enables preview publication. When enabled, the rollout server samples supported conversations about every three seconds and publishes at most the 100 most recent ATIF steps; size limits can shorten the preview further. Previews are diagnostic only and do not replace the grading sample, affect rewards, or change the savedtrajectory.json. Before publication, the SDK redacts the configured LLM API key and recognized credential patterns, including authorization headers and URL credentials.
When the host enables previews, these sources provide snapshots automatically:
Workflows that only return messages from
run() at completion have no live source, so they produce no preview. Bundles built with an older SDK version also produce no preview and keep their final-result behavior. Mini-swe-agent versions that write their trajectory only on exit can’t provide running previews.
Opt Out for a Rollout
To keep a rollout out of live previews, setpreview_enabled = False on the active rollout context. Do this at the start of run(), before you construct the agent or session and before the first await:
Add Previews to a Custom Sample Source
CustomSampleSource implementations publish no preview by default. To opt in, override async get_preview(max_messages) and return a RolloutSample holding a copy of at most max_messages recent messages:
run() with set_sample_source() on the active rollout context; each rollout accepts only one source. get_preview() must return a bounded, read-only snapshot. Don’t call get_sample() from it or mutate the history that graders read. Previews from custom sources show unknown step IDs and turn counts.
Model Routing Requirement
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, passctx.prompt directly as messages and call invoke_async():
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 anOsmosisAgent, attach OpenAI Agents ModelSettings, create one OsmosisMemorySession, and pass that session to Runner.run():
run() so it registers with the current RolloutContext.
See OpenAI Agents Integration for session behavior, tracing notes, and migration steps.
Custom Configuration
Custom configs extendAgentWorkflowConfig. Define a module-level config instance in your rollout entrypoint and pass it to the backend:
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: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.