Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions crates/goose-cli/src/session/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1220,6 +1220,17 @@ impl CliSession {
}
}
}

if let Err(e) = self
.agent
.config
.session_manager
.replace_conversation(&self.session_id, &self.messages)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid clobbering metadata when persisting interrupted CLI turns

Persisting self.messages here has the same stale-snapshot problem as the server path: local conversation state is driven by streamed events and does not observe metadata-only DB updates (e.g., agent-side update_message_metadata during tool-pair summarization in crates/goose/src/agents/agent.rs). On an interrupt, this can replace the stored conversation with an older metadata view and re-expose messages that were marked invisible.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm. we probably don't want make it complicated and the scenario of metadata being overwritten as an edge case is better than missing the full context for the interrupted turn.

.await
{
warn!("Failed to persist conversation on interruption: {}", e);
}

Ok(())
}

Expand Down
14 changes: 14 additions & 0 deletions crates/goose-server/src/routes/reply.rs
Original file line number Diff line number Diff line change
Expand Up @@ -336,6 +336,13 @@ pub async fn reply(
tokio::select! {
_ = task_cancel.cancelled() => {
tracing::info!("Agent task cancelled");
if let Err(e) = state
.session_manager()
.replace_conversation(&session_id, &all_messages)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Persist interruption state from session storage, not stream cache

This replace_conversation writes back all_messages, but that cache can be stale relative to the DB because the agent mutates existing message metadata in place via SessionManager::update_message_metadata (see crates/goose/src/agents/agent.rs around the tool-pair summarization path) without emitting AgentEvent::HistoryReplaced; this handler only updates all_messages on Message/HistoryReplaced. If a cancellation/disconnect happens after those metadata-only updates, this call can overwrite the persisted conversation with older metadata and effectively undo invisibility flags for prior tool messages.

Useful? React with 👍 / 👎.

.await
{
tracing::warn!("Failed to persist conversation on cancellation: {}", e);
}
break;
}
_ = heartbeat_interval.tick() => {
Expand Down Expand Up @@ -385,6 +392,13 @@ pub async fn reply(
}
Err(_) => {
if tx.is_closed() {
if let Err(e) = state
.session_manager()
.replace_conversation(&session_id, &all_messages)
.await
{
tracing::warn!("Failed to persist conversation on client disconnect: {}", e);
}
break;
}
continue;
Expand Down