SOURCE / PINNED RELEASE
Made of little things.
Body Journal
- Release
- e8049f8da4e2…
- Author-recorded commit
- 61c04bf0e8aa…
- License
- LICENSE
- Author’s source reference
- nostr://npub182jczunncwe0jn6frpqwq3e0qjws7yqqnc3auccqv9nte2dnd63scjm4rf/wss%3A%2F%2Fgit.napplet.soy%2F/n-6c4554844c7
Archive hash verified: 4369d778da046a8b…. The source-to-build association is the author’s claim; it has not been independently rebuilt.
import { cvm, storage } from "@napplet/sdk";
import type { CvmServerRef, JsonObject } from "@napplet/sdk";
import { parseReport, REPORT_INSTRUCTIONS, object } from "./ai-contract.js";
import { IMAGE_CHUNK_CHARS, type BodyImage } from "./vision-contract.js";
type Part =
| { type: "text"; text: string }
| { type: "image"; mimeType: string; data: string };
export type Model = {
handle: string;
name: string;
model: string;
route: string;
images: boolean;
json: boolean;
};
export type Llm = {
select(requirements: { json?: boolean; images?: boolean }): Promise<Model>;
describe(handle: string): Promise<Model>;
generate(
request: {
handle: string;
format: "text" | "json";
messages: { role: "system" | "user"; content: Part[] }[];
},
options: { signal: AbortSignal },
): Promise<{ content: unknown[]; finish: string }>;
};
/** Optional experiment adapter: host injects the draft binding; this app never sends wire messages. */
export function llm(): Llm | undefined {
return (window as unknown as { napplet?: { llm?: Llm } }).napplet?.llm;
}
export function validateAnalysis(
raw: unknown,
caseText: string,
photoCount: number,
) {
const report = parseReport(raw, true),
ids = JSON.parse(caseText).concerns.map((c: { id: number }) => c.id);
if (
report.assessments!.length !== ids.length ||
report.assessments!.some((a) => !ids.includes(a.concernId)) ||
new Set(report.assessments!.map((a) => a.concernId)).size !== ids.length
)
throw new Error("The report omitted or invented an observation.");
if (photoCount === 0 && report.evidence!.visual.length)
throw new Error(
"The report contains photo findings although no patient photos were shared.",
);
return report;
}
export async function shellReport(
model: Model,
caseText: string,
images: BodyImage[],
signal: AbortSignal,
) {
const api = llm();
if (!api)
throw new Error(
"This shell does not offer the draft NAP-LLM interface. Use the paid service or another supporting shell.",
);
const content: Part[] = [{ type: "text", text: caseText }];
for (const image of images) {
const match = /^data:(image\/(?:png|jpeg|webp));base64,(.+)$/.exec(
image.dataUrl,
);
if (!match) throw new Error("Invalid prepared image.");
content.push(
{ type: "text", text: `${image.kind || "body-map"}: ${image.caption}` },
{ type: "image", mimeType: match[1], data: match[2] },
);
}
const result = await api.generate(
{
handle: model.handle,
// JSON transport is an optimization, not a requirement for a text report.
// The same strict report validation runs for both provider modes below.
format: model.json ? "json" : "text",
messages: [
{
role: "system",
content: [{ type: "text", text: REPORT_INSTRUCTIONS }],
},
{ role: "user", content },
],
},
{ signal },
);
if (result.finish !== "stop")
throw new Error(
`The model did not finish the report (${result.finish}). No partial assessment was accepted.`,
);
// Thinking is display-only; this consumer does not request or execute tools.
// Accept only completed text blocks as the report, never a partial delta.
if (!Array.isArray(result.content))
throw new Error("The shell returned an unsupported report format.");
let text = "";
for (const raw of result.content) {
const part = object(raw);
if (part.type === "thinking" && typeof part.text === "string") continue;
if (part.type !== "text" || typeof part.text !== "string")
throw new Error("The report contains an unexpected content block. No assessment was accepted.");
text += part.text;
}
signal.throwIfAborted();
return {
report: validateAnalysis(
JSON.parse(text),
caseText,
images.filter((i) => i.kind === "patient-photo").length,
),
model: model.model,
};
}
export type PaidOrder = {
receipt: string;
ref: CvmServerRef;
caseText: string;
imageCount: number;
photoCount: number;
invoice?: string;
amountMsat?: number;
orderId?: string;
status?: string;
model?: string;
expectedMsat?: number;
paymentConfirmation?: "manual" | "automatic";
expiresAt?: number;
paymentProtocol?: "cep8";
paymentReceived?: boolean;
};
export const ORDER_KEY = "body-journal:paid-order:v1";
export async function rememberOrder(order: PaidOrder) {
await storage.setItem(ORDER_KEY, JSON.stringify(order));
}
const wait = (signal: AbortSignal) =>
new Promise<void>((resolve, reject) => {
const stop = () => {
clearTimeout(timer);
reject(
new Error("Stopped waiting. Your paid order remains recoverable."),
);
};
const timer = setTimeout(() => {
signal.removeEventListener("abort", stop);
resolve();
}, 2500);
signal.addEventListener("abort", stop, { once: true });
if (signal.aborted) stop();
});
export class PaidClient {
async call(
ref: CvmServerRef,
tool: string,
args: Record<string, unknown>,
timeoutMs = 20000,
payment: "deny" | "prompt" = "deny",
) {
const response = await cvm.callTool(ref, tool, args as JsonObject, {
timeoutMs,
initialize: true,
payment,
});
if (response.isError)
throw new Error(
"The CVM tool failed. No native payment gate was authorized.",
);
const body = object(
response.structuredContent ??
JSON.parse(
response.content?.find((c) => c.type === "text")?.text ?? "{}",
),
);
if (body.ok !== true)
throw new Error(
typeof body.message === "string"
? body.message
: "The paid service could not complete this operation.",
);
return body;
}
private validate(order: PaidOrder, state: Record<string, unknown>) {
if (
!Number.isSafeInteger(state.amountMsat) ||
state.amountMsat !== order.expectedMsat ||
typeof state.orderId !== "string" ||
!/^[a-f0-9]{64}$/.test(state.orderId) ||
(order.orderId !== undefined && state.orderId !== order.orderId) ||
![
"prepared",
"creating",
"awaiting-payment",
"generating",
"complete",
"attention",
].includes(String(state.status))
)
throw new Error(
"The service returned an unexpected order or amount. Keep your receipt; do not pay.",
);
if (
state.status === "awaiting-payment" &&
state.paymentProtocol !== "cep8" &&
(typeof state.invoice !== "string" ||
!/^lnbc/i.test(state.invoice) ||
state.invoice.length > 12000)
)
throw new Error("Invalid report invoice.");
}
private async saveState(order: PaidOrder, state: Record<string, unknown>) {
this.validate(order, state);
Object.assign(order, {
invoice: state.invoice,
amountMsat: state.amountMsat,
orderId: state.orderId,
status: state.status,
paymentConfirmation:
state.paymentConfirmation === "manual" ? "manual" : "automatic",
paymentProtocol: state.paymentProtocol === "cep8" ? "cep8" : undefined,
paymentReceived: state.paymentReceived === true,
expiresAt:
typeof state.expiresAt === "number" ? state.expiresAt : undefined,
});
await rememberOrder(order);
}
async confirm(order: PaidOrder) {
// Only the explicit checkout action calls this. Status/recovery stay passive.
const state = await this.call(
order.ref,
"body_journal_paid_confirm",
{ receipt: order.receipt },
45000,
);
await this.saveState(order, state);
return state;
}
info(ref: CvmServerRef) {
return this.call(ref, "body_journal_paid_info", {});
}
async prepare(order: PaidOrder, images: BodyImage[], signal: AbortSignal) {
order.status = "staging";
await rememberOrder(order); // no invoice exists until a durable receipt is retained
const refs = [];
for (const image of images) {
const sha256 = Array.from(
new Uint8Array(
await crypto.subtle.digest(
"SHA-256",
new TextEncoder().encode(image.dataUrl),
),
),
(b) => b.toString(16).padStart(2, "0"),
).join("");
const id = "image-" + crypto.randomUUID(),
total = Math.ceil(image.dataUrl.length / IMAGE_CHUNK_CHARS);
for (let index = 0; index < total; index++) {
signal.throwIfAborted();
await this.call(order.ref, "body_journal_paid_image", {
id,
sha256,
index,
total,
chunk: image.dataUrl.slice(
index * IMAGE_CHUNK_CHARS,
(index + 1) * IMAGE_CHUNK_CHARS,
),
});
}
refs.push({
id,
sha256,
concernId: image.concernId,
kind: image.kind || "body-map",
caption: image.caption.slice(0, 1200),
...(image.attachmentId ? { attachmentId: image.attachmentId } : {}),
});
}
signal.throwIfAborted();
order.status = "creating";
await rememberOrder(order);
const result = await this.call(order.ref, "body_journal_paid_prepare", {
receipt: order.receipt,
caseText: order.caseText,
images: refs,
});
await this.saveState(order, result);
return result;
}
close(order: PaidOrder) {
return cvm.close(order.ref);
}
async run(order: PaidOrder) {
const state = await this.call(
order.ref,
"body_journal_paid_run",
{ receipt: order.receipt },
300000,
"prompt",
);
await this.saveState(order, state);
return state;
}
async status(order: PaidOrder) {
const state = await this.call(order.ref, "body_journal_paid_status", {
receipt: order.receipt,
});
await this.saveState(order, state);
return state;
}
async poll(
order: PaidOrder,
signal: AbortSignal,
update: (state: Record<string, unknown>) => void,
) {
for (;;) {
signal.throwIfAborted();
const state = await this.call(order.ref, "body_journal_paid_status", {
receipt: order.receipt,
});
signal.throwIfAborted();
await this.saveState(order, state);
update(state);
if (state.status === "complete") return object(state.result);
if (
state.paymentProtocol === "cep8" &&
["prepared", "awaiting-payment"].includes(String(state.status))
)
return null;
if (state.status === "attention" || state.status === "creating")
throw new Error(
String(
state.message ||
"This order needs operator attention. Keep its recovery receipt; do not pay again.",
),
);
await wait(signal);
}
}
}
