> ## Documentation Index
> Fetch the complete documentation index at: https://dify-6c0370d8-docs-new-agent-experience.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Tool Return

> How tool plugins return messages (text, links, images, files, JSON), create standard and streaming variables, and define output schemas for workflow references

## Overview

A tool returns its results as messages and variables. This page covers the message interfaces, variable creation, and output schema definitions.

<CardGroup cols={2}>
  <Card title="Message Types" icon="comment-dots" href="#message-return">
    Return different types of messages such as text, links, images, and JSON
  </Card>

  <Card title="Variables" icon="code-branch" href="#variables">
    Create and manipulate variables for workflow integration
  </Card>

  <Card title="Output Schema" icon="diagram-project" href="#custom-output-variables">
    Define custom output variables for workflow references
  </Card>
</CardGroup>

## Data Structure

### Message Return

Dify supports several message types—text, links, images, file blobs, and JSON—each returned through a dedicated interface.

By default, a tool's output in a workflow includes three fixed variables: `files`, `text`, and `json`. The methods below populate these variables.

<Tip>
  While you can use methods like `create_image_message` to return an image, tools also support custom output variables, which make it easier to reference specific data in a workflow.
</Tip>

### Message Types

<CodeGroup>
  ```python Image URL theme={null}
  def create_image_message(self, image: str) -> ToolInvokeMessage:
      """
      Return an image URL message
      
      Dify will automatically download the image from the provided URL
      and display it to the user.
      
      Args:
          image: URL to an image file
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```

  ```python Link theme={null}
  def create_link_message(self, link: str) -> ToolInvokeMessage:
      """
      Return a clickable link message
      
      Args:
          link: URL to be displayed as a clickable link
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```

  ```python Text theme={null}
  def create_text_message(self, text: str) -> ToolInvokeMessage:
      """
      Return a text message
      
      Args:
          text: Text content to be displayed
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```

  ```python File theme={null}
  def create_blob_message(self, blob: bytes, meta: dict = None) -> ToolInvokeMessage:
      """
      Return a file blob message
      
      For returning raw file data such as images, audio, video, 
      or documents (PPT, Word, Excel, etc.)
      
      Args:
          blob: Raw file data in bytes
          meta: File metadata dictionary. Include 'mime_type' to specify 
                the file type, otherwise 'octet/stream' will be used
                
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```

  ```python JSON theme={null}
  def create_json_message(self, json: dict) -> ToolInvokeMessage:
      """
      Return a formatted JSON message
      
      Useful for data transmission between workflow nodes.
      In agent mode, most LLMs can read and understand JSON data.
      
      Args:
          json: Python dictionary to be serialized as JSON
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="image" type="string" required>
    URL to an image that will be downloaded and displayed.
  </ParamField>

  <ParamField path="link" type="string" required>
    URL to display as a clickable link.
  </ParamField>

  <ParamField path="text" type="string" required>
    Text content to display.
  </ParamField>

  <ParamField path="blob" type="bytes" required>
    Raw file data in bytes.
  </ParamField>

  <ParamField path="meta" type="dict">
    File metadata, including:

    * `mime_type`: The MIME type of the file, for example `image/png`.
    * Other metadata relevant to the file.
  </ParamField>

  <ParamField path="json" type="dict" required>
    Python dictionary to serialize as JSON.
  </ParamField>
</Accordion>

<Tip>
  When working with file blobs, always specify the `mime_type` in the `meta` dictionary to ensure proper handling of the file. For example: `{"mime_type": "image/png"}`.
</Tip>

### Variables

<CodeGroup>
  ```python Standard Variable theme={null}
  from typing import Any

  def create_variable_message(self, variable_name: str, variable_value: Any) -> ToolInvokeMessage:
      """
      Create a named variable for workflow integration
      
      For non-streaming output variables. If multiple instances with the 
      same name are created, the latest one overrides previous values.
      
      Args:
          variable_name: Name of the variable to create
          variable_value: Value of the variable (any Python data type)
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```

  ```python Streaming Variable theme={null}
  def create_stream_variable_message(
      self, variable_name: str, variable_value: str
  ) -> ToolInvokeMessage:
      """
      Create a streaming variable with typewriter effect
      
      When referenced in an answer node in a chatflow application,
      the text will be output with a typewriter effect.
      
      Args:
          variable_name: Name of the variable to create
          variable_value: String value to stream (only strings supported)
          
      Returns:
          ToolInvokeMessage: Message object for the tool response
      """
      pass
  ```
</CodeGroup>

<Accordion title="Parameters">
  <ParamField path="variable_name" type="string" required>
    Name of the variable to create or update.
  </ParamField>

  <ParamField path="variable_value" type="Any/string" required>
    Value to assign to the variable:

    * Standard variables: any Python data type.
    * Streaming variables: string data only.
  </ParamField>
</Accordion>

<Warning>
  `create_stream_variable_message` currently only supports string data. Complex data types cannot be streamed with the typewriter effect.
</Warning>

## Custom Output Variables

To reference a tool's output variables in a workflow application, declare which variables the tool might output using [JSON Schema](https://json-schema.org/) in the tool's manifest.

### Define Output Schema

<CodeGroup>
  ```yaml Tool Manifest with Output Schema theme={null}
  identity:
    author: example_author
    name: example_tool
    label:
      en_US: Example Tool
      zh_Hans: 示例工具
      ja_JP: ツール例
      pt_BR: Ferramenta de exemplo
  description:
    human:
      en_US: A simple tool that returns a name
      zh_Hans: 返回名称的简单工具
      ja_JP: 名前を返す簡単なツール
      pt_BR: Uma ferramenta simples que retorna um nome
    llm: A simple tool that returns a name variable
  output_schema:
    type: object
    properties:
      name:
        type: string
        description: "The name returned by the tool"
      age:
        type: integer
        description: "The age returned by the tool"
      profile:
        type: object
        properties:
          interests:
            type: array
            items:
              type: string
          location:
            type: string
  ```
</CodeGroup>

<Accordion title="Schema Structure">
  <ParamField path="output_schema" type="object" required>
    Root object defining the tool's output schema.
  </ParamField>

  <ParamField path="type" type="string" required>
    Must be `object` for tool output schemas.
  </ParamField>

  <ParamField path="properties" type="object" required>
    Dictionary of all possible output variables.
  </ParamField>

  <ParamField path="properties.[variable_name]" type="object">
    Definition of each output variable, including its type and description.
  </ParamField>
</Accordion>

<Warning>
  Defining an output schema is not enough on its own: your implementation must still return each variable with `create_variable_message()`. Otherwise, the workflow receives `None` for that variable.
</Warning>

### Example Implementation

<CodeGroup>
  ```python Basic Variable Example theme={null}
  def run(self, inputs):
      # Process inputs and generate a name
      generated_name = "Alice"
      
      # Return the name as a variable that matches the output_schema
      return self.create_variable_message("name", generated_name)
  ```

  ```python Complex Structure Example theme={null}
  def run(self, inputs):
      # Generate complex structured data
      user_data = {
          "name": "Bob",
          "age": 30,
          "profile": {
              "interests": ["coding", "reading", "hiking"],
              "location": "San Francisco"
          }
      }
      
      # Return individual variables
      self.create_variable_message("name", user_data["name"])
      self.create_variable_message("age", user_data["age"])
      self.create_variable_message("profile", user_data["profile"])
      
      # Also return a text message for display
      return self.create_text_message(f"User {user_data['name']} processed successfully")
  ```
</CodeGroup>

<Tip>
  For complex workflows, you can define multiple output variables and return them all. This gives workflow designers more flexibility when using your tool.
</Tip>

## Examples

### Complete Tool Implementation

<CodeGroup>
  ```python Weather Forecast Tool theme={null}
  import requests
  from typing import Any

  class WeatherForecastTool:
      def run(self, inputs: dict) -> Any:
          # Get location from inputs
          location = inputs.get("location", "London")
          
          try:
              # Call weather API (example only)
              weather_data = self._get_weather_data(location)
              
              # Create variables for workflow use
              self.create_variable_message("temperature", weather_data["temperature"])
              self.create_variable_message("conditions", weather_data["conditions"])
              self.create_variable_message("forecast", weather_data["forecast"])
              
              # Create a JSON message for data transmission
              self.create_json_message(weather_data)
              
              # Create an image message for the weather map
              self.create_image_message(weather_data["map_url"])
              
              # Return a formatted text response
              return self.create_text_message(
                  f"Weather in {location}: {weather_data['temperature']}°C, {weather_data['conditions']}. "
                  f"Forecast: {weather_data['forecast']}"
              )
              
          except Exception as e:
              # Handle errors gracefully
              return self.create_text_message(f"Error retrieving weather data: {str(e)}")
      
      def _get_weather_data(self, location: str) -> dict:
          # Mock implementation - in a real tool, this would call a weather API
          return {
              "location": location,
              "temperature": 22,
              "conditions": "Partly Cloudy",
              "forecast": "Sunny with occasional showers tomorrow",
              "map_url": "https://example.com/weather-map.png"
          }
  ```
</CodeGroup>

<Tip>
  When designing tools, consider both the direct output (what the user sees) and the variable output (what other workflow nodes can use). This separation provides flexibility in how your tool is used.
</Tip>
