Content Parts
Agent responses (and user messages) use content_parts to carry structured data alongside the plain content string. There are four types:
| Type | Purpose | Details |
|---|---|---|
"text" | A text segment of the response | Mirrors content; used when the response interleaves text with other part types |
"context" | Documents/filters/tags the agent found or that the client attached | See Passing Context |
"tool" | Tool execution lifecycle events | Described below |
"table" | Structured tabular data | Described below |
During streaming, content_parts grows with each SSE event as the agent progresses through tool calls and text generation.
Tool Content Parts
When an agent executes tools (search, sub-agents, custom functions), it streams tool execution state to the client via content_parts with type: "tool". This lets you build UIs that show what the agent is doing in real time — "Searching for documents...", "Analyzing results...", etc.
Which tool calls are streamed to the client, and which fields (params, response, display_text) are included, is controlled by the agent's streaming tool events configuration.
Tool Lifecycle
Each tool call progresses through a lifecycle reflected in the status field:
running → completed
running → error
The agent streams a ContentPartTool for each state transition:
1. Running
When the agent decides to call a tool, it emits a tool content part with status: "running":
{
"type": "tool",
"tool": {
"tool_call_id": "call_abc123",
"name": "document_search",
"params": {"query": "What is BERT?"},
"display_text": "Searching for documents about BERT...",
"status": "running"
}
}
2. Completed
When the tool finishes successfully:
{
"type": "tool",
"tool": {
"tool_call_id": "call_abc123",
"name": "document_search",
"params": {"query": "What is BERT?"},
"response": {"document_ids": ["abc_0", "def_0"], "count": 2},
"display_text": "Found 2 documents about BERT",
"status": "completed"
}
}
3. Error
If the tool execution fails:
{
"type": "tool",
"tool": {
"tool_call_id": "call_abc123",
"name": "document_search",
"params": {"query": "What is BERT?"},
"display_text": null,
"status": "error"
}
}
ContentPartTool Fields
| Field | Type | Description |
|---|---|---|
tool_call_id | string | Unique identifier for this specific tool invocation |
name | string | The tool that was called |
params | object or null | Visible parameters (may be a subset of actual params, filtered by the tool's configuration) |
response | object or null | Tool result (present only when status is "completed", may be filtered) |
display_text | string or null | Human-readable text describing what the tool is doing or did |
status | "running" / "completed" / "error" | Current lifecycle state |
Rendering in a UI
A typical pattern for rendering tool content parts during streaming:
import json
import sseclient
# ... set up streaming request ...
client = sseclient.SSEClient(response)
tool_states = {} # track by tool_call_id
for event in client.events():
message = json.loads(event.data)
for part in message.get("content_parts") or []:
if part["type"] != "tool":
continue
tool = part["tool"]
tool_id = tool["tool_call_id"]
status = tool.get("status")
if status == "running":
# Show a spinner or "in progress" indicator
print(f"⏳ {tool.get('display_text', tool['name'])}")
tool_states[tool_id] = "running"
elif status == "completed":
# Replace spinner with completion state
print(f"✓ {tool.get('display_text', tool['name'])}")
tool_states[tool_id] = "completed"
elif status == "error":
print(f"✗ {tool['name']} failed")
tool_states[tool_id] = "error"
UI Recommendations
- Show
display_textrather than rawname+params— it is formatted for human consumption. - Use
tool_call_idto correlate running → completed/error transitions for the same call. - Multiple tool calls can run concurrently — track each by
tool_call_id. - The
paramsandresponsefields are optional and may contain filtered subsets. Use them for advanced UIs (e.g., showing search parameters or result previews) but don't depend on their presence.
Multiple Tool Calls
Agents may call multiple tools in parallel. Each tool has its own tool_call_id. In a single SSE event, you may see multiple tool content parts at different lifecycle stages:
{
"content_parts": [
{"type": "tool", "tool": {"tool_call_id": "call_1", "name": "search", "status": "completed", ...}},
{"type": "tool", "tool": {"tool_call_id": "call_2", "name": "summarize", "status": "running", ...}},
{"type": "text", "text": "Based on the search results..."}
]
}
Table Content Parts
Agents can also return structured tabular data via content_parts with type: "table". This is used when the response contains data best presented as a table rather than prose.
{
"type": "table",
"table": {
"format": "row",
"headers": ["Document", "Score", "Source"],
"rows": [
{"Document": "BERT: Pre-training of Deep Bidirectional Transformers", "Score": "0.95", "Source": "arXiv"},
{"Document": "Attention Is All You Need", "Score": "0.87", "Source": "arXiv"}
]
}
}
Table Formats
| Format | Shape | Use when |
|---|---|---|
"row" | rows: array of {header: value} objects | Most common — each row is a record |
"columnar" | columns: object mapping header → [values] | Efficient for large uniform datasets |
Exactly one of rows or columns is present. headers provides column ordering for rendering.