feat: Added todo__clear function to the todo system and updated REPL commands to have a .clear todo as well for significant changes in agent direction
This commit is contained in:
+2
-1
@@ -467,11 +467,12 @@ inject_todo_instructions: true # Include the default todo instructions into pr
|
|||||||
|
|
||||||
### How It Works
|
### How It Works
|
||||||
|
|
||||||
1. When `inject_todo_instructions` is enabled, agents receive instructions on using four built-in tools:
|
1. When `inject_todo_instructions` is enabled, agents receive instructions on using five built-in tools:
|
||||||
- `todo__init`: Initialize a todo list with a goal
|
- `todo__init`: Initialize a todo list with a goal
|
||||||
- `todo__add`: Add a task to the list
|
- `todo__add`: Add a task to the list
|
||||||
- `todo__done`: Mark a task complete
|
- `todo__done`: Mark a task complete
|
||||||
- `todo__list`: View current todo state
|
- `todo__list`: View current todo state
|
||||||
|
- `todo__clear`: Clear the entire todo list and reset the goal
|
||||||
|
|
||||||
These instructions are a reasonable default that detail how to use Loki's To-Do System. If you wish,
|
These instructions are a reasonable default that detail how to use Loki's To-Do System. If you wish,
|
||||||
you can disable the injection of the default instructions and specify your own instructions for how
|
you can disable the injection of the default instructions and specify your own instructions for how
|
||||||
|
|||||||
+2
-1
@@ -121,9 +121,10 @@ Loki lets you build OpenAI GPT-style agents. The following commands let you inte
|
|||||||
Loki:
|
Loki:
|
||||||
|
|
||||||
| Command | Description |
|
| Command | Description |
|
||||||
|----------------------|------------------------------------------------------------|
|
|----------------------|-----------------------------------------------------------------------------------------------|
|
||||||
| `.agent` | Use an agent |
|
| `.agent` | Use an agent |
|
||||||
| `.starter` | Display and use conversation starters for the active agent |
|
| `.starter` | Display and use conversation starters for the active agent |
|
||||||
|
| `.clear todo` | Clear the todo list and stop auto-continuation (requires `auto_continue: true` on the agent) |
|
||||||
| `.edit agent-config` | Open the agent configuration in your preferred text editor |
|
| `.edit agent-config` | Open the agent configuration in your preferred text editor |
|
||||||
| `.info agent` | Display information about the active agent |
|
| `.info agent` | Display information about the active agent |
|
||||||
| `.exit agent` | Leave the active agent |
|
| `.exit agent` | Leave the active agent |
|
||||||
|
|||||||
@@ -117,6 +117,22 @@ Display the current todo list with status of each item.
|
|||||||
|
|
||||||
**Returns:** The full todo list with goal, progress, and item statuses
|
**Returns:** The full todo list with goal, progress, and item statuses
|
||||||
|
|
||||||
|
### `todo__clear`
|
||||||
|
Clear the entire todo list and reset the goal. Use when the current task has been canceled or invalidated.
|
||||||
|
|
||||||
|
**Parameters:** None
|
||||||
|
|
||||||
|
**Returns:** Confirmation that the todo list was cleared
|
||||||
|
|
||||||
|
### REPL Command: `.clear todo`
|
||||||
|
You can also clear the todo list manually from the REPL by typing `.clear todo`. This is useful when:
|
||||||
|
- You gave a custom response that changes or cancels the current task
|
||||||
|
- The agent is stuck in auto-continuation with stale todos
|
||||||
|
- You want to start fresh without leaving and re-entering the agent
|
||||||
|
|
||||||
|
**Note:** This command is only available when an agent with `auto_continue: true` is active. If the todo
|
||||||
|
system isn't enabled for the current agent, the command will display an error message.
|
||||||
|
|
||||||
## Auto-Continuation
|
## Auto-Continuation
|
||||||
When `auto_continue` is enabled, Loki automatically sends a continuation prompt if:
|
When `auto_continue` is enabled, Loki automatically sends a continuation prompt if:
|
||||||
|
|
||||||
|
|||||||
@@ -476,6 +476,11 @@ impl Agent {
|
|||||||
self.todo_list.mark_done(id)
|
self.todo_list.mark_done(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear_todo_list(&mut self) {
|
||||||
|
self.todo_list.clear();
|
||||||
|
self.reset_continuation();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn continuation_prompt(&self) -> String {
|
pub fn continuation_prompt(&self) -> String {
|
||||||
self.config.continuation_prompt.clone().unwrap_or_else(|| {
|
self.config.continuation_prompt.clone().unwrap_or_else(|| {
|
||||||
formatdoc! {"
|
formatdoc! {"
|
||||||
|
|||||||
@@ -7,10 +7,12 @@ pub(in crate::config) const DEFAULT_TODO_INSTRUCTIONS: &str = indoc! {"
|
|||||||
- `todo__add`: Add individual tasks. Add all planned steps before starting work.
|
- `todo__add`: Add individual tasks. Add all planned steps before starting work.
|
||||||
- `todo__done`: Mark a task done by id. Call this immediately after completing each step.
|
- `todo__done`: Mark a task done by id. Call this immediately after completing each step.
|
||||||
- `todo__list`: Show the current todo list.
|
- `todo__list`: Show the current todo list.
|
||||||
|
- `todo__clear`: Clear the entire todo list and reset the goal. Use when the user cancels or changes direction.
|
||||||
|
|
||||||
RULES:
|
RULES:
|
||||||
- Always create a todo list before starting work.
|
- Always create a todo list before starting work.
|
||||||
- Mark each task done as soon as you finish it; do not batch.
|
- Mark each task done as soon as you finish it; do not batch.
|
||||||
|
- If the user cancels the current task or changes direction, call `todo__clear` immediately.
|
||||||
- If you stop with incomplete tasks, the system will automatically prompt you to continue."
|
- If you stop with incomplete tasks, the system will automatically prompt you to continue."
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,11 @@ impl TodoList {
|
|||||||
self.todos.is_empty()
|
self.todos.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.goal.clear();
|
||||||
|
self.todos.clear();
|
||||||
|
}
|
||||||
|
|
||||||
pub fn render_for_model(&self) -> String {
|
pub fn render_for_model(&self) -> String {
|
||||||
let mut lines = Vec::new();
|
let mut lines = Vec::new();
|
||||||
if !self.goal.is_empty() {
|
if !self.goal.is_empty() {
|
||||||
@@ -149,6 +154,21 @@ mod tests {
|
|||||||
assert!(rendered.contains("○ 2. Map"));
|
assert!(rendered.contains("○ 2. Map"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_clear() {
|
||||||
|
let mut list = TodoList::new("Some goal");
|
||||||
|
list.add("Task 1");
|
||||||
|
list.add("Task 2");
|
||||||
|
list.mark_done(1);
|
||||||
|
assert!(!list.is_empty());
|
||||||
|
|
||||||
|
list.clear();
|
||||||
|
assert!(list.is_empty());
|
||||||
|
assert!(list.goal.is_empty());
|
||||||
|
assert_eq!(list.todos.len(), 0);
|
||||||
|
assert!(!list.has_incomplete());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serialization_roundtrip() {
|
fn test_serialization_roundtrip() {
|
||||||
let mut list = TodoList::new("Roundtrip");
|
let mut list = TodoList::new("Roundtrip");
|
||||||
|
|||||||
@@ -76,6 +76,16 @@ pub fn todo_function_declarations() -> Vec<FunctionDeclaration> {
|
|||||||
},
|
},
|
||||||
agent: false,
|
agent: false,
|
||||||
},
|
},
|
||||||
|
FunctionDeclaration {
|
||||||
|
name: format!("{TODO_FUNCTION_PREFIX}clear"),
|
||||||
|
description: "Clear the entire todo list and reset the goal. Use when the current task has been canceled or invalidated.".to_string(),
|
||||||
|
parameters: JsonSchema {
|
||||||
|
type_value: Some("object".to_string()),
|
||||||
|
properties: Some(IndexMap::new()),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
agent: false,
|
||||||
|
},
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,6 +166,17 @@ pub fn handle_todo_tool(config: &GlobalConfig, cmd_name: &str, args: &Value) ->
|
|||||||
None => bail!("No active agent"),
|
None => bail!("No active agent"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
"clear" => {
|
||||||
|
let mut cfg = config.write();
|
||||||
|
let agent = cfg.agent.as_mut();
|
||||||
|
match agent {
|
||||||
|
Some(agent) => {
|
||||||
|
agent.clear_todo_list();
|
||||||
|
Ok(json!({"status": "ok", "message": "Todo list cleared"}))
|
||||||
|
}
|
||||||
|
None => bail!("No active agent"),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => bail!("Unknown todo action: {action}"),
|
_ => bail!("Unknown todo action: {action}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-1
@@ -33,7 +33,7 @@ use std::{env, mem, process};
|
|||||||
|
|
||||||
const MENU_NAME: &str = "completion_menu";
|
const MENU_NAME: &str = "completion_menu";
|
||||||
|
|
||||||
static REPL_COMMANDS: LazyLock<[ReplCommand; 38]> = LazyLock::new(|| {
|
static REPL_COMMANDS: LazyLock<[ReplCommand; 39]> = LazyLock::new(|| {
|
||||||
[
|
[
|
||||||
ReplCommand::new(".help", "Show this help guide", AssertState::pass()),
|
ReplCommand::new(".help", "Show this help guide", AssertState::pass()),
|
||||||
ReplCommand::new(".info", "Show system info", AssertState::pass()),
|
ReplCommand::new(".info", "Show system info", AssertState::pass()),
|
||||||
@@ -137,6 +137,11 @@ static REPL_COMMANDS: LazyLock<[ReplCommand; 38]> = LazyLock::new(|| {
|
|||||||
"Leave agent",
|
"Leave agent",
|
||||||
AssertState::True(StateFlags::AGENT),
|
AssertState::True(StateFlags::AGENT),
|
||||||
),
|
),
|
||||||
|
ReplCommand::new(
|
||||||
|
".clear todo",
|
||||||
|
"Clear the todo list and stop auto-continuation",
|
||||||
|
AssertState::True(StateFlags::AGENT),
|
||||||
|
),
|
||||||
ReplCommand::new(
|
ReplCommand::new(
|
||||||
".rag",
|
".rag",
|
||||||
"Initialize or access RAG",
|
"Initialize or access RAG",
|
||||||
@@ -804,6 +809,25 @@ pub async fn run_repl_command(
|
|||||||
Some("messages") => {
|
Some("messages") => {
|
||||||
bail!("Use '.empty session' instead");
|
bail!("Use '.empty session' instead");
|
||||||
}
|
}
|
||||||
|
Some("todo") => {
|
||||||
|
let mut cfg = config.write();
|
||||||
|
match cfg.agent.as_mut() {
|
||||||
|
Some(agent) => {
|
||||||
|
if !agent.auto_continue_enabled() {
|
||||||
|
bail!(
|
||||||
|
"The todo system is not enabled for this agent. Set 'auto_continue: true' in the agent's config.yaml to enable it."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if agent.todo_list().is_empty() {
|
||||||
|
println!("Todo list is already empty.");
|
||||||
|
} else {
|
||||||
|
agent.clear_todo_list();
|
||||||
|
println!("Todo list cleared.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => bail!("No active agent"),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unknown_command()?,
|
_ => unknown_command()?,
|
||||||
},
|
},
|
||||||
".vault" => match split_first_arg(args) {
|
".vault" => match split_first_arg(args) {
|
||||||
|
|||||||
Reference in New Issue
Block a user