mirror of
https://github.com/FoundationAgents/MetaGPT.git
synced 2026-06-02 14:45:17 +02:00
Merge pull request #851 from orange-crow/add_parse_arguments_for_openai
feat: add parse arguments for openai tool_calls.
This commit is contained in:
commit
21f974de5d
2 changed files with 38 additions and 4 deletions
|
|
@ -8,6 +8,7 @@
|
|||
"""
|
||||
|
||||
import json
|
||||
import re
|
||||
from typing import AsyncIterator, Optional, Union
|
||||
|
||||
from openai import APIConnectionError, AsyncOpenAI, AsyncStream
|
||||
|
|
@ -194,6 +195,30 @@ class OpenAILLM(BaseLLM):
|
|||
rsp = await self._achat_completion_function(messages, **kwargs)
|
||||
return self.get_choice_function_arguments(rsp)
|
||||
|
||||
def _parse_arguments(self, arguments: str) -> dict:
|
||||
"""parse arguments in openai function call"""
|
||||
if "langugae" not in arguments and "code" not in arguments:
|
||||
logger.warning(f"Not found `code`, `language`, We assume it is pure code:\n {arguments}\n. ")
|
||||
return {"language": "python", "code": arguments}
|
||||
|
||||
# 匹配language
|
||||
language_pattern = re.compile(r'[\"\']?language[\"\']?\s*:\s*["\']([^"\']+?)["\']', re.DOTALL)
|
||||
language_match = language_pattern.search(arguments)
|
||||
language_value = language_match.group(1) if language_match else "python"
|
||||
|
||||
# 匹配code
|
||||
code_pattern = r'(["\'`]{3}|["\'`])([\s\S]*?)\1'
|
||||
try:
|
||||
code_value = re.findall(code_pattern, arguments)[-1][-1]
|
||||
except Exception as e:
|
||||
logger.error(f"{e}, when re.findall({code_pattern}, {arguments})")
|
||||
code_value = None
|
||||
|
||||
if code_value is None:
|
||||
raise ValueError(f"Parse code error for {arguments}")
|
||||
# arguments只有code的情况
|
||||
return {"language": language_value, "code": code_value}
|
||||
|
||||
# @handle_exception
|
||||
def get_choice_function_arguments(self, rsp: ChatCompletion) -> dict:
|
||||
"""Required to provide the first function arguments of choice.
|
||||
|
|
@ -209,7 +234,14 @@ class OpenAILLM(BaseLLM):
|
|||
and message.tool_calls[0].function.arguments is not None
|
||||
):
|
||||
# reponse is code
|
||||
return json.loads(message.tool_calls[0].function.arguments, strict=False)
|
||||
try:
|
||||
return json.loads(message.tool_calls[0].function.arguments, strict=False)
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
error_msg = (
|
||||
f"Got JSONDecodeError for \n{'--'*40} \n{message.tool_calls[0].function.arguments}, {str(e)}"
|
||||
)
|
||||
logger.error(error_msg)
|
||||
return self._parse_arguments(message.tool_calls[0].function.arguments)
|
||||
elif message.tool_calls is None and message.content is not None:
|
||||
# reponse is code, fix openai tools_call respond bug,
|
||||
# The response content is `code``, but it appears in the content instead of the arguments.
|
||||
|
|
|
|||
|
|
@ -106,9 +106,11 @@ class TestOpenAI:
|
|||
|
||||
def test_aask_code_json_decode_error(self, json_decode_error):
|
||||
instance = OpenAILLM(mock_llm_config)
|
||||
with pytest.raises(json.decoder.JSONDecodeError) as e:
|
||||
instance.get_choice_function_arguments(json_decode_error)
|
||||
assert "JSONDecodeError" in str(e)
|
||||
code = instance.get_choice_function_arguments(json_decode_error)
|
||||
assert "code" in code
|
||||
assert "language" in code
|
||||
assert "hello world" in code["code"]
|
||||
logger.info(f'code is : {code["code"]}')
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue