Skip to main content

Breaking Changes

[2.14.x]

Tracker API

Changed DTMF behavior in tracker_api.enable_dtmf()

enable_dtmf() now enables DTMF (touch-tone) input for exactly one turn only. After user input is received, DTMF mode is automatically disabled.

This is a breaking change for phone flows or custom scripts that previously relied on DTMF staying active across multiple turns.

Migration guidance:

  • Re-enable DTMF before each turn where keypad input is expected.
  • Do not rely on speech + DTMF in the same input turn: while DTMF mode is active, speech recognition is disabled and users must use keypad input only.

[2.11.x]

Tracker API

Removed together as subdependency together was removed as a subdependency - custom form agents that were created in earlier versions have to be updated.

You have to remove all together type imports and references

import json
from copy import deepcopy
from typing import Any, Optional
from uuid import uuid4

from botario_gpt_events.api_config.types import TogetherAIChatCompletionResponse # remove this
from loguru import logger
from openai.types.chat import (
ChatCompletion,
ChatCompletionMessageToolCall,
ChatCompletionToolChoiceOptionParam,
)
from shared.agents.agent_definitions import LocalAgentDefinition
from shared.agents.agents import (
ExtractionFieldDefinition,
RemoteExtractionAgent,
generate_dynamic_model,
)
from shared.conversation import ToolTurn
from shared.remote_llm_api.responses import ChatApiResponse
from shared.tracker.api import RemoteLLMTrackerApi
from shared.utils.templating import PromptTemplate
from together.types.chat_completions import ToolCalls # remove this


class ExtractionAgent(RemoteExtractionAgent):
"""
Remote Extraction Agent Template Class. This class is used to define a Remote Extraction Agent that can be used to extract data from a user input.
"""

def __init__(self, agent_definition: LocalAgentDefinition):
...

def _get_messages(
self, tracker_api: RemoteLLMTrackerApi, system_message: str
) -> list[dict[str, Any]]:
...

def format_tool_call_result(
self, error_slots: dict[str, Any], process_name: str
) -> dict[str, Any]:
...

async def get_tool_call_from_llm(
self,
tracker_api: RemoteLLMTrackerApi,
messages: list,
tools: list[dict],
tool_choice: ChatCompletionToolChoiceOptionParam = "auto",
) -> tuple[
Optional[dict],
Optional[ChatCompletionMessageToolCall | ToolCalls], # remove ToolCalls here
ChatApiResponse,
]:
"""Helper Method to call the LLM API with the given messages and tools and extract the tool call from the response.

Args:
tracker_api (RemoteAgentTrackerApi): The current RemoteAgentTrackerApi
messages (list): The list of messages that should be sent to the LLM API has to conform the OpenAI API
tools (list[dict]): The list of tools that should be used in the LLM API has to conform the OpenAI API
tool_choice (ChatCompletionToolChoiceOptionParam, optional): "none" or "auto" has to conform the OpenAI API. Defaults to "auto".

Returns:
tuple[Optional[dict], Optional[ChatCompletionMessageToolCall], ChatApiResponse]: _description_
"""
chat_api_response = await tracker_api.a_call_llm_w_tools(
messages=messages,
tools=tools,
tool_choice=tool_choice,
)
tool_calls = (
chat_api_response.completion.choices[0].message.tool_calls
if chat_api_response.completion.choices is not None and chat_api_response.completion.choices[0].message is not None
else []
)
fn_args = None
if tool_calls:
tool: ChatCompletionMessageToolCall | ToolCalls = tool_calls[0] # remove ToolCalls here
if tool.function is not None:
logger.debug(tool.function.arguments)
argument_str = tool.function.arguments
if argument_str is not None:
fn_args = json.loads(argument_str)
else:
fn_args = {}
return fn_args, tool, chat_api_response
return None, None, chat_api_response

async def on_failed_extraction(
self,
tracker_api: RemoteLLMTrackerApi,
messages: list[dict],
completion: ChatCompletion | TogetherAIChatCompletionResponse, # remove TogetherAIChatCompletionResponse here
process_name: str,
tool: ChatCompletionMessageToolCall | ToolCalls, # remove ToolCalls here
tools: list[dict],
function_call_result: dict,
) -> None:
...

def get_tools(
self,
tracker_api: RemoteLLMTrackerApi,
process_name: str,
process_description: str,
extraction_fields: list[ExtractionFieldDefinition],
) -> list[dict]:
...

async def run_extractors(
self,
tracker_api: RemoteLLMTrackerApi,
process_name: str,
process_description: str,
extraction_fields: list[ExtractionFieldDefinition],
additional_input_vars: dict[str, Any] | None = None,
) -> bool:
...