Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ demonstrate basic system features, integration APIs, and best practices.
| [Jira assignee from Google Calendar](./jira_google_calendar/assignee_from_schedule/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=jira_google_calendar/assignee_from_schedule) | Set assignee in Jira ticket to the person currently on-call | jira, googlecalendar |
| [Create calendar due date event for Jira ticket](./jira_google_calendar/deadline_to_event/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=jira_google_calendar/deadline_to_event) | When a new Jira issue is created, the workflow automatically generates a Google Calendar event with a deadline | googlecalendar, jira |
| [Leash - Incident Management & On-Call Escalation](./leash/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=leash) | Automated incident management system with on-call rotation, escalation workflows, and multi-channel notifications | googlesheets, slack, twilio, gmail |
| [Ask - Slack Q&A Bot](./pydantic/ask/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic/ask) | Simple one-shot question answering bot for Slack using Pydantic AI | slack |
| [Chat - Conversational Slack Bot](./pydantic/chat/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic/chat) | Multi-turn conversation bot for Slack with persistent history using Pydantic AI | slack |
| [Chat with UI - Web-Based Conversational AI](./pydantic/chat_with_ui/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic/chat_with_ui) | Browser-based chat interface with persistent conversation history using Pydantic AI | |
| [D&D Party Chat - AI-Powered Multiplayer RPG](./pydantic/dnd/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic/dnd) | Web-based D&D game where you adventure with AI teammates, powered by multiple LLM providers | pydanticgw |
| [Gamble - AI Casino Bot](./pydantic/gamble/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic/gamble) | Interactive roulette and blackjack games powered by AI tool calling with Pydantic AI | slack |
| [Quickstart](./quickstart/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=quickstart) | Sample for quickstart | |
| [AWS Health monitor](./reliability/aws_health_monitor/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=reliability/aws_health_monitor) | Announce AWS Health events in Slack channels, based on resource ownership data in a Google Sheet | aws, slack, googlesheets |
| [Missing Jira events monitor](./reliability/missing_jira_events_monitor/)<br/>[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=reliability/missing_jira_events_monitor) | Send Slack alerts when AutoKitteh doesn't receive certain Jira events in time | jira, slack |
Expand Down
183 changes: 183 additions & 0 deletions pydantic/ask/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
---
title: Ask - Slack Q&A Bot
description: Simple one-shot question answering bot for Slack using Pydantic AI
integrations: ["slack"]
categories: ["AI", "Samples"]
tags:
[
"slack_bot",
"pydantic_ai",
"question_answering",
"stateless",
"single_turn",
]
---

# Ask - Slack Q&A Bot 🤖

[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic-ask)

A simple Slack bot that answers questions using Pydantic AI. Send a message starting with `!ask` and get an instant AI-powered response in a thread. Each question is treated independently without conversation history.

### What AutoKitteh Provides

- **Slack Integration**: Seamless Slack event handling and message posting
- **Event Filtering**: Automatic routing of `!ask` commands to the handler
- **Connection Management**: Secure credential storage for Slack and AI providers
- **Reliable Execution**: Guaranteed message processing and response delivery

## Features

- **One-Shot Q&A**: Each question is independent with no conversation memory
- **Threaded Responses**: Replies appear as threads to keep channels clean
- **Configurable Models**: Switch between any Pydantic AI-compatible model
- **Simple Integration**: Just add the bot to your Slack workspace and start asking

## How It Works

1. **User posts message**: `!ask What is the capital of France?`
2. **AutoKitteh triggers**: Filters and routes the message to the handler
3. **AI processes**: Pydantic AI agent generates a concise response
4. **Bot replies**: Response appears in a thread attached to the original message

## Architecture

```
Slack Message (!ask) → AutoKitteh Event Trigger → Pydantic AI Agent → Slack Thread Reply
```

### Key Components

- **`handlers.py`**: Event handler that processes Slack messages and generates AI responses
- **`autokitteh.yaml`**: AutoKitteh project configuration with Slack trigger and event filter

## Setup

### Prerequisites

- AutoKitteh account (cloud or self-hosted)
- Slack workspace where you can install apps
- API key for your chosen AI provider (Anthropic, OpenAI, etc.)

### Installation

1. Start using AutoKitteh Cloud:

[![Start with AutoKitteh](https://autokitteh.com/assets/autokitteh-badge.svg)](https://app.autokitteh.cloud/template?template-name=pydantic-ask)

2. Configure your API key:
- Navigate to the project configuration in AutoKitteh UI
- Go to the **Variables** tab
- Set `ANTHROPIC_API_KEY` (or your provider's key)
- Optionally change `MODEL_NAME` (default: `anthropic:claude-sonnet-4-0`)

3. Initialize the Slack connection:
- Go to the **Connections** tab
- Initialize the `slack` connection
- Follow the OAuth flow to authorize your Slack workspace

4. Invite the bot to a channel:
- In Slack, type `/invite @AutoKitteh` in any channel
- Or add it from the channel details

## Usage

### Asking Questions

Simply type `!ask` followed by your question in any channel where the bot is present:

```
!ask What is the speed of light?
!ask Explain quantum entanglement in simple terms
!ask Who wrote "The Great Gatsby"?
```

The bot will respond in a thread with a concise answer.

### Changing the AI Model

Update the `MODEL_NAME` variable in `autokitteh.yaml` or in the AutoKitteh UI:

```yaml
vars:
- name: MODEL_NAME
value: "anthropic:claude-sonnet-4-0" # or "openai:gpt-4o", etc.
```

Supported model formats:
- Anthropic: `anthropic:claude-sonnet-4-0`
- OpenAI: `openai:gpt-4o`
- Any other Pydantic AI-compatible provider

## Technical Details

### Pydantic AI Integration

The project uses [Pydantic AI](https://ai.pydantic.dev/) for AI interactions:

- **Stateless Agent**: No conversation history - each question is independent
- **Concise Instructions**: Agent is configured to respond in one sentence
- **Synchronous Processing**: Uses `run_sync()` for simple request/response flow

### Event Filtering

The AutoKitteh trigger uses a filter to only process relevant messages:

```python
filter: "data.thread_ts == '' && data.text.startsWith('!ask')"
```

This ensures:
- Only top-level messages are processed (not thread replies)
- Only messages starting with `!ask` trigger the bot

### Response Format

Responses are posted as threaded replies with the format:

```
`<model-name>` says:
```<answer>```
```

This keeps the main channel clean while providing context about which model generated the response.

## Comparison with Other Samples

| Sample | Conversation History | UI | Use Case |
|--------|---------------------|-----|----------|
| **ask** | ❌ No | Slack | Quick one-off questions |
| **chat** | ✅ Yes | Slack | Multi-turn conversations |
| **chat_with_ui** | ✅ Yes | Web | Browser-based chat |
| **gamble** | ✅ Yes | Slack | Interactive AI games |

## Development

Run type checking and validation locally:

```bash
ak make
```

Deploy from the command line:

1. **Install the CLI**: https://docs.autokitteh.com/get_started/install
2. **Authenticate**: `ak auth login`
3. **Deploy**: `ak deploy`
4. **Initialize connections**: Log in to https://autokitteh.cloud and set up Slack
5. **Start asking**: Use `!ask` in Slack

## Customization Ideas

- **Change response style**: Modify the agent's instructions for different tones
- **Add context**: Pass additional information to the agent (company docs, user data, etc.)
- **Multi-language**: Detect language and respond accordingly
- **Rate limiting**: Track usage per user or channel
- **Custom commands**: Add more `!` commands for different behaviors

## Known Limitations

- No conversation memory across questions
- Single sentence responses (by design)
- Requires the bot to be in the channel
- No support for direct messages (DMs) - only channels
24 changes: 24 additions & 0 deletions pydantic/ask/autokitteh.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
version: v2

project:
name: pydantic_ask

vars:
- name: ANTHROPIC_API_KEY
value: ""
secret: true
- name: MODEL_NAME
value: "claude-sonnet-4-0"

connections:
- name: slack
integration: slack
- name: anthropic
integration: anthropic

triggers:
- name: slack_message
connection: slack
event_type: message
filter: "data.thread_ts == '' && data.text.startsWith('!ask')"
call: handlers.py:on_slack_message
80 changes: 80 additions & 0 deletions pydantic/ask/handlers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
"""Slack Q&A Bot - Simple one-shot question answering using Pydantic AI

This module implements a stateless Slack bot that answers questions using AI.
Each message is treated independently without conversation history.

Architecture:
Slack Message (!ask) → AutoKitteh Trigger → Pydantic AI Agent → Slack Reply

Key Features:
- One-shot Q&A (no conversation history)
- Configurable AI model via environment variable
- Threaded replies in Slack
- Synchronous processing
"""

from os import getenv

from pydantic_ai import Agent
from pydantic_ai.models.anthropic import AnthropicModel

from autokitteh import Event
from autokitteh.pydantic import anthropic_pydantic_ai_provider
from autokitteh.slack import slack_client


# Initialize Slack client using AutoKitteh connection
_slack = slack_client("slack")

# AI model configuration
_MODEL_NAME = getenv("MODEL_NAME", "claude-sonnet-4-0")

# Create Anthropic model with AutoKitteh provider
model = AnthropicModel(
_MODEL_NAME,
provider=anthropic_pydantic_ai_provider("anthropic")
)

# Create Pydantic AI agent with the configured model
# This agent is stateless - each run is independent
agent = Agent(
model=model,
instructions="Be concise, reply with one sentence.",
)


def on_slack_message(event: Event) -> None:
Comment thread
itayd marked this conversation as resolved.
"""Handle incoming Slack messages starting with !ask command.

Triggered by Slack messages matching the filter in autokitteh.yaml:
- Must not be in a thread (thread_ts == '')
- Must start with '!ask'

Args:
event: AutoKitteh event containing Slack message data

Process:
1. Extract question text (remove !ask prefix)
2. Send to Pydantic AI agent for processing
3. Post response back to Slack in a thread

Note:
No conversation history is maintained - each question is independent.
"""
data = event.data
# Remove the !ask command prefix and any leading/trailing whitespace
q = data.text.removeprefix("!ask").strip()

print(f"Q: {q}")

# Run agent synchronously - no message history passed
a = agent.run_sync(q).output

print(f"A: {a}")

# Post response in a thread attached to the original message
_slack.chat_postMessage(
channel=event.data.channel,
text=f"```{a}```",
thread_ts=event.data.ts, # Creates a thread reply
)
Loading
Loading