Source code for kani.utils.message_formatters
"""
A couple convenience formatters to customize :meth:`.Kani.full_round_str`.
You can pass any of these functions in with, e.g., ``Kani.full_round_str(..., message_formatter=all_message_contents)``.
"""
import itertools
from kani.models import ChatMessage, ChatRole
from kani.parts.reasoning import ReasoningPart
[docs]
def all_message_contents(msg: ChatMessage):
"""Return the content of any message."""
return msg.text
[docs]
def assistant_message_contents(msg: ChatMessage, show_reasoning=True, color=True):
"""
Return the content of any assistant message; otherwise don't return anything.
:param show_reasoning: If True, include any ReasoningParts in the output.
:param color: If True, the returned reasoning parts will be surrounded in ANSI codes to make it appear gray.
"""
if msg.role != ChatRole.ASSISTANT:
return
if show_reasoning:
text_parts = []
for t, grp in itertools.groupby(msg.parts, lambda p: type(p)):
if issubclass(t, ReasoningPart):
content = "".join(p.content for p in grp)
text_parts.append(f"\033[0;37m{content}\033[0m" if color else content)
else:
text_parts.append("".join(map(str, grp)))
return "\n".join(text_parts)
return msg.text or ""
[docs]
def assistant_message_contents_thinking(msg: ChatMessage, show_args=False, show_reasoning=True, color=True):
"""
Return the content of any assistant message, and "Thinking..." on function calls.
You can use this in ``full_round_str`` by using a partial, e.g.:
``ai.full_round_str(..., message_formatter=functools.partial(assistant_message_contents_thinking, show_args=True))``
:param show_args: If True, include the arguments to each function call.
:param show_reasoning: If True, include any ReasoningParts in the output.
:param color: If True, the returned reasoning parts will be surrounded in ANSI codes to make it appear gray.
"""
if msg.role != ChatRole.ASSISTANT:
return
# text
text = assistant_message_contents(msg, show_reasoning, color)
# function calls
if not msg.tool_calls:
return text
if not text:
return assistant_message_thinking(msg, show_args).strip()
return f"{text}\n{assistant_message_thinking(msg, show_args)}".strip()
[docs]
def assistant_message_thinking(msg: ChatMessage, show_args=False):
"""Return "Thinking..." on assistant messages with function calls, ignoring any content.
This is useful if you are streaming the message's contents.
If *show_args* is True, include the arguments to each function call.
"""
if msg.role != ChatRole.ASSISTANT or not msg.tool_calls:
return
# with args: show a nice repr (e.g. `get_weather(location="San Francisco, CA", unit="fahrenheit")`)
if show_args:
parts = []
for tc in msg.tool_calls:
args = ", ".join(f"{kwarg}={v!r}" for kwarg, v in tc.function.kwargs.items())
parts.append(f"{tc.function.name}({args})")
called_functions = "; ".join(parts)
# no args: just print the function name
else:
called_functions = "; ".join(tc.function.name for tc in msg.tool_calls)
return f"Thinking... [{called_functions}]"