fix(tui): /compact <instructions> reach the compaction request
The queued /compact command drained into Effect::Compact with only the session id, so the instructions typed after the command never reached the shell's compaction prompt (which already accepts userContext). The effect carries the parsed instructions, trimmed so an edited queue row with leading whitespace still counts. Ported from upstream 1.0.22 (grok-build dispatch/queue.rs). Claude-Session: https://claude.ai/code/session_01RUqV8HVGXcAETyYbZ2tPQ4
This commit is contained in:
1 parent
4512df79e6
commit
584d0fb77e
4 files changed
+46
-6
No files matched your search
@@ -1431,6 +1431,8 @@ pub enum Effect {
|
||||
Compact {
|
||||
agent_id: AgentId,
|
||||
session_id: acp::SessionId,
|
||||
/// `/compact <instructions>`, forwarded as `userContext`.
|
||||
user_context: Option<String>,
|
||||
},
|
||||
/// Kill a background task.
|
||||
KillBgTask {
|
||||
|
||||
@@ -162,6 +162,12 @@ fn format_cron_prompt(prompt: &str, task_id: &str, human_schedule: &str) -> Stri
|
||||
kigi_tools::reminders::format_scheduled_task_prompt(prompt, task_id, human_schedule)
|
||||
}
|
||||
|
||||
/// `/compact <instructions>` text from a queued command; a queue edit may leave leading whitespace.
|
||||
pub(super) fn compact_user_context(text: &str) -> Option<String> {
|
||||
let inv = crate::slash::parse_invocation(text.trim_start())?;
|
||||
let args = inv.args.trim();
|
||||
(inv.token == "compact" && !args.is_empty()).then(|| args.to_string())
|
||||
}
|
||||
/// Try to send the next queued entry (prompt, command, bash, or cron) if the agent is idle.
|
||||
///
|
||||
/// Called after enqueue operations and task completions to advance the queue.
|
||||
@@ -392,10 +398,12 @@ pub(crate) fn maybe_drain_queue(agent: &mut AgentView) -> Vec<Effect> {
|
||||
agent.end_work_announced = false;
|
||||
agent.session.start_command(AgentCommand::Compact);
|
||||
agent.turn_started_at = Some(Instant::now());
|
||||
let user_context = compact_user_context(&queued.text);
|
||||
|
||||
vec![Effect::Compact {
|
||||
agent_id,
|
||||
session_id,
|
||||
user_context,
|
||||
}]
|
||||
}
|
||||
QueueEntryKind::BashCommand => {
|
||||
|
||||
@@ -1810,7 +1810,13 @@ fn slash_compact_enqueues_command() {
|
||||
let effects = dispatch(Action::SendPrompt("/compact".into()), &mut app);
|
||||
// /compact enqueues as Command and drains immediately (agent was idle).
|
||||
assert_eq!(effects.len(), 1);
|
||||
assert!(matches!(&effects[0], Effect::Compact { .. }));
|
||||
assert!(matches!(
|
||||
&effects[0],
|
||||
Effect::Compact {
|
||||
user_context: None,
|
||||
..
|
||||
}
|
||||
));
|
||||
// Prompt should be cleared.
|
||||
assert!(app.agents[&id].prompt.text().is_empty());
|
||||
}
|
||||
@@ -1853,6 +1859,19 @@ fn palette_dispatch_preserves_prompt_draft() {
|
||||
);
|
||||
}
|
||||
|
||||
/// An edited queue row keeps its text verbatim, so leading whitespace must not drop the instructions.
|
||||
#[test]
|
||||
fn compact_user_context_survives_leading_whitespace_from_a_queue_edit() {
|
||||
use crate::app::dispatch::queue::compact_user_context;
|
||||
assert_eq!(
|
||||
compact_user_context(" /compact focus on auth").as_deref(),
|
||||
Some("focus on auth")
|
||||
);
|
||||
assert_eq!(compact_user_context("\n/compact x ").as_deref(), Some("x"));
|
||||
assert_eq!(compact_user_context("/compact"), None);
|
||||
assert_eq!(compact_user_context("/other args"), None);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn slash_compact_with_context_enqueues_command() {
|
||||
let mut app = test_app_with_agent();
|
||||
@@ -1861,7 +1880,13 @@ fn slash_compact_with_context_enqueues_command() {
|
||||
&mut app,
|
||||
);
|
||||
assert_eq!(effects.len(), 1);
|
||||
assert!(matches!(&effects[0], Effect::Compact { .. }));
|
||||
assert!(matches!(
|
||||
&effects[0],
|
||||
Effect::Compact {
|
||||
user_context: Some(ctx),
|
||||
..
|
||||
} if ctx == "focus on auth"
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -1388,13 +1388,18 @@ pub(crate) fn execute(
|
||||
}
|
||||
});
|
||||
}
|
||||
Effect::Compact { agent_id, session_id } => {
|
||||
Effect::Compact {
|
||||
agent_id,
|
||||
session_id,
|
||||
user_context,
|
||||
} => {
|
||||
let tx = acp_tx.clone();
|
||||
tasks
|
||||
.spawn(async move {
|
||||
let params = serde_json::json!(
|
||||
{ "sessionId" : session_id.0.to_string(), }
|
||||
);
|
||||
let params = serde_json::json!({
|
||||
"sessionId": session_id.0.to_string(),
|
||||
"userContext": user_context,
|
||||
});
|
||||
let req = acp::ExtRequest::new(
|
||||
"kigi/compact_conversation",
|
||||
serde_json::value::to_raw_value(¶ms)
|
||||
|
||||
Reference in new issue
Block a user