Skip to main content

Message Types

The API sends different message types during streaming to provide rich context.

AI Content

The main response text from the AI comes in the standard OpenAI format:

{
"choices": [{
"delta": {
"content": "text chunk"
}
}]
}

How to handle it:

for chunk in stream:
# Check for AI content
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

Step Messages

Shows what the AI is doing in real-time (e.g., "Planning", "Searching documents", "Analyzing results"):

{
"custom_data": {
"type": "step_message",
"title": "Searching IRC Code",
"status": "in_progress"
}
}

How to handle it:

if hasattr(chunk, 'custom_data'):
if chunk.custom_data.get('type') == 'step_message':
title = chunk.custom_data.get('title')
print(f"\nStep: {title}")

Status values:

  • in_progress - Currently running
  • completed - Finished successfully
  • failed - Encountered an error

Source Messages

Shows which documents were referenced to generate the answer. This helps verify the answer's accuracy:

{
"custom_data": {
"type": "source_message",
"content": [
{
"node_id": "source_123",
"text": "Section 179 allows businesses...",
"metadata": {
"file_name": "IRC_Code.pdf",
"page": 42
},
"score": 0.95
}
]
}
}

How to handle it:

if chunk.custom_data.get('type') == 'source_message':
sources = chunk.custom_data.get('content', [])
print(f"\nFound {len(sources)} sources:")
for source in sources:
file_name = source.get('metadata', {}).get('file_name', 'Unknown')
page = source.get('metadata', {}).get('page', 'N/A')
print(f" {file_name} (page {page})")
Advanced Usage

For detailed information on how to use Page Labels for navigation and Source Origin links, see the Page Labels and Source Origin guide.

Suggestions

Follow-up questions that users might want to ask based on the current conversation:

{
"custom_data": {
"type": "suggestions",
"suggestions": [
"What are the dollar limits for section 179?",
"What types of property qualify for section 179?",
"How does section 179 differ from bonus depreciation?"
]
}
}

How to handle it:

if chunk.custom_data.get('type') == 'suggestions':
suggestions = chunk.custom_data.get('suggestions', [])
print(f"\nSuggested questions:")
for i, suggestion in enumerate(suggestions, 1):
print(f" {i}. {suggestion}")

Human Message

Echo of the user's question:

{
"type": "human_message",
"content": "What is section 169?"
}

AI Metadata

Additional information about the response:

{
"type": "ai_metadata",
"metadata": {
"model": "bizora-1.0",
"tokens_used": 150,
"processing_time_ms": 1250
}
}

Complete Example

Here's a complete example that handles all message types:

# Enable streaming for complete message handling
stream = client.chat.completions.create(
model="bizora-1.0",
messages=[{"role": "human", "content": "What is section 179?"}],
stream=True
)

for chunk in stream:
# AI content - the actual answer
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

# Custom messages - steps, sources, suggestions
elif hasattr(chunk, 'custom_data'):
msg_type = chunk.custom_data.get('type')

if msg_type == 'step_message':
print(f"\nStep: {chunk.custom_data.get('title')}")

elif msg_type == 'source_message':
sources = chunk.custom_data.get('content', [])
print(f"\nFound {len(sources)} sources")

elif msg_type == 'suggestions':
suggestions = chunk.custom_data.get('suggestions', [])
print(f"\n{len(suggestions)} suggested questions")

Deep Research Mode

Here's a complete example that handles all message types with deep research:

# Enable streaming with deep research
stream = client.chat.completions.create(
model="bizora-1.0",
messages=[{"role": "human", "content": "Analyze the tax treatment of cryptocurrency staking rewards and airdrops."}],
stream=True,
extra_body={"askMode": "tax_research_deep_research"}
)

for chunk in stream:
# AI content - the actual answer
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

# Custom messages - steps, sources, suggestions
elif hasattr(chunk, 'custom_data'):
msg_type = chunk.custom_data.get('type')

if msg_type == 'step_message':
print(f"\nStep: {chunk.custom_data.get('title')}")

elif msg_type == 'source_message':
sources = chunk.custom_data.get('content', [])
print(f"\nFound {len(sources)} sources")

elif msg_type == 'suggestions':
suggestions = chunk.custom_data.get('suggestions', [])
print(f"\n{len(suggestions)} suggested questions")

Audit Research Mode

Here's a complete example that handles all message types with audit research:

# Enable streaming with audit research
stream = client.chat.completions.create(
model="bizora-1.0",
messages=[{"role": "human", "content": "Analyze the reporting requirements for lease modifications under ASC 842."}],
stream=True,
extra_body={"askMode": "audit_research"}
)

for chunk in stream:
# AI content - the actual answer
if chunk.choices and chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="", flush=True)

# Custom messages - steps, sources, suggestions
elif hasattr(chunk, 'custom_data'):
msg_type = chunk.custom_data.get('type')

if msg_type == 'step_message':
print(f"\nStep: {chunk.custom_data.get('title')}")

elif msg_type == 'source_message':
sources = chunk.custom_data.get('content', [])
print(f"\nFound {len(sources)} sources")

elif msg_type == 'suggestions':
suggestions = chunk.custom_data.get('suggestions', [])
print(f"\n{len(suggestions)} suggested questions")