mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
feat(coach): resolve the turn's thinking depth from the person and the operator
The chat route hands the turn the level resolveCoachTurnReasoningLevel returns: the stored Coach preference, absent read as medium, after the operator's switch and cap. The turn still applies the operator-paid ceiling once its chain is known. The controls loader no longer throws when the request cache cannot serve it; it fails closed to off. The admin guard pins the route to the resolver.
This commit is contained in:
1 parent
85ebdad5c9
commit
ae5cee331e
6 files changed
+168
-10
No files matched your search
@@ -175,6 +175,8 @@ export function resetGolden(): void {
|
||||
},
|
||||
);
|
||||
m.getEvent.mockReturnValue({
|
||||
// A request event, so the per-request cache memoises as in production.
|
||||
getKind: () => "request",
|
||||
setError: (err: Error) =>
|
||||
record("event.setError", { message: err.message }),
|
||||
});
|
||||
|
||||
@@ -63,6 +63,8 @@ vi.mock("@/lib/db", () => ({
|
||||
user: { findUnique: h.m.userFindUnique, update: h.m.userUpdate },
|
||||
coachConversation: { findFirst: h.m.conversationFindFirst },
|
||||
coachMessage: { findMany: h.m.coachMessageFindMany },
|
||||
// v1.41 — the operator's reasoning controls; an untouched instance.
|
||||
appSettings: { findUnique: vi.fn(async () => null) },
|
||||
},
|
||||
}));
|
||||
vi.mock("@/lib/rate-limit", () => ({
|
||||
|
||||
@@ -37,10 +37,8 @@ import { coachChatRequestSchema } from "@/lib/ai/coach/types";
|
||||
import { listConversations } from "@/lib/ai/coach/persistence";
|
||||
import { detectRefusal } from "@/lib/ai/coach/refusal";
|
||||
import { runCoachTurn } from "@/lib/ai/coach/turn/pipeline";
|
||||
import {
|
||||
DEFAULT_REASONING_LEVEL,
|
||||
type ReasoningLevel,
|
||||
} from "@/lib/ai/reasoning/levels";
|
||||
import type { ReasoningLevel } from "@/lib/ai/reasoning/levels";
|
||||
import { resolveCoachTurnReasoningLevel } from "@/lib/ai/reasoning/controls";
|
||||
import { streamProviderError, streamRefusal } from "@/lib/ai/coach/turn/sse";
|
||||
|
||||
/**
|
||||
@@ -182,10 +180,13 @@ async function handleChatRequest(request: NextRequest): Promise<Response> {
|
||||
}
|
||||
|
||||
// v1.41 — the person's effective reasoning level: their choice after the
|
||||
// operator's switch and highest level. Integration points this one call
|
||||
// site at the shared resolver (`src/lib/ai/reasoning/resolve.ts`); until
|
||||
// then every turn thinks at the default level.
|
||||
const reasoningLevel: ReasoningLevel = DEFAULT_REASONING_LEVEL;
|
||||
// operator's switch and highest level, from the shared resolver. Who pays
|
||||
// is not known until the turn resolves its chain, so the turn applies the
|
||||
// operator-paid ceiling itself (`turn/reasoning.ts`); the provider's own
|
||||
// ability is left to its client.
|
||||
const reasoningLevel: ReasoningLevel = await resolveCoachTurnReasoningLevel(
|
||||
auth.user.coachPrefsJson,
|
||||
);
|
||||
|
||||
// v1.41 — the person's turn slot. The counter is the rate-limit row's own
|
||||
// (an atomic upsert), given back when the turn is over; a refused slot is
|
||||
|
||||
Reference in new issue
Block a user