Add image search with local cache (Phase 23)

Images found via SearXNG are fetched server-side, stored on disk, and
served from /api/images/<id> — the user's browser never contacts the
original image host.  Original URLs are preserved for citation.

New files:
- alembic/versions/0016_add_image_cache.py  — image_cache table
- src/fabledassistant/models/image_cache.py — SQLAlchemy model
- src/fabledassistant/services/images.py    — fetch/store/serve logic
- src/fabledassistant/routes/images.py      — GET /api/images/<id>

Modified:
- config.py: IMAGE_CACHE_DIR (/data/images), IMAGE_MAX_BYTES (5 MB)
- research.py: _search_searxng_images() — SearXNG categories=images
- tools.py: _IMAGE_TOOLS def + search_images branch in execute_tool
- intent.py: search_images routing rule (explicit visual language only)
- app.py: register images_bp
- docker-compose.yml: image_cache named volume mounted at /data/images
- ToolCallCard.vue: "image_search" label

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 12:55:10 -05:00
parent 90afd3f131
commit efe0a15b8c
12 changed files with 392 additions and 1 deletions
+4
View File
@@ -106,6 +106,10 @@ Rules:
the internet. Do NOT use for creative questions, brainstorming, game design, writing help, or
when the user is building on content they already have. Do NOT use when the user references
their own notes or prior research — use search_notes instead.
- search_images: ONLY when the user explicitly asks to SEE, SHOW, DISPLAY, or VIEW an image or
photo. Trigger phrases: "show me a picture/photo/image of", "what does X look like",
"find a photo of", "display an image of". Do NOT use for general questions about appearance,
descriptions, or when the user just wants information without visual content.
- research_topic: user wants a comprehensive, multi-section research note created from web sources.
Use whenever the user wants to deeply understand, learn about, or get a full written reference
on any subject — regardless of how they phrase it. The topic can be anything: technical subjects,