Skip to main content

ag-ui-dify-adapter

AG-UI protocol adapter for Dify — translates Dify API responses to AG-UI streaming events, enabling Dify-powered AI agents to integrate with any AG-UI-compatible frontend.

Features

  • All 4 Dify app types: Chat, Agent, Workflow, Completion
  • 24+ AG-UI event types: TEXT_MESSAGE, TOOL_CALL, TOOL_CALL_RESULT, REASONING, STATE_SNAPSHOT, MESSAGES_SNAPSHOT, STEP, CUSTOM, RAW, RUN
  • Tool call lifecycle: TOOL_CALL_STARTARGSENDRESULT for Agent ReAct loops
  • Reasoning events: <think> tag streaming detection → REASONING_START/MESSAGE_START/CONTENT/MESSAGE_END/END
  • Snapshots: MESSAGES_SNAPSHOT + STATE_SNAPSHOT emitted at start of every run
  • Streaming: Real-time text streaming with <think> block separation
  • Multi-turn conversation: thread_idconversation_id tracking
  • State & context: AG-UI state/context → Dify input variables
  • Single-port multi-agent: One server, multiple Dify apps routed by path
  • YAML config: Clean config.yaml — no JSON crammed into env vars
  • .env auto-load: Reads .env file automatically via python-dotenv
  • RAW passthrough: Unrecognized Dify events forwarded as RAW, never dropped
  • Async: Full async support with httpx

Installation

pip install ag-ui-dify-adapter

For the HTTP server:

pip install ag-ui-dify-adapter[server]

Quick Start

Library

import asyncio
from ag_ui_dify import DifyAgent, DifyConfig, DifyAppType
from ag_ui.core import RunAgentInput, UserMessage

async def main():
    agent = DifyAgent(DifyConfig(
        api_key="app-xxx",
        base_url="https://api.dify.ai/v1",
        app_type=DifyAppType.AGENT,
    ))

    input = RunAgentInput(
        thread_id="thread-1",
        run_id="run-1",
        state=None,
        messages=[UserMessage(id="u1", role="user", content="Hello!")],
        tools=[], context=[], forwarded_props={},
    )

    async for event in agent.run(input):
        print(event.model_dump_json(by_alias=True))

asyncio.run(main())

HTTP Server

Three ways to configure agents — pick one:

YAML config file (recommended):

# config.yaml
base_url: http://localhost/v1
agents:
  agent-a:
    key: app-xxx
    type: agent
  wf-b:
    key: app-yyy
    type: workflow
uvicorn ag_ui_dify:create_app --port 8080

Environment variables:

# Single agent
DIFY_API_KEY=app-xxx DIFY_APP_TYPE=agent \
  uvicorn ag_ui_dify:create_app --port 8080

# Multi-agent (single port)
DIFY_AGENTS='{"agent-a":{"key":"app-xxx","type":"agent"}}' \
  uvicorn ag_ui_dify:create_app --port 8080

.env file (auto-loaded):

# .env
DIFY_AGENTS={"agent-a":{"key":"app-xxx","type":"agent"}}
uvicorn ag_ui_dify:create_app --port 8080

API keys stay server-side — never exposed to clients.

# Endpoints
curl -X POST http://localhost:8080/agent-a \
  -H "Content-Type: application/json" \
  -d '{"threadId":"t1","runId":"r1","messages":[{"id":"u1","role":"user","content":"Hello"}],"tools":[],"context":[]}'

curl http://localhost:8080/health   # → {"status":"ok"}
curl http://localhost:8080/info     # → agent discovery

Dify → AG-UI Event Mapping

Agent App

Dify SSE Event AG-UI Event(s)
agent_thought (with thought) STEP_STARTED + CUSTOM (thought)
agent_thought (with tool) TOOL_CALL_START + TOOL_CALL_ARGS + TOOL_CALL_END
agent_thought (with observation) TOOL_CALL_RESULT
agent_message (first) TEXT_MESSAGE_START
agent_message TEXT_MESSAGE_CONTENT (with <think>REASONING)
message_replace CUSTOM
message_file CUSTOM
message_end TEXT_MESSAGE_END + RUN_FINISHED

Workflow App

Dify SSE Event AG-UI Event(s)
workflow_started RUN_STARTED + TEXT_MESSAGE_START
node_started / node_retry STEP_STARTED
node_finished STEP_FINISHED
agent_log STEP_STARTED / STEP_FINISHED
iteration_started/completed STEP_STARTED / STEP_FINISHED
loop_started/completed STEP_STARTED / STEP_FINISHED
text_chunk TEXT_MESSAGE_CONTENT (with <think>REASONING)
text_replace CUSTOM
workflow_paused CUSTOM + RUN_FINISHED
human_input_* CUSTOM
workflow_finished TEXT_MESSAGE_END + RUN_FINISHED

Chat / Completion App

Dify SSE Event AG-UI Event(s)
message (first) TEXT_MESSAGE_START
message TEXT_MESSAGE_CONTENT (with <think>REASONING)
message_replace CUSTOM
message_file CUSTOM
tts_message / tts_message_end CUSTOM
message_end TEXT_MESSAGE_END + RUN_FINISHED

All app types: MESSAGES_SNAPSHOT + STATE_SNAPSHOT at start, RUN_STARTED, RUN_ERROR on error, ping ignored, unknown events → RAW.

API Reference

DifyAgent

agent = DifyAgent(DifyConfig(
    api_key="app-xxx",          # Required: Dify API key
    base_url="...",             # Default: https://api.dify.ai/v1
    app_type=DifyAppType.AGENT, # Auto-detected if omitted
    user="ag-ui-user",          # Default user identifier
    timeout=120.0,              # HTTP timeout in seconds
))
async for event in agent.run(run_input):
    ...

HTTP Server

from ag_ui_dify import create_app, load_agents
import uvicorn

# Programmatic
agents = load_agents()  # reads DIFY_AGENTS / DIFY_API_KEY from env
app = create_app()      # Starlette app with /info, /health, /<agent>
uvicorn.run(app, port=8080)
Routes:
  POST /<agent-name>   AG-UI RunAgentInput → SSE stream
  GET  /info           Agent discovery
  GET  /health         Health check

DifyClient (low-level)

client = DifyClient(config)
async for evt in client.stream_chat(query="Hello", inputs={}): ...
async for evt in client.stream_workflow(inputs={"url": "..."}): ...
async for evt in client.stream_completion(inputs={}): ...
await client.stop_chat(task_id="...")

Project Structure

ag_ui_dify/
├── __init__.py           # Package exports
├── types.py              # Dify type definitions (Pydantic models)
├── dify_client.py        # Async HTTP client for all Dify endpoints
├── event_translator.py   # Event translators (Chat/Agent/Workflow/Completion)
├── agent.py              # DifyAgent main adapter
└── server.py             # Starlette single-port multi-agent server

Verification Status

All 4 Dify app types verified against a real Dify instance:

App Type Status Coverage
Agent Tool calls, reasoning chain, multi-turn conversation
Workflow Node execution, agent_log sub-steps, text output
Chat Streaming text, message lifecycle
Completion Streaming text, <think> → REASONING events

Requirements

  • Python >= 3.9
  • ag-ui-protocol >= 0.1.17
  • httpx >= 0.27.0
  • pydantic >= 2.11.0
  • starlette >= 0.40.0 (optional, for HTTP server)
  • uvicorn (optional, for HTTP server)

License

MIT

Release files for ag-ui-dify-adapter 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ag-ui-dify-adapter 0.1.4
File Size Uploaded
ag_ui_dify_adapter-0.1.4.tar.gz 59.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ag-ui-dify-adapter 0.1.4
File Interpreter ABI Platform
ag_ui_dify_adapter-0.1.4-py3-none-any.whl Python 3 none any Details

Total release size: 104.5 kB

Release files / ag_ui_dify_adapter-0.1.4.tar.gz

Download URL ag_ui_dify_adapter-0.1.4.tar.gz
Size 59.9 kB
Tags Source
SHA-256 checksum
How to use checksums
696b6ec575d33bd65c7f7e385cb65c9c87582ebf9258aa0fbdefc823f93d2bba
BLAKE2b-256 checksum
How to use checksums
b997a84070681d076ac3de5bdc687a3e7f963abd473cda8a7508d0ebb6980879
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.7

Release files / ag_ui_dify_adapter-0.1.4-py3-none-any.whl

Download URL ag_ui_dify_adapter-0.1.4-py3-none-any.whl
Size 44.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
0f77150aef166ba46c4599967089089b24072e0502db2a7680cff22b6e40dd22
BLAKE2b-256 checksum
How to use checksums
54173bd35ab484c73a3cca1e8263e06fdb7faf5158f167e6f0f30b36a6d1311f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.9.7

Release history Release notifications | RSS feed

This release

0.1.4 This release

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page