# Tool loop


<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! -->

``` python
model = models[0]
```

``` python
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']])
}
```

``` python
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
```

``` python
tools = [get_customer_info, get_order_details, cancel_order]
chat = Chat(model, tools=tools)
```

``` python
r = chat('Can you tell me the email address for customer C2?')
```

    - Retrieving customer C2

``` python
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')

``` python
r = chat()
r
```

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

<details>

- 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’)\]

</details>

``` python
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')

------------------------------------------------------------------------

<a
href="https://github.com/franckalbinet/mistinguette/blob/main/mistinguette/toolloop.py#L17"
target="_blank" style="float:right; font-size:smaller">source</a>

### 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*

<table>
<colgroup>
<col style="width: 6%" />
<col style="width: 25%" />
<col style="width: 34%" />
<col style="width: 34%" />
</colgroup>
<thead>
<tr>
<th></th>
<th><strong>Type</strong></th>
<th><strong>Default</strong></th>
<th><strong>Details</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>pr</td>
<td></td>
<td></td>
<td>Prompt to pass to model</td>
</tr>
<tr>
<td>max_steps</td>
<td>int</td>
<td>10</td>
<td>Maximum number of tool requests to loop through</td>
</tr>
<tr>
<td>trace_func</td>
<td>Optional</td>
<td>None</td>
<td>Function to trace tool use steps (e.g <code>print</code>)</td>
</tr>
<tr>
<td>cont_func</td>
<td>Optional</td>
<td>noop</td>
<td>Function that stops loop if returns False</td>
</tr>
<tr>
<td>temperature</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>top_p</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>max_tokens</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>stream</td>
<td>Optional</td>
<td>False</td>
<td></td>
</tr>
<tr>
<td>stop</td>
<td>Union</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>random_seed</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>response_format</td>
<td>Union</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>tools</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>tool_choice</td>
<td>Union</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>presence_penalty</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>frequency_penalty</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>n</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>prediction</td>
<td>Union</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>parallel_tool_calls</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>safe_prompt</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>retries</td>
<td>OptionalNullable</td>
<td></td>
<td></td>
</tr>
<tr>
<td>server_url</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>timeout_ms</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
<tr>
<td>http_headers</td>
<td>Optional</td>
<td>None</td>
<td></td>
</tr>
</tbody>
</table>

<details open class="code-fold">
<summary>Exported source</summary>

``` python
@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
```

</details>

``` python
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.

<details>

- 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’)\]

</details>

``` python
chat.toolloop('What is the status of order O2?')
```

    - Retrieving order O2

The status of order O2 is Cancelled.

<details>

- 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’)\]

</details>
