project-nomad/admin/start
Chris Sherwood fd153b46b8 feat(KB): first-chat JIT prompt for ingest policy (RFC #883 Phase 3 task 12)
When a user opens AI Chat with content available but no global ingest
policy yet recorded, surface a one-time banner above the chat header
asking how they want new content handled:

  - 'Index existing content' -> sets rag.defaultIngestPolicy=Always and
    triggers a sync so pending_decision files queue immediately
  - 'Maybe later' -> sets policy=Manual; existing and future content
    waits in pending_decision until the user opts in from the KB modal

After either button is clicked the banner never reappears, because both
write the policy KV (the same one #894 manages via the KB modal toggle).
There is intentionally no 'dismiss without deciding' X — that would just
re-show the banner forever.

Backend
- New GET /api/rag/policy-prompt-state returns
  {shouldPrompt, hasContent, totalFiles}
- RagService.getPolicyPromptState() reads KVStore('rag.defaultIngestPolicy')
  and counts kb_ingest_state rows; shouldPrompt is true only when policy
  is null AND scanner has seen >=1 file (avoids prompting on empty NOMADs)

Frontend
- New KbPolicyPromptBanner component (~120 LOC) handles the two-button
  decision flow with optimistic loading state, success/error toasts, and
  invalidates kbPolicyPromptState + ingestPolicy + embed-jobs + storedFiles
  on success
- Mounted in components/chat/index.tsx as the first child of the main
  content column so it sits above the chat title bar without taking space
  when shouldPrompt is false (renders nothing)
- Reads aiAssistantName from Inertia page props so banner copy matches
  the user's chosen assistant name

Stacks on feat/kb-policy-toggle (#894) because the policy KV mechanism
it writes through is introduced there. Both can land in rc.5; this PR
auto-rebases to rc once #894 merges.

Existing users on first upgrade to v1.32.0 will see this banner on first
chat visit post-upgrade — an explicit opt-in moment for content that was
already on disk. New users see it the first time they have curated
content downloaded.
2026-05-20 10:16:00 -07:00
..
env.ts feat: gzip compression by default for all registered routes 2026-04-03 14:26:50 -07:00
kernel.ts feat: gzip compression by default for all registered routes 2026-04-03 14:26:50 -07:00
routes.ts feat(KB): first-chat JIT prompt for ingest policy (RFC #883 Phase 3 task 12) 2026-05-20 10:16:00 -07:00