Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.watson-orchestrate.ibm.com/llms.txt

Use this file to discover all available pages before exploring further.

Python tools can return structured responses with rich content, widgets, and metadata by using the ToolResult class. This class follows the Model Context Protocol (MCP) specification and provides granular control over how tool outputs are processed by the agent and displayed to users.

Overview

The ToolResult class is the primary way developers structure tool responses. It’s key features includes:
  • Text content with audience targeting via annotations
  • Structured data for programmatic use
  • Widget integration for rich UI rendering
The following examples demonstrate common use cases for structuring tool responses:
from ibm_watsonx_orchestrate.run import ToolResult

@tool()
def get_status():
    return ToolResult(
        content=["Operation completed successfully"]
    )

ToolResult class

The ToolResult class provides structured tool responses following the MCP specification. It allows tools to return content blocks, structured data, and widgets a in a standardized format.

Import

Import the ToolResult .class to create structured responses in your Python tools:
from ibm_watsonx_orchestrate.run import ToolResult

Constructor parameters

content
List[Union[ContentBlock, str]]
required
Content blocks or strings to display to the user and LLM. Strings are automatically converted to TextContent blocks.
# Using strings (automatically converted to TextContent)
content=["Operation completed", "Status: Active"]

# Using TextContent blocks explicitly
from ibm_watsonx_orchestrate.run import TextContent
content=[TextContent(text="Operation completed")]
structuredContent
Dict[str, Any]
Structured data for programmatic use. This data is available for downstream processing but not directly displayed to users.
structuredContent={
    "user_id": 123,
    "name": "John Doe",
    "balance": 5000.00
}
widget
Any
Widget to render in the UI. Supports form widgets and other interactive components.
from ibm_watsonx_orchestrate.run.forms import FormWidget, TextInput

widget=FormWidget(
    title="Update Profile",
    inputs=[TextInput(name="email", title="Email")]
)
For more information about widgets, see Creating a form tool.
meta
Dict[str, Any]
Additional metadata for custom extensions or context. This field is serialized as _meta in the response.
meta={
    "priority": "high",
    "department": "finance"
}

Example usage

This example demonstrates a tool that retrieves account information and returns a comprehensive response with multiple content blocks, structured data, a form widget for updating the budget, and custom metadata:
from ibm_watsonx_orchestrate.run import ToolResult, TextContent
from ibm_watsonx_orchestrate.run.forms import FormWidget, NumberInput

@tool()
def check_account_status(user_id: str):
    # Fetch account data
    account_data = fetch_account(user_id)
    
    # Create form for next action
    form = FormWidget(
        title="Update Budget",
        inputs=[
            NumberInput(
                name="amount",
                title="New Budget Amount",
                default_value=account_data["budget"]
            )
        ]
    )
    
    return ToolResult(
        content=[
            TextContent(text=f"Account Status: {account_data['status']}"),
            TextContent(text=f"Current Budget: ${account_data['budget']}")
        ],
        structuredContent=account_data,
        widget=form,
        meta={"account_type": "premium"}
    )

Content blocks and annotations

Content blocks follow the MCP specification and support audience targeting through annotations. This controls how content is processed by the agent and displayed to users.

TextContent

Text content blocks represent textual information with optional audience targeting.
from ibm_watsonx_orchestrate.run import TextContent, Annotations, Role

# Simple text
TextContent(text="Operation completed")

# Text with user audience
TextContent(
    text="Your account has been updated",
    annotations=Annotations(audience=[Role.USER])
)

# Text with assistant audience
TextContent(
    text="Account data: {...}",
    annotations=Annotations(audience=[Role.ASSISTANT])
)

Annotations

Annotations control content visibility and processing behavior.
audience
List[Role]
Specifies who should see and process the content. Possible values:
  • Role.USER
    The content is intended for and displayed to users.
  • Role.ASSISTANT
    The content is intended for the agent and for LLM processing.
  • [Role.USER, Role.ASSISTANT]
    The content is intended for both user and agent.
The audience affects agent reasoning and message display behavior. See Audience behavior for details.

Role enum

from ibm_watsonx_orchestrate.run import Role

Role.USER        # Content for end users
Role.ASSISTANT   # Content for agent/LLM

Audience behavior

The audience annotation controls how content is processed by the agent and displayed to users. Behavior varies based on whether a widget is present in the response.

Content with annotations only

When tool responses contain content with annotations but no widget, the following behavior applies:

Audience: User

PropertyBehavior
Agent reasoningText is not used for reasoning that would trigger next actions.
Message to agent contextText is passed as AI message to prevent hallucinations.
User outputThe exact text displayed as provided.
For the following code snippet, user messages are passed through without agent reasoning, the exact text content is preserved and displayed to the user, context is maintained to prevent hallucinations in follow-up questions, and no transformation or summarization occurs:
from ibm_watsonx_orchestrate.run import ToolResult, TextContent, Annotations, Role

return ToolResult(
    content=[
        TextContent(
            text="Account status retrieved successfully",
            annotations=Annotations(audience=[Role.USER])
        )
    ]
)

Audience: Assistant

PropertyBehavior
Agent reasoningYes - Text IS used for reasoning, triggering next actions
Message to agent contextYes - Full reasoning chain passed to context
User outputAgent-generated message after summarization
For the following code snippet, the agent performs reasoning on the message, uses the text for reasoning that results in additional tool calls or response modifications, the message undergoes summarization before being shown to the user, and the user sees the agent’s processed output rather than the raw content:
return ToolResult(
    content=[
        TextContent(
            text="Account data: status=active, balance=5000",
            annotations=Annotations(audience=[Role.ASSISTANT])
        )
    ]
)

Audience: Both user and assistant

PropertyBehavior
Agent reasoningThe text is used for reasoning.
Message to agent contextThe full reasoning chain is passed to context.
User outputThe agent-generated message. It might differ from original message.
For the following code snippet, the agent performs reasoning despite user audience inclusion, the original content text may or may not be displayed since the final message is generated by the agent, may involve multiple tool calls, and the user sees the agent’s synthesized response:
return ToolResult(
    content=[
        TextContent(
            text="Account status retrieved",
            annotations=Annotations(audience=[Role.USER, Role.ASSISTANT])
        )
    ]
)

Content with annotations and widget metadata

When tool responses contain both content with annotations and a widget contract in widget=form, widget-specific behavior is activated.
If widget=form is present in the tool response, the agent runtime do not send the response for agent reasoning. The tool response is considered final and passed directly back to the user.

Audience: User

PropertyBehavior
Agent reasoningThe text is no used for reasoning.
Message to agent contextThe message is passed to context to prevent hallucinations.
User outputThe exact text and widget are rendered.
For the following code snippet, no agent reasoning occurs, the user message is preserved exactly as provided, and the widget data is rendered alongside the content:
from ibm_watsonx_orchestrate.run import ToolResult, TextContent, Annotations, Role
from ibm_watsonx_orchestrate.run.forms import FormWidget, TextInput

return ToolResult(
    content=[
        TextContent(
            text="Account status retrieved successfully",
            annotations=Annotations(audience=[Role.USER])
        )
    ],
    widget=FormWidget(
        title="Update Account",
        inputs=[TextInput(name="email", title="Email")]
    )
)

Audience: Assistant

PropertyBehavior
Agent reasoningThe text is not used for reasoning.
Message to agent contextThe message is passed to context for continuity.
User outputShows the widget only and empty text content.
For the following code snippet, no agent reasoning is performed, the content text is empty and not displayed to the user, and only the widget is shown to the user:
return ToolResult(
    content=[
        TextContent(
            text="Internal: Account data processed",
            annotations=Annotations(audience=[Role.ASSISTANT])
        )
    ],
    widget=FormWidget(
        title="Account Form",
        inputs=[TextInput(name="account_id", title="Account ID")]
    )
)

Audience: Both user and assistant

PropertyBehavior
Agent reasoningNo - Text is NOT used for reasoning
Message to agent contextYes - Full message passed to context
User outputExact text + widget displayed
For the following code snippet, no agent reasoning occurs, the message text is displayed exactly as provided to the user, and the widget is rendered alongside the text:
return ToolResult(
    content=[
        TextContent(
            text="Please update your account information",
            annotations=Annotations(audience=[Role.USER, Role.ASSISTANT])
        )
    ],
    widget=FormWidget(
        title="Update Account",
        inputs=[TextInput(name="email", title="Email")]
    )
)

Widget integration

Widgets provide interactive UI components in tool responses. The following example demonstrates a tool that creates a support ticket form with multiple input types such as text input, text area, and radio buttons, returns user-facing content with appropriate audience targeting, and renders the form widget for user interaction:
from ibm_watsonx_orchestrate.run import ToolResult, TextContent, Annotations, Role
from ibm_watsonx_orchestrate.run.forms import FormWidget, TextInput, RadioButton

@tool()
def create_support_ticket():
    form = FormWidget(
        title="Create Support Ticket",
        submit_text="Submit Ticket",
        inputs=[
            TextInput(
                name="title",
                title="Ticket Title",
                required=True
            ),
            TextArea(
                name="description",
                title="Description",
                required=True
            ),
            RadioButton(
                name="priority",
                title="Priority",
                options=["low", "medium", "high"],
                option_labels=["Low", "Medium", "High"],
                default_value="medium"
            )
        ]
    )
    
    return ToolResult(
        content=[
            TextContent(
                text="Please fill out the support ticket details",
                annotations=Annotations(audience=[Role.USER])
            )
        ],
        widget=form
    )
For more information about the supported widgets, see Creating a form tool.