Files
temetro/backend/drizzle/meta/_journal.json
T
Khalid Abdi 3a7378e00d backend: AI chat agent with Veil PHI safeguard (providers, /chat, import)
Real LLM chat replacing the mock, backend-centric per the plan:

- Multi-provider API-key mode (OpenAI / Anthropic / Gemini via the AI SDK) plus
  local Ollama (OpenAI-compatible endpoint). Provider is derived from the
  picked model id; the matching stored key is used. New user_ai_settings table
  holds per-user config with provider API keys encrypted at rest (AES-256-GCM,
  src/lib/crypto.ts, keyed by AI_CREDENTIALS_KEY).
- POST /api/ai/config (get/put, secrets never returned), POST /api/ai/test
  (Ollama ping / key presence), POST /api/ai/import (approved migration commit,
  re-validated server-side, reuses the audited patient service).
- POST /api/chat: streamText agent with tools (getPatient, getPatientLabs,
  searchPatients, previewImport). Real record data streams to the clinician as
  custom data parts (cards) while the model sees only Veil-redacted results.
- Veil (src/services/ai/veil.ts): de-identifies patient identifiers to tokens
  before external calls, resolves tokens on tool args, and rehydrates the final
  answer. Bypassed for local Ollama. External mode runs non-streamed so the
  rehydrated text is correct. Every call is audited (provider + Veil level).
- Shared role-scoping helpers extracted to src/lib/role-scope.ts (reused by the
  patient routes and chat tools so visibility rules match).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 18:35:16 +03:00

104 lines
2.0 KiB
JSON

{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1780413912874,
"tag": "0000_small_sir_ram",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1780591375930,
"tag": "0001_boring_puck",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1780849813505,
"tag": "0002_fluffy_longshot",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1780850147682,
"tag": "0003_lame_rawhide_kid",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1780850364853,
"tag": "0004_dizzy_scarlet_spider",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1780850717058,
"tag": "0005_true_gwen_stacy",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1780856647280,
"tag": "0006_square_wither",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1780933857005,
"tag": "0007_skinny_bloodstrike",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1780937195597,
"tag": "0008_luxuriant_blue_blade",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1781022080228,
"tag": "0009_melted_puck",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1781111039837,
"tag": "0010_eager_hellfire_club",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1781196252617,
"tag": "0011_remap_viewer_to_member",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1781279151289,
"tag": "0012_wonderful_terrax",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1781364502603,
"tag": "0013_strange_medusa",
"breakpoints": true
}
]
}