Once tools or reasoning are involved, output_text alone hides what happened; and usage is your bill.
output_text is a shortcut. The full answer lives in response.output, a list of items. Each item has a type:
message: text written by the model, withcontentparts of typeoutput_text.reasoning: a record of the model thinking before it answered (reasoning models).function_call: the model asking your code to run a function.- tool items such as
web_search_callfor built-in tools.
A simple question returns one message item; with tools you may get several items in order. Loop over them and handle each type you care about.
Check response.status. completed means a full answer. incomplete means it was cut short, and response.incomplete_details says why, for example max_output_tokens when it hit your limit. Do not treat an incomplete answer as finished.
response.usage shows the cost drivers: input_tokens, output_tokens and total_tokens, plus details such as cached input tokens and reasoning tokens. Output tokens normally cost more than input, and reasoning tokens are billed as output even though you never see them.
Log response.id and usage for each call; it makes debugging and cost reports straightforward.
Example
from openai import OpenAI
client = OpenAI()
r = client.responses.create(
model="gpt-6-astra",
input="Explain photosynthesis in detail.",
max_output_tokens=200,
)
for item in r.output:
print(item.type) # e.g. reasoning, message
print(r.status) # completed / incomplete
if r.status == "incomplete":
print("cut short:", r.incomplete_details.reason)
u = r.usage
print(u.input_tokens, u.output_tokens,
u.output_tokens_details.reasoning_tokens)Remember
response.outputis a list of typed items- status
incompletemeans the answer was cut short - usage shows input, output and hidden reasoning tokens
Watch out for
- Setting max_output_tokens very low for a reasoning model; it can run out before writing any visible text.