Question
Are preambles supported when using structured output?
According to the documentation(Preamble topic), preambles are brief user-visible messages that GPT-5.4 generates before invoking a tool call. I'm trying to use preambles with the OpenAI Agents SDK, but they don't appear when output_type is set (which translates to text.format: json_schema in the Responses API).
Observed behavior:
The first response contains only:
ResponseReasoningItem (internal reasoning, not user-visible)
ResponseFunctionToolCall
There is no ResponseOutputMessage before the tool call — i.e., no preamble is generated.
Expected behavior:
A user-visible text message (preamble) should appear before the tool call, as described in the documentation.
Reproducible Example
from agents import Agent, ModelSettings, Runner, function_tool
class Weather(BaseModel):
city: str
temperature_range: str
conditions: str
class QueryResult(BaseModel):
check_tool_preambles: bool = Field(description="Whether this content is a tool preamble.")
content: str
@function_tool
def get_weather(city: str) -> Weather:
print("[debug] get_weather called")
return Weather(city=city, temperature_range="14-20C", conditions="Sunny with wind.")
agent = Agent(
name="Hello world",
instructions="""You are a helpful agent. <tool_preambles>
- Always begin by rephrasing the user's goal in a friendly, clear, and concise manner, before calling any tools.
- Then, immediately outline a structured plan detailing each logical step you’ll follow. - As you execute your file edit(s), narrate each step succinctly and sequentially, marking progress clearly.
- Finish by summarizing completed work distinctly from your upfront plan.
</tool_preambles>""",
model="gpt-5.4-mini",
tools=[get_weather],
output_type=QueryResult
)
async def main():
result = Runner.run_streamed(agent, input="What's the weather in Tokyo?")
with open("stream_events_output.txt", "w") as f:
async for event in result.stream_events():
#print(event, flush=True)
f.write(str(event) + "\n")
f.write("--------------------------------\n")
print(result.to_input_list())
print("--------------------------------")
print(result.final_output)
if __name__ == "__main__":
asyncio.run(main())
Output
[debug] get_weather called
[{'content': "What's the weather in Tokyo?", 'role': 'user'}, {'id': 'rs_0fc4000fb9b8b38d0069ccc026c4708195a7eb7f2de5455747', 'summary': [], 'type': 'reasoning'}, {'arguments': '{"city":"Tokyo"}', 'call_id': 'call_PdvYnxzSBa0j4gUFAdmOSyaI', 'name': 'get_weather', 'type': 'function_call', 'id': 'fc_0fc4000fb9b8b38d0069ccc026ee7c8195b61ac903b0be407d', 'status': 'completed'}, {'call_id': 'call_PdvYnxzSBa0j4gUFAdmOSyaI', 'output': "city='Tokyo' temperature_range='14-20C' conditions='Sunny with wind.'", 'type': 'function_call_output'}, {'id': 'msg_0fc4000fb9b8b38d0069ccc028367081958aac269a1ab73ca7', 'content': [{'annotations': [], 'text': '{"check_tool_preambles":false,"content":"You’re asking for the current weather in Tokyo.\\n\\nPlan:\\n1. Check the weather for Tokyo.\\n2. Summarize the temperature and conditions clearly.\\n\\nCompleted: Tokyo is sunny and windy, with temperatures around 14–20°C."}', 'type': 'output_text', 'logprobs': []}], 'role': 'assistant', 'status': 'completed', 'type': 'message', 'phase': 'final_answer'}]
--------------------------------
check_tool_preambles=False content='You’re asking for the current weather in Tokyo.\n\nPlan:\n1. Check the weather for Tokyo.\n2. Summarize the temperature and conditions clearly.\n\nCompleted: Tokyo is sunny and windy, with temperatures around 14–20°C.'
Question: How to achieve follow-up messages before tool calls with structured output?
Preambles are critical for reducing perceived latency — users see an immediate acknowledgment ("Let me check the weather in Tokyo...") before the tool executes. Without preambles, there's a noticeable "dead zone" where nothing is streamed to the user while the tool runs.
When output_type is removed, preambles work correctly — the model emits a phase: "commentary" message before the tool call:
[
{'content': "What's the weather in Tokyo?", 'role': 'user'},
{'id': '...', 'summary': [], 'type': 'reasoning'},
{'id': '...', 'content': [{'text': "You'd like to know the current weather in Tokyo.\n\nPlan:\n1. Check the latest weather for Tokyo.\n2. Share a concise summary...", 'type': 'output_text'}], 'role': 'assistant', 'status': 'completed', 'type': 'message', 'phase': 'commentary'},
{'arguments': '{"city":"Tokyo"}', 'call_id': '...', 'name': 'get_weather', 'type': 'function_call', ...},
...
]
But as soon as output_type (i.e., text.format: json_schema) is set, the commentary message disappears entirely, and the model jumps straight to the tool call.
Is there a recommended pattern to combine structured output with preamble/commentary messages? For example:
- Could phase: "commentary" messages be exempt from the json_schema format constraint, since they are not the final answer?
- Is there a planned SDK-level or API-level solution for this use case?
- Any suggested workaround that preserves both type-safe output and user-visible pre-tool-call messages?
Question
Are preambles supported when using structured output?
According to the documentation(Preamble topic), preambles are brief user-visible messages that GPT-5.4 generates before invoking a tool call. I'm trying to use preambles with the OpenAI Agents SDK, but they don't appear when output_type is set (which translates to text.format: json_schema in the Responses API).
Observed behavior:
The first response contains only:
ResponseReasoningItem (internal reasoning, not user-visible)
ResponseFunctionToolCall
There is no ResponseOutputMessage before the tool call — i.e., no preamble is generated.
Expected behavior:
A user-visible text message (preamble) should appear before the tool call, as described in the documentation.
Reproducible Example
Output
Question: How to achieve follow-up messages before tool calls with structured output?
Preambles are critical for reducing perceived latency — users see an immediate acknowledgment ("Let me check the weather in Tokyo...") before the tool executes. Without preambles, there's a noticeable "dead zone" where nothing is streamed to the user while the tool runs.
When output_type is removed, preambles work correctly — the model emits a phase: "commentary" message before the tool call:
[ {'content': "What's the weather in Tokyo?", 'role': 'user'}, {'id': '...', 'summary': [], 'type': 'reasoning'}, {'id': '...', 'content': [{'text': "You'd like to know the current weather in Tokyo.\n\nPlan:\n1. Check the latest weather for Tokyo.\n2. Share a concise summary...", 'type': 'output_text'}], 'role': 'assistant', 'status': 'completed', 'type': 'message', 'phase': 'commentary'}, {'arguments': '{"city":"Tokyo"}', 'call_id': '...', 'name': 'get_weather', 'type': 'function_call', ...}, ... ]But as soon as output_type (i.e., text.format: json_schema) is set, the commentary message disappears entirely, and the model jumps straight to the tool call.
Is there a recommended pattern to combine structured output with preamble/commentary messages? For example: