mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 06:06:10 +00:00
Reading a stored document (suggest, summary, extract, index, chat, reindex), scanning a lab report and turning medication text into a schedule now answer under documentAi, labsOcr and medicationExtract. The operator's master switch and the new reading-documents switch stop the work and the egress; a module off for the record, a delegate inside somebody else's record, and a missing receipt refuse with the capability envelope. Existing no-provider codes keep their status. The document pick and the labs pick re-check the capability for the provider they picked, immediately before anything is sent, so a job enqueued before a switch flipped finds no provider and falls back to the provider-free text layer. Consent follows the document rule for all three: any provider that leaves the machine needs an ai_extraction or ai_full receipt, answered for the provider actually picked. The fenced Coach chat and attachments answer under coach and documentAi. Uploads are always stored and indexed; the background summary is only enqueued while documentAi is open. The capability probes report the capability beside the provider answer and keep a read offered when only the receipt is missing. medications/extract keeps its 503 for no provider and adds ai.provider.none, and its budget refusal gains the coach.budget.exceeded code.
44 lines
1.6 KiB
TypeScript
44 lines
1.6 KiB
TypeScript
/**
|
|
* GET /api/documents/inbound/capability
|
|
*
|
|
* Document-scoped AI capability probe (no provider call). Mirrors the labs
|
|
* `/api/labs/ocr/capability` probe but resolves over the DOCUMENT provider
|
|
* order (local-first, codex last — governance fix, oauth-investigation
|
|
* SYNTHESIS §1) and adds the vendor-blind `egress` class so the vault UI can
|
|
* show the "this leaves your machine to a third-party AI" notice BEFORE a read.
|
|
*
|
|
* The `mode` / `pdfSupported` / `egress` here reflect exactly what the document
|
|
* routes (suggest / summary / extract / index) will do, so the affordance the
|
|
* UI offers never diverges from what the endpoint accepts.
|
|
*/
|
|
import { apiHandler, requireAuth } from "@/lib/api-handler";
|
|
import { apiSuccess } from "@/lib/api-response";
|
|
import { resolveDocumentAiCapability } from "@/lib/documents/provider-order";
|
|
import { annotate } from "@/lib/logging/context";
|
|
import { requireModuleEnabled } from "@/lib/modules/gate";
|
|
|
|
export const dynamic = "force-dynamic";
|
|
|
|
export const GET = apiHandler(async () => {
|
|
const { user } = await requireAuth();
|
|
|
|
const gate = await requireModuleEnabled(user.id, "inboundDocuments");
|
|
if (!gate.enabled) return gate.response;
|
|
|
|
const capability = await resolveDocumentAiCapability(user.id);
|
|
|
|
annotate({
|
|
action: { name: "documents.ai.capability" },
|
|
meta: {
|
|
available: capability.available,
|
|
mode: capability.mode,
|
|
reason: capability.reason,
|
|
pdfSupported: capability.pdfSupported,
|
|
egress: capability.egress,
|
|
aiReason: capability.ai.reason,
|
|
},
|
|
});
|
|
|
|
return apiSuccess(capability);
|
|
});
|