> ## Documentation Index
> Fetch the complete documentation index at: https://agno-v2-docs-scavio-google-v2.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Slack HITL: User Input

> Support-intake agent that drafts a ticket title and body but declares priority and component as user_input_fields, pausing Slack with an input form the requester fills before the tool runs.

Open engineering tickets from Slack conversations. The agent extracts `title` and `description`, then Slack collects `priority` and `component` before the tool runs.

```python hitl_user_input.py theme={null}
"""
Slack HITL — User Input
=======================

Support agent that opens engineering tickets from Slack chatter. The agent
extracts `title` and `description` from the conversation, but `priority`
and `component` are fields the requester must fill in — they're listed in
`user_input_fields`, so Slack pauses with an input form before the tool
runs. Read-only tools help the agent avoid duplicates and search web
docs before filing.

Try in Slack:
  @bot open a ticket — checkout page throws 500 when the cart is empty

Slack scopes: app_mentions:read, assistant:write, chat:write, im:history
"""

from typing import Dict, List, Literal
from uuid import uuid4

from agno.agent import Agent
from agno.db.sqlite.sqlite import SqliteDb
from agno.models.openai import OpenAIResponses
from agno.os.app import AgentOS
from agno.os.interfaces.slack import Slack
from agno.tools import tool
from agno.tools.duckduckgo import DuckDuckGoTools

# Stand-in ticket store — replace with Jira / Linear client


_TICKETS: List[Dict[str, str]] = [
    {
        "id": "SUP-A1B2C3",
        "title": "Checkout 500 when cart empty",
        "status": "open",
        "component": "payments",
    },
    {
        "id": "SUP-F7E5D9",
        "title": "Apple Pay button misaligned on iOS",
        "status": "open",
        "component": "mobile-web",
    },
]


# Read-only helpers


@tool
def search_existing_tickets(query: str) -> List[Dict[str, str]]:
    """Return open tickets whose title contains the query (case-insensitive).
    Use this before filing a new ticket to avoid duplicates.

    Args:
        query: Free-text fragment to match in existing ticket titles.
    """
    q = query.lower()
    return [t for t in _TICKETS if q in t["title"].lower() and t["status"] == "open"]


# Ticket creation — pauses for priority + component


@tool(requires_user_input=True, user_input_fields=["priority", "component"])
def create_support_ticket(
    title: str,
    description: str,
    priority: Literal["P0", "P1", "P2", "P3"],
    component: str,
) -> str:
    """Open a support / engineering ticket.

    Args:
        title: Short ticket title. The agent drafts this from the chat.
        description: Longer body. The agent drafts this from the chat.
        priority: One of "P0" | "P1" | "P2" | "P3". Requester picks.
        component: Subsystem or team name the ticket should be routed to.
    """
    ticket_id = f"SUP-{uuid4().hex[:6].upper()}"
    _TICKETS.append(
        {"id": ticket_id, "title": title, "status": "open", "component": component}
    )
    return (
        f"Ticket {ticket_id} opened: {title} "
        f"(priority={priority}, component={component}).\n"
        f"Description: {description}"
    )


# Agent + AgentOS + Slack interface

db = SqliteDb(
    db_file="tmp/hitl_user_input.db",
    session_table="agent_sessions",
    approvals_table="approvals",
)

agent = Agent(
    name="Support Intake Agent",
    id="support-intake-agent",
    model=OpenAIResponses(id="gpt-5.4"),
    db=db,
    tools=[
        search_existing_tickets,
        DuckDuckGoTools(),
        create_support_ticket,
    ],
    instructions=[
        "You are a Slack support-intake assistant.",
        "Workflow: (1) call search_existing_tickets with a fragment of the "
        "issue description — if you find a live duplicate, surface it and ask "
        "the user whether to still open a new one; (2) if the issue looks like "
        "a known library error, optionally use DuckDuckGo for a link to docs; "
        "(3) call create_support_ticket with a concise title and clean multi-"
        "line description. Pass empty strings for priority and component — the "
        "user will supply those via the Slack pause form.",
    ],
    markdown=True,
)

agent_os = AgentOS(
    description="Slack HITL — user input (support ticket intake)",
    agents=[agent],
    db=db,
    interfaces=[
        Slack(
            agent=agent,
            reply_to_mentions_only=True,
        ),
    ],
)
app = agent_os.get_app()


if __name__ == "__main__":
    agent_os.serve(app="hitl_user_input:app", reload=True)
```

## Run the Example

<Steps>
  <Snippet file="create-venv-step.mdx" />

  <Step title="Install dependencies">
    ```bash theme={null}
    uv pip install -U "agno[os,slack]" ddgs openai
    ```
  </Step>

  <Step title="Export environment variables">
    <CodeGroup>
      ```bash Mac/Linux theme={null}
      export OPENAI_API_KEY="your_openai_api_key_here"
      export SLACK_SIGNING_SECRET="your_slack_signing_secret_here"
      export SLACK_TOKEN="your_slack_token_here"
      ```

      ```bash Windows theme={null}
      $Env:OPENAI_API_KEY="your_openai_api_key_here"
      $Env:SLACK_SIGNING_SECRET="your_slack_signing_secret_here"
      $Env:SLACK_TOKEN="your_slack_token_here"
      ```
    </CodeGroup>
  </Step>

  <Step title="Configure Slack">
    Complete [Slack setup](/agent-os/interfaces/slack/setup): create and install the app, expose the server through public HTTPS, and add the scopes listed in the example. The default event request URL is `<public-url>/slack/events`; HITL examples also use `<public-url>/slack/interactions` for interactivity. Use any custom prefix shown in the example instead of `/slack`.
  </Step>

  <Step title="Run the example">
    Save the code above as `hitl_user_input.py`, then run:

    ```bash theme={null}
    python hitl_user_input.py
    ```
  </Step>
</Steps>

Full source: [cookbook/05\_agent\_os/interfaces/slack/hitl\_user\_input.py](https://github.com/agno-agi/agno/blob/main/cookbook/05_agent_os/interfaces/slack/hitl_user_input.py)
