Absolutely—here’s a concise post you can drop into the Make Community, fully in English and with a real response sample.
Title: OpenAI Responses API output structure varies when tools are enabled → mapping intermittently empty in Make
Post:
Hi all,
I’m calling the OpenAI Responses API from Make via HTTP (not the built-in OpenAI app).
Model: gpt-4o-mini with text.format.type = "text". Sometimes I also pass tools with tool_choice: "auto" for file_search (vector store).
Problem
When tools are enabled, the API returns a mixed output[] array (e.g., a file_search_call followed by a message). The UI “click-to-map” path (like output[1].content[0].text) then changes between runs, and output_text may be missing; result: my mapping is sometimes empty.
If I remove tools/tool_choice, the structure stays stable and {{<step>.data.output_text}} works every time.
Concrete response example (trimmed):
{
"id": "resp_...",
"model": "gpt-4o-mini-2024-07-18",
"text": { "format": { "type": "text" }, "verbosity": "medium" },
"tools": [
{ "type": "file_search", "vector_store_ids": ["vs_..."], "max_num_results": 5 }
],
"tool_choice": "auto",
"output": [
{
"id": "fs_...",
"type": "file_search_call",
"status": "completed",
"queries": ["..."]
},
{
"id": "msg_...",
"type": "message",
"status": "completed",
"role": "assistant",
"content": [
{ "type": "output_text", "text": "Hello …(final text)…" }
]
}
],
"output_text": null
}
Because of this, index-based mappings (e.g., output[1].content[0].text) are brittle.
Question
What’s your best practice in Make to reliably extract the text when tools might add/remove entries in output[]?
What I’m doing now (works):
- HTTP body (simplified)
{
"model": "gpt-4o-mini",
"temperature": 0.2,
"max_output_tokens": 400,
"text": { "format": { "type": "text" } },
"input": [ ... ],
"tools": [
{ "type": "file_search", "vector_store_ids": ["vs_..."], "max_num_results": 5 }
],
"tool_choice": "auto"
}
- Normalizer step in Make (Set variable right after the HTTP call)
I create a singleai_textvariable so all later modules can use it without deep, indexy mappings.
(Replace8with your HTTP step number; Make mapper syntax):
{{
ifempty(
8.data.output_text;
join(
map(
8.data.output[];
join(
map(
ifempty(get(item;"content"); array());
get(item;"text")
);
""
)
);
""
)
)
}}
-
First tries
output_text(when present). -
Otherwise: loops through all
output[], safely getscontent[](or empty array), pulls eachtext, and concatenates.
Then in my JSON body / email body / anywhere I need the answer, I just use {{ai_text}}. This made the flow stable even with tools on.
Alternative (UI-driven): Iterator + Text Aggregator
-
Iterator over
8.data.output[] -
(Optional) Filter for
type = message -
Text Aggregator to
join(map(content[]; text); "") -
Store result as
ai_text
Why it “just works” without tools
If I remove tools (or set tool_choice: "none"), the response is usually a single message and output_text is filled; index paths remain stable.
Would love to hear if there’s an even cleaner pattern (e.g., a recommended “coalesce text” recipe in Make) or tips to handle tool-added outputs more elegantly. Thanks!