You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

utils.py 6.0 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import os
  2. from typing import Any, List, Optional, Union
  3. from autogen_core.components.models import (
  4. AssistantMessage,
  5. ChatCompletionClient,
  6. FunctionExecutionResult,
  7. FunctionExecutionResultMessage,
  8. LLMMessage,
  9. UserMessage,
  10. )
  11. from autogen_ext.models import AzureOpenAIChatCompletionClient, OpenAIChatCompletionClient
  12. from azure.identity import DefaultAzureCredential, get_bearer_token_provider
  13. from typing_extensions import Literal
  14. from .types import (
  15. FunctionCallMessage,
  16. Message,
  17. MultiModalMessage,
  18. TextMessage,
  19. )
  20. def convert_content_message_to_assistant_message(
  21. message: Union[TextMessage, MultiModalMessage, FunctionCallMessage],
  22. handle_unrepresentable: Literal["error", "ignore", "try_slice"] = "error",
  23. ) -> Optional[AssistantMessage]:
  24. match message:
  25. case TextMessage() | FunctionCallMessage():
  26. return AssistantMessage(content=message.content, source=message.source)
  27. case MultiModalMessage():
  28. if handle_unrepresentable == "error":
  29. raise ValueError("Cannot represent multimodal message as AssistantMessage")
  30. elif handle_unrepresentable == "ignore":
  31. return None
  32. elif handle_unrepresentable == "try_slice":
  33. return AssistantMessage(
  34. content="".join([x for x in message.content if isinstance(x, str)]),
  35. source=message.source,
  36. )
  37. def convert_content_message_to_user_message(
  38. message: Union[TextMessage, MultiModalMessage, FunctionCallMessage],
  39. handle_unrepresentable: Literal["error", "ignore", "try_slice"] = "error",
  40. ) -> Optional[UserMessage]:
  41. match message:
  42. case TextMessage() | MultiModalMessage():
  43. return UserMessage(content=message.content, source=message.source)
  44. case FunctionCallMessage():
  45. if handle_unrepresentable == "error":
  46. raise ValueError("Cannot represent multimodal message as UserMessage")
  47. elif handle_unrepresentable == "ignore":
  48. return None
  49. elif handle_unrepresentable == "try_slice":
  50. # TODO: what is a sliced function call?
  51. raise NotImplementedError("Sliced function calls not yet implemented")
  52. def convert_tool_call_response_message(
  53. message: FunctionExecutionResultMessage,
  54. handle_unrepresentable: Literal["error", "ignore", "try_slice"] = "error",
  55. ) -> Optional[FunctionExecutionResultMessage]:
  56. match message:
  57. case FunctionExecutionResultMessage():
  58. return FunctionExecutionResultMessage(
  59. content=[FunctionExecutionResult(content=x.content, call_id=x.call_id) for x in message.content]
  60. )
  61. def convert_messages_to_llm_messages(
  62. messages: List[Message],
  63. self_name: str,
  64. handle_unrepresentable: Literal["error", "ignore", "try_slice"] = "error",
  65. ) -> List[LLMMessage]:
  66. result: List[LLMMessage] = []
  67. for message in messages:
  68. match message:
  69. case (
  70. TextMessage(content=_, source=source)
  71. | MultiModalMessage(content=_, source=source)
  72. | FunctionCallMessage(content=_, source=source)
  73. ) if source == self_name:
  74. converted_message_1 = convert_content_message_to_assistant_message(message, handle_unrepresentable)
  75. if converted_message_1 is not None:
  76. result.append(converted_message_1)
  77. case (
  78. TextMessage(content=_, source=source)
  79. | MultiModalMessage(content=_, source=source)
  80. | FunctionCallMessage(content=_, source=source)
  81. ) if source != self_name:
  82. converted_message_2 = convert_content_message_to_user_message(message, handle_unrepresentable)
  83. if converted_message_2 is not None:
  84. result.append(converted_message_2)
  85. case FunctionExecutionResultMessage(_):
  86. converted_message_3 = convert_tool_call_response_message(message, handle_unrepresentable)
  87. if converted_message_3 is not None:
  88. result.append(converted_message_3)
  89. case _:
  90. raise AssertionError("unreachable")
  91. return result
  92. def get_chat_completion_client_from_envs(**kwargs: Any) -> ChatCompletionClient:
  93. # Check API type.
  94. api_type = os.getenv("OPENAI_API_TYPE", "openai")
  95. if api_type == "openai":
  96. # Check API key.
  97. api_key = os.getenv("OPENAI_API_KEY")
  98. if api_key is None:
  99. raise ValueError("OPENAI_API_KEY is not set")
  100. kwargs["api_key"] = api_key
  101. return OpenAIChatCompletionClient(**kwargs)
  102. elif api_type == "azure":
  103. # Check Azure API key.
  104. azure_api_key = os.getenv("AZURE_OPENAI_API_KEY")
  105. if azure_api_key is not None:
  106. kwargs["api_key"] = azure_api_key
  107. else:
  108. # Try to use token from Azure CLI.
  109. token_provider = get_bearer_token_provider(
  110. DefaultAzureCredential(), "https://cognitiveservices.azure.com/.default"
  111. )
  112. kwargs["azure_ad_token_provider"] = token_provider
  113. # Check Azure API endpoint.
  114. azure_api_endpoint = os.getenv("AZURE_OPENAI_API_ENDPOINT")
  115. if azure_api_endpoint is None:
  116. raise ValueError("AZURE_OPENAI_API_ENDPOINT is not set")
  117. kwargs["azure_endpoint"] = azure_api_endpoint
  118. # Get Azure API version.
  119. kwargs["api_version"] = os.getenv("AZURE_OPENAI_API_VERSION", "2024-06-01")
  120. # Set model capabilities.
  121. if "model_capabilities" not in kwargs or kwargs["model_capabilities"] is None:
  122. kwargs["model_capabilities"] = {
  123. "vision": True,
  124. "function_calling": True,
  125. "json_output": True,
  126. }
  127. return AzureOpenAIChatCompletionClient(**kwargs) # type: ignore
  128. raise ValueError(f"Unknown API type: {api_type}")