fix(memory): standardize tool parameter names (#9552)
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 <noreply@letta.com>
EOF
)
This commit is contained in:
150
fern/pages/agents/base_tools.mdx
Normal file
150
fern/pages/agents/base_tools.mdx
Normal file
@@ -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)
|
||||
@@ -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]
|
||||
)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)"
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
},
|
||||
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user