Commit Graph
8 Commits
Author SHA1 Message Date
Claude 1bd11e6acd feat: inject today's date into system prompt and add extended thinking support
Fixes age validation errors caused by the LLM not knowing the current date.

Changes:
- prompts.py: inject date.today() at the top of both system prompts so the
  LLM can accurately calculate a child's age from their date of birth
- llm.py: add optional thinking_budget parameter to complete(); when set,
  passes thinking={"type": "enabled", "budget_tokens": N} to litellm and
  raises max_tokens to thinking_budget + 4096 (Anthropic models only)
- config.py: add thinking_budget field, read from THINKING_BUDGET env var
- .env.example: document the THINKING_BUDGET option
- core.py: pass thinking_budget through to llm.complete()
- main.py: pass thinking_budget when constructing EmailAgent
- chat_app.py: switch from stream_complete to asyncio.to_thread(complete)
  so extended thinking works and so only the reply field is shown to
  the parent (not the raw JSON wrapper)

To enable extended thinking set THINKING_BUDGET=8000 in .env.

https://claude.ai/code/session_01SUWzMzFvSfWiHXA2p6rPg9
2026-02-22 19:57:32 +00:00
Claude 8217b33f38 Remove hardcoded language list from greeting prompt
Replace the explicit enumeration of German, English, French, Italian,
and Spanish with "any human language" to be inclusive of all parents
(Arabic, Turkish, etc.).

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-21 21:44:38 +00:00
Claude af96c7a310 German admin emails and German-only registration data storage
notifier.py:
- All email body text translated to German (section headers, labels,
  day names, playgroup type names, age format, change diff labels)
- Subject lines changed to German: "Neue Anmeldung:" / "Anmeldung aktualisiert:"
- Channel label localised: "E-Mail" / "Chat"
- Fallback special needs label changed to "Keine"

prompts.py:
- New rule: always store free-text field values (especially specialNeeds)
  in German in `updates`, translating from the parent's language if needed;
  use "Keine" for no special needs

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-21 21:13:19 +00:00
Claude c488a0061e Improve email conversation efficiency: language hint + aggressive info collection
Two prompt changes:

1. Greeting step: explicitly tell parents they can write in any language
   (German, English, French, Italian, Spanish, …) and the agent will reply
   in the same language. Also kick off info collection immediately by asking
   for child name + DOB in the greeting reply.

2. Personality: replace the "1–2 questions at a time" rule with a strategy
   that gathers all relevant questions per step in one message (woven into
   natural sentences, not a form), and explicitly re-asks any unanswered
   questions before advancing — no open question is silently skipped.

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-21 21:01:01 +00:00
Claude 9c33bafbf3 Prohibit markdown in email reply text
Tell the LLM explicitly that the reply field must be plain text with no
markdown (no bold, italic, headers, bullet points, or backticks). Email
clients display raw text so markdown syntax would appear as literal
characters rather than formatting.

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-21 20:10:41 +00:00
Claude 98a5f5b5b1 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
2026-02-21 13:35:35 +00:00
Claude 0c3b5a9033 Implement email-address-based conversation matching
Closes the gap where parents sending a new email (instead of replying)
would lose their registration progress. All changes follow the
email-based-conversation-matching OpenSpec change.

Key changes
-----------
storage/json_store.py
  - normalize_email() helper (lowercase + trim)
  - Conversations now keyed by sender email address, not thread ID
  - Versioned registration storage: data/registrations/<email>/v<N>_<ts>.json
  - current.json always reflects the latest version
  - save_registration() returns (email_key, version) tuple
  - save_registration_version() for updates with change_summary
  - get_registration_history() returns all versions in order

models/conversation.py
  - Added last_inbound_message_id field for reply threading (not matching)

channels/email_channel.py
  - fetch_unread_messages() no longer exposes thread_id
  - Conversation matching removed from channel layer (now in agent)
  - Removed _resolve_thread_id() — threading headers kept for SMTP only

agent/core.py
  - process_message() takes parent_email + inbound_message_id (no thread ID)
  - Looks up conversation by normalized email address
  - Post-completion handler: detects intent (question / update / new_child)
  - Registration updates: diffs old vs new, versions storage, notifies admin

agent/prompts.py
  - build_system_prompt() dispatches to registration or post-completion prompt
  - Post-completion prompt guides LLM to return intent field
  - Reminder language updated: no expiration threats

notifications/notifier.py
  - notify_admin() accepts version parameter
  - notify_registration_update() sends "Registration Updated" emails with diff
  - _build_update_body() includes field-level old→new change summary

main.py
  - Poll loop passes parent_email + inbound_message_id to agent (no thread_id)

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-20 22:15:49 +00:00
Claude b82ff27efd Implement Python email agent with multi-model AI support
Adds a complete email-based registration agent for Spielgruppe Pumuckl
based on the OpenSpec define-project-scope specifications.

Architecture
- Channel-agnostic EmailAgent core — no email-specific code in business logic
- Pluggable AI provider layer: Anthropic (Claude) and OpenAI (GPT) supported
  via a shared LLMProvider interface; switch with AI_PROVIDER env var
- IMAP polling for inbound emails with thread-tracking via email headers
  (Message-ID / In-Reply-To / References)
- SMTP for outbound replies and admin notifications
- File-based JSON storage for conversation state and completed registrations
- Admin-editable knowledge-base loaded from markdown files at startup

Key files
  src/config.py                  — env-var configuration
  src/providers/base.py          — abstract LLMProvider
  src/providers/anthropic_provider.py — Claude backend
  src/providers/openai_provider.py    — OpenAI backend
  src/agent/core.py              — EmailAgent orchestrator
  src/agent/prompts.py           — system prompt builder (KB + registration state)
  src/models/registration.py     — RegistrationData matching the JSON schema
  src/models/conversation.py     — ConversationState persisted per thread
  src/channels/email_channel.py  — IMAP/SMTP I/O + quoted-text stripping
  src/storage/json_store.py      — conversation & registration persistence
  src/notifications/notifier.py  — admin notification routing by playgroup type
  main.py                        — polling entry point
  requirements.txt               — anthropic, openai, python-dotenv, jsonschema
  .env.example                   — configuration template

https://claude.ai/code/session_01HaUFs7SaLD5SoiuGCY27Tw
2026-02-20 20:17:00 +00:00