Files
brain-of-reese/.agents/phases/todo/122_image_documents/01_image_toggle.md
T
ducoterra 0ff1f8c4d6 chore(agent): phase roadmap from TODO.md — 4 phases (120–123)
Protocol B append: failed-turn retry (L3–4), git source tokens (L5),
image documents (L6 ingest), chat image questions (L6 chat side).
TODO.md items now live in .agents/phases/todo/ and the file is cleared.

LLM-Generated: true
2026-09-24 16:27:44 -04:00

2.8 KiB

Task 01 — Image toggle: BOR_IMAGES + extensions + dir, off by default

Phase: 122_image_documents · Source: TODO.md:6 — "The user should be able to turn on and off image support in their .env depending on whether their model supports it."

Objective

The single env knob for image support exists and is surfaced — BOR_IMAGES (default false), BOR_IMAGE_EXTENSIONS, BOR_IMAGE_DIR — with GET /api/config exposing the flag for UI gating. Toggle off = byte-identical behavior to pre-phase.

Work

  1. app/config.py — three new Settings fields (house docstring style, the upload_dir/llm_retries precedents):
    • images: bool = False — BOR_IMAGES, 0/false off (LOCKED A3 default). Docstring: master switch for image-document indexing (phase 122) — off by default, enable only when the chat model supports vision (descriptions come from it).
    • image_extensions: str = "png,jpg,jpeg,webp,gif,bmp" — BOR_IMAGE_EXTENSIONS, comma-separated, case-insensitive; a property/parse into a lowercased-dotted frozenset (the import_extension_set precedent) — the image set is SEPARATE from import_extension_set (images are never user-added via BOR_IMPORT_EXTENSIONS).
    • image_dir: str = "~/bor-sources/images" — BOR_IMAGE_DIR, raw string, Path.expanduser() applied by the importer (the sources_dir/upload_dir convention) — the persistent home for image bytes (uploads are replaced, checkouts re-cloned — the copy must outlive the source file).
  2. .env.example — the three entries with the comment block: off by default + the vision-model dependency note (LOCKED A3).
  3. app/api/config.py:30 — the app_config dict gains "images": settings.images (the dict is str | bool-valued — bools already allowed). Extend the docstring: consumed by the chat composer (phase 123) to show/hide the attach control, optionally by the Sources page.
  4. ASSUMPTION: GET /api/config is already anonymous-readable (the UI gates on it pre-login in phase 123 — no auth change here).

Testing & Quality

  • Unit: tests/unit/test_image_documents.py (task 06 finalizes) — defaults (images False, extensions frozenset {".png", …} with the dotted form the matchers expect, dir default), env overrides, the frozenset parse is case-insensitive and trims spaces.
  • Integration: the existing GET /api/config test asserts the new images key (default false in the test env).
  • Coverage: >90% on the touched modules.

Completion Criteria

  • Settings() with no env: images is False, the extension set is the six defaults, image_dir is the default path.
  • GET /api/config returns images: false in the default test env (byte-check the other keys unchanged).
  • uv run pytest green; uv run ruff check . && uv run pyright clean.