2.6 KiB
AGENTS.md
Run
python main.py
Uses runpy to exec bot.py. No tests, no lint, no CI.
Architecture
bot.py— Telegram bot (python-telegram-bot), single-workerasyncio.Queue, all crawl/parse serializedagent.py— pydantic-ai with local Ollama (granite4.1:8b), three agents (opportunity/event/workshop),output_type=strdatabase.py— PocketBase client, collectionsevents/opportunities/workshopsscraper.py— crawl4aiAsyncWebCrawlerURL → markdownprompts.py— system prompts for both agent typesschemas.py— unused at runtime, per file comment: "File doesn't do anything, its just an outline"
Windows event-loop quirk
DO NOT remove the dual-event-loop pattern in bot.py:
- PTB runs on
WindowsSelectorEventLoopPolicy(line 357) - Scraper runs in a separate thread with
WindowsProactorEventLoopPolicy(line 25) — required for Playwright subprocesses on Windows
The get_clean_content() wrapper in bot.py runs _run_scraper_in_thread via ThreadPoolExecutor. Scraper functions must not be called directly.
Agent output format
Agents use output_type=str (not structured output). JSON is parsed manually from agent.run() result:
- LLM returns JSON wrapped in
json ...markdown backticks agent.py:56strips the backtick wrappers beforejson.loads()- The markdown wrapper is specified in
prompts.py— don't change prompt format without updating the strip logic
Date formats
- Prompts instruct LLM:
DD-MM-YYYY(orDD-MM-YYYY (HH:MM)for events) - PocketBase expects:
YYYY-MM-DD HH:MM:SS database.pyfield mapping: eventdate_time→ PocketBasedatetime,end_date→end_datetime; workshop same; opportunitydeadlinestaysdeadline
PocketBase collections
events— fields:title,org,datetime,end_datetime,summary,location,urlopportunities— fields:title,org,type,deadline,summary,location,urlworkshops— fields:title,org,datetime,end_datetime,summary,location,url- Auth uses admin credentials from
.env
Env vars
.env required: TG_TOKEN, OLLAMA_BASE_URL, ALLOWED_USERS, POCKETBASE_URL, POCKETBASE_ADMIN_EMAIL, POCKETBASE_ADMIN_PASSWORD
Auth
ALLOWED_USERS — comma-separated Telegram user IDs (no brackets). Checked on every command/message handler.
Save flow
When source is pasted text (not URL), the bot asks for a source URL before saving. context.user_data keys: last_extracted, last_source_value, last_source_kind, last_entry_type, awaiting_save_url, pending_save_url, pending_url_to_process.