ducoterra
1925bb66a8
feat(sources): admin page to add and remove git sources (TODO.md L4)
2026-08-26 18:42:28 -04:00
ducoterra
8fabb7efda
perf(ui): cache busting — HTML no-cache + versioned asset URLs (?v=) with immutable 1y asset caching
...
Phase 33 (story: .agent/user_stories/cache-busting.md).
- app/core/caching.py: asset_version() — git short SHA (a commit is a
deploy), stable content-hash fallback for non-git checkouts, "dev"
for a missing static dir; computed once per process. CachingMiddleware
— the five HTML pages revalidate (no-cache) with ?v=<token> asset refs
rewritten in flight; /assets/* is public, max-age=31536000, immutable;
everything else (all /api/*, the SSE chat stream in particular) passes
through byte-identical.
- tests/e2e/test_cache_busting.py: fresh-Chromium wire assertions —
document no-cache, versioned CSS/JS request URLs sharing one token,
immutable asset headers, /api/health baseline headers, SSE chat to
done (mock LLM).
- README 'Caching / deploys' section + story file.
Also fixed two prod-image defects surfaced by this phase's podman smoke
(the full app would not boot):
- Containerfile: ship the scripts/ package — app/api/sync.py (phase 32)
imports scripts.git_sync / scripts.import_docs at module level, so the
container crashed on boot (ModuleNotFoundError: No module named
'scripts').
- compose.yaml: pass BOR_ADMIN_PASSWORD / BOR_SESSION_SECRET through to
the app service (:- defaults keep 'podman compose up -d db' working;
the app's own fail-loud gate still names missing admin auth).
Smoke: podman compose --profile prod up -d on a fresh image + a fresh
Chromium profile — /, /sources.html and /login.html all served
Cache-Control: no-cache; all 8 asset requests versioned with one shared
token (content-hash fallback inside the image — no .git there);
/assets/* immutable for a year.
2026-08-25 22:42:10 -04:00
ducoterra
52136fe307
feat(admin): one-click sources sync — admin-only button triggers git clone/pull + re-import + KB overview refresh with polled live status
2026-08-25 21:39:38 -04:00
ducoterra
0654b304e1
feat(rag): lite-generated KB overview in the system prompt — stored single row, regenerated on import, <knowledge_base> section in HIGH+LOW prompts
2026-08-25 20:22:51 -04:00
ducoterra
572a4190a6
feat(rag): lite-model document summaries — non-markdown docs summarized at import, summary chunk retrieves and resolves to the full source doc
2026-08-25 17:48:37 -04:00
ducoterra
3d044f33a1
feat(rag): git-based import sources — BOR_GIT_SOURCES repos cloned (first run, --depth 1) or pulled (--ff-only) into BOR_SOURCES_DIR/<repo>/ then indexed; --source still wins; a failed sync aborts before importing anything
2026-08-25 14:23:02 -04:00
ducoterra
1e6ae360e0
feat(rag): feed whole matched documents to the LLM — no context truncation (A7 revised)
2026-08-24 23:37:44 -04:00
ducoterra
b16deb2b1d
feat(chat): stream model thinking over SSE and show it in a collapsible block
2026-08-24 09:52:27 -04:00
ducoterra
cbc263a4b2
feat(auth): single-admin password login (signed cookie) — gate tuning + Sources catalog, keep chat and document viewer public
2026-08-23 19:58:39 -04:00
ducoterra
fc0d9a2d5c
feat(rag): steering notes — tune how Brain answers, stored in Postgres and injected into every system prompt
2026-08-22 16:44:42 -04:00
ducoterra
6ec6181c7b
feat(ui): clickable document viewer — open any cited document in the browser from chat chips and the sources table
2026-08-22 02:08:49 -04:00
ducoterra
7e8d14702e
feat(rag): hybrid FTS+vector retrieval and multi-format ingestion — name-your-tool questions find the right document
2026-08-22 01:27:02 -04:00
ducoterra
1b29b1cf9d
feat(ui): responsive + WCAG AA polish pass across chat and sources — v1 feature complete
2026-08-21 19:44:46 -04:00
ducoterra
cbf8e39e63
feat(rag): honest deflection gate with amber UI state and alternative-question chips
2026-08-21 17:50:33 -04:00
ducoterra
99c48cbe06
feat(rag): index markdown KB — chunker, embed client, delta importer, Sources page
...
Phase 02 (story: import documents):
- fence-aware markdown chunker (heading sections, 200-char overlap,
heading anchor on every chunk, 1200-char hard cap, fence blocks
kept atomic and split under the cap)
- LLMClient over aipi (LiteLLM) reusing the openai client's httpx
transport to send a clean {model, input} payload — the openai SDK
injects encoding_format, which aipi's openai_like group rejects;
token-budget batching + halving retry for the endpoint's
~1024-token per-request input cap
- two-phase per-file upsert importer: sha256 delta (unchanged skip),
atomic commit, A9 exclusion walk, per-source prune, per-file error
tolerance (rollback + log + continue, non-zero CLI exit), adaptive
re-chunk at half target for URL-dense files the endpoint rejects
- scripts/import_docs CLI (repeatable --source, --prune, --limit,
defaults ~/Homelab + ~/Deployments)
- GET /api/docs with per-doc chunk counts; Sources page wired to the
real endpoint (stat cards, full-width a11y table, designed empty
state, DOM-built rows — no innerHTML)
- tests: 63 passed (chunker/llm/importer units, docs API + importer
integration), story E2E 3/3 (real endpoints, in-thread import);
app/ coverage 98%
- real KB imported: 672 docs / 8969 chunks in ~3m, idempotent
re-run (672 unchanged, 0 batches)
- harness: .agent/validate.sh now gates through uv (pytest +
coverage >90% + ruff + pyright) instead of system python3
2026-08-21 16:24:45 -04:00
ducoterra
022da8e2bc
feat: scaffold Brain of Reese — FastAPI RAG chat over Postgres 17 + pgvector
...
Foundation (phase 01, verified):
- FastAPI app: /api/health, /api/suggestions, /api/chat (placeholder),
static frontend served locally (no CDN)
- Postgres 17 + pgvector via db/Containerfile + compose.yaml
(podman compose up -d db), Alembic initial migration (documents,
chunks with vector(768), query_log)
- LLM client targeting https://aipi.reeseapps.com/v1 (turbo/embed);
scripts/llm_probe.py verified models + 768-dim embeddings live
- Conditional debugpy: imported only when DEBUGPY=1 (attach on demand,
:5678); logging config for clean single-line logs
- Frontend shell: mobile-first chat + Sources pages, tokens, a11y baselines
- Tests: 24 unit+integration (99% coverage on app/), ruff + pyright clean,
Playwright smoke E2E (3 tests) against a deterministic mock LLM
- Planning: .agent/PLAN.md (architecture + LOCKED decisions), AGENTS.md,
6 user stories, 7 phase files (one story / one phase / one Playwright
suite each)
2026-08-21 13:42:21 -04:00