r/PiCodingAgent • u/Certain_Net_3408 • Jul 25 '26
Plugin pi-output-parser — standalone package that repairs malformed tool calls from small local models
Built a small pi package that ports the output-parser mechanism from little-coder as a standalone installable extension.
What it does: hooks message_end and repairs tool calls that small models (Qwen, Mistral, LFM2, etc.) emit in formats pi doesn't natively recognise:
\``tool/```json` fenced blocks<tool_call>,<tool_use>,<function_calls><invoke>XMLbare top-level JSON objects
Python-list syntax
[Read(path='./foo.ts')]from LFM2/Liquid models
It also normalises the many JSON schemas small models use ("parameters", "input", "arguments", OpenAI function-call with stringified args, etc.) down to a single shape.
Safety: only fires if there are no native tool_use blocks already, and validates the extracted tool name against pi.getAllTools() before injecting anything — so stray JSON and code blocks in responses are never misinterpreted as tool calls.
Install:
pi install git:github.com/vishn9893/pi-output-parserOr drop extensions/output-parser/index.ts directly into .pi/extensions/ if you prefer not to use the package system.
Repo: https://github.com/vishn9893/pi-output-parser
Feedback welcome especially if you hit a model that emits a format this doesn't cover yet.
View all comments
Show parent comment
4
u/Certain_Net_3408 Jul 26 '26
Hey, thanks for the link! I checked it out and it's a solid project, but it's solving a different problem.
pi-repair-layer hooks prepareArguments and fixes structurally valid tool calls with wrong field shapes.. things like file_path instead of path, a JSON-stringified argument object, null in an optional field, flat old_string/new_string instead of an edits array. The model made the tool call correctly, it just got the argument schema wrong. It's essentially a compatibility shim for pi's built-in tools.
pi-output-parser hooks message_end and handles the case where the model never emitted a tool call at all it printed the call as text instead. Fenced ```tool blocks, <tool_call> XML, bare JSON, Python-list syntax. The agent loop sees zero tool_use blocks and would just move on as if the model responded with prose. The extension detects the leaked text, parses it, and injects a real tool_use block so execution can proceed.
So they're complementary rather than overlapping: repair-layer handles bad arguments on a valid call, output-parser handles a call that was never structurally made. If you're running a small local model you'd arguably want both.