feat: Support persisting paused todo lists to sessions so users can exit and resume paused todo sessions; Also fixed a bug so todo list pausing is only supported when being used in a session since it typically requires multi-turn communication
This commit is contained in:
7 files changed
+473
-33
No files matched your search
+5
-1
@@ -2681,7 +2681,7 @@ mod tests {
|
||||
FIXTURE_ANNOTATED_TEXT, FIXTURE_ANNOTATED_URI, FIXTURE_BLOB_BYTES, FIXTURE_BLOB_URI,
|
||||
FIXTURE_LOG_TEXT, FIXTURE_LOG_URI, FixtureServer, fixture_runtime,
|
||||
};
|
||||
use crate::config::{Agent, AgentConfig, AppConfig, AppState, WorkingMode};
|
||||
use crate::config::{Agent, AgentConfig, AppConfig, AppState, Session, WorkingMode};
|
||||
use crate::supervisor::escalation::{EscalationQueue, EscalationRequest};
|
||||
use crate::supervisor::mailbox::Inbox;
|
||||
use crate::supervisor::notification::{agent_notification, job_notification};
|
||||
@@ -5081,6 +5081,9 @@ mod tests {
|
||||
};
|
||||
let mut ctx = RequestContext::new(Arc::new(app), WorkingMode::Cmd);
|
||||
ctx.tool_scope.functions.append_todo_functions();
|
||||
// Pausing requires an active session (there is no cross-turn history
|
||||
// to resume from otherwise), so give the ctx one.
|
||||
ctx.session = Some(Session::default());
|
||||
|
||||
// A blank reason is rejected and does not pause.
|
||||
let out = run_async(call_with_args("todo__pause", json!({"reason": " "})).eval(&mut ctx))
|
||||
@@ -5130,6 +5133,7 @@ mod tests {
|
||||
};
|
||||
let mut ctx = RequestContext::new(Arc::new(app), WorkingMode::Cmd);
|
||||
ctx.tool_scope.functions.append_todo_functions();
|
||||
// session is deliberately None: the subagent reject must win over the session reject.
|
||||
ctx.self_agent_id = Some("agent_sisyphus_abc123".to_string());
|
||||
|
||||
let out = run_async(
|
||||
|
||||
+38
-3
@@ -92,9 +92,11 @@ pub fn todo_function_declarations() -> Vec<FunctionDeclaration> {
|
||||
incomplete todos intact. Use when you cannot proceed without user input \
|
||||
or a user-side action. NEVER mark unfinished todos as done just to stop \
|
||||
auto-continuation. Auto-continue resumes automatically on the user's \
|
||||
next message. Unavailable to subagents: they are driven to completion \
|
||||
autonomously — a subagent needing input must use a user__* tool, which \
|
||||
escalates to the root agent mid-turn and blocks until answered."
|
||||
next message. Requires an active session (the pause/resume cycle needs \
|
||||
cross-turn history). Unavailable to subagents: they are driven to \
|
||||
completion autonomously — a subagent needing input must use a user__* \
|
||||
tool, which escalates to the root agent mid-turn and blocks until \
|
||||
answered."
|
||||
.to_string(),
|
||||
parameters: JsonSchema {
|
||||
type_value: Some("object".to_string()),
|
||||
@@ -189,6 +191,15 @@ pub fn handle_todo_tool(ctx: &mut RequestContext, cmd_name: &str, args: &Value)
|
||||
}));
|
||||
}
|
||||
|
||||
if ctx.session.is_none() {
|
||||
return Ok(json!({
|
||||
"error": "todo__pause requires an active session: without one there is no \
|
||||
cross-turn history, so the user's answer would arrive with no \
|
||||
context to resume from. Ask the user your question directly in \
|
||||
your reply instead, then end your turn."
|
||||
}));
|
||||
}
|
||||
|
||||
let reason = args
|
||||
.get("reason")
|
||||
.and_then(Value::as_str)
|
||||
@@ -211,3 +222,27 @@ pub fn handle_todo_tool(ctx: &mut RequestContext, cmd_name: &str, args: &Value)
|
||||
_ => bail!("Unknown todo action: {action}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::config::{AppConfig, AppState, WorkingMode};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[test]
|
||||
fn pause_without_session_returns_teaching_error() {
|
||||
let mut app_state = AppState::test_default();
|
||||
app_state.config = Arc::new(AppConfig {
|
||||
auto_continue: true,
|
||||
..AppConfig::default()
|
||||
});
|
||||
let mut ctx = RequestContext::new(Arc::new(app_state), WorkingMode::Cmd);
|
||||
|
||||
let result =
|
||||
handle_todo_tool(&mut ctx, "todo__pause", &json!({"reason": "need input"})).unwrap();
|
||||
|
||||
let error = result["error"].as_str().unwrap();
|
||||
assert!(error.contains("requires an active session"));
|
||||
assert!(ctx.auto_continue_paused.is_none());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user