GPT-6 Astra ships four API mechanics that don't exist on older OpenAI models: async tool calling, mid-turn steering, in-conversation reasoning-effort updates, and a reworked prompt cache. This tutorial walks through each one with the exact payloads from OpenAI's docs.

Everything below is drawn from OpenAI's official Astra documentation (the model guide plus the dedicated async-tool-calling, steering, reasoning, and prompt-caching guides on developers.openai.com, fetched September 16, 2026). If you haven't done the base migration yet — model name, dropped sampling params, Responses API — do that first with our Astra migration guide; this piece assumes the request shape is already Astra-ready.

The setup: one Responses API request

Astra's model ID is gpt-6-astra (the only snapshot), with a 1,050,000-token context window, 922,000 max input tokens, and 128,000 max output tokens. Tool calling requires the Responses API — Astra technically supports Chat Completions, but function calling there is not supported, and OpenAI's misalignment monitoring doesn't cover Chat Completions requests either. A minimal request looks like any other Responses call:

POST /v1/responses
{
  "model": "gpt-6-astra",
  "reasoning": { "effort": "medium" },
  "input": "Summarize the failed deploys from the attached log."
}

Reasoning effort accepts low, medium, high, xhigh, and max — there is no none on Astra, and requesting it returns HTTP 400. If your old integration ran at none or minimal, OpenAI's guidance is to start at low and compare results. The models reason adaptively within an effort level, using fewer tokens on easy tasks, so low is less of a downgrade than it sounds.

Async tool calling: async true plus call_id

The headline change. Mark a function or custom tool with async: true and Astra keeps working — reasoning, calling other tools, answering independent parts of the request — while your application executes the tool. You return the result whenever it's ready, matched by the original call_id:

{
  "type": "function",
  "name": "lookup_price",
  "async": true,
  "description": "Look up a product price in the background. Choose a fresh
   task_handle unique within this conversation, including completed tasks.",
  "parameters": { "...": "..." }
}

// later, when your job finishes:
{
  "type": "function_call_output",
  "call_id": "call_abc123",
  "output": "{\"price\": 129.99}"
}

Three boundaries from the docs worth internalizing before you architect around this: your application still executes the tool — async tools don't move execution to OpenAI or manage your background jobs; hosted built-in tools (web search, code interpreter, and so on) can't be made async; and in multi-agent mode you shouldn't combine async tools with parallel tool calls. Results continue the conversation via previous_response_id exactly like synchronous tool outputs.

When the model genuinely needs a pending result before it can proceed, OpenAI documents a wait tool pattern: you define a synchronous wait_for_tasks function that takes a list of task_handle strings (one unique handle per async call), block in that tool until the selected tasks finish, and deliver each completed result on its original call_id before returning the wait call's status output. The handles must stay unique across the whole conversation, including completed tasks — reuse is where this pattern quietly breaks.

Free download

Astra prompts & migration quick reference (PDF)

OpenAI's official Astra prompt blocks, the migration checklist, pricing, and the new async tool-calling and steering mechanics - one 5-page indexed PDF.

Prefer no email? Grab the PDF directly.

Mid-turn steering: response.steer over WebSocket

Steering lets you redirect a response that's already generating without losing the work it has done. It's available only on Astra and only over a WebSocket connection to the Responses API. After you get response.created for the running response, send:

{
  "type": "response.steer",
  "previous_response_id": "resp_1",
  "input": "Keep the scope small enough for one developer to finish in two weeks."
}

The event accepts only those three fields. A response.steer.accepted ack means your input is queued — not that the model has acted on it yet. The interrupted response ends as response.incomplete with incomplete_details.reason: "steered", and the model continues under your new direction. If the response is blocked waiting on tool results or approvals, you'll get response.steer.pending with reason waiting_for_required_input instead.

Steering has hard limits that shape how you should use it: it cannot rewrite output already sent to your application, undo actions already taken, or cancel tools that have already started. And queued steering input lives only on the current connection — drop the WebSocket and it's gone. Treat it as "course-correct the remainder of the turn," never as an undo button. Error codes to handle: invalid_input, steering_not_supported, response_not_found, and too_many_pending_steers.

Reasoning effort mid-conversation: configuration_update

On older models, changing reasoning effort meant a new request-level setting — which changes the prompt prefix and invalidates your cache. Astra instead takes a configuration_update item placed in the input array before the next user message:

{ "type": "configuration_update", "reasoning": { "effort": "high" } },
{ "role": "user", "content": "Analyze the failure modes and propose rollback steps." }

The request-level reasoning.effort stays unchanged — which is the whole point, because that preserves the original prompt prefix for caching. The updated effort applies until another configuration_update overrides it. Constraints from the reasoning guide: Astra-only, standard single-agent mode only, effort is the only thing it can change, the API rejects two adjacent updates, and it's incompatible with automatic compaction and truncation (explicit compaction via a compaction_trigger item still works — add a fresh update after compacting). One observability gotcha: the response's reasoning.effort field keeps reporting the request-level setting, not the updated one, so log your updates yourself.

Prompt caching: one TTL, explicit breakpoints

Astra drops prompt_cache_retention; the replacement is prompt_cache_options.ttl, whose only supported value, "30m", is also the default — a cached prefix stays reusable for 30 minutes after its last write or reuse. The economics changed too: cache reads bill at 0.1x the input rate and cache writes at 1.25x, so by OpenAI's own arithmetic a prefix written once and reused nine times costs 2.15x its ordinary input cost versus 10x uncached. The minimum cacheable prefix is 1,024 tokens, each request can create up to four cache writes, and if your prefix ends with content that changes between requests you can pin the boundary with prompt_cache_options.mode: "explicit" plus a prompt_cache_breakpoint on the last stable content block. When migrating, compare cached_tokens, cache_write_tokens, latency, and total cost before and after — cache-write billing means a badly placed breakpoint can cost you money rather than save it.

What it costs, and the 403 you should expect

Standard pricing is $10 per million input tokens, $1 cached, $12.50 cache writes, $50 output — with a long-context surcharge (2x input and cache rates, 1.5x output for the whole request) once a prompt passes 272K input tokens. Batch and Flex run at half price; Fast mode at double, and Fast mode is unavailable with EU data residency. OpenAI's counterweight to the sticker shock is that Astra uses "substantially fewer output tokens — delivering a lower estimated API cost per task than earlier models despite its higher per-token pricing."

Finally, plan for one new failure mode: misalignment monitoring. OpenAI asynchronously reviews Astra's reasoning and actions in consequential contexts (sensitive data access, destructive changes) and can stop a conversation outright — your request fails with HTTP 403, error code misalignment_policy_violation, the conversation cannot be resumed through the API, and anything the agent already did is not rolled back. Build your retry logic to recognize that code and hand off to a human instead of retrying, and subscribe to the safety.alert.created webhook if you want the alert detail.

Where to go from here

The prompting layer on top of these mechanics — autonomy language, instruction hierarchy, the anti-slop blocklist — is covered in our Astra best practices guide, and all of the prompt blocks plus this tutorial's parameter tables are in the free 5-page PDF above. For picking which workloads deserve Astra's pricing in the first place, see Astra best use cases.