Calling functions from GPT
GPT Functions
Using GPT functions with DSL can give you a powerfull conversation model.
When you writing any function with JavaDoc like
context { output customerName: string? = null; output customerPhone: string? = null; } /** * Store collected customer information such as name and phone number * @param customerName customer name provided * @param customerPhone customer phone provided * @return true */ function storeCustomerInfo(customerName: string?, customerPhone: string?): boolean { set $this.customerName = $this.customerName ?? customerName; set $this.customerPhone = $this.customerPhone ?? customerPhone; return true; }
Our Dialog Engine passes information about a function storeCustomerInfo
and it's description to the OpenAI inside a request.
And this function will be called when user provides any information described in arguments.
Result of function call will be passed to GPT on next call of #answerWithGPT
/** * Get price of fruit in USD * @param fruit name of fruit * @returns price in USD or `No such fruit` if fruit is not found */ function getFruitPrice(fruit: string) : number|string { if (fruit == "apples") { return 6.29; } if (fruit == "oranges") { return 1.49; } return "No such fruit"; }
Examples
Full DSL example
context { input endpoint: string; } /** * Get price of fruit in USD * @param fruit name of fruit * @returns price in USD or `No such fruit` if fruit is not found */ function getFruitPrice(fruit: string) : number|string { if (fruit == "apples") { return 6.29; } if (fruit == "oranges") { return 1.49; } return "No such fruit"; } start node root { do { #connectSafe($endpoint); #sayText("Hi, this is Mary! How can I help you today?"); wait *; } transitions { gpt: goto gpt on true; } } node gpt { do { // We will be here when user says something, or retry is required var a = #answerWithGPT(`Your name is Mary. You are working in fruit seller contact center. You can only tell customer a price of requested fruit. If you have no price for fruit tell: We have no such fruit `, interruptible:true, gptOptions: { model:"openai/gpt-4" }, sayOptions: { interruptDelay: 1.0 }); // Call answerWithGPT one more time for passing result to the GPT if (a.functionCalled) { #log("Called a function, retry"); goto retry; } wait *; } transitions { gpt: goto gpt on true; retry: goto gpt; } } digression @exit { conditions { on true tags: onclosed; } do { exit; } }
Forcing a function call
You can use an gptOption
named function_call
with name of the function for forcing a function call.
Restricting functions passed to the GPT
You can use an gptOption
named provided_functions
with string array as value with functions, that a visible to the GPT.
For example:
{ model: "openai/gpt-4o-mini", provided_functions: ["functionA", "functionB"] }
It can help you, when you want to disable part of functionality for the conversation at a runtime.
GPT is saying a function name instead of calling it.
You can use an gptOption
named allow_function_name_in_response
with false
value.
In this case, our platform will handle it, block the sentence and enforce GPT to call this function.
GPT is saying in json
format instead of pronouncable sayText
You can us an gptOption
named ignore_json_output
with false
value.
Our platform will handle such output and drop it before response to the human.
Providing functions from the SDK (SDK 0.11.2 and higher)
You can dynamically register functions through the JavaScript SDK that will be available for GPT to call during conversations. This approach provides more flexibility than defining functions in DSL and allows you to leverage external services or databases in your function implementations.
import { Type } from "@sinclair/typebox"; app.queue.on("ready", async (id, conv, info) => { // Register a dynamic tool that GPT can call during the conversation await conv.setDynamicTool({ // Function name that GPT will use to call this tool name: "getFruitPrice", // Clear description of what the function does - this helps GPT understand when to use it description: 'Returns the price of a fruit based on its name and optional quantity', // Schema definition using TypeBox to define parameters and their types schema: Type.Object({ name: Type.String({ description: "Name of the fruit"}), count: Type.Optional(Type.Number({ description: "Count of the fruits, defaults to 1 if not provided"})) }) }, async (args, conv) => { // Implementation of the function - this code runs when GPT calls getFruitPrice console.log(`getFruitPrice called with args: ${JSON.stringify(args)}`); if (args.name === "apple") { return 3.25 * (args.count ?? 1); } if (args.name === "orange") { return 6 * (args.count ?? 1); } return "No such fruit"; }); const result = await conv.execute(); }
This approach gives you several advantages:
- Functions can be created dynamically based on conversation context
- Implementation can connect to external systems, databases, or APIs
- TypeBox provides strong typing and validation for function parameters
- Return values are automatically passed back to GPT for continuation of the conversation
You can use an gptOption
named use_dynamic_tools
to disable dynamic functions passed from the SDK for a specific call:
{ use_dynamic_tools: false }