mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-11 22:02:16 +00:00
The Anthropic client steered JSON replies by appending an assistant turn containing an opening brace and gluing the brace back onto the reply. Current Claude models (the 4.6 / 4.7 / 4.8 family, Opus 5, Sonnet 5, Fable 5 and 5.1) reject an assistant prefill with HTTP 400, so every JSON surface on the provider (briefing, status cards, document and lab extraction) failed for a self-hoster on a current model while plain chat kept working. Drop the prefill on every model. The request now carries a plain instruction on the last user turn to reply with a single JSON object and nothing else, and the reply is narrowed to the outermost object body via a shared extractJsonObject helper, so a fenced or prefixed answer still parses. The insights stripJsonFences helper delegates to the same function rather than keeping a second copy. The tool-use path is unchanged. Reported independently by @sweidinger.
36 lines
1.1 KiB
TypeScript
36 lines
1.1 KiB
TypeScript
import { describe, expect, it } from "vitest";
|
|
import { extractJsonObject } from "../json-extract";
|
|
|
|
describe("extractJsonObject", () => {
|
|
it("returns a plain object untouched", () => {
|
|
expect(extractJsonObject('{"summary":"ok"}')).toBe('{"summary":"ok"}');
|
|
});
|
|
|
|
it("unwraps a ```json fence", () => {
|
|
expect(extractJsonObject('```json\n{"summary":"ok"}\n```')).toBe(
|
|
'{"summary":"ok"}',
|
|
);
|
|
});
|
|
|
|
it("unwraps a bare ``` fence", () => {
|
|
expect(extractJsonObject('```\n{"summary":"ok"}\n```')).toBe(
|
|
'{"summary":"ok"}',
|
|
);
|
|
});
|
|
|
|
it("trims a leading sentence and a trailing remark around the object", () => {
|
|
expect(
|
|
extractJsonObject('Here is the result:\n{"summary":"ok"}\nDone.'),
|
|
).toBe('{"summary":"ok"}');
|
|
});
|
|
|
|
it("keeps nested braces inside the outermost span", () => {
|
|
const nested = '{"a":{"b":[{"c":1}]},"d":"}"}';
|
|
expect(extractJsonObject(`Sure!\n${nested}`)).toBe(nested);
|
|
});
|
|
|
|
it("returns the trimmed input when there is no object body", () => {
|
|
expect(extractJsonObject(" plain prose ")).toBe("plain prose");
|
|
});
|
|
});
|