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.

Excluding specific functions

You can use an gptOption named except_functions to explicitly exclude specific functions from being available to GPT, regardless of other inclusion rules.

{ model: "openai/gpt-4o-mini", except_functions: ["deleteCustomer", "resetDatabase"] }

How except_functions works

The except_functions option has the highest priority and will exclude functions even if they would normally be included by:

  • provided_functions
  • provided_scopes
  • Default availability (functions without scopes)

Use cases for except_functions

  1. Security: Exclude dangerous functions in certain conversation contexts

    { provided_scopes: ["admin"], except_functions: ["deleteAllData"] // Admin scope but exclude dangerous operations }
  2. Feature toggling: Temporarily disable specific functionality

    { except_functions: ["experimentalFeature"] // Disable while testing }
  3. Context-specific restrictions: Remove functions not relevant to current conversation flow

    { provided_scopes: ["customer", "support"], except_functions: ["billingOperations"] // Customer support without billing access }

Order of evaluation

The system applies function filtering in this order:

  1. Start with all available functions
  2. Apply provided_scopes filtering (if specified)
  3. Apply provided_functions filtering (if specified)
  4. Remove functions listed in except_functions (final step)

This means except_functions always wins - if a function is listed there, it will be excluded regardless of other options.

Controlling function access with scopes

You can organize your functions into logical groups using scopes and then control which functions are available to GPT by specifying allowed scopes. This provides a more flexible way to manage function access compared to listing individual functions.

Defining function scopes in DSL

To assign scopes to a function, use multiple @scope tags in the function's JavaDoc comment:

Important syntax restrictions:

  • Scope names can only contain alphabetic characters (a-z, A-Z)
  • No numbers, underscores, hyphens, or special characters are allowed
  • Use separate @scope tags for each scope (not brackets or commas)
  • Each @scope tag should contain only one scope name
/** * Store collected customer information such as name and phone number * @scope customer * @scope management * @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; } /** * Get price of fruit in USD * @scope inventory * @scope pricing * @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"; } /** * Function without scopes - available when scopes are specified (non-empty) or in legacy mode * @param text message to log * @return true */ function logMessage(text: string): boolean { #log(text); return true; }

Using provided_scopes option

You can control which functions are available to GPT by specifying allowed scopes using the provided_scopes option:

var response = #answerWithGPT("Your prompt here", gptOptions: { model: "openai/gpt-4o-mini", provided_scopes: ["customer", "inventory"] });

How scope-based filtering works

The system applies the following logic when determining which functions are available:

  1. No scopes specified (legacy behavior): All functions are available, unless provided_functions is specified
  2. Empty scopes array []: Completely restrictive mode - NO functions are available, not even common/utility functions. Only functions explicitly listed in provided_functions are allowed
  3. Non-empty scopes array: Functions are available if:
    • The function has no scopes defined (common/utility functions) - these are always included when scopes are specified
    • The function has scopes and at least one scope matches the provided scopes
    • The function is explicitly listed in provided_functions (overrides scope restrictions)

Combining scopes with other options

You can combine provided_scopes with other function control options:

{ model: "openai/gpt-4o-mini", provided_scopes: ["customer"], provided_functions: ["logMessage"], // Always include this function except_functions: ["deleteCustomer"] // Always exclude this function }

Dynamic scopes from SDK

When using dynamic tools from the SDK (version 0.11.5 and higher), you can also specify scopes:

await conv.setDynamicTool({ name: "getUserInfo", description: 'Get user information from database', scopes: ["user", "database"], // Specify scopes for this tool schema: Type.Object({ userId: Type.String({ description: "User ID to lookup"}) }) }, async (args, conv) => { // Implementation return await getUserFromDatabase(args.userId); });

Then control access using the same provided_scopes option:

{ provided_scopes: ["user"] // This will include the getUserInfo dynamic tool }

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 }
Found a mistake? Let us know.

Enroll in beta

Request invite to our private Beta program for developers to join the waitlist. No spam, we promise.