Imported from Zephyr-Isle/flarum-zai-bot (
AGENTS.md). Install upstream withnpx skills add Zephyr-Isle/flarum-zai-bot. Copyright stays with the author.
AGENTS.md
Flarum extension (zephyrisle/flarum-zai-bot): an AI bot that auto-replies to forum posts and private messages. PHP backend in src/, TypeScript frontend in js/src/. Comments throughout the codebase are written in Chinese — match that style when adding comments.
Commands
- Test (PHP):
composer test(=phpunit). All tests are unit tests against an in-memory SQLite DB (schema created intests/bootstrap.php, not migrations) — no DB server needed.phpunit.xml.distsetsfailOnWarning/failOnRisky. - Run a single test file:
vendor/bin/phpunit tests/Unit/AIServiceTest.php - Frontend build:
cd js && npm install && npm run build— outputsjs/dist/forum.jsandjs/dist/admin.js, whichextend.phpreferences.npmmust run injs/, not the repo root.dev/watchalso exist. - Keep the compiled
js/dist/*.jsin sync —extend.phploads them directly. composer.lockandvendor/are gitignored.flarum/coreis^2.0@dev(pre-2.0-stable), socomposer install --prefer-sourceisn't special; just install normally.
Frontend
js/tsconfig.jsonmapsflarum/*to../vendor/flarum/core/js/dist-typings/*— TypeScript typings only resolve aftercomposer installpopulatesvendor/.- Admin settings live in
js/src/admin/extend.ts; admin can be fully tested only inside a real Flarum install (it needs the running forum), so PHP unit tests are the primary verification path.
Architecture / wiring
- Extensions are loaded via two mechanisms, both critical:
extend.phpregisters events, routes (the/zai-bot/*API controllers fromsrc/Api/Controller/), models, locales, and settings. Settings keys use theflarum-zai-bot.prefix.- Event listeners must be registered as plain class-name strings (e.g.
->listen(Event::class, Listener::class)), not[Class::class, 'method']arrays — Flarum callshandle(), and the array form is not a valid callable for non-static methods (startupTypeError). See the comment inextend.php.
- Optional integrations (fof/upload, ramon/stickers, flarum/likes, flarum/messages, etc.) are all loaded via
Extend\Conditionaland guarded withclass_exists()at runtime — there are no hard dependencies. When touching integration code, checkclass_exists()guards are correct; a previous commit fixed systemic class_exists mistakes that silently disabled features. - Replies are generated asynchronously via queue jobs (
src/Job/GenerateReplyForPost.php,src/Job/GenerateReplyForMessage.php), dispatched from listeners. A running queue worker (php flarum queue:work) is required at runtime. - Tools implement
src/Service/Tool/ToolInterfaceand are built per-reply insrc/Job/Concerns/BuildsBotTools.php. - Models (
src/Model/) map tobot_memories,bot_context_events,bot_affinities,bot_user_portraits,bot_relations,bot_expressionstables (seemigrations/). src/Console/exists but is empty — no console commands.
Testing gotchas
- Message-job tests need
flarum/messagesinstalled as a dev dependency (it is). Stubs forramon/stickersandfof/uploadare loaded intests/bootstrap.phponly when the real extensions aren't present — keep them in sync with whatever the tests touch. BotAffinityuses aResetsBotAffinitiestrait in tests; model-backed tests rely on the exact schema intests/bootstrap.php— if you change a model, update the bootstrap schema too.- Settings and Guzzle HTTP calls are mocked with Mockery (see
AIServiceTestfor the canonical pattern); there is no real network access in tests.
Deploy / runtime notes
- Memory system uses pgvector (
bot_memories.embeddingisvector(1024)) — only meaningful on a PostgreSQL DB with the extension; embedding dimension must match the configured embedding model. - Migration
2026_08_30_...fix_bot_memories_created_at_type.phprepairs a botchedcreated_atcolumn type and is PostgreSQL-aware — keep new migrations DB-specific where needed. - No CI workflow or linter config exists;
composer test(phpunit) is the only automated check.
