Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
e5dc709
feat: wire retry and edit buttons on user messages
tellaho Apr 14, 2026
71a9323
fix: sync ChatInput text state when initialValue prop changes
tellaho Apr 14, 2026
47d1154
fix: focus textarea when entering edit mode
tellaho Apr 14, 2026
5eef949
feat: inline edit UX — edit message in-place with Save/Cancel
tellaho Apr 14, 2026
7486ec5
feat: full-width inline edit with hinted background and info message
tellaho Apr 14, 2026
0bdae1e
fix: stale closure, focus churn, dead draft write, dead i18n keys
tellaho Apr 14, 2026
4ece14d
style: user bubble with bg-muted on content div, max-w-640px, no avatar
tellaho Apr 14, 2026
b7dcb1a
refactor: replace CSS group-hover with Radix HoverCard for message ac…
tellaho Apr 14, 2026
5d6e8bf
fix: strip all visual chrome from HoverCard actions, add gap for overlap
tellaho Apr 14, 2026
536d623
fix: restore Radix open/close animations on HoverCard actions
tellaho Apr 14, 2026
18690e7
fix: add sideOffset to HoverCard actions for breathing room
tellaho Apr 14, 2026
6a8567e
test: add inline edit tests and fix hover test for HoverCard
tellaho Apr 14, 2026
553de5b
fix: guard handleSaveEdit against vanished messages
tellaho Apr 14, 2026
e5061bc
cleanup: HoverCard bare variant, dedup resize, gate edit state, es lo…
tellaho Apr 14, 2026
2348e1e
fix: increase bottom padding so last message hover actions aren't cli…
tellaho Apr 14, 2026
6456a76
fix: lower z-index on bare HoverCard so popovers/menus win
tellaho Apr 14, 2026
2eecade
style: restyle inline edit action bar — default buttons, flipped layout
tellaho Apr 14, 2026
79b2836
style: even padding on user message bubble
tellaho Apr 14, 2026
4f68bb6
fix: retry/edit preserve attachments & persona, remove MessageBranch …
tellaho Apr 14, 2026
143ab86
fix: address 3 review blockers — unify deferred sends, gate retry, na…
tellaho Apr 15, 2026
cbf6732
fix: preserve pathless browser-uploaded file attachments on retry/edit
tellaho Apr 15, 2026
913932c
fix: update retry/edit tests to match new acpSendMessage signature (n…
tellaho Apr 16, 2026
a5d12c2
feat: truncate backend conversation on edit/retry via _meta.truncate_…
tellaho Apr 16, 2026
39c6149
feat: wire truncate_before_message_id through frontend for edit/retry
tellaho Apr 17, 2026
def6cca
fix: sync message IDs between frontend and backend for edit/retry tru…
tellaho Apr 17, 2026
afa1c06
chore: downgrade truncation log from info to debug
tellaho Apr 17, 2026
c5aa09f
test: add unit tests for ThreadManager.truncate_from_message
tellaho Apr 17, 2026
87bfe5a
fix: IME composition guard and queued-send race in edit flow
tellaho Apr 17, 2026
4823251
fix: atomic truncation, precise boundary, and snapshot+restore
tellaho Apr 17, 2026
103865b
fix: use .catch() instead of try/catch for async snapshot restore
tellaho Apr 17, 2026
c7e96ed
fix: guard Escape key against IME composition in inline edit
tellaho Apr 17, 2026
becf37f
fix: sync local message ID to backend via acpSendMessage
tellaho Apr 17, 2026
da05d60
fix: separate user message ID from assistant notification preset ID
tellaho Apr 20, 2026
6e1d68d
debug: add tracing to on_prompt truncation path
tellaho Apr 20, 2026
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
70 changes: 62 additions & 8 deletions crates/goose-acp/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1523,12 +1523,17 @@ impl GooseAcpAgent {
continue;
}

let msg_id = message.id.clone();

for content_item in &message.content {
match content_item {
MessageContent::Text(text) => {
let chunk = ContentChunk::new(ContentBlock::Text(TextContent::new(
let mut chunk = ContentChunk::new(ContentBlock::Text(TextContent::new(
text.text.clone(),
)));
if let Some(ref id) = msg_id {
chunk = chunk.message_id(id.clone());
}
let update = match message.role {
Role::User => SessionUpdate::UserMessageChunk(chunk),
Role::Assistant => SessionUpdate::AgentMessageChunk(chunk),
Expand Down Expand Up @@ -1691,14 +1696,63 @@ impl GooseAcpAgent {
.get_session_agent(&thread_id, Some(cancel_token.clone()))
.await?;

let user_message = self.convert_acp_prompt_to_message(args.prompt);
let mut user_message = self.convert_acp_prompt_to_message(args.prompt);
if let Some(client_msg_id) = args.message_id {
user_message.id = Some(client_msg_id);
}

self.thread_manager
.append_message(&thread_id, Some(&internal_session_id), &user_message)
.await
.map_err(|e| {
sacp::Error::internal_error().data(format!("Failed to persist message: {}", e))
})?;
// Handle edit/retry: atomically truncate + append in one transaction,
// or just append for normal prompts.
tracing::warn!(
has_meta = args.meta.is_some(),
meta_keys = ?args.meta.as_ref().map(|m| m.keys().collect::<Vec<_>>()),
user_msg_id = ?user_message.id,
"EDIT/RETRY: on_prompt received"
Comment on lines +1706 to +1710
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 Downgrade edit/retry diagnostics from warn level

These tracing::warn! statements execute on normal prompt flow, so successful edit/retry sends are emitted as warnings and can flood warning-level logs/alerts in production. This also conflicts with /workspace/goose/AGENTS.md (Logging: ... don't add more unless for errors or security events). Please move these to debug/trace (or remove them) and keep warn for actual failure conditions.

Useful? React with 👍 / 👎.

);
let truncate_id = args
.meta
.as_ref()
.and_then(|m| m.get("truncate_before_message_id"))
.and_then(|v| v.as_str())
.map(String::from);

if let Some(ref truncate_id) = truncate_id {
tracing::warn!(
thread_id = %thread_id,
session_id = %internal_session_id,
truncate_id = %truncate_id,
user_msg_id = ?user_message.id,
"EDIT/RETRY: attempting truncation"
);
let (_, rows_deleted) = self
.thread_manager
.truncate_and_append(
&thread_id,
truncate_id,
&internal_session_id,
&user_message,
)
.await
Comment thread
tellaho marked this conversation as resolved.
.map_err(|e| {
sacp::Error::internal_error()
.data(format!("Failed to truncate and append: {}", e))
})?;

tracing::warn!(
thread_id = %thread_id,
truncate_id = %truncate_id,
rows_deleted = rows_deleted,
"EDIT/RETRY: truncation complete"
);
} else {
self.thread_manager
.append_message(&thread_id, Some(&internal_session_id), &user_message)
.await
.map_err(|e| {
sacp::Error::internal_error()
.data(format!("Failed to persist message: {}", e))
})?;
}

let session_config = SessionConfig {
id: internal_session_id.clone(),
Expand Down
16 changes: 11 additions & 5 deletions crates/goose/src/session/session_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1590,11 +1590,17 @@ impl SessionStorage {

async fn truncate_conversation(&self, session_id: &str, timestamp: i64) -> Result<()> {
let pool = self.pool().await?;
sqlx::query("DELETE FROM messages WHERE session_id = ? AND created_timestamp >= ?")
.bind(session_id)
.bind(timestamp)
.execute(pool)
.await?;
// Use autoincrement id for precise ordering — timestamps have only
// second resolution and multiple messages can share the same second.
sqlx::query(
"DELETE FROM messages WHERE session_id = ? AND id >= \
(SELECT id FROM messages WHERE session_id = ? AND created_timestamp >= ? ORDER BY id ASC LIMIT 1)",
)
.bind(session_id)
.bind(session_id)
.bind(timestamp)
.execute(pool)
.await?;

Ok(())
}
Expand Down
Loading
Loading