76 lines
2.7 KiB
Markdown
76 lines
2.7 KiB
Markdown
# 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": "<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:
|
|
|
|
```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 <name> {json-args}
|
|
|
|
Example: @tool kom.memory.v1.search_memory {"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":{"items":[{"text":"Embedding model comparison takeaways"}]}}}
|
|
Tool (kom.memory.v1.upsert_memory): { "upserted": 1 }
|
|
Assistant:
|
|
{"final":{"content":{"status":"ok","upserted":1}}}
|