DeltaKitDeltaKit

Tool Calls

The SSE protocol for tool calling.

Tool calling (function calling) follows a specific event sequence in the SSE stream. The server performs the tool execution and streams the events. The client receives and renders them.

Protocol Flow

  1. The server runs a model that decides to call a tool.
  2. It sends a tool_call event over SSE.
  3. The server executes the tool and sends a tool_result event.
  4. Optionally, it continues with text_delta events.
  5. The stream ends with data: [DONE].

Event Sequence

A typical tool call stream:

data: {"type":"tool_call","tool_name":"get_weather","argument":"{\"city\":\"London\"}","call_id":"call_1"}
data: {"type":"tool_result","call_id":"call_1","output":"Sunny, 18°C in London"}
data: {"type":"text_delta","delta":"The weather in London is sunny, 18°C."}
data: [DONE]

Event Types

tool_call

Signals that the model wants to invoke a tool.

interface ToolCallEvent {
  type: "tool_call";
  tool_name: string;    // Name of the tool
  argument: string;     // JSON string of arguments
  call_id?: string;     // Unique ID linking to the result
}

tool_result

Contains the output of the tool execution.

interface ToolResultEvent {
  type: "tool_result";
  call_id: string;      // Matches the tool_call's call_id
  output: string;       // Result string
}

Multiple Tool Calls

A single response can include multiple tool calls. Each gets its own tool_call and tool_result pair, linked by call_id:

data: {"type":"tool_call","tool_name":"search","argument":"...","call_id":"call_1"}
data: {"type":"tool_result","call_id":"call_1","output":"..."}
data: {"type":"tool_call","tool_name":"calculate","argument":"...","call_id":"call_2"}
data: {"type":"tool_result","call_id":"call_2","output":"..."}
data: {"type":"text_delta","delta":"Based on the results..."}
data: [DONE]

The call_id field connects each result to its call. Always include it when using multiple tools.

ToolCallPart Structure

On the client side, tool calls are stored as ToolCallPart in the message's parts array:

interface ToolCallPart {
  type: "tool_call";
  tool_name: string;   // Name of the tool
  argument: string;    // JSON string of arguments
  callId?: string;     // Matches call_id from events
  result?: string;     // Filled by tool_result event
}

Server Example (FastAPI)

from fastapi import FastAPI
from fastapi.responses import StreamingResponse
import json

app = FastAPI()

def get_weather(city: str) -> str:
    return f"Sunny, 18°C in {city}"

@app.post("/api/chat")
async def chat(request: dict):
    message = request["message"]

    async def generate():
        if "weather" in message.lower():
            # 1. Send tool call
            yield f'data: {json.dumps({
                "type": "tool_call",
                "tool_name": "get_weather",
                "argument": json.dumps({"city": "London"}),
                "call_id": "call_1"
            })}\n\n'

            # 2. Execute tool
            result = get_weather("London")

            # 3. Send tool result
            yield f'data: {json.dumps({
                "type": "tool_result",
                "call_id": "call_1",
                "output": result
            })}\n\n'

            # 4. Continue with text
            for word in ["The weather", " in London", f" is {result}."]:
                yield f'data: {json.dumps({
                    "type": "text_delta",
                    "delta": word
                })}\n\n'
        else:
            for word in ["I can", " help with", " weather!"]:
                yield f'data: {json.dumps({
                    "type": "text_delta",
                    "delta": word
                })}\n\n'

        yield "data: [DONE]\n\n"

    return StreamingResponse(generate(), media_type="text/event-stream")

Client-Side Rendering

For handling tool call events and rendering them in React, see Tool Call Rendering.

On this page