> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/block/goose/llms.txt
> Use this file to discover all available pages before exploring further.

# Conversation

> Message history and conversation management in Goose

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

```rust theme={null}
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.

```rust theme={null}
pub fn new<I>(messages: I) -> Result<Self, InvalidConversation>
where
    I: IntoIterator<Item = Message>,
```

<ParamField path="messages" type="I: IntoIterator<Item = Message>" required>
  Iterator of messages
</ParamField>

**Returns:** Validated Conversation or error

**Errors:** Returns `InvalidConversation` if messages violate conversation rules

**Source:** `crates/goose/src/conversation/mod.rs:22-27`

**Example:**

```rust theme={null}
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.

```rust theme={null}
pub fn new_unvalidated<I>(messages: I) -> Self
where
    I: IntoIterator<Item = Message>,
```

<ParamField path="messages" type="I: IntoIterator<Item = Message>" required>
  Iterator of messages
</ParamField>

**Returns:** Unvalidated Conversation

**Note:** Used internally before applying fixes

**Source:** `crates/goose/src/conversation/mod.rs:29-34`

### empty()

Create an empty conversation.

```rust theme={null}
pub fn empty() -> Self
```

**Source:** `crates/goose/src/conversation/mod.rs:36-38`

## Message Access

### messages()

Get the message list.

```rust theme={null}
pub fn messages(&self) -> &Vec<Message>
```

**Returns:** Reference to message vector

**Source:** `crates/goose/src/conversation/mod.rs:40-42`

**Example:**

```rust theme={null}
for message in conversation.messages() {
    println!("Role: {:?}, Text: {}", message.role, message.as_concat_text());
}
```

### last()

Get the last message.

```rust theme={null}
pub fn last(&self) -> Option<&Message>
```

**Source:** `crates/goose/src/conversation/mod.rs:65-67`

### first()

Get the first message.

```rust theme={null}
pub fn first(&self) -> Option<&Message>
```

**Source:** `crates/goose/src/conversation/mod.rs:69-71`

### len()

Get message count.

```rust theme={null}
pub fn len(&self) -> usize
```

**Source:** `crates/goose/src/conversation/mod.rs:73-75`

### is\_empty()

Check if conversation is empty.

```rust theme={null}
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.

```rust theme={null}
pub fn push(&mut self, message: Message)
```

<ParamField path="message" type="Message" required>
  Message to append
</ParamField>

**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:**

```rust theme={null}
let mut conversation = Conversation::empty();
conversation.push(Message::user().with_text("Hello"));
conversation.push(Message::assistant().with_text("Hi!"));
```

### extend()

Add multiple messages.

```rust theme={null}
pub fn extend<I>(&mut self, iter: I)
where
    I: IntoIterator<Item = Message>,
```

<ParamField path="iter" type="I: IntoIterator<Item = Message>" required>
  Messages to add
</ParamField>

**Source:** `crates/goose/src/conversation/mod.rs:81-88`

### pop()

Remove and return the last message.

```rust theme={null}
pub fn pop(&mut self) -> Option<Message>
```

**Source:** `crates/goose/src/conversation/mod.rs:94-96`

### truncate()

Keep only the first N messages.

```rust theme={null}
pub fn truncate(&mut self, len: usize)
```

<ParamField path="len" type="usize" required>
  Number of messages to keep
</ParamField>

**Source:** `crates/goose/src/conversation/mod.rs:98-100`

### clear()

Remove all messages.

```rust theme={null}
pub fn clear(&mut self)
```

**Source:** `crates/goose/src/conversation/mod.rs:102-104`

## Filtering

### filtered\_messages()

Filter messages by metadata.

```rust theme={null}
pub fn filtered_messages<F>(&self, filter: F) -> Vec<Message>
where
    F: Fn(&MessageMetadata) -> bool,
```

<ParamField path="filter" type="F: Fn(&MessageMetadata) -> bool" required>
  Predicate function
</ParamField>

**Returns:** Filtered message vector

**Source:** `crates/goose/src/conversation/mod.rs:106-115`

### agent\_visible\_messages()

Get messages visible to the agent.

```rust theme={null}
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:**

```rust theme={null}
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.

```rust theme={null}
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.

```rust theme={null}
pub fn fix_conversation(conversation: Conversation) -> (Conversation, Vec<String>)
```

<ParamField path="conversation" type="Conversation" required>
  Conversation to fix
</ParamField>

**Returns:** Tuple of (fixed\_conversation, issues\_found)

**Fixes Applied:**

1. Merge consecutive text content in assistant messages
2. Trim trailing whitespace from assistant messages
3. Remove empty messages
4. Fix orphaned tool calls/responses
5. Merge consecutive messages with same role
6. Ensure conversation starts with user and ends with user
7. Add placeholder "Hello" if empty

**Source:** `crates/goose/src/conversation/mod.rs:164-200`

**Example:**

```rust theme={null}
let (fixed, issues) = fix_conversation(conversation);
if !issues.is_empty() {
    println!("Fixed issues: {:?}", issues);
}
```

## Message Type

### Message Struct

```rust theme={null}
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`

<ResponseField name="id" type="Option<String>">
  Unique message identifier (auto-generated if not set)
</ResponseField>

<ResponseField name="role" type="Role" required>
  `Role::User` or `Role::Assistant`
</ResponseField>

<ResponseField name="created" type="i64" required>
  Unix timestamp (seconds)
</ResponseField>

<ResponseField name="content" type="Vec<MessageContent>" required>
  Message content items (text, images, tool calls, etc.)
</ResponseField>

<ResponseField name="metadata" type="MessageMetadata" required>
  Visibility settings
</ResponseField>

### Message Constructors

#### user()

Create a user message.

```rust theme={null}
pub fn user() -> Self
```

**Source:** `crates/goose/src/conversation/message.rs:700-708`

#### assistant()

Create an assistant message.

```rust theme={null}
pub fn assistant() -> Self
```

**Source:** `crates/goose/src/conversation/message.rs:710-718`

**Example:**

```rust theme={null}
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.

```rust theme={null}
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.

```rust theme={null}
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`

#### with\_tool\_request()

Add a tool call.

```rust theme={null}
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`

#### with\_tool\_response()

Add a tool result.

```rust theme={null}
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.

```rust theme={null}
pub fn with_visibility(mut self, user_visible: bool, agent_visible: bool) -> Self
```

**Source:** `crates/goose/src/conversation/message.rs:927-931`

**Example:**

```rust theme={null}
// 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.

```rust theme={null}
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`

#### is\_tool\_call()

Check if message contains tool requests.

```rust theme={null}
pub fn is_tool_call(&self) -> bool
```

**Source:** `crates/goose/src/conversation/message.rs:844-848`

#### is\_tool\_response()

Check if message contains tool responses.

```rust theme={null}
pub fn is_tool_response(&self) -> bool
```

**Source:** `crates/goose/src/conversation/message.rs:851-855`

## MessageContent Variants

```rust theme={null}
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`

## MessageMetadata

Controls message visibility.

```rust theme={null}
pub struct MessageMetadata {
    pub user_visible: bool,
    pub agent_visible: bool,
}
```

**Source:** `crates/goose/src/conversation/message.rs:586-591`

### Constructors

```rust theme={null}
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:**

```rust theme={null}
let internal_msg = Message::assistant()
    .with_text("System processing")
    .with_metadata(MessageMetadata::agent_only());
```

## Related Types

* [Agent](/api/core/agent) - Uses Conversation for context
* [Session](/api/core/session) - Persists Conversation
* [Config](/api/core/config) - Configuration system
