Skip to main content
The Edgee TypeScript SDK supports OpenAI-compatible function calling (tools), allowing models to request execution of functions you define. This enables models to interact with external APIs, databases, and your application logic.

Overview

Function calling works in two steps:
  1. Request: Send a request with tool definitions. The model may request to call one or more tools.
  2. Execute & Respond: Execute the requested functions and send the results back to the model.

Tool Definition

A tool is defined using the Tool interface:
interface Tool {
  type: "function";
  function: FunctionDefinition;
}

FunctionDefinition

PropertyTypeDescription
name stringThe name of the function (must be unique, a-z, A-Z, 0-9, _, -)
descriptionstringDescription of what the function does. Highly recommended - helps the model understand when to use it
parametersRecord<string, unknown>JSON Schema object describing the function parameters

Parameters Schema

The parameters field uses JSON Schema format:
{
  type: "object",
  properties: {
    paramName: {
      type: "string" | "number" | "boolean" | "object" | "array",
      description: "Parameter description"
    }
  },
  required: ["paramName"]  // Array of required parameter names
}
Example - Defining a Tool:
const response = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [
      { role: 'user', content: 'What is the weather in Paris?' }
    ],
    tools: [
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather for a location',
          parameters: {
            type: 'object',
            properties: {
              location: {
                type: 'string',
                description: 'The city and state, e.g. San Francisco, CA'
              },
              unit: {
                type: 'string',
                enum: ['celsius', 'fahrenheit'],
                description: 'Temperature unit'
              }
            },
            required: ['location']
          }
        }
      }
    ],
    tool_choice: 'auto'
  }
});

Tool Choice

The tool_choice parameter controls when and which tools the model should call:
ValueTypeDescription
"auto"stringLet the model decide whether to call tools (default)
"none"stringDon’t call any tools, even if provided
{ type: "function", function: { name: "function_name" } }objectForce the model to call a specific function

ToolChoice Type

type ToolChoice =
  | "none"
  | "auto"
  | { type: "function"; function: { name: string } };
Example - Force a Specific Tool:
const response = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [
      { role: 'user', content: 'What is the weather?' }
    ],
    tools: [
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather',
          parameters: { /* ... */ }
        }
      }
    ],
    tool_choice: {
      type: 'function',
      function: { name: 'get_weather' }
    }
  }
});
// Model will always call get_weather
Example - Disable Tool Calls:
const response = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [
      { role: 'user', content: 'What is the weather?' }
    ],
    tools: [
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather',
          parameters: { /* ... */ }
        }
      }
    ],
    tool_choice: 'none'
  }
});
// Model will not call tools, even though they're available

Tool Call Object Structure

When the model requests a tool call, you receive a ToolCall object:
PropertyTypeDescription
idstringUnique identifier for this tool call
typestringType of tool call (typically "function")
functionobjectFunction call details
function.namestringName of the function to call
function.argumentsstringJSON string containing the function arguments

Parsing Arguments

const toolCall = response.toolCalls[0];
const args = JSON.parse(toolCall.function.arguments);
// args is now a JavaScript object
console.log(args.location);  // e.g., "Paris"

Complete Example

Here’s a complete end-to-end example with error handling:
import Edgee from 'edgee';

const edgee = new Edgee('your-api-key');

// Define the weather function
async function getWeather(location: string, unit: string = 'celsius') {
  // Simulate API call
  return {
    location,
    temperature: 15,
    unit,
    condition: 'sunny'
  };
}

// Step 1: Initial request with tools
const response1 = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [
      { role: 'user', content: 'What is the weather in Paris and Tokyo?' }
    ],
    tools: [
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather for a location',
          parameters: {
            type: 'object',
            properties: {
              location: {
                type: 'string',
                description: 'The city name'
              },
              unit: {
                type: 'string',
                enum: ['celsius', 'fahrenheit'],
                description: 'Temperature unit'
              }
            },
            required: ['location']
          }
        }
      }
    ],
    tool_choice: 'auto'
  }
});

// Step 2: Execute all tool calls
const messages = [
  { role: 'user', content: 'What is the weather in Paris and Tokyo?' },
  response1.message! // Include assistant's message
];

if (response1.toolCalls) {
  for (const toolCall of response1.toolCalls) {
    const args = JSON.parse(toolCall.function.arguments);
    const result = await getWeather(args.location, args.unit);
    
    messages.push({
      role: 'tool',
      tool_call_id: toolCall.id,
      content: JSON.stringify(result)
    });
  }
}

// Step 3: Send results back
const response2 = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages,
    tools: [
      // Keep tools available for follow-up
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather for a location',
          parameters: {
            type: 'object',
            properties: {
              location: { type: 'string', description: 'The city name' },
              unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }
            },
            required: ['location']
          }
        }
      }
    ]
  }
});

console.log(response2.text);
Example - Multiple Tools: You can provide multiple tools and let the model choose which ones to call: You can provide multiple tools and let the model choose:
const response = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [
      { role: 'user', content: 'Get the weather in Paris and send an email about it' }
    ],
    tools: [
      {
        type: 'function',
        function: {
          name: 'get_weather',
          description: 'Get the current weather for a location',
          parameters: {
            type: 'object',
            properties: {
              location: { type: 'string', description: 'City name' }
            },
            required: ['location']
          }
        }
      },
      {
        type: 'function',
        function: {
          name: 'send_email',
          description: 'Send an email to a recipient',
          parameters: {
            type: 'object',
            properties: {
              to: { type: 'string', description: 'Recipient email address' },
              subject: { type: 'string', description: 'Email subject' },
              body: { type: 'string', description: 'Email body' }
            },
            required: ['to', 'subject', 'body']
          }
        }
      }
    ],
    tool_choice: 'auto'
  }
});

Streaming with Tools

The stream() method also supports tools. For details about streaming, see the Stream Method documentation.
for await (const chunk of edgee.stream('gpt-4o', {
  messages: [
    { role: 'user', content: 'What is the weather in Paris?' }
  ],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_weather',
        description: 'Get the current weather for a location',
        parameters: {
          type: 'object',
          properties: {
            location: { type: 'string', description: 'City name' }
          },
          required: ['location']
        }
      }
    }
  ],
  tool_choice: 'auto'
})) {
  if (chunk.text) {
    process.stdout.write(chunk.text);
  }
  
  // Check for tool calls in the delta
  const toolCalls = chunk.choices[0]?.delta?.tool_calls;
  if (toolCalls) {
    console.log('\nTool calls detected:', toolCalls);
  }
  
  if (chunk.finishReason === 'tool_calls') {
    console.log('\nModel requested tool calls');
  }
}

Best Practices

1. Always Provide Descriptions

Descriptions help the model understand when to use each function:
// ✅ Good
{
  name: 'get_weather',
  description: 'Get the current weather conditions for a specific location',
  parameters: { /* ... */ }
}

// ❌ Bad
{
  name: 'get_weather',
  // Missing description
  parameters: { /* ... */ }
}

2. Use Clear Parameter Names

// ✅ Good
properties: {
  location: { type: 'string', description: 'The city name' }
}

// ❌ Bad
properties: {
  loc: { type: 'string' }  // Unclear name, no description
}

3. Mark Required Parameters

parameters: {
  type: 'object',
  properties: {
    location: { type: 'string', description: 'City name' },
    unit: { type: 'string', description: 'Temperature unit' }
  },
  required: ['location']  // location is required, unit is optional
}

4. Handle Multiple Tool Calls

Models can request multiple tool calls in a single response. Use Promise.all() to execute them in parallel:
if (response.toolCalls && response.toolCalls.length > 0) {
  const results = await Promise.all(
    response.toolCalls.map(async (toolCall) => {
      const args = JSON.parse(toolCall.function.arguments);
      const result = await executeFunction(toolCall.function.name, args);
      return {
        tool_call_id: toolCall.id,
        result
      };
    })
  );
  
  // Add all tool results to messages
  const toolMessages = results.map(({ tool_call_id, result }) => ({
    role: 'tool' as const,
    tool_call_id,
    content: JSON.stringify(result)
  }));
  
  messages.push(...toolMessages);
}

5. Error Handling in Tool Execution

if (response.toolCalls) {
  for (const toolCall of response.toolCalls) {
    try {
      const args = JSON.parse(toolCall.function.arguments);
      const result = await executeFunction(toolCall.function.name, args);
      
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify(result)
      });
    } catch (error) {
      // Send error back to model
      messages.push({
        role: 'tool',
        tool_call_id: toolCall.id,
        content: JSON.stringify({ error: error.message })
      });
    }
  }
}

6. Keep Tools Available

Include tools in follow-up requests so the model can call them again if needed:
const response2 = await edgee.send({
  model: 'gpt-4o',
  input: {
    messages: [...messagesWithToolResults],
    tools: [
      // Keep the same tools available
      { type: 'function', function: { /* ... */ } }
    ]
  }
});