Skip to content

fix: maintain conversation history across ACP session/prompt turns#3372

Open
xulongzhe wants to merge 2 commits into
Hmbown:mainfrom
xulongzhe:fix/acp-multi-turn-context
Open

fix: maintain conversation history across ACP session/prompt turns#3372
xulongzhe wants to merge 2 commits into
Hmbown:mainfrom
xulongzhe:fix/acp-multi-turn-context

Conversation

@xulongzhe

@xulongzhe xulongzhe commented Jun 22, 2026

Copy link
Copy Markdown

Summary

Fix multi-turn conversation context loss in ACP server. The AcpSession struct only stored cwd with no conversation history, causing run_prompt() to always construct a single-message request. Each session/prompt call was treated as an independent conversation, losing all prior context.

Changes:

  • Add messages: Vec<Message> to AcpSession for per-session conversation history
  • Append user message before LLM call, assistant response after
  • Pass full conversation history to the LLM instead of single-message request
  • Add Debug derive to AcpError for test compatibility

Reproduction:

  1. Start ACP session: session/new
  2. Prompt: "1+1等于几?只回答数字" → LLM answers "2"
  3. Prompt: "再加一等于几?只回答数字" → LLM answers "2" ✗ (should be "3")

Testing

  • cargo fmt --all -- --check
  • cargo clippy --workspace --all-targets --all-features
  • cargo test --workspace --all-features

3-turn arithmetic chain integration test (1+1→2, add one→3, add one→4):

Turn Prompt Before fix After fix
1 1+1=? 2 ✓ 2 ✓
2 add one 2 ✗ 3 ✓
3 add one 2 ✗ 4 ✓

Unit tests added in acp_server.rs:

  • new_session_starts_with_empty_messages
  • prompt_appends_user_and_assistant_messages_to_history
  • different_sessions_have_independent_history

Checklist

  • Added or updated tests where relevant
  • Updated docs or comments as needed
  • Verified TUI behavior manually if UI changes
  • Harvested/co-authored credit uses a GitHub numeric noreply address

@xulongzhe xulongzhe requested a review from Hmbown as a code owner June 22, 2026 02:37

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@github-actions

Copy link
Copy Markdown

Thanks @xulongzhe for taking the time to contribute.

This repository is observing a maintainer-managed PR intake gate in dry-run mode, so this pull request is staying open. This note helps maintainers prepare the allowlist before any enforcement is considered.

Please read CONTRIBUTING.md for the expected contribution shape. A maintainer can grant recurring PR access by commenting /lgtm on a pull request.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Code Review

This pull request introduces session-based message history tracking in AcpServer by adding a messages list to AcpSession. This allows sending the full conversation history to the LLM instead of just the single latest prompt. The feedback suggests combining two consecutive lookups of the session in the sessions map into a single mutable lookup to avoid redundant map queries and improve performance.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread crates/tui/src/acp_server.rs Outdated
Comment on lines +166 to +188
// Append user message to session history
{
let session = self
.sessions
.get_mut(&session_id)
.ok_or_else(|| AcpError::invalid_params("unknown sessionId"))?;
session.messages.push(Message {
role: "user".to_string(),
content: vec![ContentBlock::Text {
text: prompt,
cache_control: None,
}],
});
}

// Clone messages for the LLM call (avoids borrowing self across await)
let (messages, cwd) = {
let session = self
.sessions
.get(&session_id)
.ok_or_else(|| AcpError::invalid_params("unknown sessionId"))?;
(session.messages.clone(), session.cwd.clone())
};

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

medium

The session is looked up twice in the sessions map: first mutably to append the user message, and then immutably to clone the messages and cwd. These two lookups can be combined into a single mutable lookup to avoid redundant map queries and improve performance.

Suggested change
// Append user message to session history
{
let session = self
.sessions
.get_mut(&session_id)
.ok_or_else(|| AcpError::invalid_params("unknown sessionId"))?;
session.messages.push(Message {
role: "user".to_string(),
content: vec![ContentBlock::Text {
text: prompt,
cache_control: None,
}],
});
}
// Clone messages for the LLM call (avoids borrowing self across await)
let (messages, cwd) = {
let session = self
.sessions
.get(&session_id)
.ok_or_else(|| AcpError::invalid_params("unknown sessionId"))?;
(session.messages.clone(), session.cwd.clone())
};
// Append user message to session history and clone for the LLM call (avoids borrowing self across await)
let (messages, cwd) = {
let session = self
.sessions
.get_mut(&session_id)
.ok_or_else(|| AcpError::invalid_params("unknown sessionId"))?;
session.messages.push(Message {
role: "user".to_string(),
content: vec![ContentBlock::Text {
text: prompt,
cache_control: None,
}],
});
(session.messages.clone(), session.cwd.clone())
};

- Add messages: Vec<Message> to AcpSession for per-session history
- Append user message before LLM call, assistant response after
- Pass full conversation history to LLM instead of single-message request
- Add unit tests for session history accumulation
- Add Debug derive to AcpError for test compatibility
- Run cargo fmt
@xulongzhe xulongzhe force-pushed the fix/acp-multi-turn-context branch from cc3a373 to a37038d Compare June 22, 2026 02:54

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

Merge get_mut + get into a single get_mut in prompt(), as suggested by
Gemini Code Assist review.

@greptile-apps greptile-apps Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@Hmbown

Hmbown commented Jun 22, 2026

Copy link
Copy Markdown
Owner

Thanks @xulongzhe — I carried this into the v0.8.64 integration branch with your two commits cherry-picked and original authorship preserved:

  • 9d2950fe5 fix: maintain conversation history across ACP session/prompt turns
  • 37c5d19cd refactor: combine two session map lookups into one per review feedback

Verified on the integration branch with:

  • cargo test -p codewhale-tui --bin codewhale-tui --locked acp_server -- --nocapture
  • cargo fmt --all -- --check
  • git diff --check
  • python3 scripts/check-coauthor-trailers.py --author-map .github/AUTHOR_MAP --range HEAD~2..HEAD --check-authors

I am keeping this PR open until the integration branch lands so the public repo state stays accurate. Appreciate the focused ACP repro and fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants