Tool loop

model = models[0]
orders = {
    "O1": dict(id="O1", product="Widget A", quantity=2, price=19.99, status="Shipped"),
    "O2": dict(id="O2", product="Gadget B", quantity=1, price=49.99, status="Processing"),
    "O3": dict(id="O3", product="Gadget B", quantity=2, price=49.99, status="Shipped")}

customers = {
    "C1": dict(name="John Doe", email="john@example.com", phone="123-456-7890",
               orders=[orders['O1'], orders['O2']]),
    "C2": dict(name="Jane Smith", email="jane@example.com", phone="987-654-3210",
               orders=[orders['O3']])
}
def get_customer_info(
    customer_id:str # ID of the customer
): # Customer's name, email, phone number, and list of orders
    "Retrieves a customer's information and their orders based on the customer ID"
    print(f'- Retrieving customer {customer_id}')
    return customers.get(customer_id, "Customer not found")

def get_order_details(
    order_id:str # ID of the order
): # Order's ID, product name, quantity, price, and order status
    "Retrieves the details of a specific order based on the order ID"
    print(f'- Retrieving order {order_id}')
    return orders.get(order_id, "Order not found")

def cancel_order(
    order_id:str # ID of the order to cancel
)->bool: # True if the cancellation is successful
    "Cancels an order based on the provided order ID"
    print(f'- Cancelling order {order_id}')
    if order_id not in orders: return False
    orders[order_id]['status'] = 'Cancelled'
    return True
tools = [get_customer_info, get_order_details, cancel_order]
chat = Chat(model, tools=tools)
r = chat('Can you tell me the email address for customer C2?')
- Retrieving customer C2
choice = r.choices[0]
print(choice.finish_reason)
choice
tool_calls
ChatCompletionChoice(index=0, message=AssistantMessage(content='', tool_calls=[ToolCall(function=FunctionCall(name='get_customer_info', arguments='{"customer_id": "C2"}'), id='5x9gdVe3v', type=None, index=0)], prefix=False, role='assistant'), finish_reason='tool_calls')
r = chat()
r

The email address for customer C2 is jane@example.com.

  • id: 3d09df23ad184c85a3206b78b0e70faf
  • object: chat.completion
  • model: codestral-2501
  • usage: prompt_tokens=376 completion_tokens=14 total_tokens=390
  • created: 1743590196
  • choices: [ChatCompletionChoice(index=0, message=AssistantMessage(content=‘The email address for customer C2 is jane@example.com.’, tool_calls=None, prefix=False, role=‘assistant’), finish_reason=‘stop’)]
chat = Chat(model, tools=tools)
r = chat('Please cancel all orders for customer C1 for me.')
print(r.choices[0].finish_reason)
find_block(r)
- Retrieving customer C1
tool_calls
AssistantMessage(content='', tool_calls=[ToolCall(function=FunctionCall(name='get_customer_info', arguments='{"customer_id": "C1"}'), id='hjIMAgj4g', type=None, index=0)], prefix=False, role='assistant')

source

Chat.toolloop

 Chat.toolloop (pr, max_steps=10, trace_func:Optional[<built-
                infunctioncallable>]=None, cont_func:Optional[<built-
                infunctioncallable>]=<function noop>,
                temperature:OptionalNullable[float]=Unset(),
                top_p:Optional[float]=None,
                max_tokens:OptionalNullable[int]=Unset(),
                stream:Optional[bool]=False,
                stop:Union[Stop,StopTypedDict,NoneType]=None,
                random_seed:OptionalNullable[int]=Unset(), response_format
                :Union[mistralai.models.responseformat.ResponseFormat,mist
                ralai.models.responseformat.ResponseFormatTypedDict,NoneTy
                pe]=None, tools:OptionalNullable[typing.Union[typing.List[
                mistralai.models.tool.Tool],typing.List[mistralai.models.t
                ool.ToolTypedDict]]]=Unset(), tool_choice:Union[ChatComple
                tionRequestToolChoice,ChatCompletionRequestToolChoiceTyped
                Dict,NoneType]=None,
                presence_penalty:Optional[float]=None,
                frequency_penalty:Optional[float]=None,
                n:OptionalNullable[int]=Unset(), prediction:Union[mistrala
                i.models.prediction.Prediction,mistralai.models.prediction
                .PredictionTypedDict,NoneType]=None,
                parallel_tool_calls:Optional[bool]=None,
                safe_prompt:Optional[bool]=None, retries:OptionalNullable[
                mistralai.utils.retries.RetryConfig]=Unset(),
                server_url:Optional[str]=None,
                timeout_ms:Optional[int]=None,
                http_headers:Optional[Mapping[str,str]]=None)

Add prompt pr to dialog and get a response from the model, automatically following up with tool_use messages

Type Default Details
pr Prompt to pass to model
max_steps int 10 Maximum number of tool requests to loop through
trace_func Optional None Function to trace tool use steps (e.g print)
cont_func Optional noop Function that stops loop if returns False
temperature OptionalNullable
top_p Optional None
max_tokens OptionalNullable
stream Optional False
stop Union None
random_seed OptionalNullable
response_format Union None
tools OptionalNullable
tool_choice Union None
presence_penalty Optional None
frequency_penalty Optional None
n OptionalNullable
prediction Union None
parallel_tool_calls Optional None
safe_prompt Optional None
retries OptionalNullable
server_url Optional None
timeout_ms Optional None
http_headers Optional None
Exported source
@patch
@delegates(mistralai.Chat.complete)
def toolloop(self:Chat,
             pr, # Prompt to pass to model
             max_steps=10, # Maximum number of tool requests to loop through
             trace_func:Optional[callable]=None, # Function to trace tool use steps (e.g `print`)
             cont_func:Optional[callable]=noop, # Function that stops loop if returns False
             **kwargs):
    "Add prompt `pr` to dialog and get a response from the model, automatically following up with `tool_use` messages"
    import time
    r = self(pr, **kwargs)
    for i in range(max_steps):
        ch = r.choices[0]
        if ch.finish_reason!='tool_calls': break
        if trace_func: trace_func(r)
        time.sleep(1)  # Add 1 second pause between queries to avoid rate limiting
        r = self(**kwargs)
        if not (cont_func or noop)(self.h[-2]): break
    if trace_func: trace_func(r)
    return r
chat = Chat(model, tools=tools)
r = chat.toolloop('Please cancel all orders for customer C1 for me.', trace_func=print)
r
- Retrieving customer C1
id='7fd7c25aba0f4b199b5a55a658609d4d' object='chat.completion' model='codestral-2501' usage=In: 253; Out: 23; Total: 276 created=1743590326 choices=[ChatCompletionChoice(index=0, message=AssistantMessage(content='', tool_calls=[ToolCall(function=FunctionCall(name='get_customer_info', arguments='{"customer_id": "C1"}'), id='cRrdLFWDH', type=None, index=0)], prefix=False, role='assistant'), finish_reason='tool_calls')]
- Cancelling order O1
- Cancelling order O2
id='8cfd03d225394b488b2ea8b7269b0d86' object='chat.completion' model='codestral-2501' usage=In: 408; Out: 41; Total: 449 created=1743590328 choices=[ChatCompletionChoice(index=0, message=AssistantMessage(content='', tool_calls=[ToolCall(function=FunctionCall(name='cancel_order', arguments='{"order_id": "O1"}'), id='CoejqXYQw', type=None, index=0), ToolCall(function=FunctionCall(name='cancel_order', arguments='{"order_id": "O2"}'), id='GiYzxpY3Y', type=None, index=1)], prefix=False, role='assistant'), finish_reason='tool_calls')]
id='321e089641684d5a921a81b0cb4ba5f5' object='chat.completion' model='codestral-2501' usage=In: 494; Out: 11; Total: 505 created=1743590329 choices=[ChatCompletionChoice(index=0, message=AssistantMessage(content='All orders for customer C1 have been cancelled.', tool_calls=None, prefix=False, role='assistant'), finish_reason='stop')]

All orders for customer C1 have been cancelled.

  • id: 321e089641684d5a921a81b0cb4ba5f5
  • object: chat.completion
  • model: codestral-2501
  • usage: prompt_tokens=494 completion_tokens=11 total_tokens=505
  • created: 1743590329
  • choices: [ChatCompletionChoice(index=0, message=AssistantMessage(content=‘All orders for customer C1 have been cancelled.’, tool_calls=None, prefix=False, role=‘assistant’), finish_reason=‘stop’)]
chat.toolloop('What is the status of order O2?')
- Retrieving order O2

The status of order O2 is Cancelled.

  • id: 1ac07a89c98c4495af308cb7011587ac
  • object: chat.completion
  • model: codestral-2501
  • usage: prompt_tokens=597 completion_tokens=11 total_tokens=608
  • created: 1743590335
  • choices: [ChatCompletionChoice(index=0, message=AssistantMessage(content=‘The status of order O2 is Cancelled.’, tool_calls=None, prefix=False, role=‘assistant’), finish_reason=‘stop’)]