"""Recover gemma-4 coder tool_calls WITHOUT litellm (or any framework). Call your llama.cpp / OpenAI-compatible endpoint however you like, then run `recovered_tool_calls()` on the assistant message text. The heavy lifting is in `gemma_tool_parse.py` (pure stdlib) — this file is just the thin OpenAI-shape glue. Run me directly for a demo: python standalone.py """ from __future__ import annotations import json from gemma_tool_parse import clean_content, find_tool_calls def recovered_tool_calls(completion_text: str) -> tuple[list[dict], str | None]: """Turn a raw gemma-4 completion into OpenAI-style tool_calls. Returns (tool_calls, leftover_content). When no call is present, tool_calls is empty and leftover_content is the cleaned text (or None if it was pure markup). """ calls, leftover = find_tool_calls(completion_text) if not calls: return [], (clean_content(completion_text) or None) tool_calls = [ { "id": f"call_{i}", "type": "function", "function": { "name": c["name"], "arguments": json.dumps(c["arguments"], ensure_ascii=False), }, } for i, c in enumerate(calls) ] return tool_calls, (leftover or None) if __name__ == "__main__": # The model leaks its call into `content` as native markup instead of structured # tool_calls; recover it into the shape an OpenAI client expects. demo = 'Sure! <|tool_call>call:get_weather{"city": "Paris", "units": "celsius"}' tcs, content = recovered_tool_calls(demo) print(json.dumps({"tool_calls": tcs, "content": content}, indent=2, ensure_ascii=False))