mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-15 15:02:04 +00:00
feat(ai): resolve an AI usage level per record and publish it as ai.usage
Three levels (frugal, standard, full) with an operator ceiling and default and a per-account choice within them, resolved in the capability layer for the record and published on GET /api/auth/me as ai.usage: the level in effect, the stored choice, the bounds, why (user, default, admin_cap), the three options with whether each is allowed and an estimate of tokens per day scaled from the record's last seven full days of coach_usage, and the measured mean. A delegate sees the level, never the owner's spend. PUT /api/auth/me/ai-usage stores the account's own choice or null for the default, refusing a level above the ceiling with 422 ai.usage.aboveCeiling and meta.maxLevel. The new supplementLabel capability needs standard or above; below it the capability is unavailable with the new usage_level reason, refused with 403 ai.usage.levelTooLow and meta.requiredLevel. Refs #1217
This commit is contained in:
1 parent
e573f28ae8
commit
6f673a7b84
22 files changed
+1342
-84
No files matched your search
@@ -9,6 +9,7 @@ import type {
|
||||
} from "@/lib/ai/capabilities/types";
|
||||
import { PROVIDER_DEFAULT_TIMEOUT_MS } from "@/lib/ai/effective-timeout";
|
||||
import type { CoachReasoningState } from "@/lib/ai/reasoning/resolve";
|
||||
import type { AiUsageState } from "@/lib/ai/usage-level";
|
||||
|
||||
/**
|
||||
* The web reader for the `ai` block on `GET /api/auth/me`.
|
||||
@@ -85,6 +86,25 @@ function useCoachReasoningInner(): CoachReasoningState | null {
|
||||
return user?.coachReasoning ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* v1.43 (#1217) — the record's AI usage level (`ai.usage` on
|
||||
* `GET /api/auth/me`): the level in effect, the person's choice, the
|
||||
* operator's bounds, the three options with their estimates. `null` while it
|
||||
* is not known or on a server that does not publish it; the setting is then
|
||||
* not shown. Render from it; never compute an estimate or an allowance here.
|
||||
*/
|
||||
export function useAiUsage(): AiUsageState | null {
|
||||
const hasClient = useQueryClientMounted();
|
||||
if (!hasClient) return null;
|
||||
// eslint-disable-next-line react-hooks/rules-of-hooks
|
||||
return useAiUsageInner();
|
||||
}
|
||||
|
||||
function useAiUsageInner(): AiUsageState | null {
|
||||
const { user } = useAuth();
|
||||
return user?.ai?.usage ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The server's answer for one capability, or `null` while there is none yet
|
||||
* (`/me` loading, no signed-in account, no query client). For the few places
|
||||
|
||||
Reference in new issue
Block a user