Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: Cohere tool calling with regular LLM call later results in BadRequestError: status_code: 400 #3270

Closed
jaygdesai opened this issue Aug 1, 2024 · 2 comments
Labels
models Pertains to using alternate, non-GPT, models (e.g., local models, llama, etc.)

Comments

@jaygdesai
Copy link
Contributor

Describe the bug

Getting an error as under when using Cohere with tool use.

BadRequestError                           Traceback (most recent call last)
[<ipython-input-20-914b6f98f052>](https://localhost:8080/#) in <cell line: 1>()
----> 1 chat_result = human.initiate_chat(
      2     manager,
      3     message="""First add 1 and 60. Then multiply answer by 2"""
      4 )

12 frames
[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in initiate_chat(self, recipient, clear_history, silent, cache, max_turns, summary_method, summary_args, message, **kwargs)
   1017             else:
   1018                 msg2send = self.generate_init_message(message, **kwargs)
-> 1019             self.send(msg2send, recipient, silent=silent)
   1020         summary = self._summarize_chat(
   1021             summary_method,

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in send(self, message, recipient, request_reply, silent)
    654         valid = self._append_oai_message(message, "assistant", recipient)
    655         if valid:
--> 656             recipient.receive(message, self, request_reply, silent)
    657         else:
    658             raise ValueError(

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in receive(self, message, sender, request_reply, silent)
    817         if request_reply is False or request_reply is None and self.reply_at_receive[sender] is False:
    818             return
--> 819         reply = self.generate_reply(messages=self.chat_messages[sender], sender=sender)
    820         if reply is not None:
    821             self.send(reply, sender, silent=silent)

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in generate_reply(self, messages, sender, **kwargs)
   1971                 continue
   1972             if self._match_trigger(reply_func_tuple["trigger"], sender):
-> 1973                 final, reply = reply_func(self, messages=messages, sender=sender, config=reply_func_tuple["config"])
   1974                 if logging_enabled():
   1975                     log_event(

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/groupchat.py](https://localhost:8080/#) in run_chat(self, messages, sender, config)
   1050                     iostream.print(colored(f"\nNext speaker: {speaker.name}\n", "green"), flush=True)
   1051                 # let the speaker speak
-> 1052                 reply = speaker.generate_reply(sender=self)
   1053             except KeyboardInterrupt:
   1054                 # let the admin agent speak if interrupted

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in generate_reply(self, messages, sender, **kwargs)
   1971                 continue
   1972             if self._match_trigger(reply_func_tuple["trigger"], sender):
-> 1973                 final, reply = reply_func(self, messages=messages, sender=sender, config=reply_func_tuple["config"])
   1974                 if logging_enabled():
   1975                     log_event(

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in generate_oai_reply(self, messages, sender, config)
   1339         if messages is None:
   1340             messages = self._oai_messages[sender]
-> 1341         extracted_response = self._generate_oai_reply_from_client(
   1342             client, self._oai_system_message + messages, self.client_cache
   1343         )

[/usr/local/lib/python3.10/dist-packages/autogen/agentchat/conversable_agent.py](https://localhost:8080/#) in _generate_oai_reply_from_client(self, llm_client, messages, cache)
   1358 
   1359         # TODO: #1143 handle token limit exceeded error
-> 1360         response = llm_client.create(
   1361             context=messages[-1].pop("context", None), messages=all_messages, cache=cache, agent=self
   1362         )

[/usr/local/lib/python3.10/dist-packages/autogen/oai/client.py](https://localhost:8080/#) in create(self, **config)
    730             try:
    731                 request_ts = get_current_ts()
--> 732                 response = client.create(params)
    733             except APITimeoutError as err:
    734                 logger.debug(f"config {i} timed out", exc_info=True)

[/usr/local/lib/python3.10/dist-packages/autogen/oai/cohere.py](https://localhost:8080/#) in create(self, params)
    175                     response = client.chat_stream(**cohere_params)
    176                 else:
--> 177                     response = client.chat(**cohere_params)
    178             except CohereRateLimitError as e:
    179                 raise RuntimeError(f"Cohere exception occurred: {e}")

[/usr/local/lib/python3.10/dist-packages/cohere/client.py](https://localhost:8080/#) in _wrapped(*args, **kwargs)
    101                 "To suppress this warning, set `log_warning_experimental_features=False` when initializing the client."
    102             )
--> 103         return func(*args, **kwargs)
    104 
    105     async def _async_wrapped(*args, **kwargs):

[/usr/local/lib/python3.10/dist-packages/cohere/client.py](https://localhost:8080/#) in _wrapped(*args, **kwargs)
     33     def _wrapped(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:
     34         check_fn(*args, **kwargs)
---> 35         return method(*args, **kwargs)
     36 
     37     async def _async_wrapped(*args: typing.Any, **kwargs: typing.Any) -> typing.Any:

[/usr/local/lib/python3.10/dist-packages/cohere/base_client.py](https://localhost:8080/#) in chat(self, message, model, preamble, chat_history, conversation_id, prompt_truncation, connectors, search_queries_only, documents, citation_quality, temperature, max_tokens, max_input_tokens, k, p, seed, stop_sequences, frequency_penalty, presence_penalty, raw_prompting, return_prompt, tools, tool_results, force_single_step, response_format, request_options)
    853             return typing.cast(NonStreamedChatResponse, construct_type(type_=NonStreamedChatResponse, object_=_response.json()))  # type: ignore
    854         if _response.status_code == 400:
--> 855             raise BadRequestError(
    856                 typing.cast(typing.Any, construct_type(type_=typing.Any, object_=_response.json()))  # type: ignore
    857             )

BadRequestError: status_code: 400, body: {'message': 'invalid request: all elements in history must have a message.'}

Steps to reproduce

  1. Run conversation between agents for few cycles.
  2. Inbetween have a tool call.
  3. Before calling a normal LLM call, ensure that chat history has a tool call, but it is not the latest one.
  4. It creates above mentioned error.

Model Used

Cohere command-r-plus

Expected Behavior

Code should handle such situations without running into the error.

Screenshots and logs

image
image
image
image

Additional Information

No response

@jaygdesai
Copy link
Contributor Author

Code which reproduces error for me:

original_task = """take a 3. multiply it by 764557. add -567 to answer."""

def addition(a: int, b: int) -> int:
  """Tool to add two integer numbers a and b"""
  return a + b

def subtraction(a: int, b: int) -> int:
  """Tool to subtract integer number b from integer number a"""
  return a - b

def multiplication(a: int, b: int) -> int:
  """Tool to multiply two integer numbers a and b"""
  return a * b

def division(a: int, b: int) -> int:
  """Tool to divide integer numbers a by b"""
  return a / b

class MyConversableAgent(ConversableAgent):
  def get_human_input(self, prompt):
    # Custom method to get human input
    print("I am here")
    print(groupchat.messages[-1])
    user_input = input()  # This could be replaced with a more sophisticated input method
    return user_input

human = MyConversableAgent(
    name="Human",
    system_message="A human user",
    human_input_mode="TERMINATE",
    llm_config=False,
    default_auto_reply="Continue please"
)

class DebugConversableAgent(ConversableAgent):
  def get_human_input(self, prompt):
    user_input = input(prompt)
    return user_input


llm = DebugConversableAgent(
    name="LLM_Generic",
    system_message="A generic large language model with tools. If multiple tool calls are required, then return only first one as response. Do not mention subsequent ones.",
    human_input_mode="NEVER",
    llm_config={"config_list": config_list}
)

llm.register_for_llm(name="addition", description=addition.__doc__)(addition)
llm.register_for_llm(name="subtraction", description=subtraction.__doc__)(subtraction)
llm.register_for_llm(name="multiplication", description=multiplication.__doc__)(multiplication)
llm.register_for_llm(name="division", description=division.__doc__)(division)


llm2 = ConversableAgent(
    name="LLM_Prompt_for_human",
    system_message="Refer to messages recevied and convert it into a prompt or information message for human user. Based on the messages ask for additional information that human has to provide or give him information. If the original task is complete, send message as TERMINATE. original task is " + original_task,
    human_input_mode="NEVER",
    llm_config={"config_list": config_list}
)

executor = ConversableAgent(
    name="Tool Executor",
    system_message="This class is used to execute tools passed to it",
    human_input_mode="NEVER",
    llm_config={"config_list": config_list}
)


executor.register_for_execution(name="addition")(addition)
executor.register_for_execution(name="subtraction")(subtraction)
executor.register_for_execution(name="multiplication")(multiplication)
executor.register_for_execution(name="division")(division)


groupchat = autogen.GroupChat(agents=[human, llm, executor, llm2], messages=[], max_round=20, speaker_selection_method=custom_speaker_selection_func)
manager = autogen.GroupChatManager(groupchat=groupchat, llm_config=False)

from autogen import Agent
def custom_speaker_selection_func(last_speaker, groupchat):
  """Define a customized speaker selection function.
  A recommended way is to define a transition for each speaker in the groupchat.

  Parameters:
      - last_speaker: Agent
          The last speaker in the group chat.
      - groupchat: GroupChat
          The GroupChat object
  Return:
      Return one of the following:
      1. an `Agent` class it must be one of the agents in the group chat.
      2. a string from ['auto' 'manual' 'random' 'round_robin'] to select a default method to use.
      3. None which indicates the chat should be terminated.
  """
  messages = groupchat.messages

  if "TERMINATE" in messages[-1]['content']:
    print("%%%%%%%%%%%%%%%% Calling TERMINATE")
    return None

  if last_speaker is llm:
    if "tool_calls" in messages[-1]:
      print("%%%%%%%%%%%%%%%% Calling executor")
      return executor
    else:
      print("%%%%%%%%%%%%%%%% Calling LLM2")
      return llm2
  if last_speaker is human:
    print("%%%%%%%%%%%%%%%% Calling LLM")
    return llm
  if last_speaker is executor:
    print("%%%%%%%%%%%%%%%% Calling LLM2")
    return llm2
  if last_speaker is llm2:
    print("%%%%%%%%%%%%%%%% Calling Human")
    return human
  return None


chat_result = human.initiate_chat(
    manager,
    message=original_task
)

@marklysze marklysze added the models Pertains to using alternate, non-GPT, models (e.g., local models, llama, etc.) label Aug 2, 2024
@marklysze
Copy link
Collaborator

Thanks @jaygdesai, your #3271 PR fixes this bug :).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
models Pertains to using alternate, non-GPT, models (e.g., local models, llama, etc.)
Projects
None yet
Development

No branches or pull requests

2 participants