chore(labs): tidy OCR capability enum, Fitbit key delimiter, Coach docblock

Drop the unreachable text-only-model reason from the OCR capability
enum and its DTO type. Replace the literal NUL delimiter in the Fitbit
dedup map keys with a named constant so text tooling stops treating the
file as binary (behaviour unchanged). Correct the Coach tool-executor
docblock, which overstated cross-tool snapshot-cache sharing.
This commit is contained in:
Marc-André Bombeck committed 2026-06-26 09:27:05 +02:00
1 parent 1c93a670f0
commit e023571a08
5 files changed
+23 -10

No files matched your search

+1 -1
View File
@@ -4,7 +4,7 @@
* Cheap probe (no provider call) the Labs UI uses to decide whether to show
* the "Scan a report" affordance. Returns `{ available, reason, pdfSupported }`
* for the calling user's configured AI provider. The surface stays dark for
* codex-only / text-only-model users.
* users with no provider configured and no local-OCR opt-in.
*/
import { apiHandler, requireAuth } from "@/lib/api-handler";
import { apiSuccess } from "@/lib/api-response";
+4 -2
View File
@@ -20,8 +20,10 @@
* mutation or egress surface.
*
* The builder result is memoised by the 60s snapshot LRU keyed on
* `(userId, window, sources)`, so several tool calls in one turn (and the
* base-context inventory build) share the underlying reads.
* `(userId, window, sources)`. Each tool scopes to a different source set, so
* tool calls for distinct domains do NOT share a cache entry; sharing happens
* only when the SAME scope recurs (a repeated call, or a turn that re-enters
* the same domain) within the 60s window.
*/
import { z } from "zod/v4";
+16 -3
View File
@@ -47,6 +47,14 @@ import {
/** Refresh the access token this many ms before `tokenExpiresAt`. */
const TOKEN_REFRESH_BUFFER_MS = 5 * 60 * 1000;
/**
* Delimiter joining `(type, externalId)` into a single dedup map key. A
* control character keeps it unambiguous against any value a real type or
* externalId could contain, while staying a normal printable-safe constant
* (a literal NUL in the source made text tooling treat the file as binary).
*/
const DEDUP_KEY_DELIM = "\u0000";
/**
* Overlap window for the incremental sync, in ms. Fitbit finalises daily
* summaries after the fact (a daily SpO2 / HRV / RHR can settle hours after the
@@ -396,7 +404,10 @@ export async function upsertFitbitMeasurements(
liveByKey = new Map(
existing
.filter((e) => e.externalId !== null)
.map((e) => [`${e.type}${e.externalId}`, { id: e.id }]),
.map((e) => [
`${e.type}${DEDUP_KEY_DELIM}${e.externalId}`,
{ id: e.id },
]),
);
} catch (err) {
// A probe failure must not strand the whole batch; fall back to treating
@@ -421,7 +432,7 @@ export async function upsertFitbitMeasurements(
const plannedCreateKeys = new Set<string>();
for (const r of readings) {
const type = r.type as MeasurementType;
const key = `${type}${r.externalId}`;
const key = `${type}${DEDUP_KEY_DELIM}${r.externalId}`;
const live = liveByKey.get(key);
if (live) {
toUpdate.push({ id: live.id, r });
@@ -438,7 +449,9 @@ export async function upsertFitbitMeasurements(
} else {
// A duplicate fresh key inside the same batch — overwrite the planned
// create's payload so last-write-wins, matching the prior upsert loop.
const idx = toCreate.findIndex((c) => `${c.type}${c.externalId}` === key);
const idx = toCreate.findIndex(
(c) => `${c.type}${DEDUP_KEY_DELIM}${c.externalId}` === key,
);
if (idx >= 0) {
toCreate[idx] = {
type,
+1 -3
View File
@@ -29,9 +29,7 @@ const capabilityResponse = z
.object({
available: z.boolean(),
mode: z.enum(["vision", "text"]).nullable(),
reason: z
.enum(["no-provider", "text-only-model", "enable-local-ocr"])
.nullable(),
reason: z.enum(["no-provider", "enable-local-ocr"]).nullable(),
pdfSupported: z.boolean(),
})
.meta({
+1 -1
View File
@@ -207,7 +207,7 @@ export interface OcrCapabilityDto {
*/
mode: "vision" | "text" | null;
/** Why scanning is unavailable, when it is. */
reason: "no-provider" | "text-only-model" | "enable-local-ocr" | null;
reason: "no-provider" | "enable-local-ocr" | null;
/** Whether PDF uploads are accepted (Anthropic vision provider only). */
pdfSupported: boolean;
}