From 8fc77af685007cb470ce606fd57b063d8664eafc Mon Sep 17 00:00:00 2001 From: Kevin Lin Date: Fri, 20 Feb 2026 16:14:48 -0800 Subject: [PATCH] fix(memory): standardize tool parameter names (#9552) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix(memory): standardize tool parameter names Use old_string/new_string across memory edit tools, docs, tests, and starter kits to avoid mismatched parameter names. 👾 Generated with [Letta Code](https://letta.com) Co-Authored-By: Letta EOF ) --- fern/pages/agents/base_tools.mdx | 150 ++++++++++++++++++ letta/functions/function_sets/base.py | 78 ++++----- .../tool_executor/core_tool_executor.py | 96 ++++++----- tests/test_agent_files/deep-thought.af | 12 +- tests/test_agent_files/max_messages.af | 12 +- tests/test_agent_files/test_agent.af | 8 +- .../test_agent_with_files_and_sources.af | 12 +- ...sic_agent_with_blocks_tools_messages_v2.af | 20 +-- tests/test_sdk_client.py | 2 +- 9 files changed, 278 insertions(+), 112 deletions(-) create mode 100644 fern/pages/agents/base_tools.mdx diff --git a/fern/pages/agents/base_tools.mdx b/fern/pages/agents/base_tools.mdx new file mode 100644 index 00000000..ef33d926 --- /dev/null +++ b/fern/pages/agents/base_tools.mdx @@ -0,0 +1,150 @@ +--- +title: Base Tools +subtitle: Built-in tools for memory management and user communication +slug: guides/agents/base-tools +--- + +Base tools are built-in tools that enable memory management, user communication, and access to conversation history and archival storage. + +## Available Base Tools + +| Tool | Purpose | +|------|---------| +| `memory_insert` | Insert text into a memory block | +| `memory_replace` | Replace specific text in a memory block | +| `memory_rethink` | Completely rewrite a memory block | +| `memory_finish_edits` | Signal completion of memory editing | +| `conversation_search` | Search prior conversation history | +| `archival_memory_insert` | Add content to archival memory | +| `archival_memory_search` | Search archival memory | +| `send_message` | Send a message to the user (legacy architectures only) | + +## Memory Block Editing + +Memory blocks are editable sections in the agent's context window. These tools let agents update their own memory. + +See the [Memory Blocks guide](/guides/agents/memory-blocks) for more about how memory blocks work. + +### memory_insert + +Insert text at a specific line in a memory block. + +**Parameters:** +- `label`: Which memory block to edit +- `new_string`: Text to insert +- `insert_line`: Line number (0 for beginning, -1 for end) + +**Common uses:** +- Add new information to the end of a block +- Insert context at the beginning +- Add items to a list + +### memory_replace + +Replace specific text in a memory block. + +**Parameters:** +- `label`: Which memory block to edit +- `old_string`: Exact text to find and replace +- `new_string`: Replacement text + +**Common uses:** +- Update outdated information +- Fix typos or errors +- Delete text (by replacing with empty string) + +**Important:** The `old_string` must match exactly, including whitespace. If it appears multiple times, the tool will error. + +### memory_rethink + +Completely rewrite a memory block's contents. + +**Parameters:** +- `label`: Which memory block to rewrite +- `new_memory`: Complete new contents + +**When to use:** +- Condensing cluttered information +- Major reorganization +- Combining multiple pieces of information + +**When not to use:** +- Adding one line (use `memory_insert`) +- Changing specific text (use `memory_replace`) + +### memory_finish_edits + +Signals that memory editing is complete. + +**Parameters:** None + +Some agent architectures use this to mark the end of a memory update cycle. + +## Recall Memory + +### conversation_search + +Search prior conversation history using both text matching and semantic similarity. + +**Parameters:** +- `query`: What to search for +- `roles`: Optional filter by message role (user, assistant, tool) +- `limit`: Maximum number of results +- `start_date`, `end_date`: ISO 8601 date/datetime filters (inclusive) + +**Returns:** +Matching messages with role and content, ordered by relevance. + +**Example queries:** +- "What did the user say about deployment?" +- "Find previous responses about error handling" +- "Search tool outputs from last week" + +## Archival Memory + +Archival memory stores information long-term outside the context window. See the [Archival Memory documentation](/guides/agents/archival-memory) for details. + +### archival_memory_insert + +Add content to archival memory for long-term storage. + +**Parameters:** +- `content`: Text to store +- `tags`: Optional tags for organization + +**Common uses:** +- Storing reference information for later +- Saving important context that doesn't fit in memory blocks +- Building a knowledge base over time + +### archival_memory_search + +Search archival memory using semantic (embedding-based) search. + +**Parameters:** +- `query`: What to search for semantically +- `tags`: Optional tag filters +- `tag_match_mode`: "any" or "all" for tag matching +- `top_k`: Maximum results +- `start_datetime`, `end_datetime`: ISO 8601 filters (inclusive) + +**Returns:** +Matching passages with timestamps and content, ordered by semantic similarity. + +## Deprecated Tools + +These tools are still available but deprecated: + +| Tool | Use Instead | +|------|-------------| +| `send_message` | Agent responses (no tool needed). See [legacy architectures](/guides/legacy/memgpt_agents_legacy) | +| `core_memory_append` | `memory_insert` with `insert_line=-1` | +| `core_memory_replace` | `memory_replace` | + +## Related Documentation + +- [Memory Blocks](/guides/agents/memory-blocks) +- [Archival Memory](/guides/agents/archival-memory) +- [Utilities](/guides/agents/prebuilt-tools) +- [Multi-Agent Tools](/guides/agents/multi-agent) +- [Custom Tools](/guides/agents/custom-tools) diff --git a/letta/functions/function_sets/base.py b/letta/functions/function_sets/base.py index 4e866d18..56e79183 100644 --- a/letta/functions/function_sets/base.py +++ b/letta/functions/function_sets/base.py @@ -308,116 +308,118 @@ SNIPPET_LINES: int = 4 # Based off of: https://github.com/anthropics/anthropic-quickstarts/blob/main/computer-use-demo/computer_use_demo/tools/edit.py?ref=musings.yasyf.com#L154 -def memory_replace(agent_state: "AgentState", label: str, old_str: str, new_str: str) -> str: # type: ignore +def memory_replace(agent_state: "AgentState", label: str, old_string: str, new_string: str) -> str: # type: ignore """ The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits. Do NOT attempt to replace long strings, e.g. do not attempt to replace the entire contents of a memory block with a new string. Args: label (str): Section of the memory to be edited, identified by its label. - old_str (str): The text to replace (must match exactly, including whitespace and indentation). - new_str (str): The new text to insert in place of the old text. Do not include line number prefixes. + old_string (str): The text to replace (must match exactly, including whitespace and indentation). + new_string (str): The new text to insert in place of the old text. Do not include line number prefixes. Examples: # Update a block containing information about the user - memory_replace(label="human", old_str="Their name is Alice", new_str="Their name is Bob") + memory_replace(label="human", old_string="Their name is Alice", new_string="Their name is Bob") # Update a block containing a todo list - memory_replace(label="todos", old_str="- [ ] Step 5: Search the web", new_str="- [x] Step 5: Search the web") + memory_replace(label="todos", old_string="- [ ] Step 5: Search the web", new_string="- [x] Step 5: Search the web") # Pass an empty string to - memory_replace(label="human", old_str="Their name is Alice", new_str="") + memory_replace(label="human", old_string="Their name is Alice", new_string="") # Bad example - do NOT add (view-only) line numbers to the args - memory_replace(label="human", old_str="1: Their name is Alice", new_str="1: Their name is Bob") + memory_replace(label="human", old_string="1: Their name is Alice", new_string="1: Their name is Bob") # Bad example - do NOT include the line number warning either - memory_replace(label="human", old_str="# NOTE: Line numbers shown below (with arrows like '1→') are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\n1→ Their name is Alice", new_str="1→ Their name is Bob") + memory_replace(label="human", old_string="# NOTE: Line numbers shown below (with arrows like '1→') are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\n1→ Their name is Alice", new_string="1→ Their name is Bob") # Good example - no line numbers or line number warning (they are view-only), just the text - memory_replace(label="human", old_str="Their name is Alice", new_str="Their name is Bob") + memory_replace(label="human", old_string="Their name is Alice", new_string="Their name is Bob") Returns: str: The updated value of the memory block. """ import re - if bool(re.search(r"\nLine \d+: ", old_str)): + if bool(re.search(r"\nLine \d+: ", old_string)): raise ValueError( - "old_str contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." + "old_string contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." ) - if CORE_MEMORY_LINE_NUMBER_WARNING in old_str: + if CORE_MEMORY_LINE_NUMBER_WARNING in old_string: raise ValueError( - "old_str contains a line number warning, which is not allowed. Do not include line number information when calling memory tools (line numbers are for display purposes only)." + "old_string contains a line number warning, which is not allowed. Do not include line number information when calling memory tools (line numbers are for display purposes only)." ) - if bool(re.search(r"\nLine \d+: ", new_str)): + if bool(re.search(r"\nLine \d+: ", new_string)): raise ValueError( - "new_str contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." + "new_string contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." ) - old_str = str(old_str).expandtabs() - new_str = str(new_str).expandtabs() + old_string = str(old_string).expandtabs() + new_string = str(new_string).expandtabs() current_value = str(agent_state.memory.get_block(label).value).expandtabs() - # Check if old_str is unique in the block - occurences = current_value.count(old_str) + # Check if old_string is unique in the block + occurences = current_value.count(old_string) if occurences == 0: - raise ValueError(f"No replacement was performed, old_str `{old_str}` did not appear verbatim in memory block with label `{label}`.") + raise ValueError( + f"No replacement was performed, old_string `{old_string}` did not appear verbatim in memory block with label `{label}`." + ) elif occurences > 1: content_value_lines = current_value.split("\n") - lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_str in line] + lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_string in line] raise ValueError( - f"No replacement was performed. Multiple occurrences of old_str `{old_str}` in lines {lines}. Please ensure it is unique." + f"No replacement was performed. Multiple occurrences of old_string `{old_string}` in lines {lines}. Please ensure it is unique." ) - # Replace old_str with new_str - new_value = current_value.replace(str(old_str), str(new_str)) + # Replace old_string with new_string + new_value = current_value.replace(str(old_string), str(new_string)) # Write the new content to the block agent_state.memory.update_block_value(label=label, value=new_value) # Create a snippet of the edited section # SNIPPET_LINES = 3 - # replacement_line = current_value.split(old_str)[0].count("\n") + # replacement_line = current_value.split(old_string)[0].count("\n") # start_line = max(0, replacement_line - SNIPPET_LINES) - # end_line = replacement_line + SNIPPET_LINES + new_str.count("\n") + # end_line = replacement_line + SNIPPET_LINES + new_string.count("\n") # snippet = "\n".join(new_value.split("\n")[start_line : end_line + 1]) return new_value -def memory_insert(agent_state: "AgentState", label: str, new_str: str, insert_line: int = -1) -> str: # type: ignore +def memory_insert(agent_state: "AgentState", label: str, new_string: str, insert_line: int = -1) -> str: # type: ignore """ The memory_insert command allows you to insert text at a specific location in a memory block. Args: label (str): Section of the memory to be edited, identified by its label. - new_str (str): The text to insert. Do not include line number prefixes. + new_string (str): The text to insert. Do not include line number prefixes. insert_line (int): The line number after which to insert the text (0 for beginning of file). Defaults to -1 (end of the file). Examples: # Update a block containing information about the user (append to the end of the block) - memory_insert(label="customer", new_str="The customer's ticket number is 12345") + memory_insert(label="customer", new_string="The customer's ticket number is 12345") # Update a block containing information about the user (insert at the beginning of the block) - memory_insert(label="customer", new_str="The customer's ticket number is 12345", insert_line=0) + memory_insert(label="customer", new_string="The customer's ticket number is 12345", insert_line=0) Returns: Optional[str]: None is always returned as this function does not produce a response. """ import re - if bool(re.search(r"\nLine \d+: ", new_str)): + if bool(re.search(r"\nLine \d+: ", new_string)): raise ValueError( - "new_str contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." + "new_string contains a line number prefix, which is not allowed. Do not include line numbers when calling memory tools (line numbers are for display purposes only)." ) - if CORE_MEMORY_LINE_NUMBER_WARNING in new_str: + if CORE_MEMORY_LINE_NUMBER_WARNING in new_string: raise ValueError( - "new_str contains a line number warning, which is not allowed. Do not include line number information when calling memory tools (line numbers are for display purposes only)." + "new_string contains a line number warning, which is not allowed. Do not include line number information when calling memory tools (line numbers are for display purposes only)." ) current_value = str(agent_state.memory.get_block(label).value).expandtabs() - new_str = str(new_str).expandtabs() + new_string = str(new_string).expandtabs() current_value_lines = current_value.split("\n") n_lines = len(current_value_lines) @@ -430,11 +432,11 @@ def memory_insert(agent_state: "AgentState", label: str, new_str: str, insert_li ) # Insert the new string as a line - new_str_lines = new_str.split("\n") - new_value_lines = current_value_lines[:insert_line] + new_str_lines + current_value_lines[insert_line:] + new_string_lines = new_string.split("\n") + new_value_lines = current_value_lines[:insert_line] + new_string_lines + current_value_lines[insert_line:] ( current_value_lines[max(0, insert_line - SNIPPET_LINES) : insert_line] - + new_str_lines + + new_string_lines + current_value_lines[insert_line : insert_line + SNIPPET_LINES] ) diff --git a/letta/services/tool_executor/core_tool_executor.py b/letta/services/tool_executor/core_tool_executor.py index e1896731..d5b7bf76 100644 --- a/letta/services/tool_executor/core_tool_executor.py +++ b/letta/services/tool_executor/core_tool_executor.py @@ -343,48 +343,55 @@ class LettaCoreToolExecutor(ToolExecutor): await self.agent_manager.update_memory_if_changed_async(agent_id=agent_state.id, new_memory=agent_state.memory, actor=actor) return new_value - async def memory_replace(self, agent_state: AgentState, actor: User, label: str, old_str: str, new_str: str) -> str: + async def memory_replace( + self, + agent_state: AgentState, + actor: User, + label: str, + old_string: str, + new_string: str, + ) -> str: if agent_state.memory.get_block(label).read_only: raise ValueError(f"{READ_ONLY_BLOCK_EDIT_ERROR}") - if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(old_str)): + if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(old_string)): raise ValueError( - "old_str contains a line number prefix, which is not allowed. " + "old_string contains a line number prefix, which is not allowed. " "Do not include line numbers when calling memory tools (line " "numbers are for display purposes only)." ) - if CORE_MEMORY_LINE_NUMBER_WARNING in old_str: + if CORE_MEMORY_LINE_NUMBER_WARNING in old_string: raise ValueError( - "old_str contains a line number warning, which is not allowed. " + "old_string contains a line number warning, which is not allowed. " "Do not include line number information when calling memory tools " "(line numbers are for display purposes only)." ) - if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_str)): + if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_string)): raise ValueError( - "new_str contains a line number prefix, which is not allowed. " + "new_string contains a line number prefix, which is not allowed. " "Do not include line numbers when calling memory tools (line " "numbers are for display purposes only)." ) - old_str = str(old_str).expandtabs() - new_str = str(new_str).expandtabs() + old_string = str(old_string).expandtabs() + new_string = str(new_string).expandtabs() current_value = str(agent_state.memory.get_block(label).value).expandtabs() - # Check if old_str is unique in the block - occurences = current_value.count(old_str) + # Check if old_string is unique in the block + occurences = current_value.count(old_string) if occurences == 0: raise ValueError( - f"No replacement was performed, old_str `{old_str}` did not appear verbatim in memory block with label `{label}`." + f"No replacement was performed, old_string `{old_string}` did not appear verbatim in memory block with label `{label}`." ) elif occurences > 1: content_value_lines = current_value.split("\n") - lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_str in line] + lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_string in line] raise ValueError( - f"No replacement was performed. Multiple occurrences of old_str `{old_str}` in lines {lines}. Please ensure it is unique." + f"No replacement was performed. Multiple occurrences of old_string `{old_string}` in lines {lines}. Please ensure it is unique." ) - # Replace old_str with new_str - new_value = current_value.replace(str(old_str), str(new_str)) + # Replace old_string with new_string + new_value = current_value.replace(str(old_string), str(new_string)) # Write the new content to the block agent_state.memory.update_block_value(label=label, value=new_value) @@ -678,27 +685,27 @@ class LettaCoreToolExecutor(ToolExecutor): agent_state: AgentState, actor: User, label: str, - new_str: str, + new_string: str, insert_line: int = -1, ) -> str: if agent_state.memory.get_block(label).read_only: raise ValueError(f"{READ_ONLY_BLOCK_EDIT_ERROR}") - if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_str)): + if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_string)): raise ValueError( - "new_str contains a line number prefix, which is not allowed. Do not " + "new_string contains a line number prefix, which is not allowed. Do not " "include line numbers when calling memory tools (line numbers are for " "display purposes only)." ) - if CORE_MEMORY_LINE_NUMBER_WARNING in new_str: + if CORE_MEMORY_LINE_NUMBER_WARNING in new_string: raise ValueError( - "new_str contains a line number warning, which is not allowed. Do not " + "new_string contains a line number warning, which is not allowed. Do not " "include line number information when calling memory tools (line numbers " "are for display purposes only)." ) current_value = str(agent_state.memory.get_block(label).value).expandtabs() - new_str = str(new_str).expandtabs() + new_string = str(new_string).expandtabs() current_value_lines = current_value.split("\n") n_lines = len(current_value_lines) @@ -714,11 +721,11 @@ class LettaCoreToolExecutor(ToolExecutor): # Insert the new string as a line SNIPPET_LINES = 3 - new_str_lines = new_str.split("\n") - new_value_lines = current_value_lines[:insert_line] + new_str_lines + current_value_lines[insert_line:] + new_string_lines = new_string.split("\n") + new_value_lines = current_value_lines[:insert_line] + new_string_lines + current_value_lines[insert_line:] snippet_lines = ( current_value_lines[max(0, insert_line - SNIPPET_LINES) : insert_line] - + new_str_lines + + new_string_lines + current_value_lines[insert_line : insert_line + SNIPPET_LINES] ) @@ -874,7 +881,14 @@ class LettaCoreToolExecutor(ToolExecutor): f"Your system prompt has been recompiled with the new memory block and is now active in your context." ) - async def memory_str_replace(self, agent_state: AgentState, actor: User, path: str, old_str: str, new_str: str) -> str: + async def memory_str_replace( + self, + agent_state: AgentState, + actor: User, + path: str, + old_string: str, + new_string: str, + ) -> str: """Replace text in a memory block.""" label = path.removeprefix("/memories/").removeprefix("/") @@ -885,44 +899,44 @@ class LettaCoreToolExecutor(ToolExecutor): if memory_block.read_only: raise ValueError(f"{READ_ONLY_BLOCK_EDIT_ERROR}") - if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(old_str)): + if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(old_string)): raise ValueError( - "old_str contains a line number prefix, which is not allowed. " + "old_string contains a line number prefix, which is not allowed. " "Do not include line numbers when calling memory tools (line " "numbers are for display purposes only)." ) - if CORE_MEMORY_LINE_NUMBER_WARNING in old_str: + if CORE_MEMORY_LINE_NUMBER_WARNING in old_string: raise ValueError( - "old_str contains a line number warning, which is not allowed. " + "old_string contains a line number warning, which is not allowed. " "Do not include line number information when calling memory tools " "(line numbers are for display purposes only)." ) - if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_str)): + if bool(MEMORY_TOOLS_LINE_NUMBER_PREFIX_REGEX.search(new_string)): raise ValueError( - "new_str contains a line number prefix, which is not allowed. " + "new_string contains a line number prefix, which is not allowed. " "Do not include line numbers when calling memory tools (line " "numbers are for display purposes only)." ) - old_str = str(old_str).expandtabs() - new_str = str(new_str).expandtabs() + old_string = str(old_string).expandtabs() + new_string = str(new_string).expandtabs() current_value = str(memory_block.value).expandtabs() - # Check if old_str is unique in the block - occurences = current_value.count(old_str) + # Check if old_string is unique in the block + occurences = current_value.count(old_string) if occurences == 0: raise ValueError( - f"No replacement was performed, old_str `{old_str}` did not appear verbatim in memory block with label `{label}`." + f"No replacement was performed, old_string `{old_string}` did not appear verbatim in memory block with label `{label}`." ) elif occurences > 1: content_value_lines = current_value.split("\n") - lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_str in line] + lines = [idx + 1 for idx, line in enumerate(content_value_lines) if old_string in line] raise ValueError( - f"No replacement was performed. Multiple occurrences of old_str `{old_str}` in lines {lines}. Please ensure it is unique." + f"No replacement was performed. Multiple occurrences of old_string `{old_string}` in lines {lines}. Please ensure it is unique." ) - # Replace old_str with new_str - new_value = current_value.replace(str(old_str), str(new_str)) + # Replace old_string with new_string + new_value = current_value.replace(str(old_string), str(new_string)) # Write the new content to the block await self.block_manager.update_block_async(block_id=memory_block.id, block_update=BlockUpdate(value=new_value), actor=actor) diff --git a/tests/test_agent_files/deep-thought.af b/tests/test_agent_files/deep-thought.af index 43b683f2..6a7e932c 100644 --- a/tests/test_agent_files/deep-thought.af +++ b/tests/test_agent_files/deep-thought.af @@ -276,19 +276,19 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "old_str": { + "old_string": { "type": "string", "description": "The text to replace (must match exactly, including whitespace and indentation)." }, - "new_str": { + "new_string": { "type": "string", "description": "The new text to insert in place of the old text. Do not include line number prefixes." } }, "required": [ "label", - "old_str", - "new_str" + "old_string", + "new_string" ] }, "type": null, @@ -319,7 +319,7 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "new_str": { + "new_string": { "type": "string", "description": "The text to insert. Do not include line number prefixes." }, @@ -330,7 +330,7 @@ }, "required": [ "label", - "new_str" + "new_string" ] }, "type": null, diff --git a/tests/test_agent_files/max_messages.af b/tests/test_agent_files/max_messages.af index 346fed99..87b13fb3 100644 --- a/tests/test_agent_files/max_messages.af +++ b/tests/test_agent_files/max_messages.af @@ -799,7 +799,7 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "new_str": { + "new_string": { "type": "string", "description": "The text to insert." }, @@ -810,7 +810,7 @@ }, "required": [ "label", - "new_str" + "new_string" ] }, "type": null, @@ -911,19 +911,19 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "old_str": { + "old_string": { "type": "string", "description": "The text to replace (must match exactly, including whitespace and indentation)." }, - "new_str": { + "new_string": { "type": "string", "description": "The new text to insert in place of the old text. Do not include line number prefixes." } }, "required": [ "label", - "old_str", - "new_str" + "old_string", + "new_string" ] }, "type": null, diff --git a/tests/test_agent_files/test_agent.af b/tests/test_agent_files/test_agent.af index 452ce1bc..91f5116c 100644 --- a/tests/test_agent_files/test_agent.af +++ b/tests/test_agent_files/test_agent.af @@ -1678,7 +1678,7 @@ { "id": "tool-5", "tool_type": "letta_memory_core", - "description": "Memory management tool with various sub-commands for memory block operations.\n\nExamples:\n # Replace text in a memory block\n memory(agent_state, \"str_replace\", path=\"/memories/user_preferences\", old_str=\"theme: dark\", new_str=\"theme: light\")\n\n # Insert text at line 5\n memory(agent_state, \"insert\", path=\"/memories/notes\", insert_line=5, insert_text=\"New note here\")\n\n # Delete a memory block\n memory(agent_state, \"delete\", path=\"/memories/old_notes\")\n\n # Rename a memory block\n memory(agent_state, \"rename\", old_path=\"/memories/temp\", new_path=\"/memories/permanent\")\n\n # Update the description of a memory block\n memory(agent_state, \"rename\", path=\"/memories/temp\", description=\"The user's temporary notes.\")\n\n # Create a memory block with starting text\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\", \"file_text\": \"The user seems to add type hints to all of their Python code.\")\n\n # Create an empty memory block\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\")", + "description": "Memory management tool with various sub-commands for memory block operations.\n\nExamples:\n # Replace text in a memory block\n memory(agent_state, \"str_replace\", path=\"/memories/user_preferences\", old_string=\"theme: dark\", new_string=\"theme: light\")\n\n # Insert text at line 5\n memory(agent_state, \"insert\", path=\"/memories/notes\", insert_line=5, insert_text=\"New note here\")\n\n # Delete a memory block\n memory(agent_state, \"delete\", path=\"/memories/old_notes\")\n\n # Rename a memory block\n memory(agent_state, \"rename\", old_path=\"/memories/temp\", new_path=\"/memories/permanent\")\n\n # Update the description of a memory block\n memory(agent_state, \"rename\", path=\"/memories/temp\", description=\"The user's temporary notes.\")\n\n # Create a memory block with starting text\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\", \"file_text\": \"The user seems to add type hints to all of their Python code.\")\n\n # Create an empty memory block\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\")", "source_type": "python", "name": "memory", "tags": [ @@ -1687,7 +1687,7 @@ "source_code": null, "json_schema": { "name": "memory", - "description": "Memory management tool with various sub-commands for memory block operations.\n\nExamples:\n # Replace text in a memory block\n memory(agent_state, \"str_replace\", path=\"/memories/user_preferences\", old_str=\"theme: dark\", new_str=\"theme: light\")\n\n # Insert text at line 5\n memory(agent_state, \"insert\", path=\"/memories/notes\", insert_line=5, insert_text=\"New note here\")\n\n # Delete a memory block\n memory(agent_state, \"delete\", path=\"/memories/old_notes\")\n\n # Rename a memory block\n memory(agent_state, \"rename\", old_path=\"/memories/temp\", new_path=\"/memories/permanent\")\n\n # Update the description of a memory block\n memory(agent_state, \"rename\", path=\"/memories/temp\", description=\"The user's temporary notes.\")\n\n # Create a memory block with starting text\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\", \"file_text\": \"The user seems to add type hints to all of their Python code.\")\n\n # Create an empty memory block\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\")", + "description": "Memory management tool with various sub-commands for memory block operations.\n\nExamples:\n # Replace text in a memory block\n memory(agent_state, \"str_replace\", path=\"/memories/user_preferences\", old_string=\"theme: dark\", new_string=\"theme: light\")\n\n # Insert text at line 5\n memory(agent_state, \"insert\", path=\"/memories/notes\", insert_line=5, insert_text=\"New note here\")\n\n # Delete a memory block\n memory(agent_state, \"delete\", path=\"/memories/old_notes\")\n\n # Rename a memory block\n memory(agent_state, \"rename\", old_path=\"/memories/temp\", new_path=\"/memories/permanent\")\n\n # Update the description of a memory block\n memory(agent_state, \"rename\", path=\"/memories/temp\", description=\"The user's temporary notes.\")\n\n # Create a memory block with starting text\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\", \"file_text\": \"The user seems to add type hints to all of their Python code.\")\n\n # Create an empty memory block\n memory(agent_state, \"create\", path=\"/memories/coding_preferences\", \"description\": \"The user's coding preferences.\")", "parameters": { "type": "object", "properties": { @@ -1707,11 +1707,11 @@ "type": "string", "description": "The description to set in the memory block (for create, rename)" }, - "old_str": { + "old_string": { "type": "string", "description": "Old text to replace (for str_replace)" }, - "new_str": { + "new_string": { "type": "string", "description": "New text to replace with (for str_replace)" }, diff --git a/tests/test_agent_files/test_agent_with_files_and_sources.af b/tests/test_agent_files/test_agent_with_files_and_sources.af index f2b75b2f..81b8cbe9 100644 --- a/tests/test_agent_files/test_agent_with_files_and_sources.af +++ b/tests/test_agent_files/test_agent_with_files_and_sources.af @@ -514,7 +514,7 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "new_str": { + "new_string": { "type": "string", "description": "The text to insert. Do not include line number prefixes." }, @@ -525,7 +525,7 @@ }, "required": [ "label", - "new_str" + "new_string" ] } }, @@ -557,19 +557,19 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "old_str": { + "old_string": { "type": "string", "description": "The text to replace (must match exactly, including whitespace and indentation)." }, - "new_str": { + "new_string": { "type": "string", "description": "The new text to insert in place of the old text. Do not include line number prefixes." } }, "required": [ "label", - "old_str", - "new_str" + "old_string", + "new_string" ] } }, diff --git a/tests/test_agent_files/test_basic_agent_with_blocks_tools_messages_v2.af b/tests/test_agent_files/test_basic_agent_with_blocks_tools_messages_v2.af index 43103213..a92096e1 100644 --- a/tests/test_agent_files/test_basic_agent_with_blocks_tools_messages_v2.af +++ b/tests/test_agent_files/test_basic_agent_with_blocks_tools_messages_v2.af @@ -574,7 +574,7 @@ { "id": "tool-6", "tool_type": "letta_sleeptime_core", - "description": "The memory_insert command allows you to insert text at a specific location in a memory block.\n\nExamples:\n # Update a block containing information about the user (append to the end of the block)\n memory_insert(label=\"customer\", new_str=\"The customer's ticket number is 12345\")\n\n # Update a block containing information about the user (insert at the beginning of the block)\n memory_insert(label=\"customer\", new_str=\"The customer's ticket number is 12345\", insert_line=0)\n\n Returns:\n Optional[str]: None is always returned as this function does not produce a response.", + "description": "The memory_insert command allows you to insert text at a specific location in a memory block.\n\nExamples:\n # Update a block containing information about the user (append to the end of the block)\n memory_insert(label=\"customer\", new_string=\"The customer's ticket number is 12345\")\n\n # Update a block containing information about the user (insert at the beginning of the block)\n memory_insert(label=\"customer\", new_string=\"The customer's ticket number is 12345\", insert_line=0)\n\n Returns:\n Optional[str]: None is always returned as this function does not produce a response.", "source_type": "python", "name": "memory_insert", "tags": [ @@ -583,7 +583,7 @@ "source_code": null, "json_schema": { "name": "memory_insert", - "description": "The memory_insert command allows you to insert text at a specific location in a memory block.\n\nExamples:\n # Update a block containing information about the user (append to the end of the block)\n memory_insert(label=\"customer\", new_str=\"The customer's ticket number is 12345\")\n\n # Update a block containing information about the user (insert at the beginning of the block)\n memory_insert(label=\"customer\", new_str=\"The customer's ticket number is 12345\", insert_line=0)\n\n Returns:\n Optional[str]: None is always returned as this function does not produce a response.", + "description": "The memory_insert command allows you to insert text at a specific location in a memory block.\n\nExamples:\n # Update a block containing information about the user (append to the end of the block)\n memory_insert(label=\"customer\", new_string=\"The customer's ticket number is 12345\")\n\n # Update a block containing information about the user (insert at the beginning of the block)\n memory_insert(label=\"customer\", new_string=\"The customer's ticket number is 12345\", insert_line=0)\n\n Returns:\n Optional[str]: None is always returned as this function does not produce a response.", "parameters": { "type": "object", "properties": { @@ -591,7 +591,7 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "new_str": { + "new_string": { "type": "string", "description": "The text to insert. Do not include line number prefixes." }, @@ -602,7 +602,7 @@ }, "required": [ "label", - "new_str" + "new_string" ] } }, @@ -618,7 +618,7 @@ { "id": "tool-1", "tool_type": "letta_sleeptime_core", - "description": "The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits.\n\nExamples:\n # Update a block containing information about the user\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"Their name is Bob\")\n\n # Update a block containing a todo list\n memory_replace(label=\"todos\", old_str=\"- [ ] Step 5: Search the web\", new_str=\"- [x] Step 5: Search the web\")\n\n # Pass an empty string to\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"\")\n\n # Bad example - do NOT add (view-only) line numbers to the args\n memory_replace(label=\"human\", old_str=\"Line 1: Their name is Alice\", new_str=\"Line 1: Their name is Bob\")\n\n # Bad example - do NOT include the number number warning either\n memory_replace(label=\"human\", old_str=\"# NOTE: Line numbers shown below are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\nLine 1: Their name is Alice\", new_str=\"Line 1: Their name is Bob\")\n\n # Good example - no line numbers or line number warning (they are view-only), just the text\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"Their name is Bob\")\n\n Returns:\n str: The success message", + "description": "The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits.\n\nExamples:\n # Update a block containing information about the user\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"Their name is Bob\")\n\n # Update a block containing a todo list\n memory_replace(label=\"todos\", old_string=\"- [ ] Step 5: Search the web\", new_string=\"- [x] Step 5: Search the web\")\n\n # Pass an empty string to\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"\")\n\n # Bad example - do NOT add (view-only) line numbers to the args\n memory_replace(label=\"human\", old_string=\"Line 1: Their name is Alice\", new_string=\"Line 1: Their name is Bob\")\n\n # Bad example - do NOT include the number number warning either\n memory_replace(label=\"human\", old_string=\"# NOTE: Line numbers shown below are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\nLine 1: Their name is Alice\", new_string=\"Line 1: Their name is Bob\")\n\n # Good example - no line numbers or line number warning (they are view-only), just the text\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"Their name is Bob\")\n\n Returns:\n str: The success message", "source_type": "python", "name": "memory_replace", "tags": [ @@ -627,7 +627,7 @@ "source_code": null, "json_schema": { "name": "memory_replace", - "description": "The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits.\n\nExamples:\n # Update a block containing information about the user\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"Their name is Bob\")\n\n # Update a block containing a todo list\n memory_replace(label=\"todos\", old_str=\"- [ ] Step 5: Search the web\", new_str=\"- [x] Step 5: Search the web\")\n\n # Pass an empty string to\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"\")\n\n # Bad example - do NOT add (view-only) line numbers to the args\n memory_replace(label=\"human\", old_str=\"Line 1: Their name is Alice\", new_str=\"Line 1: Their name is Bob\")\n\n # Bad example - do NOT include the number number warning either\n memory_replace(label=\"human\", old_str=\"# NOTE: Line numbers shown below are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\nLine 1: Their name is Alice\", new_str=\"Line 1: Their name is Bob\")\n\n # Good example - no line numbers or line number warning (they are view-only), just the text\n memory_replace(label=\"human\", old_str=\"Their name is Alice\", new_str=\"Their name is Bob\")\n\n Returns:\n str: The success message", + "description": "The memory_replace command allows you to replace a specific string in a memory block with a new string. This is used for making precise edits.\n\nExamples:\n # Update a block containing information about the user\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"Their name is Bob\")\n\n # Update a block containing a todo list\n memory_replace(label=\"todos\", old_string=\"- [ ] Step 5: Search the web\", new_string=\"- [x] Step 5: Search the web\")\n\n # Pass an empty string to\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"\")\n\n # Bad example - do NOT add (view-only) line numbers to the args\n memory_replace(label=\"human\", old_string=\"Line 1: Their name is Alice\", new_string=\"Line 1: Their name is Bob\")\n\n # Bad example - do NOT include the number number warning either\n memory_replace(label=\"human\", old_string=\"# NOTE: Line numbers shown below are to help during editing. Do NOT include line number prefixes in your memory edit tool calls.\\nLine 1: Their name is Alice\", new_string=\"Line 1: Their name is Bob\")\n\n # Good example - no line numbers or line number warning (they are view-only), just the text\n memory_replace(label=\"human\", old_string=\"Their name is Alice\", new_string=\"Their name is Bob\")\n\n Returns:\n str: The success message", "parameters": { "type": "object", "properties": { @@ -635,19 +635,19 @@ "type": "string", "description": "Section of the memory to be edited, identified by its label." }, - "old_str": { + "old_string": { "type": "string", "description": "The text to replace (must match exactly, including whitespace and indentation)." }, - "new_str": { + "new_string": { "type": "string", "description": "The new text to insert in place of the old text. Do not include line number prefixes." } }, "required": [ "label", - "old_str", - "new_str" + "old_string", + "new_string" ] } }, diff --git a/tests/test_sdk_client.py b/tests/test_sdk_client.py index 4c0ddf2a..99de594c 100644 --- a/tests/test_sdk_client.py +++ b/tests/test_sdk_client.py @@ -2438,7 +2438,7 @@ def test_calling_tools(client: LettaSDKClient, agent: AgentState) -> None: assert len(blocks) == 1, f"Expected 1 block, got {len(blocks)}" # test calling a stateful tool - result = client.agents.tools.run(agent_id=agent.id, tool_name="memory_insert", args={"label": "human", "new_str": "test"}) + result = client.agents.tools.run(agent_id=agent.id, tool_name="memory_insert", args={"label": "human", "new_string": "test"}) assert result.status == "success", f"Expected success, got {result.status}" # get the block block = client.agents.blocks.retrieve(agent_id=agent.id, block_label="human")