Skip to main content

GPT-6 Astra API Tutorial: Build a Release Check Agent With Async Tools and Steering

Use GPT-6 Astra via the OpenAI API to build a Python release check agent with async tools, reasoning controls, Structured Outputs, and cost tracking, then test computer use and steering.
Sep 7, 2026  · 14 min read

Explore with AI

ChatGPTClaudePerplexity

The first time I gave GPT-6 Astra a slow tool and a fast one in the same turn, I expected a traditional synchronous loop: it would ask for the slow tool and block my code while everyone waited. OpenAI's async tool calling docs said Astra could keep working instead, but I was not convinced. The application still manages the background work, so async tool calling does not remove orchestration. The question is whether it changes enough to matter.

Our GPT-6 Astra overview covers the launch and benchmarks, and our GPT-6 Astra vs. Claude Fable 5.1 guide compares its performance and pricing with its biggest competitor. In this tutorial, we'll get GPT-6 Astra working to build a release-check workflow with a test suite, a health endpoint, and a fixed browser check. Separate demos cover model-authored computer use and mid-turn steering.

We'll cover how to:

  • Make a GPT-6 Astra API call
  • Build a synchronous tool-calling loop as the baseline
  • Switch slow checks to async tool calling
  • Run a bounded computer-use check
  • Compare steering with a finish-then-restart baseline over WebSocket
  • Raise the reasoning effort only for the final diagnosis
  • Return a validated go/no-go report with structured outputs
  • Calculate API cost correctly, including cache writes
  • Watch the run live in Streamlit
  • Handle the edge cases that async jobs create

TL;DR

GPT-6 Astra adds three API features to the standard Responses loop: async tool calling, mid-turn steering over WebSockets, and mid-conversation changes to reasoning effort. Four findings from combining all three into a single release-check agent changed how I would build it.

  • Async tool calling cut waiting time, not model work: turn count still depends on the model's call sequence.
  • Steering took less time than the finish-then-restart baseline, though the test did not compare every restart policy.
  • Higher reasoning effort does not necessarily change the diagnosis, even though it uses more reasoning tokens.
  • Running checks together can expose race conditions that a sequential version would hide.

Those results apply to this release check, not every agent workload. Tool duration, shared state, and the number of turns the model takes can all change the outcome.

Working With the OpenAI API

Start your journey developing AI-powered applications with the OpenAI API.
Explore Course

What Is the GPT-6 Astra API?

The GPT-6 Astra API is how you access OpenAI's new flagship model, released on September 3, 2026, through the Responses API. For this tutorial, what matters is the surface: gpt-6-astra accepts text and image inputs through OpenAI’s Responses API. Its reasoning effort ranges from low to max, with no none option. 

The examples in this tutorial use client.responses.create instead of client.chat.completions.create, but migration also requires changes to request, output, and tool-result formats. Remove the custom temperature, top_p, and log-probability settings as well, since Astra does not support them. Before making the first call, let's look at pricing.

How much does GPT-6 Astra cost?

For requests with at most 272,000 input tokens, standard pricing is $10 per million ordinary input tokens and $50 per million output tokens. Cached input costs $1 per million, and cache writes cost $12.50 per million. 

Once a request exceeds that threshold, OpenAI applies a 2x multiplier to the input and cache rates and a 1.5x multiplier to the output rate. The higher rates apply to the entire request, not only the tokens above the threshold. None of the runs in this tutorial came close to the threshold.

What Will We Build With the GPT-6 Astra API?

The staging app is a small Flask task board: a home page, a form to add a task, a button to mark one done, and a /health endpoint. The complete code, staging app included, is in this GitHub repository.

The staging task board the agent checks, showing the task list and add-task form

Three seeded tasks appear before testing. Image by Author.

The app has one intentional flaw. The agent has three checks, but only the test suite is designed to catch them.

Why does the app accept blank task titles?

The task-creation endpoint does not reject a blank title. I left that behavior in place so the agent has a known failure to find without revealing it in the prompt.

Which release checks can the agent run?

The agent can call three tools:

  • run_test_suite runs pytest, including a bulk import test with around 250 HTTP requests. 

  • check_ui_flow uses Playwright to add a task and confirm that it appears. 

  • check_staging_health sends a GET request to /health

All three run against staging, with no mocks. The browser check uses fixed code; the model-authored computer use demo comes later.

How to Set Up the GPT-6 Astra API in Python

You need an OpenAI API key with access to gpt-6-astra. Create a key at platform.openai.com/api-keys, and check that your project has gpt-6-astra enabled. Enterprise workspaces have Astra off by default at launch.

The commands below use Windows PowerShell and install all packages needed for this tutorial, including OpenAI’s realtime for the steering demo.

python -m venv .venv
.venv\Scripts\Activate.ps1
Copy-Item .env.example .env
pip install "openai[realtime]" flask pytest playwright pydantic matplotlib python-dotenv streamlit
playwright install chromium

On macOS or Linux, replace the activation command with source .venv/bin/activate and the copy command with cp .env.example .env

Then add the API key to the new .env file: Open the .env file you just copied and add OPENAI_API_KEY=sk-..., which python-dotenv loads and the SDK picks up automatically, so you never pass the key in code.

If project-specific dependencies or .env files are new to you, our virtual environment and environment variables guides explain them. Confirm the key works before building on it.

If your API key already works with the Responses API, skip the next subsection and start with the synchronous tool loop. The first request only verifies setup.

Make your first GPT-6 Astra API call

Once the key is in place, it needs to be loaded using dotenv. After that, you can create an OpenAI client and send your first request using the client.responses.create() function. The smallest possible request looks like this:

from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

client = OpenAI()
response = client.responses.create(
    model="gpt-6-astra",
    reasoning={"effort": "low"},
    input="In one sentence, what is a staging environment used for?",
)
print(response.output_text)

The response's usage field lists the token counts needed for the later cost calculation.

Build a Synchronous GPT-6 Astra Tool Loop

Snippets below are excerpts; the runnable versions are in the accompanying GitHub repository.

Before touching anything async, I built the ordinary version: 

  1. Call the model

  2. Check for a function_call item

  3. Run the matching tool

  4. Send the result back with previous_response_id

  5. Repeat until the model stops asking for tools. 

This blocking loop is the baseline for the async comparison.

for turn in range(max_turns):
    response = client.responses.create(
        model="gpt-6-astra",
        reasoning={"effort": "low"},
        tools=TOOLS,
        input=next_input,
        previous_response_id=previous_response_id,
    )
    calls = [item for item in response.output if item.type == "function_call"]
    if not calls:
        final_text = response.output_text
        break
    outputs = [
        {"type": "function_call_output", "call_id": call.call_id, "output": run_tool(call)}
        for call in calls
    ]
    next_input, previous_response_id = outputs, response.id

What the baseline run found

In the baseline run, the model called each tool in turn. It found the known validation failure and returned a no-go decision. Across three runs, the total wall-clock time averaged 23.40 seconds. That average covers the whole run, not individual tool times.

How Does GPT-6 Astra Async Tool Calling Work?

Mark a tool with "async": true in its schema, and your app can defer that result while the model either continues working or waits. Your application still runs the tool and manages the background job.

How to run independent checks concurrently

I marked run_test_suite and check_ui_flow as async, and added an app-defined wait_for_tasks tool with no arguments, since this demo only ever has one batch of pending work at a time. That no-argument wait keeps the example small. 

In a production runner, identify jobs with task handles, bind each handle to its original call_id, and wait only when the next step depends on a pending result.

Return each completed result on its original call_id, then return the wait status on the wait tool's own call_id.

TOOLS = [
    {"type": "function", "name": "run_test_suite", "async": True, ...},
    {"type": "function", "name": "check_ui_flow", "async": True, ...},
    {"type": "function", "name": "check_staging_health", ...},
    {"type": "function", "name": "wait_for_tasks", ...},
]

For this run, the app submitted each marked call to a thread pool. While the background checks ran, it performed the fast synchronous health check. It then blocked at wait_for_tasks until the pending checks were completed.

Does async tool calling reduce wall-clock time?

Across three runs, async reduced mean wall-clock time by 19.1%, from 23.40 seconds to 18.94 seconds. The average looked straightforward until the individual runs came in; the chart below shows how much they actually varied. Three runs are enough to show what happened here, not to predict production latency.

Line chart comparing wall clock seconds for three sync runs and three async runs of the same release check

Run times varied in both modes. Image by Author.

Why did concurrent checks cause a race condition?

Running the browser check and the bulk import test at once sometimes caused the bulk import assertion to fail because both checks modified the same in-memory task list. That broke the test's assumption of exclusive access. Isolating data in either the runner or the tests would avoid the race.

Bounded GPT-6 Astra Computer Use for UI Testing

For computer use, GPT-6 Astra's docs recommend code execution, while the structured computer tool remains supported as an alternative. With code execution, one call can combine several actions, loops, and conditional logic, while the computer tool returns one structured mouse or keyboard action at a time for your application to translate and replay.

How to limit the computer-use runner

I called the class BrowserSandbox, but that name overstates its protection. It gives model-authored code a Playwright page, a log() function, and an expect_text() helper. Python can still inject built-ins into exec(), and the page can navigate to another origin.

sandbox_globals = {"page": self.page, "log": log, "expect_text": expect_text}
exec(code, sandbox_globals)

Treat this as a demo runner, not a security boundary. Model-authored code needs an isolated process or container with filesystem, process, network, and origin restrictions.

What happened in the UI check?

I capped the loop at eight turns because a bounded check needs a hard stop. The model inspected the page, found the form input, created the title "UI flow check, cobalt otter 73921," submitted the task, and confirmed that the title appeared, which took 13 seconds. Our GPT-5.4 computer use tutorial covers a detailed example using a predecessor model of Astra.

How Does GPT-6 Astra Mid-Turn Steering Work?

Mid-turn steering is available only for gpt-6-astra over a WebSocket connection.

Open a connection and create a response, then send a response.steer event with new instructions while the response is generating. A response.steer.accepted event means the update is queued, not applied. Before creating the automatic continuation, the server finishes the current output item and any hosted tool work already running. 

If it still needs a client tool result or approval, response.steer.pending identifies the missing input.

async with client.responses.connect() as connection:
    await connection.response.create(model="gpt-6-astra", input=TASK)
    async for event in connection:
        if event.type == "response.created" and initial_response_id is None:
            initial_response_id = event.response.id
            await asyncio.sleep(1.0)
            await connection.response.steer(
                previous_response_id=initial_response_id,
                input="Also add a rollback plan, but skip mobile.",
            )

The one-second delay matches the experiment code and gives the first response time to start. Without that delay, this would test a different point in the response lifecycle.

What does mid-turn steering leave unchanged?

Steering does not rewrite the original response. If the update interrupts it, that response ends with status: "incomplete" and incomplete_details.reason: "steered".A successor response then continues with the new instruction. 

If the first response finishes before the update takes effect, it stays completed. Steering does not reverse or cancel client-side actions that have already started; your application still owns that behavior. Queued steering exists only on the current WebSocket connection, so record the update before attempting a reconnect.

The comparison path lets the first response finish, then sends a new request with the combined instructions. Across two runs, steering averaged 26.91 seconds versus 50.02 seconds for that finish-then-restart path. This comparison does not cover a cancel-and-restart policy or score the final text for correctness.

Two bar charts comparing average seconds and average cost for steering versus restarting

Two-run averages for time and cost. Image by Author.

The restart path generates two full responses that cover some of the same requests. That setup explains part of the time gap, so I would not treat these two runs as a general benchmark for steering.

How to Change GPT-6 Astra Reasoning Effort Mid-Conversation

gpt-6-astra supports reasoning effort from low through max. Higher effort can increase reasoning-token use, but it does not guarantee a different answer. A configuration_update changes the next and later responses until another update overrides it, while the request-level setting stays unchanged. 

In this pipeline, the report ends the conversation, so the update affects only that final step.

response = client.responses.create(
    model="gpt-6-astra",
    previous_response_id=previous_id,
    reasoning={"effort": "low"},  # default remains low
    input=[
        {"type": "configuration_update", "reasoning": {"effort": "high"}},
        {"role": "user", "content": "Diagnose the root cause and recommend a fix."},
    ],
)

I used the same failure trace at both effort levels and compared the diagnosis and token use.

One subtlety: the response's reasoning.effort field still reports the request-level setting, not the effort selected by configuration_update. Do not use that field to check whether the update took effect.

Did high reasoning effort change the diagnosis?

In the full combined run, the escalated step used 108 reasoning tokens. Every other step at low used zero. In an earlier isolated test with a longer failure trace, low effort used zero reasoning tokens, and high effort used 318. Both versions identified the validation bug, so a higher-effort change altered token usage but not the diagnosis.

Configuration updates work only in standard, single-agent requests. The API rejects adjacent updates, and they cannot be combined with automatic compaction or automatic truncation.

How to Use GPT-6 Astra Structured Outputs

The pipeline's last step calls client.responses.parse to replace free text with a validated Pydantic model.

class GoNoGoReport(BaseModel):
    decision: str
    summary: str
    checks_completed: list[str]
    failures: list[str]
    risks: list[str]
    follow_up_actions: list[str]
    confidence: float

response = client.responses.parse(
    model="gpt-6-astra",
    previous_response_id=previous_id,
    text_format=GoNoGoReport,
    input=[...],
)

Pydantic checks the field types declared here. It does not prove that the report matches the evidence, and this version does not restrict decision to two values or confidence to a range.

What did the go/no-go report catch?

The report returned decision: "no_go". It classified the validation failure mentioned earlier under failures and the concurrency issue under risks. For the latter, it wrote: "possible interference from concurrent UI checks against shared staging data." The prompt did not name that risk.

Keep latency and cost outside this schema and calculate them in code. The model fills the report fields from the tool evidence.

The Streamlit interface consumes the same generator as the command-line runner. It renders each tool event as it arrives, then shows the parsed report in the Report and JSON tabs.

Live agent progress next to the final report. Video by Author.

The dashboard runs the combined async release pipeline with its fixed browser check, reasoning update, structured report, and timing display. Its cost panel reads the same ledger as the command-line runner. It does not run the separate model-authored computer use or steering demos.

How to Track GPT-6 Astra API Token Usage and Cost

For the model-token portion of these runs, the usage field contains the four token counts needed to price each response. Cache writes have their own rate, so do not group them with ordinary input. The tools here run in your application; if you add a hosted tool with a separate fee, include that charge as well.

details = usage.input_tokens_details
cached_tokens = details.cached_tokens
cache_write_tokens = details.cache_write_tokens
ordinary_tokens = usage.input_tokens - cached_tokens - cache_write_tokens

cost = (
    ordinary_tokens * PRICE_INPUT
    + cached_tokens * PRICE_CACHED_INPUT
    + cache_write_tokens * PRICE_CACHE_WRITE
    + usage.output_tokens * PRICE_OUTPUT
) / 1_000_000

This calculation covers one response. The ledger applies it after every response, then adds the call totals.

Log cache_write_tokens even when the value is zero. Otherwise, a future cache write can hide inside the ordinary input count, and that is an annoying way to discover a billing error.

GPT-6 Astra Agent Production Considerations

The demo needs these changes before it can gate deployments.

Tool permissions and isolation

Keep the staging boundary and isolate BrowserSandbox as described above. Do not give it database credentials or production access.

Async job lifecycle

In the demo, every pending job finishes, and nothing else touches it. A deployed runner has to survive the cases where neither is true. It needs, for every pending entry:

  • A deadline and a final state, so nothing sits pending forever
  • A delivery flag, so a callback and a retry can't send the same result twice
  • Start and finish timestamps, to tell a timeout apart from a late but valid completion
  • Duplicate-call rejection, so the same task can't be launched twice
  • Background-thread error handling, so a thrown exception surfaces instead of vanishing into the pool
  • Cancellation, which means ignoring a late result and stopping any external work already underway

Steering and irreversible actions

A steer can change future instructions, but it cannot reverse a completed side effect. If a tool has already changed an external system, a separate tool action must compensate for it.

Misalignment monitoring

Automatic stopping applies to Responses API requests that use persisted reasoning, WebSockets, or OpenAI compaction. Other requests can trigger alerts, but are not stopped automatically. 

Before streaming, misalignment monitoring can block a covered run with HTTP 403 and the code misalignment_policy_violation. A streaming client may instead receive an error after output has begun. The API provides no general resume path for the stopped conversation.

GPT-6 Astra Agent Deployment Checklist

Before moving this agent from a local demo to deployment, add these controls. They belong in the application code rather than the model instructions.

  • Set explicit timeouts on the staging app's HTTP calls and the WebSocket connection

  • Log ordinary input, cached input, cache writes, output, response ID, and turn count

  • Alert on incomplete runs or runs that hit the turn cap. Set a separate alert for budget overruns

  • Pin the openai SDK version and recheck async, steering, and configuration_update behavior before upgrading

When Should You Use GPT-6 Astra Async Tools or Steering?

Choose the simplest path that fits the job.

  • Start with a synchronous request and structured outputs when tools return quickly, and requirements stay fixed.
  • Add async tool calling when the model or another tool can perform useful work during a slow call, and the time saved justifies the extra job management overhead.
  • Use mid-turn steering when requirements change during a run.

Final Thoughts

The synchronous release check became more useful once slow tools could overlap, though the result was not a clean win. Across three runs, async reduced the mean time from 23.40 seconds to 18.94 seconds, then exposed a shared-state race that the sequential loop had hidden. 

I would isolate the browser and test data, keep routine turns at low, and raise reasoning effort only when the evidence needs a closer look. If the tools finish quickly and the requirements stay fixed, stop at the synchronous loop with structured outputs. Use async when independent work can overlap, and use steering when instructions change during a response.

For API basics, I recommend taking our Working with the OpenAI API course. For larger agent systems, see our Building Scalable Agentic Systems course.

FAQs

Can I use Chat Completions with GPT-6 Astra?

For plain text, yes. For tool calling, no: Astra requires the Responses API, so every example here uses client.responses.create.

Which models support async tool calling and steering?

Async tool calling was introduced with GPT-6 Astra. Mid-turn steering is Astra-only and WebSocket-only; GPT-5.6 and earlier don't support it at all.

What breaks when I switch an existing request to gpt-6-astra?

Three things. reasoning.effort: "none" returns HTTP 400, so start at low. temperature, top_p, and log-probability settings have to go. And tool calling has to move to Responses if it isn't there already.

Does async tool calling replace parallel tool calls?

No, they solve different problems. Parallel tool calls let the model request several tools in one turn; async lets your app defer one tool's result while the model keeps going.

Why did my async tool call error out with a missing function_call_output?

This error can occur when a non-async tool call in the same batch has not been resolved. Async defers only the marked call; every other tool call still needs an output first.

Does async tool calling require WebSockets?

No. The async implementation above uses regular Responses API calls.

Did the blank-title bug ever get caught by the UI check instead of the test suite?

No. Only the test suite exercised blank-title validation; the UI and health checks tested other behavior.

Why do we use previous_response_id in the tool loop?

It connects each tool result to the response that requested it. The loop can continue the same Responses API conversation without resending the full transcript in every call.


Khalid Abdelaty's photo
Author
Khalid Abdelaty
LinkedIn

I’m a data engineer and community builder who works across data pipelines, cloud, and AI tooling while writing practical, high-impact tutorials for DataCamp and emerging developers.

Topics
Artificial Intelligence
Large Language Models
AI Agents

Learn AI With DataCamp!

Track

Associate AI Engineer for Developers

29 hr
Learn how to integrate AI into software applications using APIs and open-source libraries. Start your journey to becoming an AI Engineer today!
See DetailsRight Arrow
Start Course
See MoreRight Arrow
Related

blog

GPT-6 Astra: Features, Benchmarks, Pricing, and How to Access It

OpenAI's GPT-6 Astra tops computer use, coding, and math benchmarks. Full breakdown of features, scores vs Claude and Gemini, pricing, and how to access it.
Matt Crabtree's photo

Matt Crabtree

12 min

Tutorial

GPT-5.1 Codex Guide With Hands-On Project: Building a GitHub Issue Analyzer Agent

In this GPT-5.1-Codex tutorial, you’ll transform GitHub issues into real engineering plans using GitHub CLI, FireCrawl API, and OpenAI Agents.
Abid Ali Awan's photo

Abid Ali Awan

10 min

Tutorial

AutoGPT Guide: Creating And Deploying Autonomous AI Agents Locally

Learn how to set up AutoGPT, create custom AI agents with a low-code interface, and extend functionality with Python blocks. This hands-on tutorial covers installation, UI basics, and agent creation.
Bex Tuychiev's photo

Bex Tuychiev

Tutorial

GPT-5.4 Computer Use Tutorial: Build a Live News Dashboard

Learn how to use GPT-5.4 computer use to build a live news dashboard that automatically gathers and summarizes news.
Aashi Dutt's photo

Aashi Dutt

11 min

Tutorial

Grok 4.6 API Tutorial: From First Call to a Tool-Using Agent

Learn how to harness SpaceXAI’s newest frontier model to build intelligent, tool-using agents from scratch. This comprehensive guide walks you through everything from basic API setup to deploying a fully autonomous loop with prompt caching and custom tools.
François Aubry's photo

François Aubry

14 min

Tutorial

GPT-4.5 API Tutorial: Getting Started With OpenAI's API

Learn how to connect to the OpenAI API, create an API key, set up a Python environment, and build a basic chatbot using GPT-4.5.
François Aubry's photo

François Aubry

8 min

See MoreSee More