Source code for agentscope.formatter._formatter_base
# -*- coding: utf-8 -*-
"""The formatter module."""
from abc import abstractmethod
from typing import Any, List
from .._utils._common import _save_base64_data
from ..message import Msg, AudioBlock, ImageBlock, TextBlock
[docs]
class FormatterBase:
"""The base class for formatters."""
[docs]
@abstractmethod
async def format(self, *args: Any, **kwargs: Any) -> list[dict[str, Any]]:
"""Format the Msg objects to a list of dictionaries that satisfy the
API requirements."""
[docs]
@staticmethod
def assert_list_of_msgs(msgs: list[Msg]) -> None:
"""Assert that the input is a list of Msg objects.
Args:
msgs (`list[Msg]`):
A list of Msg objects to be validated.
"""
if not isinstance(msgs, list):
raise TypeError("Input must be a list of Msg objects.")
for msg in msgs:
if not isinstance(msg, Msg):
raise TypeError(
f"Expected Msg object, got {type(msg)} instead.",
)
[docs]
@staticmethod
def convert_tool_result_to_string(
output: List[TextBlock | ImageBlock | AudioBlock],
) -> str:
"""Turn the tool result list into a textual output to be compatible
with the LLM API that doesn't support multimodal data.
Args:
output (`List[TextBlock | ImageBlock | AudioBlock]`):
The output of the tool response, including text and multimodal
data like images and audio.
Returns:
`str`:
A string representation of the tool result, with text blocks
concatenated and multimodal data represented by file paths
or URLs.
"""
textual_output = []
for block in output:
assert isinstance(block, dict) and "type" in block, (
f"Invalid block: {block}, a TextBlock, ImageBlock, or "
f"AudioBlock is expected."
)
if block["type"] == "text":
textual_output.append(block["text"])
elif block["type"] in ["image", "audio", "video"]:
assert "source" in block, (
f"Invalid {block['type']} block: {block}, 'source' key "
"is required."
)
source = block["source"]
# Save the image locally and return the file path
if source["type"] == "url":
textual_output.append(
f"The returned {block['type']} can be found "
f"at: {source['url']}",
)
elif source["type"] == "base64":
path_temp_file = _save_base64_data(
source["media_type"],
source["data"],
)
textual_output.append(
f"The returned {block['type']} can be found "
f"at: {path_temp_file}",
)
else:
raise ValueError(
f"Invalid image source: {block['source']}, "
"expected 'url' or 'base64'.",
)
else:
raise ValueError(
f"Unsupported block type: {block['type']}, "
"expected 'text', 'image', 'audio', or 'video'.",
)
if len(textual_output) == 1:
return textual_output[0]
else:
return "\n".join("- " + _ for _ in textual_output)