The Conversation type manages message history, validation, and transformations for LLM interactions.
Overview
Conversation provides:
- Ordered message storage
- Automatic message validation and fixing
- Message visibility filtering (user vs agent)
- Tool call/response pairing
- Message deduplication and merging
Conversation Struct
pub struct Conversation(Vec<Message>);
A validated sequence of messages.
Source: crates/goose/src/conversation/mod.rs:12
Constructor Methods
new()
Create a validated conversation.
pub fn new<I>(messages: I) -> Result<Self, InvalidConversation>
where
I: IntoIterator<Item = Message>,
messages
I: IntoIterator<Item = Message>
required
Iterator of messages
Returns: Validated Conversation or error
Errors: Returns InvalidConversation if messages violate conversation rules
Source: crates/goose/src/conversation/mod.rs:22-27
Example:
let messages = vec![
Message::user().with_text("Hello"),
Message::assistant().with_text("Hi there!"),
];
let conversation = Conversation::new(messages)?;
new_unvalidated()
Create an unvalidated conversation.
pub fn new_unvalidated<I>(messages: I) -> Self
where
I: IntoIterator<Item = Message>,
messages
I: IntoIterator<Item = Message>
required
Iterator of messages
Returns: Unvalidated Conversation
Note: Used internally before applying fixes
Source: crates/goose/src/conversation/mod.rs:29-34
empty()
Create an empty conversation.
Source: crates/goose/src/conversation/mod.rs:36-38
Message Access
messages()
Get the message list.
pub fn messages(&self) -> &Vec<Message>
Returns: Reference to message vector
Source: crates/goose/src/conversation/mod.rs:40-42
Example:
for message in conversation.messages() {
println!("Role: {:?}, Text: {}", message.role, message.as_concat_text());
}
last()
Get the last message.
pub fn last(&self) -> Option<&Message>
Source: crates/goose/src/conversation/mod.rs:65-67
first()
Get the first message.
pub fn first(&self) -> Option<&Message>
Source: crates/goose/src/conversation/mod.rs:69-71
len()
Get message count.
pub fn len(&self) -> usize
Source: crates/goose/src/conversation/mod.rs:73-75
is_empty()
Check if conversation is empty.
pub fn is_empty(&self) -> bool
Source: crates/goose/src/conversation/mod.rs:77-79
Message Manipulation
push()
Add a message, merging with the last if IDs match.
pub fn push(&mut self, message: Message)
Behavior:
- If the last message has the same ID, content is merged
- Otherwise, message is appended
Source: crates/goose/src/conversation/mod.rs:44-63
Example:
let mut conversation = Conversation::empty();
conversation.push(Message::user().with_text("Hello"));
conversation.push(Message::assistant().with_text("Hi!"));
extend()
Add multiple messages.
pub fn extend<I>(&mut self, iter: I)
where
I: IntoIterator<Item = Message>,
iter
I: IntoIterator<Item = Message>
required
Messages to add
Source: crates/goose/src/conversation/mod.rs:81-88
pop()
Remove and return the last message.
pub fn pop(&mut self) -> Option<Message>
Source: crates/goose/src/conversation/mod.rs:94-96
truncate()
Keep only the first N messages.
pub fn truncate(&mut self, len: usize)
Number of messages to keep
Source: crates/goose/src/conversation/mod.rs:98-100
clear()
Remove all messages.
Source: crates/goose/src/conversation/mod.rs:102-104
Filtering
filtered_messages()
Filter messages by metadata.
pub fn filtered_messages<F>(&self, filter: F) -> Vec<Message>
where
F: Fn(&MessageMetadata) -> bool,
filter
F: Fn(&MessageMetadata) -> bool
required
Predicate function
Returns: Filtered message vector
Source: crates/goose/src/conversation/mod.rs:106-115
agent_visible_messages()
Get messages visible to the agent.
pub fn agent_visible_messages(&self) -> Vec<Message>
Returns: Messages with metadata.agent_visible = true
Source: crates/goose/src/conversation/mod.rs:117-119
Example:
let agent_messages = conversation.agent_visible_messages();
for msg in agent_messages {
// These messages will be sent to the LLM
}
user_visible_messages()
Get messages visible to the user.
pub fn user_visible_messages(&self) -> Vec<Message>
Returns: Messages with metadata.user_visible = true
Source: crates/goose/src/conversation/mod.rs:121-123
Validation and Fixing
fix_conversation()
Automatically fix conversation issues.
pub fn fix_conversation(conversation: Conversation) -> (Conversation, Vec<String>)
Returns: Tuple of (fixed_conversation, issues_found)
Fixes Applied:
- Merge consecutive text content in assistant messages
- Trim trailing whitespace from assistant messages
- Remove empty messages
- Fix orphaned tool calls/responses
- Merge consecutive messages with same role
- Ensure conversation starts with user and ends with user
- Add placeholder “Hello” if empty
Source: crates/goose/src/conversation/mod.rs:164-200
Example:
let (fixed, issues) = fix_conversation(conversation);
if !issues.is_empty() {
println!("Fixed issues: {:?}", issues);
}
Message Type
Message Struct
pub struct Message {
pub id: Option<String>,
pub role: Role,
pub created: i64,
pub content: Vec<MessageContent>,
pub metadata: MessageMetadata,
}
Source: crates/goose/src/conversation/message.rs:663-670
Unique message identifier (auto-generated if not set)
Role::User or Role::Assistant
content
Vec<MessageContent>
required
Message content items (text, images, tool calls, etc.)
Message Constructors
user()
Create a user message.
Source: crates/goose/src/conversation/message.rs:700-708
assistant()
Create an assistant message.
pub fn assistant() -> Self
Source: crates/goose/src/conversation/message.rs:710-718
Example:
let user_msg = Message::user()
.with_text("Run the tests")
.with_generated_id();
let assistant_msg = Message::assistant()
.with_text("I'll run the tests for you.")
.with_tool_request("req_1", Ok(tool_params));
Message Builders
with_text()
Add text content.
pub fn with_text<S: Into<String>>(self, text: S) -> Self
Source: crates/goose/src/conversation/message.rs:737-748
with_image()
Add image content.
pub fn with_image<S: Into<String>, T: Into<String>>(self, data: S, mime_type: T) -> Self
Source: crates/goose/src/conversation/message.rs:751-753
Add a tool call.
pub fn with_tool_request<S: Into<String>>(
self,
id: S,
tool_call: ToolResult<CallToolRequestParams>,
) -> Self
Source: crates/goose/src/conversation/message.rs:756-762
Add a tool result.
pub fn with_tool_response<S: Into<String>>(
self,
id: S,
result: ToolResult<CallToolResult>,
) -> Self
Source: crates/goose/src/conversation/message.rs:780-786
with_visibility()
Set visibility flags.
pub fn with_visibility(mut self, user_visible: bool, agent_visible: bool) -> Self
Source: crates/goose/src/conversation/message.rs:927-931
Example:
// Message visible only to agent
let internal_msg = Message::assistant()
.with_text("Internal processing note")
.with_visibility(false, true);
Message Utilities
as_concat_text()
Get all text content concatenated.
pub fn as_concat_text(&self) -> String
Returns: Newline-joined text from all text content items
Source: crates/goose/src/conversation/message.rs:835-841
Check if message contains tool requests.
pub fn is_tool_call(&self) -> bool
Source: crates/goose/src/conversation/message.rs:844-848
Check if message contains tool responses.
pub fn is_tool_response(&self) -> bool
Source: crates/goose/src/conversation/message.rs:851-855
MessageContent Variants
pub enum MessageContent {
Text(TextContent),
Image(ImageContent),
ToolRequest(ToolRequest),
ToolResponse(ToolResponse),
ToolConfirmationRequest(ToolConfirmationRequest),
ActionRequired(ActionRequired),
FrontendToolRequest(FrontendToolRequest),
Thinking(ThinkingContent),
RedactedThinking(RedactedThinkingContent),
SystemNotification(SystemNotificationContent),
Reasoning(ReasoningContent),
}
Source: crates/goose/src/conversation/message.rs:185-199
Controls message visibility.
pub struct MessageMetadata {
pub user_visible: bool,
pub agent_visible: bool,
}
Source: crates/goose/src/conversation/message.rs:586-591
Constructors
impl MessageMetadata {
pub fn agent_only() -> Self; // user_visible: false, agent_visible: true
pub fn user_only() -> Self; // user_visible: true, agent_visible: false
pub fn invisible() -> Self; // user_visible: false, agent_visible: false
}
Source: crates/goose/src/conversation/message.rs:603-625
Example:
let internal_msg = Message::assistant()
.with_text("System processing")
.with_metadata(MessageMetadata::agent_only());
- Agent - Uses Conversation for context
- Session - Persists Conversation
- Config - Configuration system