{"id":48362645,"url":"https://github.com/deepset-ai/hitl-hayhooks-redis-openwebui","last_synced_at":"2026-04-05T13:04:08.548Z","repository":{"id":335523691,"uuid":"1106008039","full_name":"deepset-ai/hitl-hayhooks-redis-openwebui","owner":"deepset-ai","description":"A Redis-based Human-in-the-Loop implementation for Haystack Agents, integrated with Open WebUI for interactive tool approval workflows.","archived":false,"fork":false,"pushed_at":"2026-01-30T17:15:04.000Z","size":6495,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-01-31T10:21:51.266Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/deepset-ai.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-11-28T13:35:27.000Z","updated_at":"2026-01-30T17:15:09.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/deepset-ai/hitl-hayhooks-redis-openwebui","commit_stats":null,"previous_names":["deepset-ai/hitl-hayhooks-redis-openwebui"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/deepset-ai/hitl-hayhooks-redis-openwebui","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepset-ai%2Fhitl-hayhooks-redis-openwebui","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepset-ai%2Fhitl-hayhooks-redis-openwebui/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepset-ai%2Fhitl-hayhooks-redis-openwebui/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepset-ai%2Fhitl-hayhooks-redis-openwebui/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/deepset-ai","download_url":"https://codeload.github.com/deepset-ai/hitl-hayhooks-redis-openwebui/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/deepset-ai%2Fhitl-hayhooks-redis-openwebui/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31436304,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-05T08:13:15.228Z","status":"ssl_error","status_checked_at":"2026-04-05T08:13:11.839Z","response_time":75,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-05T13:04:07.916Z","updated_at":"2026-04-05T13:04:08.540Z","avatar_url":"https://github.com/deepset-ai.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Hayhooks HITL (Human-in-the-Loop) with Open WebUI\n\nA Redis-based Human-in-the-Loop implementation for Hayhooks / Haystack Agents, integrated with Open WebUI for interactive tool approval workflows.\n\n![HITL Demo](./assets/hitl-demo.gif)\n\n## Table of Contents\n\n- [Overview](#overview)\n- [Architecture](#architecture)\n  - [Request Flow](#request-flow)\n  - [Detailed Flow Diagram](#detailed-flow-diagram)\n- [Prerequisites](#prerequisites)\n- [Quick Start with Docker Compose](#quick-start-with-docker-compose)\n- [Manual Installation (Alternative)](#manual-installation-alternative)\n  - [1. Set Up Python Environment](#1-set-up-python-environment)\n  - [2. Start Redis](#2-start-redis)\n  - [3. Start Hayhooks Server](#3-start-hayhooks-server)\n  - [4. Start Open WebUI](#4-start-open-webui)\n  - [5. Deploy and Configure the Pipe Function](#5-deploy-and-configure-the-pipe-function)\n- [Usage](#usage)\n- [Configuration](#configuration)\n  - [Environment Variables (Hayhooks)](#environment-variables-hayhooks)\n  - [Open WebUI Pipe Valves](#open-webui-pipe-valves)\n- [Available Tools](#available-tools)\n- [Adding Custom Tools](#adding-custom-tools)\n- [Troubleshooting](#troubleshooting)\n  - [Connection Refused to Hayhooks](#connection-refused-to-hayhooks)\n  - [Redis Connection Error](#redis-connection-error)\n  - [Tool Call Timeout](#tool-call-timeout)\n  - [SSE Streaming Issues](#sse-streaming-issues)\n- [How It Works](#how-it-works)\n  - [Pipeline Side](#pipeline-side-pipelineshitlpipeline_wrapperpy)\n  - [UI Side](#ui-side-open-webui-pipepy)\n- [License](#license)\n\n## Overview\n\nThis implementation allows users to approve or reject tool calls made by a Haystack Agent in real-time through Open WebUI's confirmation dialogs.\n\nThe system consists of two main components:\n\n- **`pipelines/hitl/pipeline_wrapper.py`** - A Hayhooks pipeline containing a Haystack Agent with Redis-based HITL confirmation strategy\n- **`open-webui-pipe.py`** - A Pipe function deployed in Open WebUI that bridges the frontend with Hayhooks\n\nRedis is used as a message broker to coordinate approval decisions between the Pipe function and the backend pipeline.\n\n## Architecture\n\n```text\n┌─────────────────┐         ┌─────────────────┐     HTTP/SSE      ┌─────────────────┐\n│                 │         │                 │ ───────────────▶  │                 │\n│   Open WebUI    │ ──────▶ │   Pipe Function │                   │    Hayhooks     │\n│   (Frontend)    │ ◀────── │ (open-webui-    │ ◀───────────────  │    (Server)     │\n│                 │         │     pipe.py)    │   SSE Events      │                 │\n└─────────────────┘         └────────┬────────┘                   └────────┬────────┘\n                                     │                                     │\n                                     │  ┌─────────────────┐                │\n                                     │  │                 │                │\n                                     └─▶│     Redis       │◀──────────────┘\n                                        │    (Broker)     │\n                                        │                 │\n                                        └─────────────────┘\n```\n\n### Request Flow\n\n1. **User sends message** → Open WebUI frontend calls the Pipe function (`open-webui-pipe.py`)\n2. **Pipe forwards request** → Pipe function makes HTTP POST to Hayhooks (`/hitl/run`)\n3. **Agent processes** → Hayhooks streams SSE events back to the Pipe function\n4. **Tool call detected** → Agent emits `tool_call_start` event via SSE\n5. **Approval requested** → Pipe function shows confirmation dialog to user via Open WebUI\n6. **User decides** → Pipe function sends approval/rejection to Redis (`LPUSH`)\n7. **Pipeline unblocks** → Hayhooks reads from Redis (`BLPOP`) and continues\n8. **Result streamed** → Pipe function receives response and streams it back to Open WebUI frontend\n\n### Detailed Flow Diagram\n\n```text\nOpen WebUI                                                   Hayhooks\nFrontend              Pipe Function                          /Agent                 Redis\n │                        │                                    │                       │\n │  \"What's the weather?\" │                                    │                       │\n │───────────────────────▶│                                    │                       │\n │                        │  POST /hitl/run                    │                       │\n │                        │───────────────────────────────────▶│                       │\n │                        │                                    │                       │\n │                        │    SSE: tool_call_start            │                       │\n │                        │◀───────────────────────────────────│                       │\n │                        │                                    │   BLPOP (waiting)     │\n │                        │                                    │──────────────────────▶│\n │  🔧 Approve tool?      │                                    │                       │\n │◀───────────────────────│                                    │                       │\n │                        │                                    │                       │\n │  ✅ Yes / ❌ No        │                                    │                       │\n │───────────────────────▶│                                    │                       │\n │                        │   LPUSH \"approved\"                 │                       │\n │                        │───────────────────────────────────────────────────────────▶│\n │                        │                                    │   (unblocks)          │\n │                        │                                    │◀──────────────────────│\n │                        │                                    │                       │\n │                        │    SSE: text (result)              │                       │\n │                        │◀───────────────────────────────────│                       │\n │  \"Weather is cloudy\"   │                                    │                       │\n │◀───────────────────────│                                    │                       │\n │                        │                                    │                       │\n```\n\n## Prerequisites\n\n- **Docker** and **Docker Compose**\n- **OpenAI API key** (or compatible LLM endpoint)\n\n## Quick Start with Docker Compose\n\nThe easiest way to get started is using Docker Compose, which sets up all services (Redis, Hayhooks, Open WebUI) automatically.\n\n### 1. Set your OpenAI API key and start all services\n\n```bash\nexport OPENAI_API_KEY=\"your-api-key-here\"\ndocker compose up -d --build\n```\n\nThis starts:\n\n- **Redis** on port 6379\n- **Hayhooks** on port 1416 (with the HITL pipeline loaded)\n- **Open WebUI** on port 3000\n\n### 2. Deploy the Pipe Function to Open WebUI\n\nFollow [Deploy and Configure the Pipe Function](#5-deploy-and-configure-the-pipe-function) section instructions to deploy the Pipe Function to Open WebUI.\n\n---\n\n## Manual Installation (Alternative)\n\nIf you prefer to run services manually without Docker Compose:\n\n### 1. Set Up Python Environment\n\n```bash\n# Create virtual environment\npython -m venv .venv\nsource .venv/bin/activate  # Linux/macOS\n# .venv\\Scripts\\activate   # Windows\n\n# Install dependencies for Hayhooks server\npip install -r requirements.txt\n```\n\n### 2. Start Redis\n\n```bash\ndocker run -d --name redis -p 6379:6379 redis:alpine\n```\n\n### 3. Start Hayhooks Server\n\n```bash\n# Set your OpenAI API key\nexport OPENAI_API_KEY=\"your-api-key-here\"\n\n# Redis defaults to localhost:6379, override if needed:\n# export REDIS_HOST=\"localhost\"\n# export REDIS_PORT=\"6379\"\n\n# Start Hayhooks and deploy the pipeline\nhayhooks run\n```\n\nHayhooks will start on `http://localhost:1416` and automatically load `pipelines/hitl/pipeline_wrapper.py`.\n\n### 4. Start Open WebUI\n\n```bash\ndocker run -d \\\n  --name open-webui \\\n  -p 3000:8080 \\\n  -e WEBUI_AUTH=False \\\n  -v open-webui:/app/backend/data \\\n  --add-host=host.docker.internal:host-gateway \\\n  ghcr.io/open-webui/open-webui:main\n```\n\n### 5. Deploy and Configure the Pipe Function\n\n**NOTE**: This step can be automated, but will require to _enable authentication_ in Open WebUI, in order to get a JWT token and use it in the curl command. For this demo, since it's a one-time setup, we'll do it manually.\n\n![Pipe function deploy](./assets/pipe-function-deploy.gif)\n\n1. Open \u003chttp://localhost:3000\u003e in your browser\n2. Go to **Settings** → **Admin Settings**\n3. Select **Functions** from top bar\n4. Copy the contents of `open-webui-pipe.py` into the editor\n5. Give a title, name and description to the function\n6. Save and enable the function\n7. **Important:** Update the Valves for manual setup:\n   - `BASE_URL`: `http://host.docker.internal:1416`\n   - `REDIS_HOST`: `host.docker.internal`\n\n## Usage\n\n1. In Open WebUI, start a new chat\n2. Select the **Hayhooks HITL Pipe** as your model (this routes requests through the Pipe function)\n3. Ask something that triggers a tool call, e.g.:\n   - _\"What's the weather in Rome?\"_\n   - _\"What time is it in UTC?\"_\n4. The Pipe function will forward your message to Hayhooks\n5. When the Agent decides to call a tool, a confirmation dialog will appear\n6. Click **Confirm** to approve or **Cancel** to reject the tool execution\n7. The response will stream back through the Pipe function to your chat\n\n## Configuration\n\n### Environment Variables (Hayhooks)\n\n| Variable | Default | Description |\n|----------|---------|-------------|\n| `OPENAI_API_KEY` | - | Required. Your OpenAI API key |\n| `REDIS_HOST` | `localhost` | Redis server hostname |\n| `REDIS_PORT` | `6379` | Redis server port |\n\n### Open WebUI Pipe Valves\n\n| Valve | Docker Compose | Manual Setup | Description |\n|-------|----------------|--------------|-------------|\n| `BASE_URL` | `http://hayhooks:1416` | `http://host.docker.internal:1416` | Hayhooks server URL |\n| `PIPELINE_NAME` | `hitl` | `hitl` | Pipeline endpoint name |\n| `REDIS_HOST` | `redis` | `host.docker.internal` | Redis host |\n| `REDIS_PORT` | `6379` | `6379` | Redis port |\n\n\u003e **Note:** The defaults in `open-webui-pipe.py` are configured for Docker Compose. For manual setup, update the Valves via **Admin Panel** → **Functions** → **Hayhooks HITL Pipe** → ⚙️\n\n## Available Tools\n\nThe default configuration includes two example tools:\n\n| Tool | Description |\n|------|-------------|\n| `weather_tool` | Returns weather information for a location |\n| `get_time` | Returns current time in a timezone |\n\n## Adding Custom Tools\n\nEdit `pipelines/hitl/pipeline_wrapper.py` to add your own tools:\n\n```python\nfrom haystack.tools import create_tool_from_function\n\ndef my_custom_tool(param: str) -\u003e str:\n    \"\"\"Your tool description.\"\"\"\n    return f\"Result for {param}\"\n\ncustom_tool = create_tool_from_function(\n    function=my_custom_tool,\n    name=\"my_custom_tool\",\n    description=\"Description shown to the LLM\",\n)\n\n# Add to agent tools list and confirmation_strategies dict\nself.agent = Agent(\n    # ...\n    tools=[weather_tool, time_tool, custom_tool],\n    confirmation_strategies={\n        # ...\n        custom_tool.name: self.confirmation_strategy,\n    },\n)\n```\n\n## Troubleshooting\n\n### Connection Refused to Hayhooks\n\n- Ensure Hayhooks is running: `curl http://localhost:1416/status`\n- **Docker Compose:** Use `http://hayhooks:1416` in Valve settings\n- **Manual setup:** Use `http://host.docker.internal:1416` in Valve settings\n\n### Redis Connection Error\n\n- Check Redis is running: `redis-cli ping` (should return `PONG`)\n- **Docker Compose:** Set `REDIS_HOST` valve to `redis`\n- **Manual setup:** Set `REDIS_HOST` valve to `host.docker.internal`\n- Verify host/port configuration in both pipeline and pipe\n\n### Tool Call Timeout\n\n- Default timeout is 5 minutes\n- Check Redis connectivity between all services\n- Verify the pipe is correctly sending approvals to the same Redis instance\n\n### SSE Streaming Issues\n\n- Ensure `Accept: text/event-stream` header is set\n- Check for proxy/firewall issues that might buffer SSE\n\n## How It Works\n\n### Pipeline Side (`pipelines/hitl/pipeline_wrapper.py`)\n\nThe `RedisConfirmationStrategy` class implements Haystack's `ConfirmationStrategy` interface:\n\n1. When a tool call is initiated, it emits a `tool_call_start` event to the async queue (obtained from `confirmation_strategy_context`)\n2. It then waits on Redis `BLPOP` for an approval decision (using the Redis client from `confirmation_strategy_context`)\n3. Once approval is received, it returns a `ToolExecutionDecision` object\n4. The agent proceeds to execute (or skip) the tool based on the decision\n\nThe per-request state (event_queue, redis_client) is passed via the `confirmation_strategy_context` parameter when calling `agent.run_async()`.\n\n### UI Side (`open-webui-pipe.py`)\n\nThe Pipe function acts as a bridge between the Open WebUI frontend and Hayhooks:\n\n1. Receives chat messages from the Open WebUI frontend\n2. Forwards the request to Hayhooks via HTTP POST (`/hitl/run`)\n3. Streams SSE events from Hayhooks back to the frontend\n4. When it receives a `tool_call_start` event, it shows a confirmation dialog to the user via `__event_call__`\n5. Based on user response, it sends `approved` or `rejected` to Redis via `LPUSH`\n6. Continues streaming the response back to the Open WebUI frontend\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepset-ai%2Fhitl-hayhooks-redis-openwebui","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdeepset-ai%2Fhitl-hayhooks-redis-openwebui","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdeepset-ai%2Fhitl-hayhooks-redis-openwebui/lists"}