# Tool Calling Without Native Support (Happy-Code Compatibility) When models lack built-in tool/function calling, we can still get reliable tool use via a **protocol-in-prompt** approach plus a thin runtime. ## 1) JSON Tool Protocol (deterministic) Model must respond with a single JSON object, no prose. ```json { "thought": "", "action": { "tool": "", "args": { } } } ``` - If more steps are needed, the runtime feeds the tool's JSON result back as the next user message with role=tool. - The model must then either emit another action or finish with: ```json { "final": { "content": { } } } ``` ### Guardrails - Reject any output that isn't valid JSON or that contains extra text. - Cap thought to ~200 chars. - Disallow calling tools not in the registry. ## 2) Command DSL (fallback) If JSON parsing is brittle, accept a single line command and parse it: @tool {json-args} Example: @tool kom.memory.v1.search_memory {"namespace":"project:metal", "query":{"text":"embedding model"}} ## 3) Prompt Template (drop-in) Use this system message for happy-code/claude-code sessions: You are a coding assistant that can call tools via a JSON protocol. Available tools (names & schema will be provided). Always reply with a single JSON object. No markdown. No commentary. Use this schema: { "thought": string (short), "action": { "tool": string, "args": object } } OR { "final": { "content": any } }. If a tool result is needed, emit action. If done, emit final. Never invent tool names or fields. ## 4) Minimal Runtime (pseudocode) while True: msg = llm(messages) data = json.loads(msg) if 'action' in data: tool = registry[data['action']['tool']] result = tool(**data['action']['args']) messages.append({"role":"tool","name":tool.name,"content":json.dumps(result)}) continue elif 'final' in data: return data['final']['content'] else: error("Invalid protocol") ## 5) MCP Integration - Map registry to MCP tools (e.g., kom.memory.v1.*). - Provide each tool's JSON Schema to the model in the system message (strict). ## 6) Testing Checklist - Invalid JSON → reject → ask to resend. - Unknown tool → reject. - Args mismatch → show schema snippet, ask to correct. - Multi-step flows → verify tool result is consumed in next turn. ## 7) Example Session System: (template above + list of tools & schemas) User: Save this note: "Embedding model comparison takeaways" into project:metal Assistant: {"thought":"need to upsert note","action":{"tool":"kom.memory.v1.upsert_memory","args":{"namespace":"project:metal","items":[{"text":"Embedding model comparison takeaways"}]}}} Tool (kom.memory.v1.upsert_memory): { "upserted": 1 } Assistant: {"final":{"content":{"status":"ok","upserted":1}}}