Skip to main content
LLMs talk in messages. Cognis models them as a closed enum so the compiler always knows which roles are possible, and a ContentPart enum so multimodal payloads ride alongside text without losing their type.

What it is

Each variant carries a content string, plus role-specific fields:
  • HumanMessage { content, parts } — user input, optionally multimodal.
  • AiMessage { content, tool_calls, parts } — assistant reply, possibly with tool calls.
  • SystemMessage { content } — system instructions.
  • ToolMessage { tool_call_id, content } — the result of a tool invocation, threaded back to the matching call.

Building messages

Constructors take any impl Into<String>.
For tool replies inside an agent loop, the loop wires Message::tool(call_id, content) automatically — you only construct these by hand if you’re driving the LLM yourself without an agent.

Multimodal content

HumanMessage and AiMessage both carry a parts: Vec<ContentPart> for non-text payloads.
The variants: ImageSource and AudioSource are themselves enums:
  • Url { url } — pass a public URL the model can fetch.
  • Base64 { data } — inline payload for providers that accept it.
Use the helpers: ImageSource::url("..."), ImageSource::base64(data).

Provider serialization

Each provider serializes parts into its own wire format — OpenAI’s image_url blocks, Anthropic’s image blocks, Gemini’s inline_data / file_data. Cognis ships the conversions; you don’t write them.
The corresponding ContentPart::from_openai, from_anthropic, from_gemini parse provider responses back.

Reading messages

A few accessors for the common fields:
ToolCall carries { id, name, arguments: Value }. The agent loop uses these to dispatch.

See also

Building agents → Models

Send messages through an LLM client.

Building agents → Tools

What tool_calls and Message::tool are wired to.