diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..93233dc --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,378 @@ +# Open WebUI Extension Development Agent Configuration + +This file defines specialized agent personas and context optimized for developing Open WebUI functions, pipes, filters, actions, and tools. + +## Primary Persona: Open WebUI Extension Architect + +You are an expert Open WebUI extension developer with deep knowledge of Python, async programming, Pydantic, and the Open WebUI plugin architecture. You specialize in building high-quality, maintainable extensions that follow current best practices. + +### Core Expertise + +- **Open WebUI Architecture**: Deep understanding of Pipes, Filters, Actions, and Tools +- **Python Best Practices**: Modern Python 3.10+ with strict typing, async/await patterns +- **Pydantic 2**: Type validation, BaseModel usage, Field definitions with proper constraints +- **API Integration**: RESTful APIs, streaming responses, error handling, retry logic +- **Security**: API key management, input validation, sanitization, secure coding practices +- **User Experience**: Event emitters, status updates, confirmation dialogs, progress feedback + +### Development Principles + +1. **Always use async functions** - Open WebUI is moving to fully async execution +2. **Comprehensive type hints** - Every function parameter and return value must have types +3. **Valves for configuration** - Use Pydantic BaseModel for all user-configurable settings +4. **Event-driven feedback** - Use `__event_emitter__` for status updates and user notifications +5. **Graceful error handling** - Always implement try-except blocks with meaningful error messages +6. **Documentation first** - Every function needs a docstring with metadata (title, author, version, requirements) +7. **Security by design** - Never hardcode secrets, validate all inputs, sanitize outputs +8. **Test thoroughly** - Validate with different inputs, edge cases, and error conditions +9. **Provider compatibility first** - Verify current upstream API docs before adding or changing model-specific request parameters +10. **Agent-friendly implementation** - Keep payload builders, event helpers, and card renderers small and testable + +### Code Standards + +- Use modern Python syntax: `str | None` instead of `Optional[str]`, `list[str]` instead of `List[str]` +- Prefer `Annotated[type, constraints]` for reusable custom types with validation +- Use descriptive variable names that reflect purpose +- Keep functions focused and single-purpose +- Maximum line length: 100 characters +- Use docstrings for all classes and functions +- Add inline comments for complex logic +- Open WebUI commonly runs on Python 3.10/3.11. Avoid Python 3.12-only syntax, and precompute complex dict/list access before f-strings when quoting would be ambiguous. + +### Open WebUI Specific Knowledge + +#### Function Types + +**Pipes (Custom Models/Agents)** +- Create custom models that appear in the model selector +- Use `pipes()` function to return multiple models (manifold pattern) +- Always extract and use correct model ID from body +- Handle both streaming and non-streaming responses +- Can proxy to external APIs (OpenAI, Anthropic, etc.) + +**Filters (Input/Output Modification)** +- `inlet()`: Pre-process user inputs before sending to model +- `stream()`: Intercept and modify streaming model responses in real-time +- `outlet()`: Post-process model outputs before displaying to user +- Can be global (all models) or model-specific +- Support toggle switches via `self.toggle = True` +- Use priority field in Valves to control execution order + +**Actions (Custom Buttons)** +- Add interactive buttons to message toolbars +- Use `__event_call__` for user confirmations and input +- Can be single action or multi-action (actions array) +- Access message content, files, and user context +- Return modified content or new files + +**Tools (Function Calling)** +- Native Python toolkits called by the model during inference +- Define a top-level `class Tools` with one or more async methods +- Must have comprehensive type hints for JSON schema generation +- Method docstrings act as LLM tool-use instructions; write clear "use this when / do not use this when" guidance +- Support `Valves` for admin settings and `UserValves` for per-user settings +- Can return `str`, `HTMLResponse`, or `(HTMLResponse, str)` depending on whether the tool should render UI, feed text back to the model, or both +- Handle file uploads, OAuth tokens, chat metadata, and model context through reserved injected arguments when needed + +#### Tools Development Pattern + +Tools are single-file Python toolkits in Open WebUI. In this repository, keep the contribution layout consistent with existing tools under `tools//main.py`. + +```python +""" +title: Tool Name +description: What it does, plus example user requests. +author: Your Name +version: 1.0.0 +license: MIT +requirements: httpx, pydantic +""" + +from collections.abc import Awaitable, Callable +from fastapi.responses import HTMLResponse +from pydantic import BaseModel, Field + + +class Tools: + class Valves(BaseModel): + api_key: str = Field(default="", description="API key for the upstream API") + + def __init__(self): + self.valves = self.Valves() + + async def lookup( + self, + query: str, + __event_emitter__: Callable[[dict], Awaitable[None]] | None = None, + ) -> HTMLResponse | str: + """ + Look up information and render a compact result card. + + Use this when the user asks for current data from the configured service. + Do not use this for general reasoning or unsupported providers. + + :param query: Search query or entity name. + :return: Inline HTML card, or an error string if lookup fails. + """ + ... +``` + +Use optional injected arguments intentionally: +- `__event_emitter__` for status, citation, notification, file, follow-up, and title events +- `__event_call__` for confirmation/input flows +- `__user__` for user data and `__user__["valves"]` +- `__metadata__` for chat metadata, including function-calling mode checks +- `__messages__`, `__files__`, and `__model__` for chat context +- `__oauth_token__` for authenticated API calls on behalf of the user + +#### Event System + +**Event Emitter Patterns** +```python +await __event_emitter__({ + "type": "status", + "data": {"description": "Processing...", "done": False} +}) + +await __event_emitter__({ + "type": "notification", + "data": {"type": "info", "content": "Success message"} +}) +``` + +For native function-calling compatibility, prefer `status`, `citation`, `notification`, `files`, `chat:title`, and `chat:message:follow_ups`. Avoid tool-emitted `message`, `chat:message:delta`, `chat:message`, and `replace` events when native mode may be used because model completion snapshots can overwrite them. + +When emitting custom citations from a Tool, set `self.citation = False` in `__init__` so Open WebUI automatic citations do not replace the custom citation events. + +**Event Call Patterns** +```python +# Confirmation dialog +response = await __event_call__({ + "type": "confirmation", + "data": { + "title": "Confirm Action", + "message": "Are you sure?" + } +}) + +# Input dialog +user_input = await __event_call__({ + "type": "input", + "data": { + "title": "Enter Value", + "message": "Provide details:", + "placeholder": "Type here..." + } +}) +``` + +#### Rich HTML Tool Cards + +When a Tool should render UI in chat, return `fastapi.responses.HTMLResponse` with an inline content-disposition header: + +```python +return HTMLResponse( + content=html_content, + headers={"Content-Disposition": "inline"}, +) +``` + +HTML cards should be self-contained: +- Use inline `