From 399557255bbdb416cd6eda5999f0f5bd0aabd942 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Wed, 30 Sep 2026 02:36:15 +0530 Subject: [PATCH 1/2] refactor(todos): shorten tool description to reduce per-request cost The tool description was paying for redundant instructions on every request, so it was trimmed to state only the essential contract while leaving the "do the next step in the same response" rule to the host prompt that already carries it. Auto-committed-on: macbook Co-authored-by: Medulla --- crates/tinyagents-graph/src/todos/tool.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/tinyagents-graph/src/todos/tool.rs b/crates/tinyagents-graph/src/todos/tool.rs index 568fa4265..a4f69c9c1 100644 --- a/crates/tinyagents-graph/src/todos/tool.rs +++ b/crates/tinyagents-graph/src/todos/tool.rs @@ -23,15 +23,13 @@ use tinytools::{Tool, ToolPolicy, ToolResult, ToolRunContext, ToolSideEffects}; const TODO_TOOL_NAME: &str = "todo"; -const TODO_DESCRIPTION: &str = "Your todo list for this thread. Pass the complete list every \ - time; it replaces what was there. Use it for work with 3+ steps: write the steps up front, \ - keep exactly one `in_progress`, mark each `completed` only after its work has actually run \ - and its result is in this conversation. Writing the list is bookkeeping, not work: after \ - updating it, immediately carry out the next step, unless this update completes the final item. \ - Providers that cannot issue parallel tool calls may make that call in the next model turn, and \ - one update per response is enough. Omit \ - `todos` to read the current list. The list is bound \ - automatically to the current thread — do not pass a thread id."; +/// Paid on every request of every agent that carries the tool, so it states +/// the contract once and leaves the "do the next step in the same response" +/// rule to the host prompt that already carries it. +const TODO_DESCRIPTION: &str = "This thread's todo list for work with 3+ steps. Pass the \ + complete list each time (it replaces the old one), or omit `todos` to read it. Keep one \ + item `in_progress`; mark it `completed` only once its result is in the conversation, then \ + do the next step."; /// The `todo` harness [`Tool`], backed by a [`Store`](tinyagents_harness::store::Store). pub struct TodoTool { From 48a4cb2927c631c31c39f4278ed46cd4e17621b8 Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Wed, 30 Sep 2026 02:36:38 +0530 Subject: [PATCH 2/2] chore(todos): tighten tool description and align test assertions Shorten the tool description to be more concise while preserving the load-bearing rules, and update the test assertions to match the new wording. The description now explicitly states that writing the list is bookkeeping, not work, and clarifies the timing of the next step. Auto-committed-on: macbook Co-authored-by: Medulla --- crates/tinyagents-graph/src/todos/test.rs | 8 ++++---- crates/tinyagents-graph/src/todos/tool.rs | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/crates/tinyagents-graph/src/todos/test.rs b/crates/tinyagents-graph/src/todos/test.rs index e1b745abd..c8fb476d6 100644 --- a/crates/tinyagents-graph/src/todos/test.rs +++ b/crates/tinyagents-graph/src/todos/test.rs @@ -365,7 +365,7 @@ mod tool_tests { let tool = TodoTool::new(store()); let description = Tool::description(&tool); assert!( - description.contains("only after its work has actually run"), + description.contains("only after its work has run"), "an item is completed after its result exists: {description}" ); assert!( @@ -373,15 +373,15 @@ mod tool_tests { "writing the list is not the work: {description}" ); assert!( - description.contains("immediately carry out the next step"), + description.contains("do the next step"), "the model advances after bookkeeping: {description}" ); assert!( - description.contains("unless this update completes the final item"), + description.contains("unless the list is finished"), "a terminal completion does not require a nonexistent next step: {description}" ); assert!( - description.contains("next model turn"), + description.contains("next turn"), "sequential providers may advance on their next turn: {description}" ); } diff --git a/crates/tinyagents-graph/src/todos/tool.rs b/crates/tinyagents-graph/src/todos/tool.rs index a4f69c9c1..b2d48f03c 100644 --- a/crates/tinyagents-graph/src/todos/tool.rs +++ b/crates/tinyagents-graph/src/todos/tool.rs @@ -23,13 +23,15 @@ use tinytools::{Tool, ToolPolicy, ToolResult, ToolRunContext, ToolSideEffects}; const TODO_TOOL_NAME: &str = "todo"; -/// Paid on every request of every agent that carries the tool, so it states -/// the contract once and leaves the "do the next step in the same response" -/// rule to the host prompt that already carries it. -const TODO_DESCRIPTION: &str = "This thread's todo list for work with 3+ steps. Pass the \ - complete list each time (it replaces the old one), or omit `todos` to read it. Keep one \ - item `in_progress`; mark it `completed` only once its result is in the conversation, then \ - do the next step."; +/// Paid on every request of every agent that carries the tool, so each rule +/// is stated once, tersely. The rules themselves are load-bearing: see the +/// `description_states_…` test for the failure each one prevents. +const TODO_DESCRIPTION: &str = "This thread's todo list, for work with 3+ steps. Pass the \ + complete list each time (it replaces the old one); omit `todos` to read it. Keep one item \ + `in_progress`; mark an item `completed` only after its work has run and its result is in \ + the conversation. Writing the list is bookkeeping, not work: in the same response (or your \ + next turn, if you cannot call tools in parallel) do the next step, unless the list is \ + finished."; /// The `todo` harness [`Tool`], backed by a [`Store`](tinyagents_harness::store::Store). pub struct TodoTool {