5 releases
| 0.1.4 | Dec 10, 2025 |
|---|---|
| 0.1.3 | Nov 3, 2025 |
| 0.1.2 | Nov 1, 2025 |
| 0.1.1 | Nov 1, 2025 |
| 0.1.0 | Oct 30, 2025 |
#613 in Encoding
Used in 2 crates
(via abk)
80KB
1.5K
SLoC
UMF - Universal Message Format
A provider-agnostic message representation for LLM (Large Language Model) interactions.
Overview
UMF provides a standardized message format that can be converted to any LLM provider format (OpenAI, Anthropic, Google Gemini, Cohere, etc.). It follows OpenAI's JSON structure as the foundation while supporting flexible conversion to provider-specific formats.
Features
- OpenAI-Compatible Base: Follows OpenAI's message structure
- Provider-Agnostic: Easily convert to any LLM provider format
- Tool Calling Support: Full support for function/tool calling
- Type-Safe: Strongly typed Rust API with comprehensive validation
- Spec-Compliant: Matches the Universal Message Format specification exactly
Usage
Add to your Cargo.toml:
[dependencies]
umf = "0.1.0"
Basic Example
use umf::{InternalMessage, MessageRole, ContentBlock};
// Create a simple text message
let msg = InternalMessage::user("Hello, world!");
// Create a message with tool calls
let msg = InternalMessage::assistant_with_tools(
"Let me search for that",
vec![ContentBlock::tool_use(
"call_123",
"search",
serde_json::json!({"query": "rust programming"}),
)],
);
// Create a tool result message
let msg = InternalMessage::tool_result(
"call_123",
"search",
"Found 5 results about rust programming",
);
Message Structure
pub struct InternalMessage {
pub role: MessageRole, // system, user, assistant, tool
pub content: MessageContent, // Text or Blocks
pub metadata: HashMap<String, String>,
pub tool_call_id: Option<String>, // For tool messages
pub name: Option<String>, // For tool messages
}
Content Types
Simple Text:
let msg = InternalMessage::user("Hello");
Structured Content Blocks:
use umf::ContentBlock;
let blocks = vec![
ContentBlock::text("I'll help you with that"),
ContentBlock::tool_use("call_123", "search", serde_json::json!({"q": "test"})),
];
let msg = InternalMessage {
role: MessageRole::Assistant,
content: MessageContent::Blocks(blocks),
// ...
};
Tool Calling
Tool Use:
let tool_call = ContentBlock::tool_use(
"call_abc123",
"search",
serde_json::json!({"query": "weather"}),
);
Tool Result:
let msg = InternalMessage::tool_result(
"call_abc123",
"search",
"It's sunny, 72°F",
);
JSON Serialization
UMF types serialize to JSON exactly as specified:
Text Block:
{
"type": "text",
"text": "Hello world"
}
Tool Use Block:
{
"type": "tool_use",
"id": "call_123",
"name": "search",
"input": {"query": "weather"}
}
Tool Result Block:
{
"type": "tool_result",
"tool_use_id": "call_123",
"content": "Result text"
}
Provider Conversion
UMF can be converted to any provider format:
OpenAI
- Keep
role,content,tool_callsas-is - Remove internal metadata fields
Anthropic
- Extract system messages to separate parameter
- Convert
tool_callsto content blocks - Convert
role: "tool"torole: "user"withtool_resultblocks
Google Gemini / Cohere
- Follow similar conversion patterns based on provider API
Spec Compliance
UMF follows the Universal Message Format specification:
- Lowercase
typefield ("text","tool_use","tool_result") - Flattened block fields (no nested
dataobjects) - OpenAI-compatible structure as baseline
- Full round-trip serialization support
Testing
Run tests:
cargo test -p umf
All tests include:
- Message creation and serialization
- Content block validation
- Spec compliance verification
- Round-trip serialization tests
License
MIT OR Apache-2.0
Related
- Simpaticoder - Terminal-first software engineering agent
- Universal Message Format Specification - See
specs/universal-message-format/
Dependencies
~15MB
~121K SLoC