Resolve PR review comments
- prompts.py: correct age restrictions (indoor ≥2 yrs, outdoor ≥2.5 yrs) Previously had indoor ≥2.5 and outdoor ≥3, which was too restrictive - README.md: add full setup and configuration guide covering prerequisites, installation, env var reference, provider switching, cron scheduling, running tests, and knowledge base editing https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
# Meister-Eder
|
# Meister-Eder
|
||||||
|
|
||||||
AI-powered conversational registration system for **Spielgruppe Pumuckl**, a playgroup run by Familienverein Fällanden (Fällanden, Switzerland).
|
AI-powered conversational registration agent for **Spielgruppe Pumuckl** (Familienverein Fällanden, Switzerland). Parents register their child and ask questions via email — the agent handles the conversation, validates all required fields, and notifies the playgroup admin on completion.
|
||||||
|
|
||||||
Replaces a static Google Forms workflow with an AI agent that guides parents through child registration via natural conversation — over email or a web chat interface.
|
Replaces a static Google Forms workflow with an AI agent that guides parents through child registration via natural conversation — over email or a web chat interface.
|
||||||
|
|
||||||
@@ -19,20 +19,102 @@ Replaces a static Google Forms workflow with an AI agent that guides parents thr
|
|||||||
| Web chat | Real-time, session-based |
|
| Web chat | Real-time, session-based |
|
||||||
| Email | Async, thread-tracked; reminders on days 3, 10, 25 |
|
| Email | Async, thread-tracked; reminders on days 3, 10, 25 |
|
||||||
|
|
||||||
## Status
|
## Prerequisites
|
||||||
|
|
||||||
Greenfield — specification complete, implementation not yet started.
|
- Python 3.13+
|
||||||
|
- [uv](https://docs.astral.sh/uv/) (dependency manager)
|
||||||
|
|
||||||
## Running the Email Agent
|
## Installation
|
||||||
|
|
||||||
The email agent is a plain script invoked periodically via cron — no long-running daemon needed.
|
```bash
|
||||||
|
git clone https://github.com/gurix/Meister-Eder.git
|
||||||
### Scheduling with cron
|
cd Meister-Eder
|
||||||
|
uv sync
|
||||||
```cron
|
|
||||||
*/5 * * * * flock -n /tmp/meister-eder-email.lock python /path/to/check_email.py
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`flock -n` acquires an exclusive lock before running the script. If a previous run is still in progress when the next cron tick fires, the new invocation exits immediately (non-blocking). The lock is released automatically by the kernel when the process ends — even on crash — so stuck locks are not a concern.
|
## Configuration
|
||||||
|
|
||||||
Adjust `*/5` to whatever polling interval makes sense (e.g. `*/2` for every 2 minutes).
|
Copy the example env file and fill in your values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
### Required variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
|---|---|
|
||||||
|
| `AI_MODEL` | litellm model string, e.g. `anthropic/claude-opus-4-6` or `openai/gpt-4o` |
|
||||||
|
| `ANTHROPIC_API_KEY` | API key for Anthropic models |
|
||||||
|
| `OPENAI_API_KEY` | API key for OpenAI models (if using OpenAI) |
|
||||||
|
| `IMAP_HOST` | IMAP server hostname for receiving parent emails |
|
||||||
|
| `IMAP_USERNAME` | Email account username |
|
||||||
|
| `IMAP_PASSWORD` | Email account password |
|
||||||
|
| `SMTP_HOST` | SMTP server hostname for sending replies |
|
||||||
|
| `REGISTRATION_EMAIL` | Sender address shown to parents |
|
||||||
|
|
||||||
|
### Optional variables
|
||||||
|
|
||||||
|
| Variable | Default | Description |
|
||||||
|
|---|---|---|
|
||||||
|
| `IMAP_PORT` | `993` | IMAP port |
|
||||||
|
| `IMAP_USE_SSL` | `true` | Use SSL for IMAP |
|
||||||
|
| `SMTP_PORT` | `587` | SMTP port |
|
||||||
|
| `SMTP_USE_TLS` | `true` | Use STARTTLS for SMTP |
|
||||||
|
| `DATA_DIR` | `data/` | Directory for conversation state and completed registrations |
|
||||||
|
| `KNOWLEDGE_BASE_DIR` | `openspec/…/knowledge-base` | Path to admin-editable knowledge base markdown files |
|
||||||
|
| `POLL_INTERVAL` | `60` | Seconds between inbox polls (only used when running as a daemon) |
|
||||||
|
|
||||||
|
### Switching AI providers
|
||||||
|
|
||||||
|
`AI_MODEL` uses [litellm](https://docs.litellm.ai/docs/providers) model strings — any supported provider works without code changes:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Anthropic (default)
|
||||||
|
AI_MODEL=anthropic/claude-opus-4-6
|
||||||
|
ANTHROPIC_API_KEY=sk-ant-...
|
||||||
|
|
||||||
|
# OpenAI
|
||||||
|
AI_MODEL=openai/gpt-4o
|
||||||
|
OPENAI_API_KEY=sk-...
|
||||||
|
|
||||||
|
# Google Gemini
|
||||||
|
AI_MODEL=gemini/gemini-2.0-flash
|
||||||
|
GEMINI_API_KEY=...
|
||||||
|
```
|
||||||
|
|
||||||
|
## Running
|
||||||
|
|
||||||
|
### As a cron job (recommended)
|
||||||
|
|
||||||
|
The agent is a plain script — no long-running daemon needed. Schedule it with cron and use `flock` to prevent overlapping runs:
|
||||||
|
|
||||||
|
```cron
|
||||||
|
*/5 * * * * flock -n /tmp/meister-eder-email.lock uv run python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
`flock -n` exits immediately if a previous run is still in progress, so the script is always safe to schedule aggressively.
|
||||||
|
|
||||||
|
### Manually
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run python main.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
### Running tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
uv run pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
All tests are unit tests — no network access or API keys required.
|
||||||
|
|
||||||
|
### Knowledge base
|
||||||
|
|
||||||
|
The agent answers parent questions from markdown files in the knowledge base directory. These files are designed to be edited directly by playgroup admins — no code changes needed to update fees, schedules, or policies.
|
||||||
|
|
||||||
|
### Adding a new AI provider
|
||||||
|
|
||||||
|
Set `AI_MODEL` to any [litellm-supported model string](https://docs.litellm.ai/docs/providers) and set the corresponding API key environment variable. No code changes required.
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ STEP_DESCRIPTIONS = {
|
|||||||
"child_name": "Ask for the child's full name.",
|
"child_name": "Ask for the child's full name.",
|
||||||
"child_dob": (
|
"child_dob": (
|
||||||
"Ask for the child's date of birth. "
|
"Ask for the child's date of birth. "
|
||||||
"Validate age: indoor requires ≥2.5 years, outdoor requires ≥3 years."
|
"Validate age: indoor requires ≥2 years, outdoor requires ≥2.5 years."
|
||||||
),
|
),
|
||||||
"playgroup_selection": (
|
"playgroup_selection": (
|
||||||
"Explain both playgroup options and ask which the parent wants "
|
"Explain both playgroup options and ask which the parent wants "
|
||||||
@@ -152,7 +152,7 @@ def _build_registration_prompt(kb: KnowledgeBase, state: ConversationState) -> s
|
|||||||
## Registration Flow (8 steps)
|
## Registration Flow (8 steps)
|
||||||
1. greeting — greet and detect intent
|
1. greeting — greet and detect intent
|
||||||
2. child_name — ask for child's full name
|
2. child_name — ask for child's full name
|
||||||
3. child_dob — ask for date of birth; validate age (indoor ≥2.5 yrs, outdoor ≥3 yrs)
|
3. child_dob — ask for date of birth; validate age (indoor ≥2 yrs, outdoor ≥2.5 yrs)
|
||||||
4. playgroup_selection — present options, collect type(s) and day(s)
|
4. playgroup_selection — present options, collect type(s) and day(s)
|
||||||
5. special_needs — ask about special needs / allergies / medical conditions
|
5. special_needs — ask about special needs / allergies / medical conditions
|
||||||
6. parent_contact — name, street address, postal code, city, phone, email
|
6. parent_contact — name, street address, postal code, city, phone, email
|
||||||
|
|||||||
Reference in New Issue
Block a user