Mastra’s agent HTTP API returns a JSON structure with steps, each containing content
items typed as reasoning, tool-call, tool-result, and text. The raw output is
dense. Start by exploring it:
# Hit the API and see raw structure
http localhost:4111/api/agents/weather-agent/generate \
messages[0]="what's the weather in montreal?" | jq .
# Get just the final answer
http localhost:4111/api/agents/weather-agent/generate \
messages[0]="what's the weather in montreal?" | jq -r '.text'
# Explore what's inside steps
http localhost:4111/api/agents/weather-agent/generate \
messages[0]="what's the weather in montreal?" | jq '.steps[].content[] | .type'
# "reasoning"
# "tool-call"
# "tool-result"
# "text"
# "reasoning"
# "text"
# See what fields each type has
http localhost:4111/api/agents/weather-agent/generate \
messages[0]="what's the weather in montreal?" | jq '.steps[].content[] | select(.type == "tool-call")'
Once the structure is clear, pipe through jq -r with inline ANSI escape sequences to
colorize each piece:
http localhost:4111/api/agents/weather-agent/generate \
messages[0]="what's the weather in montreal?" | jq -r '
(
.steps[]
| .content[]
| select(.type != "tool-result" and .type != "text")
| if .type == "tool-call" then
"\u001b[35m<\(.type)>\(.text // .toolName)</\(.type)>\u001b[0m"
else
"\u001b[90m<\(.type)>\(.text // .toolName)</\(.type)>\u001b[0m"
end
),
"\n\n\u001b[32mAssistant: \(.text)\u001b[0m"
'
The \u001b[Xm sequences are ANSI color codes: 35 is magenta for tool calls, 90 is
dark gray for reasoning, 32 is green for the final answer. jq outputs them literally in
raw mode (-r), and the terminal renders them as colors. The filter uses
.text // .toolName to handle content items that store their label in different fields
depending on type.