Graphometer Droplet

An independent compatibility kit for Liquid LFMs.

The harness can break the model. Droplet checks the fit.

When it doesn't fit, Droplet names the failing layer and applies the smallest proven repair, then gets out of the way.

Not affiliated with, endorsed by, or connected to Liquid AI.

$ pip install ./cli Source on GitHub

01

Same model. Same task. Same seeds.

One LFM2.5-1.2B-Instruct route, served by llama.cpp with the shipped chat template. The left terminal talks to it directly; the right terminal talks to it through droplet bridge. These are real recorded transcripts.

What to expect: the bridged side still ends in suite FAILED. Order is restored, and the strict check still catches the extra call the model makes on its own. That honesty is the point.

Direct: the chain dies

$ droplet doctor --base http://127.0.0.1:8402
[INFO] backend: llama.cpp server, build b1-5f55650
[INFO] model: LFM2.5-1.2B-Instruct-Q4_K_M.gguf
[OK  ] liquid model detected: profile lfm-1.2b
[OK  ] native tool template: template declares LFM tool format
[OK  ] reasoning extraction: non-reasoning model
[FAIL] assistant tool_calls history: template renders past assistant tool calls as an EMPTY turn — measured effect: 1.2B chains collapse at 2 steps; 24B loses steps 5-6
       remedy: route through `droplet bridge` (history_carry), or fix the chat template upstream (add tool_calls rendering)
       evidence: per-run A/B: 1.2B ordered 0/6 -> 6/6 (exact 0/6 -> 0/6); 24B exact 0/3 -> 3/3
[WARN] tool_choice modes: string 'none' works; 'required' cannot force a call (grammar permits unbounded pre-call content; burns max_tokens, finish=length); OBJECT form (named tool) is silently ignored with only a server-side log
       remedy: avoid named tool_choice, or use droplet bridge named_choice filtering; treat 'required' as advisory
       evidence: session-2 wire runs (0/6 required; conflict probe 6/6 wrong tool)
[INFO] raw /completion users: special tokens are stripped by default; pass "special": true or markers never appear
       evidence: session-1, 27/27

verdict: 1 FAIL (assistant tool_calls history), 1 warn — droplet bridge or an upstream template fix is needed on this route
[exit 1]

$ droplet verify --base http://127.0.0.1:8402 --out report_direct
[droplet] verify: wrote report_direct/droplet-report.json and report_direct/droplet-report.md
[droplet]   plain: compat=True ordered=None exact=None grounded=None correct=None failure_layer=None
[droplet]   one_tool: compat=True ordered=True exact=True grounded=True correct=True failure_layer=None
[droplet]   chain4: compat=True ordered=False exact=False grounded=True correct=False failure_layer=template
[droplet] verify: suite FAILED
[exit 1]

Through droplet bridge: order restored, the strict check still catches the model's extra call

$ droplet bridge --listen 127.0.0.1:8420 --target http://127.0.0.1:8402 --log bridge.jsonl &
[droplet] bridge listening on 127.0.0.1:8420 -> http://127.0.0.1:8402 profile=auto interventions=['history_carry', 'named_choice', 'required_guard']
[droplet] target identified: llamacpp b1-5f55650 model=/tmp/graphometer-demo/models/LFM2.5-1.2B-Instruct-Q4_K_M.gguf template_drops_history=True

$ droplet verify --base http://127.0.0.1:8420 --out report_bridged
[droplet] GET /props 200
[droplet] POST /apply-template 200
[droplet] POST /v1/chat/completions 200
[droplet] POST /v1/chat/completions 200
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] POST /v1/chat/completions 200
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] POST /v1/chat/completions 200 applied=history_carry
[droplet] verify: wrote report_bridged/droplet-report.json and report_bridged/droplet-report.md
[droplet]   plain: compat=True ordered=None exact=None grounded=None correct=None failure_layer=None
[droplet]   one_tool: compat=True ordered=True exact=True grounded=True correct=True failure_layer=None
[droplet]   chain4: compat=True ordered=True exact=False grounded=False correct=False failure_layer=model
[droplet] verify: suite FAILED
[exit 1]

$ kill 1274559
[droplet] shutting down (in-flight streams closing)

The only difference between the two sides is whether the model gets to see the record of its own past actions. Direct, the chain dies at step two, and the report blames the template, which is plumbing we can fix. Bridged, every requested call runs in order, and the report blames the model instead, because this small model adds one call nobody asked for. That is the failure_layer line in both terminals, the one that says whose fault it is, flipping from template to model. The strict check still fails, and it should. Droplet gives the model its memory back. It does not make the model obedient, and it says so.

02

Three commands

$ droplet doctor

Read-only diagnosis of a serving route: what is healthy, what is broken, whose fault it is (the plumbing or the model), and the exact remedy. It never installs, mutates, or silently repairs anything.

When something is wrong

$ droplet doctor --base http://127.0.0.1:8402
[FAIL] assistant tool_calls history: template renders past assistant tool calls as an EMPTY turn — measured effect: 1.2B chains collapse at 2 steps; 24B loses steps 5-6
       remedy: route through `droplet bridge` (history_carry), or fix the chat template upstream (add tool_calls rendering)

verdict: 1 FAIL (assistant tool_calls history), 1 warn — droplet bridge or an upstream template fix is needed on this route

When nothing is

$ droplet doctor --base http://127.0.0.1:8402 --live
[OK  ] assistant tool_calls history: template renders past tool calls — multi-step chains safe

verdict: healthy — no intervention needed (1 advisory warn). Direct use is fine; you don't need droplet bridge here.

Both verdicts are first-class results. The 8B's template is correct, so the 8B gets the green one. A tool that tells you when you don't need it is a tool you can trust when it says you do.

$ droplet bridge

A loopback-only pass-through with one history repair, plus two small guards around tool_choice, the setting a client uses to ask for a particular tool. The history repair gives the model back the record of its own past tool calls. Every modification is disclosed on the wire, and everything else relays byte-identical. It never executes tools, never retries, never repairs malformed model output.

$ droplet bridge --listen 127.0.0.1:8420 --target http://127.0.0.1:8402 --log bridge.jsonl &
[droplet] bridge listening on 127.0.0.1:8420 -> http://127.0.0.1:8402 profile=auto interventions=['history_carry', 'named_choice', 'required_guard']
[droplet] POST /v1/chat/completions 200 applied=history_carry

$ droplet verify

A reproducible compatibility suite that writes an honest report. It scores the things that can go wrong one at a time: did the protocol work, did every requested call happen in order, did only the requested calls happen, was the answer grounded, was it correct, and whose fault any miss was. None of that gets squashed into a single ambiguous "pass." The suite only passes when the strict check passes, the one that wants the requested calls and nothing else.

$ droplet verify --base http://127.0.0.1:8420 --out report_bridged
[droplet]   plain: compat=True ordered=None exact=None grounded=None correct=None failure_layer=None
[droplet]   one_tool: compat=True ordered=True exact=True grounded=True correct=True failure_layer=None
[droplet]   chain4: compat=True ordered=True exact=False grounded=False correct=False failure_layer=model
[droplet] verify: suite FAILED

03

The numbers

Every figure below is from recorded runs; nothing is extrapolated. These are small seeded A/B reproductions, so the number of runs behind each cell is the denominator you can see, not a large-n leaderboard. Full per-run ledgers ship in the evidence pack.

Measured on the official Q4_K_M GGUFs at pinned revisions, llama.cpp b1-5f55650, seeded runs. Two scores are always reported. Ordered means every requested call happened, in the requested order, with extra calls tolerated. Exact means the requested calls and nothing else. Per-run ledgers ship with the evidence.
MeasurementDirect (shipped template)Repaired (ordered · exact)
1.2B multi-step tool chains, seeded A/B 0/6 on both scores ordered 6/6 · exact 0/6 through droplet bridge. The model adds one call nobody asked for on every run, and the report says so.
The same repair in a live coding assistant (OpenCode) 0/3 on both scores ordered 3/3 · exact 2/3 through the bridge. One run repeated a calculator call.
24B six-step chains 0/3 on both scores ordered 3/3 · exact 3/3 through the bridge, and ordered 3/3 · exact 3/3 with the template fix alone, no bridge
8B healthy route through the bridge (it needs nothing) not applicable 18/18 task and protocol probes unchanged. Byte-parity is separately proven by hash comparison. No regression, and no need.
Honest limits

Droplet restores the model's memory of its own actions. It does not make the model smarter or more obedient. Final-answer correctness is largely unchanged, and under the strict exact score the repaired 1.2B still adds a call nobody asked for. The report names that as the model's own behavior instead of hiding it.

The 8B is a strong tool-caller and needs nothing here, and Ollama users typically don't need the bridge, because Ollama's own renderer already preserves tool history.

04

Fixed at the root

The permanent fix is a few corrected lines in the chat templates themselves. All three fixes exist, are proven live, and are being submitted upstream.

  • LFM2.5-1.2B-Instruct template renders past assistant tool calls, so the model keeps its memory of its own actions; the model's own extra call can still fail the strict check Fix prepared and reproduced
  • LFM2-24B-A2B template the same history repair, and six-step chains complete ordered 3/3 · exact 3/3 direct, with no bridge Fix prepared and reproduced
  • LFM2.5-1.2B-Thinking template the model's thinking arrives separated in its own reasoning_content field, and the leak is gone Fix prepared and reproduced

With a fixed template in place, the doctor verdict flips to healthy for all three models. On the 24B, the verify suite then passes directly, exact on both scores. On the 1.2B, the chains run in order and the template is no longer at fault (ordered 3/3, exact 0/3 in our runs), but the strict check can still fail because the model adds a call of its own, the same leftover you see through the bridge. If these fixes merge, the bridge's history repair retires, and that is the plan.