2.7 KiB
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.
{
"thought": "<very short planning note>",
"action": {
"tool": "<tool_name>",
"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:
{
"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}}}