This document provides a detailed introduction to the data structure and usage of Tools in Dify plugins. It covers how to return different types of messages (image URLs, links, text, files, JSON), how to create variable and streaming variable messages, and how to define tool output variable schemas for reference in workflows.
Dify supports various message types such as text, links, images, file BLOBs, and JSON. These messages can be returned through specialized interfaces.
By default, a tool’s output in a workflow includes three fixed variables: files, text, and json. The methods below help you populate these variables with appropriate content.
While you can use methods like create_image_message to return an image, tools also support custom output variables, making it more convenient to reference specific data in a workflow.
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
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
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
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
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
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"}.
from typing import Anydef 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
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
The streaming variable method (create_stream_variable_message) currently only supports string data. Complex data types cannot be streamed with the typewriter effect.
To reference a tool’s output variables in a workflow application, you need to define which variables might be output. This is done using the JSON Schema format in your tool’s manifest.
identity: author: example_author name: example_tool label: en_US: Example Tool zh_Hans: 示例工具 ja_JP: ツール例 pt_BR: Ferramenta de exemplodescription: 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 variableoutput_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
Definition for each output variable, including its type and description
Even with an output schema defined, you still need to actually return a variable using create_variable_message() in your implementation code. Otherwise, the workflow will receive None for that variable.
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)
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")
For complex workflows, you can define multiple output variables and return them all. This gives workflow designers more flexibility when using your tool.
import requestsfrom typing import Anyclass 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" }
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.