Files
wehub-resource-sync bbfc60cd69
Publish BFCL to PyPI / build_and_publish (push) Has been cancelled
Update API Zoo Data / send-updates (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:37:27 +08:00

216 lines
7.4 KiB
Python

import json
import os
import time
from typing import Any
from bfcl_eval.constants.enums import ModelStyle
from bfcl_eval.constants.type_mappings import GORILLA_TO_OPENAPI
from bfcl_eval.model_handler.base_handler import BaseHandler
from bfcl_eval.model_handler.utils import (
convert_to_function_call,
convert_to_tool,
default_decode_ast_prompting,
default_decode_execute_prompting,
format_execution_results_prompting,
retry_with_backoff,
system_prompt_pre_processing_chat_model,
)
from mistralai import Mistral
class MistralHandler(BaseHandler):
def __init__(
self,
model_name,
temperature,
registry_name,
is_fc_model,
**kwargs,
) -> None:
super().__init__(model_name, temperature, registry_name, is_fc_model, **kwargs)
self.model_style = ModelStyle.MISTRAL
self.client = Mistral(api_key=os.getenv("MISTRAL_API_KEY"))
def decode_ast(self, result, language, has_tool_call_tag):
if self.is_fc_model:
decoded_output = []
for invoked_function in result:
name = list(invoked_function.keys())[0]
params = json.loads(invoked_function[name])
decoded_output.append({name: params})
return decoded_output
else:
return default_decode_ast_prompting(result, language, has_tool_call_tag)
def decode_execute(self, result, has_tool_call_tag):
if self.is_fc_model:
function_call = convert_to_function_call(result)
return function_call
else:
return default_decode_execute_prompting(result, has_tool_call_tag)
@retry_with_backoff(error_message_pattern=r".*Status 429.*")
def generate_with_backoff(self, **kwargs):
start_time = time.time()
api_response = self.client.chat.complete(**kwargs)
end_time = time.time()
return api_response, end_time - start_time
#### FC methods ####
def _query_FC(self, inference_data: dict):
message = inference_data["message"]
tool = inference_data["tools"]
inference_data["inference_input_log"] = {
"message": message,
"tools": tool,
}
return self.generate_with_backoff(
model=self.model_name,
messages=message,
tools=tool,
temperature=self.temperature,
)
def _pre_query_processing_FC(self, inference_data: dict, test_entry: dict) -> dict:
inference_data["message"] = []
return inference_data
def _compile_tools(self, inference_data: dict, test_entry: dict) -> dict:
functions: list = test_entry["function"]
tools = convert_to_tool(functions, GORILLA_TO_OPENAPI, self.model_style)
inference_data["tools"] = tools
return inference_data
def _parse_query_response_FC(self, api_response: Any) -> dict:
try:
model_responses = [
{func_call.function.name: func_call.function.arguments}
for func_call in api_response.choices[0].message.tool_calls
]
tool_call_func_names = [
func_call.function.name
for func_call in api_response.choices[0].message.tool_calls
]
tool_call_ids = [
func_call.id for func_call in api_response.choices[0].message.tool_calls
]
except:
model_responses = api_response.choices[0].message.content
tool_call_func_names = []
tool_call_ids = []
return {
"model_responses": model_responses,
"model_responses_message_for_chat_history": api_response.choices[0].message,
"tool_call_func_names": tool_call_func_names,
"tool_call_ids": tool_call_ids,
"input_token": api_response.usage.prompt_tokens,
"output_token": api_response.usage.completion_tokens,
}
def add_first_turn_message_FC(
self, inference_data: dict, first_turn_message: list[dict]
) -> dict:
inference_data["message"].extend(first_turn_message)
return inference_data
def _add_next_turn_user_message_FC(
self, inference_data: dict, user_message: list[dict]
) -> dict:
inference_data["message"].extend(user_message)
return inference_data
def _add_assistant_message_FC(
self, inference_data: dict, model_response_data: dict
) -> dict:
inference_data["message"].append(
model_response_data["model_responses_message_for_chat_history"]
)
return inference_data
def _add_execution_results_FC(
self, inference_data: dict, execution_results: list[str], model_response_data: dict
) -> dict:
for execution_result, func_name, tool_call_id in zip(
execution_results,
model_response_data["tool_call_func_names"],
model_response_data["tool_call_ids"],
):
tool_message = {
"role": "tool",
"name": func_name,
"content": execution_result,
"tool_call_id": tool_call_id,
}
inference_data["message"].append(tool_message)
return inference_data
#### Prompting methods ####
def _query_prompting(self, inference_data: dict):
message = inference_data["message"]
inference_data["inference_input_log"] = {"message": message}
return self.generate_with_backoff(
model=self.model_name,
messages=message,
temperature=self.temperature,
)
def _pre_query_processing_prompting(self, test_entry: dict) -> dict:
functions: list = test_entry["function"]
test_entry_id: str = test_entry["id"]
test_entry["question"][0] = system_prompt_pre_processing_chat_model(
test_entry["question"][0], functions, test_entry_id
)
return {"message": []}
def _parse_query_response_prompting(self, api_response: Any) -> dict:
return {
"model_responses": api_response.choices[0].message.content,
"model_responses_message_for_chat_history": api_response.choices[0].message,
"input_token": api_response.usage.prompt_tokens,
"output_token": api_response.usage.completion_tokens,
}
def add_first_turn_message_prompting(
self, inference_data: dict, first_turn_message: list[dict]
) -> dict:
inference_data["message"].extend(first_turn_message)
return inference_data
def _add_next_turn_user_message_prompting(
self, inference_data: dict, user_message: list[dict]
) -> dict:
inference_data["message"].extend(user_message)
return inference_data
def _add_assistant_message_prompting(
self, inference_data: dict, model_response_data: dict
) -> dict:
inference_data["message"].append(
model_response_data["model_responses_message_for_chat_history"]
)
return inference_data
def _add_execution_results_prompting(
self, inference_data: dict, execution_results: list[str], model_response_data: dict
) -> dict:
formatted_results_message = format_execution_results_prompting(
inference_data, execution_results, model_response_data
)
inference_data["message"].append(
{"role": "user", "content": formatted_results_message}
)
return inference_data