calute.types.messages

Contents

calute.types.messages#

Message type definitions for Calute.

This module provides a comprehensive message system for handling conversations with LLM models. It includes: - Content chunk types for text, images, and image URLs - Message types for different conversation roles (system, user, assistant, tool) - Message history management with OpenAI format conversion - Support for multimodal content including images and text

The message system follows a type-safe design using Pydantic models with discriminated unions for proper serialization and validation.

Example

>>> from calute.types.messages import UserMessage, MessagesHistory
>>> user_msg = UserMessage(content="Hello, how can I help you?")
>>> history = MessagesHistory(messages=[user_msg])
>>> openai_format = history.to_openai()
class calute.types.messages.AssistantMessage(*, role: ~typing.Literal[<Roles.assistant: 'assistant'>] = Roles.assistant, content: str | None = None, tool_calls: list[calute.types.tool_calls.ToolCall] | None = None, prefix: bool = False)[source]#

Bases: BaseMessage

Message generated by the AI assistant.

Represents the model’s response in a conversation. May contain text content, tool/function calls, or both. The prefix flag indicates whether this message should be treated as a prefix-fill for the next generation (used by some model APIs).

role#

The message role, always Roles.assistant.

Type

Literal[<Roles.assistant: ‘assistant’>]

content#

The text content of the assistant’s response, or None if the response consists only of tool calls.

Type

str | None

tool_calls#

Optional list of ToolCall objects representing function/tool invocations requested by the model.

Type

list[calute.types.tool_calls.ToolCall] | None

prefix#

Whether this message serves as a prefix for continued generation (default: False).

Type

bool

Example

>>> message = AssistantMessage(content="Hello, how can I help you?")
>>> message.to_openai()
{'role': 'assistant', 'content': 'Hello, how can I help you?'}
content: str | None#
classmethod from_openai(openai_message: dict[str, str | list[dict[str, str | dict[str, Any]]]]) AssistantMessage[source]#

Create an AssistantMessage from an OpenAI-format message dictionary.

Parses both the text content and any tool calls from the OpenAI message format.

Parameters

openai_message – A dictionary with role set to "assistant", optional content string, and optional tool_calls list.

Returns

A new AssistantMessage instance with parsed content and tool calls.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

prefix: bool#
role: assistant: 'assistant'>]#
to_openai() dict[str, str | list[dict[str, str | dict[str, Any]]]][source]#

Convert the assistant message to OpenAI API format.

Always includes content so OpenAI-compatible servers that require the field for tool-call turns still accept the payload.

Returns

A dictionary with role, content, and optionally tool_calls keys in OpenAI format.

tool_calls: list[calute.types.tool_calls.ToolCall] | None#
class calute.types.messages.BaseContentChunk(*, type: ~typing.Literal[<ChunkTypes.text: 'text'>, <ChunkTypes.image: 'image'>, <ChunkTypes.image_url: 'image_url'>])[source]#

Bases: CaluteBase

Abstract base class for all content chunks in multimodal messages.

Content chunks represent individual pieces of content within a message, such as text passages, images, or image URLs. Subclasses must implement the to_openai and from_openai methods for format conversion.

type#

The discriminator type of the chunk, one of ‘text’, ‘image’, or ‘image_url’.

Type

Literal[<ChunkTypes.text: ‘text’>, <ChunkTypes.image: ‘image’>, <ChunkTypes.image_url: ‘image_url’>]

classmethod from_openai(openai_chunk: dict[str, str | dict[str, str]]) BaseContentChunk[source]#

Create a content chunk from an OpenAI-format dictionary.

Must be implemented by subclasses to parse the OpenAI content chunk format into the appropriate Calute chunk type.

Parameters

openai_chunk – A dictionary in OpenAI content chunk format containing at minimum a ‘type’ key.

Returns

An instance of the appropriate BaseContentChunk subclass.

Raises

NotImplementedError – Always raised in the base class; subclasses must override this method.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_openai() dict[str, str | dict[str, str]][source]#

Convert this content chunk to the OpenAI API format.

Must be implemented by subclasses to provide the appropriate dictionary representation for the OpenAI messages API.

Returns

A dictionary in OpenAI content chunk format with a ‘type’ key and type-specific content keys.

Raises

NotImplementedError – Always raised in the base class; subclasses must override this method.

type: image_url: 'image_url'>]#
class calute.types.messages.BaseMessage(*, role: ~typing.Literal[<Roles.system: 'system'>, <Roles.user: 'user'>, <Roles.assistant: 'assistant'>, <Roles.tool: 'tool'>])[source]#

Bases: CaluteBase

Abstract base class for all chat message types.

Provides the common interface for message serialization to and from OpenAI format. Subclasses implement role-specific content handling and serialization logic.

role#

The role of the message sender, one of system, user, assistant, or tool.

Type

Literal[<Roles.system: ‘system’>, <Roles.user: ‘user’>, <Roles.assistant: ‘assistant’>, <Roles.tool: ‘tool’>]

classmethod from_openai(openai_message: dict[str, str | list[dict[str, str | dict[str, Any]]]]) BaseMessage[source]#

Create a message instance from an OpenAI-format dictionary.

Must be implemented by subclasses to parse OpenAI-format message dictionaries into the appropriate Calute message type.

Parameters

openai_message – A dictionary in OpenAI message format containing at minimum a role key.

Returns

An instance of the appropriate BaseMessage subclass.

Raises

NotImplementedError – Always raised in the base class; subclasses must override this method.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

role: tool: 'tool'>]#
to_openai() dict[str, str | list[dict[str, str | dict[str, Any]]]][source]#

Convert this message to the OpenAI API format.

Must be implemented by subclasses to produce a dictionary compatible with the OpenAI chat completion messages format.

Returns

A dictionary with at minimum role and content keys, formatted for the OpenAI API.

Raises

NotImplementedError – Always raised in the base class; subclasses must override this method.

class calute.types.messages.ChunkTypes(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: StrEnum

Enumeration of content chunk types supported in messages.

Defines the different types of content chunks that can be included in multimodal messages sent to LLM models.

text#

A plain text content chunk.

image#

A binary image content chunk (PIL Image or base64-encoded).

image_url#

An image referenced by URL or base64 data URI.

Example

>>> from calute.types.messages import ChunkTypes
>>> chunk_type = ChunkTypes.text
>>> chunk_type.value
'text'
image = 'image'#
image_url = 'image_url'#
text = 'text'#
class calute.types.messages.ImageChunk(*, type: ~typing.Literal[<ChunkTypes.image: 'image'>] = ChunkTypes.image, image: ~PIL.Image.Image)[source]#

Bases: BaseContentChunk

Content chunk containing a binary image.

Wraps a PIL Image or base64-encoded image data for inclusion in multimodal messages. When converted to OpenAI format, the image is serialized as a base64 data URI within an image_url structure.

type#

Chunk type discriminator, always ChunkTypes.image.

Type

Literal[<ChunkTypes.image: ‘image’>]

image#

The image data, either a PIL Image object or a base64 string, wrapped in a SerializableImage for Pydantic compatibility.

Type

PIL.Image.Image

Example

>>> from PIL import Image
>>> image_chunk = ImageChunk(image=Image.new('RGB', (200, 200), color='blue'))
classmethod from_openai(openai_chunk: dict[str, str | dict[str, str]]) ImageChunk[source]#

Create an ImageChunk from an OpenAI-format image_url dictionary.

Parses the base64 data URI from the OpenAI format, stripping the data:image/...;base64, prefix if present, and creates an ImageChunk with the raw base64 image data.

Parameters

openai_chunk – A dictionary with type set to "image_url" and an image_url sub-dictionary containing a url key.

Returns

A new ImageChunk instance with the parsed image data.

Raises

AssertionError – If the chunk type is not "image_url" or the image_url dictionary is malformed.

image: Image#
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_openai() dict[str, str | dict[str, str]][source]#

Convert the image chunk to OpenAI API format.

Serializes the image to a base64 data URI and wraps it in the OpenAI image_url content chunk format.

Returns

A dictionary with type set to "image_url" and an image_url sub-dictionary containing the base64 data URI.

type: image: 'image'>]#
class calute.types.messages.ImageURL(*, url: str, detail: str | None = None)[source]#

Bases: CaluteBase

Represents an image reference by URL or base64-encoded data URI.

Used within ImageURLChunk to specify the image source and optional detail level for vision-capable models.

url#

The URL of the image or a base64-encoded data URI string (e.g., "data:image/png;base64,..." or "https://...").

Type

str

detail#

Optional detail level hint for the model (e.g., "low", "high", "auto"). Controls image processing resolution.

Type

str | None

Example

>>> image_url = ImageURL(url="https://example.com/image.png", detail="high")
detail: str | None#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

url: str#
class calute.types.messages.ImageURLChunk(*, type: ~typing.Literal[<ChunkTypes.image_url: 'image_url'>] = ChunkTypes.image_url, image_url: calute.types.messages.ImageURL | str)[source]#

Bases: BaseContentChunk

Content chunk containing an image referenced by URL or data URI.

Supports both plain URL strings and structured ImageURL objects with optional detail level hints for vision-capable models.

type#

Chunk type discriminator, always ChunkTypes.image_url.

Type

Literal[<ChunkTypes.image_url: ‘image_url’>]

image_url#

The image reference, either an ImageURL object with url and optional detail fields, or a plain URL string.

Type

calute.types.messages.ImageURL | str

Example

>>> chunk = ImageURLChunk(image_url="https://example.com/photo.jpg")
>>> chunk_with_detail = ImageURLChunk(
...     image_url=ImageURL(url="https://example.com/photo.jpg", detail="high")
... )
classmethod from_openai(openai_chunk: dict[str, str | dict[str, str]]) ImageURLChunk[source]#

Create an ImageURLChunk from an OpenAI-format content chunk dictionary.

Parameters

openai_chunk – A dictionary with an image_url key containing either a URL string or a dictionary with url and optional detail keys.

Returns

A new ImageURLChunk instance parsed from the OpenAI format.

get_url() str[source]#

Extract the URL string from the image_url attribute.

Handles both ImageURL objects and plain string URLs, providing a uniform way to access the underlying URL.

Returns

The URL string for the image, regardless of whether image_url is an ImageURL instance or a plain string.

image_url: calute.types.messages.ImageURL | str#
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True, 'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_openai() dict[str, str | dict[str, str]][source]#

Convert the image URL chunk to OpenAI API format.

Creates an OpenAI-compatible content chunk dictionary with the image URL and optional detail level.

Returns

A dictionary with type set to "image_url" and an image_url sub-dictionary containing the URL and optionally a detail key.

type: image_url: 'image_url'>]#
class calute.types.messages.MessagesHistory(*, messages: list[typing.Annotated[calute.types.messages.SystemMessage | calute.types.messages.UserMessage | calute.types.messages.AssistantMessage | calute.types.messages.ToolMessage, FieldInfo(annotation=NoneType, required=True, discriminator='role')]])[source]#

Bases: CaluteBase

Container for managing a sequence of chat messages.

Provides a structured container for storing and manipulating chat conversation history. Supports conversion to/from OpenAI format and generation of instruction prompts for model input.

messages#

List of chat messages in the conversation. Each message is discriminated by its role (system, user, assistant, or tool).

Type

list[Annotated[calute.types.messages.SystemMessage | calute.types.messages.UserMessage | calute.types.messages.AssistantMessage | calute.types.messages.ToolMessage, FieldInfo(annotation=NoneType, required=True, discriminator=’role’)]]

Example

>>> from calute.types.messages import UserMessage, AssistantMessage, MessagesHistory
>>> history = MessagesHistory(messages=[
...     UserMessage(content="Hello!"),
...     AssistantMessage(content="Hi there! How can I help you?"),
... ])
>>> openai_format = history.to_openai()
classmethod from_openai(openai_messages: list[dict[str, str | list[dict[str, str | dict[str, Any]]]]]) MessagesHistory[source]#

Create a MessagesHistory from OpenAI format messages.

Converts a list of OpenAI format message dictionaries into a MessagesHistory instance with properly typed message objects.

Parameters

openai_messages – List of message dictionaries in OpenAI format. Each dictionary must contain a ‘role’ field to determine the message type.

Returns

A MessagesHistory instance containing the converted messages.

Example

>>> openai_msgs = [
...     {"role": "user", "content": "Hello!"},
...     {"role": "assistant", "content": "Hi there!"},
... ]
>>> history = MessagesHistory.from_openai(openai_msgs)
make_instruction_prompt(conversation_name_holder: str = 'Messages', mention_last_turn: bool = True) str[source]#

Format the message history into a human-readable instruction prompt.

Converts the entire message history into a single, structured string suitable for LLM input. Tool calls are rendered in canonical XML format to encourage the LLM to follow the same pattern.

Parameters
  • conversation_name_holder – The section header name for the conversation history section (default: “Messages”).

  • mention_last_turn – Whether to append a summary of the last message at the end of the prompt (default: True).

Returns

A formatted string containing the instruction prompt with all messages properly structured and indented.

messages: list[typing.Annotated[calute.types.messages.SystemMessage | calute.types.messages.UserMessage | calute.types.messages.AssistantMessage | calute.types.messages.ToolMessage, FieldInfo(annotation=NoneType, required=True, discriminator='role')]]#
model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

to_openai() list[dict[str, str | list[dict[str, str | dict[str, Any]]]]][source]#

Convert all messages to OpenAI API format.

Iterates through all messages, converts each to OpenAI format, and filters out system messages with empty content.

Returns

A dictionary with a messages key containing a list of OpenAI-format message dictionaries.

class calute.types.messages.Roles(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)[source]#

Bases: StrEnum

Enumeration of message roles in a chat conversation.

Defines the four standard roles used in chat completion APIs to distinguish between different participants in a conversation.

system#

The system role, used for initial instructions and context.

user#

The user role, representing the human participant.

assistant#

The assistant role, representing the AI model’s responses.

tool#

The tool role, used for function/tool execution results.

Example

>>> role = Roles.user
>>> role.value
'user'
assistant = 'assistant'#
system = 'system'#
tool = 'tool'#
user = 'user'#
class calute.types.messages.SystemMessage(*, role: ~typing.Literal[<Roles.system: 'system'>] = Roles.system, content: str | list[typing.Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])[source]#

Bases: BaseMessage

System-level instruction message for configuring model behavior.

System messages set the context, personality, and constraints for the AI assistant. They are typically placed at the beginning of a conversation and support both plain text and multimodal content.

role#

The message role, always Roles.system.

Type

Literal[<Roles.system: ‘system’>]

content#

The system instruction content, either a plain text string or a list of ContentChunk objects.

Type

str | list[Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator=’type’)]]

Example

>>> message = SystemMessage(content="You are a helpful assistant.")
>>> message.to_openai()
{'role': 'system', 'content': 'You are a helpful assistant.'}
content: str | list[typing.Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator='type')]]#
classmethod from_openai(openai_message: dict[str, str | list[dict[str, str | dict[str, Any]]]]) SystemMessage[source]#

Create a SystemMessage from an OpenAI-format message dictionary.

Parameters

openai_message – A dictionary with role set to "system" and a content key containing either a string or a list of content chunk dictionaries.

Returns

A new SystemMessage instance with properly typed content.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

role: system: 'system'>]#
to_openai() dict[str, str | list[dict[str, str | dict[str, Any]]]][source]#

Convert the system message to OpenAI API format.

Returns

A dictionary with role and content keys in OpenAI format.

class calute.types.messages.TextChunk(*, type: ~typing.Literal[<ChunkTypes.text: 'text'>] = ChunkTypes.text, text: str)[source]#

Bases: BaseContentChunk

Content chunk containing plain text.

The most common content chunk type, representing a segment of text within a multimodal message.

type#

Chunk type discriminator, always ChunkTypes.text.

Type

Literal[<ChunkTypes.text: ‘text’>]

text#

The text content string.

Type

str

Example

>>> text_chunk = TextChunk(text="Hello, how can I help you?")
>>> text_chunk.to_openai()
{'type': 'text', 'text': 'Hello, how can I help you?'}
classmethod from_openai(messages: dict[str, str | dict[str, str]]) TextChunk[source]#

Create a TextChunk from an OpenAI-format content chunk dictionary.

Parameters

messages – A dictionary with type set to "text" and a text key containing the text content.

Returns

A new TextChunk instance with the parsed text.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

text: str#
to_openai() dict[str, str | dict[str, str]][source]#

Convert the text chunk to OpenAI API format.

Returns

A dictionary with type set to "text" and a text key containing the text content.

type: text: 'text'>]#
class calute.types.messages.ToolMessage(*, role: ~typing.Literal[<Roles.tool: 'tool'>] = Roles.tool, content: str, tool_call_id: str | None = None)[source]#

Bases: BaseMessage

Message containing the result of a tool/function call execution.

Tool messages are sent after a function has been executed to provide the result back to the model. Each tool message must reference the specific tool call it responds to via tool_call_id.

content#

The string result of the tool execution.

Type

str

role#

The message role, always Roles.tool.

Type

Literal[<Roles.tool: ‘tool’>]

tool_call_id#

The unique identifier of the tool call this message responds to. Must not be None when converting to OpenAI format.

Type

str | None

Example

>>> message = ToolMessage(
...     content='{"temperature": 72, "unit": "fahrenheit"}',
...     tool_call_id="call_abc123"
... )
content: str#
classmethod from_openai(messages: dict[str, str | list[dict[str, str | dict[str, Any]]]]) ToolMessage[source]#

Create a ToolMessage from an OpenAI-format message dictionary.

Parameters

messages – A dictionary with role set to "tool", a content string, and a tool_call_id string.

Returns

A new ToolMessage instance with the parsed content and tool call ID.

Raises

AssertionError – If tool_call_id is not present in the input, as it is required for tool messages.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

role: tool: 'tool'>]#
to_openai() dict[str, str | list[dict[str, str | dict[str, Any]]]][source]#

Convert the tool message to OpenAI API format.

Returns

A dictionary with role, content, and tool_call_id keys.

Raises

AssertionError – If tool_call_id is None, as OpenAI requires tool messages to reference a specific tool call.

tool_call_id: str | None#
class calute.types.messages.UserMessage(*, role: ~typing.Literal[<Roles.user: 'user'>] = Roles.user, content: str | list[typing.Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator='type')]])[source]#

Bases: BaseMessage

Message from the user in a chat conversation.

Supports both plain text content and multimodal content consisting of a list of content chunks (text, images, image URLs).

role#

The message role, always Roles.user.

Type

Literal[<Roles.user: ‘user’>]

content#

The message content, either a plain text string or a list of ContentChunk objects for multimodal messages.

Type

str | list[Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator=’type’)]]

Example

>>> message = UserMessage(content="Can you help me to write a poem?")
>>> message.role
<Roles.user: 'user'>
content: str | list[typing.Annotated[calute.types.messages.TextChunk | calute.types.messages.ImageChunk | calute.types.messages.ImageURLChunk, FieldInfo(annotation=NoneType, required=True, discriminator='type')]]#
classmethod from_openai(openai_message: dict[str, str | list[dict[str, str | dict[str, Any]]]]) UserMessage[source]#

Create a UserMessage from an OpenAI-format message dictionary.

Handles both plain text content strings and lists of content chunk dictionaries for multimodal messages.

Parameters

openai_message – A dictionary with role set to "user" and a content key containing either a string or a list of content chunk dictionaries.

Returns

A new UserMessage instance with properly typed content.

model_config: ClassVar[ConfigDict] = {'extra': 'forbid', 'use_enum_values': True, 'validate_default': True}#

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

role: user: 'user'>]#
to_openai() dict[str, str | list[dict[str, str | dict[str, Any]]]][source]#

Convert the user message to OpenAI API format.

Handles both plain text content (returned as a string) and multimodal content (returned as a list of content chunk dictionaries).

Returns

A dictionary with role and content keys in OpenAI format.